mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-26 23:50:52 +01:00
changes
This commit is contained in:
parent
1546a0446b
commit
70c1690e39
@ -0,0 +1,6 @@
|
||||
export interface IMarketplaceSearchOptions {
|
||||
query: string;
|
||||
type: number;
|
||||
minPrice: number;
|
||||
maxPrice: number;
|
||||
}
|
@ -2,8 +2,8 @@ import { IObjectData } from '@nitrots/nitro-renderer';
|
||||
|
||||
export class MarketplaceOfferData
|
||||
{
|
||||
public static TYPE_LANDSCAPE: number = 1;
|
||||
public static TYPE_FLOOR: number = 2;
|
||||
public static readonly TYPE_FLOOR: number = 1;
|
||||
public static readonly TYPE_WALL: number = 2;
|
||||
|
||||
private _offerId: number;
|
||||
private _furniId: number;
|
||||
|
@ -0,0 +1,6 @@
|
||||
export class MarketplaceSearchType
|
||||
{
|
||||
public static readonly BY_ACTIVITY = 1;
|
||||
public static readonly BY_VALUE = 2;
|
||||
public static readonly ADVANCED = 3;
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
import { CancelMarketplaceOfferMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { GetRoomEngine, LocalizeText } from '../../../../../../../api';
|
||||
import { SendMessageHook } from '../../../../../../../hooks';
|
||||
import { NitroCardGridItemView } from '../../../../../../../layout';
|
||||
import { MarketplaceOfferData } from '../common/MarketplaceOfferData';
|
||||
|
||||
export const OWN_OFFER = 1;
|
||||
export const OTHER_OFFER = 2;
|
||||
export const PUBLIC_OFFER = 2;
|
||||
|
||||
export interface MarketplaceItemViewProps
|
||||
{
|
||||
@ -14,7 +16,7 @@ export interface MarketplaceItemViewProps
|
||||
|
||||
export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
|
||||
{
|
||||
const { offerData = null, type = OTHER_OFFER } = props;
|
||||
const { offerData = null, type = PUBLIC_OFFER } = props;
|
||||
|
||||
const getImageUrlForOffer = useCallback( () =>
|
||||
{
|
||||
@ -22,9 +24,9 @@ export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
|
||||
|
||||
switch(offerData.furniType)
|
||||
{
|
||||
case 1:
|
||||
case MarketplaceOfferData.TYPE_FLOOR:
|
||||
return GetRoomEngine().getFurnitureFloorIconUrl(offerData.furniId);
|
||||
case 2:
|
||||
case MarketplaceOfferData.TYPE_WALL:
|
||||
return GetRoomEngine().getFurnitureWallIconUrl(offerData.furniId, offerData.extraData);
|
||||
}
|
||||
|
||||
@ -53,6 +55,8 @@ export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
|
||||
{
|
||||
if(!offerData) return '';
|
||||
|
||||
if(offerData.timeLeftMinutes <= 0) return LocalizeText('catalog.marketplace.offer.expired');
|
||||
|
||||
const time = Math.max(1, offerData.timeLeftMinutes);
|
||||
const hours = Math.floor(time / 60);
|
||||
const minutes = time - (hours * 60);
|
||||
@ -66,10 +70,15 @@ export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
|
||||
return LocalizeText('catalog.marketplace.offer.time_left', ['time'], [text] );
|
||||
}, [offerData]);
|
||||
|
||||
const takeItemBack = useCallback(() =>
|
||||
{
|
||||
SendMessageHook(new CancelMarketplaceOfferMessageComposer(offerData.offerId));
|
||||
}, [offerData.offerId])
|
||||
|
||||
return (
|
||||
<NitroCardGridItemView className='w-100 marketplace-item'>
|
||||
<img src={ getImageUrlForOffer() } className='mx-3'/>
|
||||
<div className='h-100 flex-grow-1 lh-1'>
|
||||
<NitroCardGridItemView className='w-100 marketplace-item align-items-center'>
|
||||
<img src={ getImageUrlForOffer() } className='mx-3' alt='' />
|
||||
<div className='h-100 flex-grow-1 justify-content-center '>
|
||||
<div className='fw-bold'>{getMarketplaceOfferTitle()}</div>
|
||||
<div className='fst-italic fs-6'>{getMarketplaceOfferDescription()}</div>
|
||||
|
||||
@ -78,14 +87,18 @@ export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
|
||||
<div>{ offerTime() }</div>
|
||||
</>
|
||||
}
|
||||
{ type === OTHER_OFFER && <>
|
||||
{ type === PUBLIC_OFFER && <>
|
||||
<div>{ LocalizeText('catalog.marketplace.offer.price_public_item', ['price', 'average'], [offerData.price.toString(), offerData.averagePrice.toString() ]) }</div>
|
||||
<div>{ LocalizeText('catalog.marketplace.offer_count', ['count'], [offerData.offerCount.toString()]) }</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
<div className='btn-group-vertical mx-1'>
|
||||
{ type === OWN_OFFER && <button className='btn btn-secondary btn-sm'>{LocalizeText('catalog.marketplace.offer.pick')}</button>}
|
||||
<div className='btn-group-vertical mx-1 gap-2'>
|
||||
{ type === OWN_OFFER && <button className='btn btn-secondary btn-sm' onClick={ takeItemBack }>{ LocalizeText('catalog.marketplace.offer.pick') }</button>}
|
||||
{ type === PUBLIC_OFFER && <>
|
||||
<button className='btn btn-secondary btn-sm'>{ LocalizeText('buy') }</button>
|
||||
<button className='btn btn-secondary btn-sm' disabled={true}>{ LocalizeText('catalog.marketplace.view_more') }</button>
|
||||
</>}
|
||||
</div>
|
||||
</NitroCardGridItemView>)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { GetMarketplaceOwnOffersMessageComposer, MarketplaceOwnOffersEvent } from '@nitrots/nitro-renderer';
|
||||
import { GetMarketplaceOwnOffersMessageComposer, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../../../../api';
|
||||
import { BatchUpdates, CreateMessageHook, SendMessageHook, UseMountEffect } from '../../../../../../../hooks';
|
||||
@ -6,6 +6,7 @@ import { NitroCardGridView } from '../../../../../../../layout';
|
||||
import { NitroLayoutBase } from '../../../../../../../layout/base';
|
||||
import { CatalogLayoutProps } from '../../CatalogLayout.types';
|
||||
import { MarketplaceOfferData } from '../common/MarketplaceOfferData';
|
||||
import { MarketPlaceOfferState } from '../common/MarketplaceOfferState';
|
||||
import { MarketplaceItemView, OWN_OFFER } from '../marketplace-item/MarketplaceItemView';
|
||||
|
||||
export interface CatalogLayoutMarketplaceOwnItemsViewProps extends CatalogLayoutProps
|
||||
@ -46,13 +47,39 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutMarketplaceOw
|
||||
|
||||
CreateMessageHook(MarketplaceOwnOffersEvent, onMarketPlaceOwnOffersEvent);
|
||||
|
||||
const redeemSoldOffers = useCallback(() =>
|
||||
{
|
||||
setOffers(prev =>
|
||||
{
|
||||
const newVal = new Map(prev);
|
||||
|
||||
const idsToDelete = [];
|
||||
|
||||
for(const offer of newVal.values())
|
||||
{
|
||||
if(offer.status === MarketPlaceOfferState.SOLD)
|
||||
{
|
||||
idsToDelete.push(offer.offerId);
|
||||
}
|
||||
}
|
||||
|
||||
for(const offerId of idsToDelete)
|
||||
{
|
||||
newVal.delete(offerId);
|
||||
}
|
||||
return newVal;
|
||||
})
|
||||
|
||||
SendMessageHook(new RedeemMarketplaceOfferCreditsMessageComposer());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{ (creditsWaiting <= 0) && <NitroLayoutBase className='text-black'>{LocalizeText('catalog.marketplace.redeem.no_sold_items')}</NitroLayoutBase>}
|
||||
|
||||
{ (creditsWaiting > 0) && <NitroLayoutBase className='text-black'>{LocalizeText('catalog.marketplace.redeem.get_credits', ['count', 'credits'], ['0', creditsWaiting.toString()])}</NitroLayoutBase>}
|
||||
|
||||
<button className='btn btn-primary btn-sm mx-auto' disabled={creditsWaiting <= 0}>{LocalizeText('catalog.marketplace.offer.redeem')}</button>
|
||||
<button className='btn btn-primary btn-sm mx-auto' disabled={creditsWaiting <= 0} onClick={redeemSoldOffers}>{LocalizeText('catalog.marketplace.offer.redeem')}</button>
|
||||
|
||||
<div className='text-black'>{LocalizeText('catalog.marketplace.items_found', ['count'], [offers.size.toString()])}</div>
|
||||
<NitroCardGridView columns={1} className='text-black'>
|
||||
|
@ -1,7 +1,18 @@
|
||||
import { FC } from 'react';
|
||||
import { UseMountEffect } from '../../../../../../../hooks';
|
||||
import { GetMarketplaceOffersMessageComposer, MarketPlaceOffersEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../../../../api';
|
||||
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../../../../hooks';
|
||||
import { NitroCardGridView } from '../../../../../../../layout';
|
||||
import { CatalogLayoutProps } from '../../CatalogLayout.types';
|
||||
import { IMarketplaceSearchOptions } from '../common/IMarketplaceSearchOptions';
|
||||
import { MarketplaceOfferData } from '../common/MarketplaceOfferData';
|
||||
import { MarketplaceSearchType } from '../common/MarketplaceSearchType';
|
||||
import { MarketplaceItemView, PUBLIC_OFFER } from '../marketplace-item/MarketplaceItemView';
|
||||
import { SearchFormView } from './SearchFormView';
|
||||
|
||||
const SORT_TYPES_VALUE = [1, 2];
|
||||
const SORT_TYPES_ACTIVITY = [3, 4, 5, 6];
|
||||
const SORT_TYPES_ADVANCED = [1, 2, 3, 4, 5, 6];
|
||||
export interface CatalogLayoutMarketplacePublicItemsViewProps extends CatalogLayoutProps
|
||||
{
|
||||
|
||||
@ -9,10 +20,73 @@ export interface CatalogLayoutMarketplacePublicItemsViewProps extends CatalogLay
|
||||
|
||||
export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplacePublicItemsViewProps> = props =>
|
||||
{
|
||||
UseMountEffect(() =>
|
||||
const [ searchType, setSearchType ] = useState(MarketplaceSearchType.BY_ACTIVITY);
|
||||
const [ totalItemsFound, setTotalItemsFound ] = useState(0);
|
||||
const [ offers, setOffers ] = useState(new Map<number, MarketplaceOfferData>());
|
||||
|
||||
const requestOffers = useCallback((options: IMarketplaceSearchOptions) =>
|
||||
{
|
||||
//request stuff
|
||||
SendMessageHook(new GetMarketplaceOffersMessageComposer(options.minPrice, options.maxPrice, options.query, options.type))
|
||||
}, []);
|
||||
|
||||
const getSortTypes = useMemo( () =>
|
||||
{
|
||||
switch(searchType)
|
||||
{
|
||||
case MarketplaceSearchType.BY_ACTIVITY:
|
||||
return SORT_TYPES_ACTIVITY;
|
||||
case MarketplaceSearchType.BY_VALUE:
|
||||
return SORT_TYPES_VALUE;
|
||||
case MarketplaceSearchType.ADVANCED:
|
||||
return SORT_TYPES_ADVANCED;
|
||||
}
|
||||
return [];
|
||||
}, [searchType]);
|
||||
|
||||
const onMarketPlaceOffersEvent = useCallback( (event: MarketPlaceOffersEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser) return;
|
||||
|
||||
const latestOffers = new Map<number, MarketplaceOfferData>();
|
||||
parser.offers.forEach(entry =>
|
||||
{
|
||||
const offerEntry = new MarketplaceOfferData(entry.offerId, entry.furniId, entry.furniType, entry.extraData, entry.stuffData, entry.price, entry.status, entry.averagePrice, entry.offerCount);
|
||||
offerEntry.timeLeftMinutes = entry.timeLeftMinutes;
|
||||
latestOffers.set(entry.offerId, offerEntry);
|
||||
});
|
||||
|
||||
return null;
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setTotalItemsFound(parser.totalItemsFound);
|
||||
setOffers(latestOffers);
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
CreateMessageHook(MarketPlaceOffersEvent, onMarketPlaceOffersEvent);
|
||||
|
||||
return (<>
|
||||
<div className="btn-group" role="group">
|
||||
<button type="button" className={`btn btn-primary ${searchType === MarketplaceSearchType.BY_ACTIVITY ? 'active' : ''}`} onClick={() => setSearchType(MarketplaceSearchType.BY_ACTIVITY)}>
|
||||
{ LocalizeText('catalog.marketplace.search_by_activity') }
|
||||
</button>
|
||||
<button type="button" className={`btn btn-primary ${searchType === MarketplaceSearchType.BY_VALUE ? 'active' : ''}`} onClick={() => setSearchType(MarketplaceSearchType.BY_VALUE)}>
|
||||
{ LocalizeText('catalog.marketplace.search_by_value') }
|
||||
</button>
|
||||
<button type="button" className={`btn btn-primary ${searchType === MarketplaceSearchType.ADVANCED ? 'active' : ''}`} onClick={() => setSearchType(MarketplaceSearchType.ADVANCED)}>
|
||||
{ LocalizeText('catalog.marketplace.search_advanced') }
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<SearchFormView sortTypes={ getSortTypes } searchType={ searchType } onSearch={ requestOffers }/>
|
||||
|
||||
<div className='text-black'>{LocalizeText('catalog.marketplace.items_found', ['count'], [offers.size.toString()])}</div>
|
||||
<NitroCardGridView columns={1} className='text-black'>
|
||||
{
|
||||
Array.from(offers.values()).map( (entry, index) => <MarketplaceItemView key={ index } offerData={ entry } type={ PUBLIC_OFFER } />)
|
||||
}
|
||||
</NitroCardGridView>
|
||||
</>);
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../../../../api';
|
||||
import { IMarketplaceSearchOptions } from '../common/IMarketplaceSearchOptions';
|
||||
import { MarketplaceSearchType } from '../common/MarketplaceSearchType';
|
||||
|
||||
export interface SearchFormViewProps
|
||||
{
|
||||
searchType: number;
|
||||
sortTypes: number[];
|
||||
onSearch(options: IMarketplaceSearchOptions): void;
|
||||
}
|
||||
|
||||
export const SearchFormView: FC<SearchFormViewProps> = props =>
|
||||
{
|
||||
const { searchType = null, sortTypes = null, onSearch = null } = props;
|
||||
const [ sortType, setSortType ] = useState(sortTypes ? sortTypes[0] : 3); // first item of SORT_TYPES_ACTIVITY
|
||||
const [ searchQuery, setSearchQuery ] = useState('');
|
||||
const [ min, setMin ] = useState(0);
|
||||
const [ max, setMax ] = useState(0);
|
||||
|
||||
const onSortTypeChange = useCallback((sortType: number) =>
|
||||
{
|
||||
setSortType(sortType);
|
||||
if(searchType === MarketplaceSearchType.BY_ACTIVITY || searchType === MarketplaceSearchType.BY_VALUE)
|
||||
onSearch({ minPrice: -1, maxPrice: -1, query: '', type: sortType });
|
||||
}, [onSearch, searchType]);
|
||||
|
||||
const onClickSearch = useCallback(() =>
|
||||
{
|
||||
const minPrice = min > 0 ? min : -1;
|
||||
const maxPrice = max > 0 ? max : -1;
|
||||
|
||||
onSearch({ minPrice: minPrice, maxPrice: maxPrice, type: sortType, query: searchQuery })
|
||||
}, [max, min, onSearch, searchQuery, sortType]);
|
||||
|
||||
useEffect( () =>
|
||||
{
|
||||
if(!sortTypes || !sortTypes.length) return;
|
||||
|
||||
const sortType = sortTypes[0];
|
||||
setSortType(sortType);
|
||||
|
||||
if(searchType === MarketplaceSearchType.BY_ACTIVITY || MarketplaceSearchType.BY_VALUE === searchType)
|
||||
onSearch({ minPrice: -1, maxPrice: -1, query: '', type: sortType });
|
||||
}, [onSearch, searchType, sortTypes]);
|
||||
|
||||
return (<>
|
||||
<div className="d-flex flex-row text-black">
|
||||
<div className="mr-2 align-self-center col-4" style={ { whiteSpace: 'nowrap' } }>{ LocalizeText('catalog.marketplace.sort_order') }</div>
|
||||
<select className="form-control form-control-sm" value={sortType} onChange={ (event) => onSortTypeChange(parseInt(event.target.value)) }>
|
||||
{ sortTypes.map( (type, index) => <option key={index} value={type}>{ LocalizeText(`catalog.marketplace.sort.${type}`) }</option>)}
|
||||
</select>
|
||||
</div>
|
||||
{ searchType === MarketplaceSearchType.ADVANCED && <>
|
||||
<div className="d-flex flex-row text-black">
|
||||
<div className="mr-2 align-self-center col-4" style={ { whiteSpace: 'nowrap' } }>{ LocalizeText('catalog.marketplace.search_name') }</div>
|
||||
<input className="form-control form-control-sm" type="text" value={ searchQuery} onChange={event => setSearchQuery(event.target.value)}/>
|
||||
</div>
|
||||
|
||||
<div className="d-flex flex-row text-black">
|
||||
<div className="mr-2 align-self-center col-4" style={ { whiteSpace: 'nowrap' } }>{ LocalizeText('catalog.marketplace.search_price') }</div>
|
||||
<input className="form-control form-control-sm" type="number" min={0} value={ min } onChange={ event => setMin(event.target.valueAsNumber) } />
|
||||
<input className="form-control form-control-sm" type="number" min={0} value={ max } onChange={ event => setMax(event.target.valueAsNumber) } />
|
||||
</div>
|
||||
|
||||
<button className="btn btn-secondary btn-sm float-end mx-auto" onClick={onClickSearch}>{ LocalizeText('generic.search') }</button>
|
||||
</>
|
||||
}
|
||||
</>);
|
||||
}
|
Loading…
Reference in New Issue
Block a user