Merge pull request #49 from billsonnn/feature/marketplace

Feature/marketplace
This commit is contained in:
Bill 2022-01-07 00:36:19 -05:00 committed by GitHub
commit 96cf11da3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 975 additions and 126 deletions

View File

@ -120,24 +120,24 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler
{ {
if(userData.ownerId === ownerId) if(userData.ownerId === ownerId)
{ {
if(userData.hasSaddle && (specialType === FurniCategory._Str_6096)) replace = true; if(userData.hasSaddle && (specialType === FurniCategory.PET_SADDLE)) replace = true;
const figureParts = userData.figure.split(' '); const figureParts = userData.figure.split(' ');
const figurePart = (figureParts.length ? parseInt(figureParts[0]) : -1); const figurePart = (figureParts.length ? parseInt(figureParts[0]) : -1);
if(figurePart === part) if(figurePart === part)
{ {
if(specialType === FurniCategory._Str_6915) if(specialType === FurniCategory.MONSTERPLANT_REVIVAL)
{ {
if(!userData.canRevive) continue; if(!userData.canRevive) continue;
} }
if(specialType === FurniCategory._Str_8726) if(specialType === FurniCategory.MONSTERPLANT_REBREED)
{ {
if((userData.petLevel < 7) || userData.canRevive || userData.canBreed) continue; if((userData.petLevel < 7) || userData.canRevive || userData.canBreed) continue;
} }
if(specialType === FurniCategory._Str_9449) if(specialType === FurniCategory.MONSTERPLANT_FERTILIZE)
{ {
if((userData.petLevel >= 7) || userData.canRevive) continue; if((userData.petLevel >= 7) || userData.canRevive) continue;
} }

View File

@ -0,0 +1,20 @@
import { CatalogEvent } from '.';
import { FurnitureItem } from '../../views/inventory/common/FurnitureItem';
export class CatalogPostMarketplaceOfferEvent extends CatalogEvent
{
public static readonly POST_MARKETPLACE = 'CE_POST_MARKETPLACE';
private _item: FurnitureItem;
constructor(item: FurnitureItem)
{
super(CatalogPostMarketplaceOfferEvent.POST_MARKETPLACE);
this._item = item;
}
public get item(): FurnitureItem
{
return this._item;
}
}

View File

@ -1,12 +1,15 @@
import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent, UserSubscriptionEvent } from '@nitrots/nitro-renderer'; import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceConfigurationEvent, MarketplaceMakeOfferResult, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent, UserSubscriptionEvent } from '@nitrots/nitro-renderer';
import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent'; import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent';
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { LocalizeText } from '../../api';
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent } from '../../events'; import { CatalogNameResultEvent, CatalogPurchaseFailureEvent } from '../../events';
import { CatalogGiftReceiverNotFoundEvent } from '../../events/catalog/CatalogGiftReceiverNotFoundEvent'; import { CatalogGiftReceiverNotFoundEvent } from '../../events/catalog/CatalogGiftReceiverNotFoundEvent';
import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent'; import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent';
import { CatalogPurchaseSoldOutEvent } from '../../events/catalog/CatalogPurchaseSoldOutEvent'; import { CatalogPurchaseSoldOutEvent } from '../../events/catalog/CatalogPurchaseSoldOutEvent';
import { dispatchUiEvent } from '../../hooks/events/ui/ui-event'; import { dispatchUiEvent } from '../../hooks/events/ui/ui-event';
import { CreateMessageHook } from '../../hooks/messages/message-event'; import { CreateMessageHook } from '../../hooks/messages/message-event';
import { NotificationAlertType } from '../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../notification-center/common/NotificationUtilities';
import { CatalogMessageHandlerProps } from './CatalogMessageHandler.types'; import { CatalogMessageHandlerProps } from './CatalogMessageHandler.types';
import { CatalogPetPalette } from './common/CatalogPetPalette'; import { CatalogPetPalette } from './common/CatalogPetPalette';
import { SubscriptionInfo } from './common/SubscriptionInfo'; import { SubscriptionInfo } from './common/SubscriptionInfo';
@ -164,6 +167,43 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
}); });
}, [ dispatchCatalogState ]); }, [ dispatchCatalogState ]);
const onMarketplaceMakeOfferResult = useCallback((event: MarketplaceMakeOfferResult) =>
{
const parser = event.getParser();
if(!parser) return;
let title = '';
if(parser.result === 1)
{
title = LocalizeText('inventory.marketplace.result.title.success');
}
else
{
title = LocalizeText('inventory.marketplace.result.title.failure');
}
const message = LocalizeText(`inventory.marketplace.result.${parser.result}`);
NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title);
}, []);
const onMarketplaceConfigurationEvent = useCallback((event: MarketplaceConfigurationEvent) =>
{
const parser = event.getParser();
if(!parser) return;
console.log(parser);
dispatchCatalogState({
type: CatalogActions.SET_MARKETPLACE_CONFIGURATION,
payload: {
marketplaceConfiguration: parser
}
});
}, [dispatchCatalogState]);
CreateMessageHook(CatalogPagesListEvent, onCatalogPagesListEvent); CreateMessageHook(CatalogPagesListEvent, onCatalogPagesListEvent);
CreateMessageHook(CatalogPageMessageEvent, onCatalogPageMessageEvent); CreateMessageHook(CatalogPageMessageEvent, onCatalogPageMessageEvent);
CreateMessageHook(PurchaseOKMessageEvent, onPurchaseOKMessageEvent); CreateMessageHook(PurchaseOKMessageEvent, onPurchaseOKMessageEvent);
@ -179,6 +219,8 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent); CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent);
CreateMessageHook(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent); CreateMessageHook(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent);
CreateMessageHook(GiftWrappingConfigurationEvent, onGiftWrappingConfigurationEvent); CreateMessageHook(GiftWrappingConfigurationEvent, onGiftWrappingConfigurationEvent);
CreateMessageHook(MarketplaceMakeOfferResult, onMarketplaceMakeOfferResult);
CreateMessageHook(MarketplaceConfigurationEvent, onMarketplaceConfigurationEvent);
return null; return null;
} }

View File

@ -1,8 +1,9 @@
import { GetCatalogIndexComposer, GetCatalogPageComposer, GetGiftWrappingConfigurationComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer'; import { GetCatalogIndexComposer, GetCatalogPageComposer, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api';
import { CREDITS, PlaySound } from '../../api/utils/PlaySound'; import { CREDITS, PlaySound } from '../../api/utils/PlaySound';
import { CatalogEvent } from '../../events'; import { CatalogEvent } from '../../events';
import { UseMountEffect } from '../../hooks';
import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages/message-event'; import { SendMessageHook } from '../../hooks/messages/message-event';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout';
@ -14,6 +15,7 @@ import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { CatalogGiftView } from './views/gift/CatalogGiftView';
import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView'; import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView';
import { CatalogPageView } from './views/page/CatalogPageView'; import { CatalogPageView } from './views/page/CatalogPageView';
import { MarketplacePostOfferView } from './views/page/layout/marketplace/post-offer/MarketplacePostOfferView';
export const CatalogView: FC<CatalogViewProps> = props => export const CatalogView: FC<CatalogViewProps> = props =>
{ {
@ -114,7 +116,6 @@ export const CatalogView: FC<CatalogViewProps> = props =>
if(loadCatalog) if(loadCatalog)
{ {
SendMessageHook(new GetCatalogIndexComposer(CatalogMode.MODE_NORMAL)); SendMessageHook(new GetCatalogIndexComposer(CatalogMode.MODE_NORMAL));
SendMessageHook(new GetGiftWrappingConfigurationComposer());
return; return;
} }
@ -188,6 +189,12 @@ export const CatalogView: FC<CatalogViewProps> = props =>
} }
}, []); }, []);
UseMountEffect(() =>
{
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
SendMessageHook(new GetGiftWrappingConfigurationComposer());
});
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab); const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
const navigationHidden = !!(pageParser && pageParser.frontPageItems.length); const navigationHidden = !!(pageParser && pageParser.frontPageItems.length);
@ -220,6 +227,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> } </NitroCardView> }
<CatalogGiftView /> <CatalogGiftView />
<MarketplacePostOfferView />
</CatalogContextProvider> </CatalogContextProvider>
); );
} }

View File

@ -1,4 +1,4 @@
import { CatalogPageMessageOfferData, CatalogPageMessageParser, ClubOfferData, GiftWrappingConfigurationParser, INodeData } from '@nitrots/nitro-renderer'; import { CatalogPageMessageOfferData, CatalogPageMessageParser, ClubOfferData, GiftWrappingConfigurationParser, INodeData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer';
import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData'; import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData';
import { Reducer } from 'react'; import { Reducer } from 'react';
import { CatalogPetPalette } from '../common/CatalogPetPalette'; import { CatalogPetPalette } from '../common/CatalogPetPalette';
@ -19,6 +19,7 @@ export interface ICatalogState
clubOffers: ClubOfferData[]; clubOffers: ClubOfferData[];
subscriptionInfo: SubscriptionInfo; subscriptionInfo: SubscriptionInfo;
giftConfiguration: GiftWrappingConfiguration; giftConfiguration: GiftWrappingConfiguration;
marketplaceConfiguration: MarketplaceConfigurationMessageParser;
} }
export interface ICatalogAction export interface ICatalogAction
@ -36,6 +37,7 @@ export interface ICatalogAction
clubOffers?: ClubOfferData[]; clubOffers?: ClubOfferData[];
subscriptionInfo?: SubscriptionInfo; subscriptionInfo?: SubscriptionInfo;
giftConfiguration?: GiftWrappingConfigurationParser; giftConfiguration?: GiftWrappingConfigurationParser;
marketplaceConfiguration?: MarketplaceConfigurationMessageParser;
} }
} }
@ -52,6 +54,7 @@ export class CatalogActions
public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT'; public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT';
public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO'; public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO';
public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION'; public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION';
public static SET_MARKETPLACE_CONFIGURATION: string = 'CA_SET_MARKETPLACE_CONFIGURATION';
} }
export const initialCatalog: ICatalogState = { export const initialCatalog: ICatalogState = {
@ -65,7 +68,8 @@ export const initialCatalog: ICatalogState = {
petPalettes: [], petPalettes: [],
clubOffers: null, clubOffers: null,
subscriptionInfo: new SubscriptionInfo(), subscriptionInfo: new SubscriptionInfo(),
giftConfiguration: null giftConfiguration: null,
marketplaceConfiguration: null
} }
export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, action) => export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, action) =>
@ -160,6 +164,11 @@ export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, ac
return { ...state, giftConfiguration }; return { ...state, giftConfiguration };
} }
case CatalogActions.SET_MARKETPLACE_CONFIGURATION: {
let marketplaceConfiguration = (action.payload.marketplaceConfiguration || state.marketplaceConfiguration || null);
return { ...state, marketplaceConfiguration }
}
default: default:
return state; return state;
} }

View File

@ -1,3 +1,5 @@
@import './frontpage4/CatalogLayoutFrontpage4View'; @import './frontpage4/CatalogLayoutFrontpage4View';
@import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss'; @import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss';
@import './vip-buy/CatalogLayoutVipBuyView'; @import './vip-buy/CatalogLayoutVipBuyView';
@import './marketplace/marketplace-item/MarketplaceItemView';
@import './marketplace/post-offer/MarketplacePostOfferView';

View File

@ -6,6 +6,8 @@ import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLa
import { CatalogLayouGuildForumView } from './guild-forum/CatalogLayoutGuildForumView'; import { CatalogLayouGuildForumView } from './guild-forum/CatalogLayoutGuildForumView';
import { CatalogLayouGuildFrontpageView } from './guild-frontpage/CatalogLayoutGuildFrontpageView'; import { CatalogLayouGuildFrontpageView } from './guild-frontpage/CatalogLayoutGuildFrontpageView';
import { CatalogLayoutInfoLoyaltyView } from './info-loyalty/CatalogLayoutInfoLoyaltyView'; import { CatalogLayoutInfoLoyaltyView } from './info-loyalty/CatalogLayoutInfoLoyaltyView';
import { CatalogLayoutMarketplaceOwnItemsView } from './marketplace/own-items/CatalogLayoutMarketplaceOwnItemsView';
import { CatalogLayoutMarketplacePublicItemsView } from './marketplace/public-items/CatalogLayoutMarketplacePublicItemsView';
import { CatalogLayoutPetView } from './pets/CatalogLayoutPetView'; import { CatalogLayoutPetView } from './pets/CatalogLayoutPetView';
import { CatalogLayoutPets2View } from './pets2/CatalogLayoutPets2View'; import { CatalogLayoutPets2View } from './pets2/CatalogLayoutPets2View';
import { CatalogLayoutPets3View } from './pets3/CatalogLayoutPets3View'; import { CatalogLayoutPets3View } from './pets3/CatalogLayoutPets3View';
@ -41,9 +43,9 @@ export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPrevi
case 'club_gifts': case 'club_gifts':
return null; return null;
case 'marketplace_own_items': case 'marketplace_own_items':
return null; return <CatalogLayoutMarketplaceOwnItemsView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
case 'marketplace': case 'marketplace':
return null; return <CatalogLayoutMarketplacePublicItemsView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
case 'single_bundle': case 'single_bundle':
return <CatalogLayoutSingleBundleView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />; return <CatalogLayoutSingleBundleView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
case 'spaces_new': case 'spaces_new':

View File

@ -0,0 +1,6 @@
export interface IMarketplaceSearchOptions {
query: string;
type: number;
minPrice: number;
maxPrice: number;
}

View File

@ -0,0 +1,6 @@
export class MarketplaceConfirmType
{
public static readonly PURCHASE_CONFIRM_TYPE_NORMAL = 1;
public static readonly PURCHASE_CONFIRM_TYPE_HIGHER = 2;
public static readonly PURCHASE_CONFIRM_TYPE_INVALID = 3;
}

View File

@ -0,0 +1,128 @@
import { IObjectData } from '@nitrots/nitro-renderer';
export class MarketplaceOfferData
{
public static readonly TYPE_FLOOR: number = 1;
public static readonly TYPE_WALL: number = 2;
private _offerId: number;
private _furniId: number;
private _furniType: number;
private _extraData: string;
private _stuffData: IObjectData;
private _price: number;
private _averagePrice: number;
private _imageCallback: number;
private _status: number;
private _timeLeftMinutes: number = -1;
private _offerCount: number;
private _image: string;
constructor(offerId: number, furniId: number, furniType: number, extraData: string, stuffData: IObjectData, price: number, status: number, averagePrice: number, offerCount: number = -1)
{
this._offerId = offerId;
this._furniId = furniId;
this._furniType = furniType;
this._extraData = extraData;
this._stuffData = stuffData;
this._price = price;
this._status = status;
this._averagePrice = averagePrice;
this._offerCount = offerCount;
}
public get offerId(): number
{
return this._offerId;
}
public set offerId(offerId: number)
{
this._offerId = offerId;
}
public get furniId(): number
{
return this._furniId;
}
public get furniType(): number
{
return this._furniType;
}
public get extraData(): string
{
return this._extraData;
}
public get stuffData(): IObjectData
{
return this._stuffData;
}
public get price(): number
{
return this._price;
}
public set price(price: number)
{
this._price = price;
}
public get averagePrice(): number
{
return this._averagePrice;
}
public get image(): string
{
return this._image;
}
public set image(image: string)
{
this._image = image;
}
public get imageCallback(): number
{
return this._imageCallback;
}
public set imageCallback(callback: number)
{
this._imageCallback = callback;
}
public get status(): number
{
return this._status;
}
public get timeLeftMinutes(): number
{
return this._timeLeftMinutes;
}
public set timeLeftMinutes(minutes: number)
{
this._timeLeftMinutes = minutes;
}
public get offerCount(): number
{
return this._offerCount;
}
public set offerCount(count: number)
{
this._offerCount = count;
}
public get isUniqueLimitedItem(): boolean
{
return (this.stuffData && (this.stuffData.uniqueSeries > 0));
}
}

View File

@ -0,0 +1,7 @@
export class MarketPlaceOfferState
{
public static readonly ONGOING = 1;
public static readonly ONGOING_OWN = 1;
public static readonly SOLD = 2;
public static readonly EXPIRED = 3;
}

View File

@ -0,0 +1,6 @@
export class MarketplaceSearchType
{
public static readonly BY_ACTIVITY = 1;
public static readonly BY_VALUE = 2;
public static readonly ADVANCED = 3;
}

View File

@ -0,0 +1,4 @@
.marketplace-item {
max-height: 70px;
height: 70px;
}

View File

@ -0,0 +1,101 @@
import { FC, useCallback } from 'react';
import { GetRoomEngine, LocalizeText } from '../../../../../../../api';
import { NitroCardGridItemView } from '../../../../../../../layout';
import { MarketplaceOfferData } from '../common/MarketplaceOfferData';
import { MarketPlaceOfferState } from '../common/MarketplaceOfferState';
export const OWN_OFFER = 1;
export const PUBLIC_OFFER = 2;
export interface MarketplaceItemViewProps
{
offerData: MarketplaceOfferData;
type?: number;
onClick(offerData: MarketplaceOfferData): void;
}
export const MarketplaceItemView: FC<MarketplaceItemViewProps> = props =>
{
const { offerData = null, type = PUBLIC_OFFER, onClick = null } = props;
const getImageUrlForOffer = useCallback( () =>
{
if(!offerData) return '';
switch(offerData.furniType)
{
case MarketplaceOfferData.TYPE_FLOOR:
return GetRoomEngine().getFurnitureFloorIconUrl(offerData.furniId);
case MarketplaceOfferData.TYPE_WALL:
return GetRoomEngine().getFurnitureWallIconUrl(offerData.furniId, offerData.extraData);
}
return '';
}, [offerData]);
const getMarketplaceOfferTitle = useCallback(() =>
{
if(!offerData) return '';
const localizationKey = offerData.furniType === 2 ? 'wallItem.name.' + offerData.furniId: 'roomItem.name.' + offerData.furniId;
return LocalizeText(localizationKey);
}, [offerData]);
const getMarketplaceOfferDescription = useCallback( () =>
{
if(!offerData) return '';
const localizationKey = offerData.furniType === 2 ? 'wallItem.desc.' + offerData.furniId : 'roomItem.desc.' + offerData.furniId;
return LocalizeText(localizationKey);
}, [offerData]);
const offerTime = useCallback( () =>
{
if(!offerData) return '';
if(offerData.status === MarketPlaceOfferState.SOLD) return LocalizeText('catalog.marketplace.offer.sold');
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);
let text = minutes + ' ' + LocalizeText('catalog.marketplace.offer.minutes');
if(hours > 0)
{
text = hours + ' ' + LocalizeText('catalog.marketplace.offer.hours') + ' ' + text;
}
return LocalizeText('catalog.marketplace.offer.time_left', ['time'], [text] );
}, [offerData]);
return (
<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>
{ type === OWN_OFFER && <>
<div>{ LocalizeText('catalog.marketplace.offer.price_own_item', ['price'], [offerData.price.toString()])}</div>
<div>{ offerTime() }</div>
</>
}
{ 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 gap-2'>
{ (type === OWN_OFFER && offerData.status !== MarketPlaceOfferState.SOLD) && <button className='btn btn-secondary btn-sm' onClick={ () => onClick(offerData) }>{ LocalizeText('catalog.marketplace.offer.pick') }</button>}
{ type === PUBLIC_OFFER && <>
<button className='btn btn-secondary btn-sm' onClick={ () => onClick(offerData) } >{ LocalizeText('buy') }</button>
<button className='btn btn-secondary btn-sm' disabled={true}>{ LocalizeText('catalog.marketplace.view_more') }</button>
</>}
</div>
</NitroCardGridItemView>)
}

View File

@ -0,0 +1,120 @@
import { CancelMarketplaceOfferMessageComposer, GetMarketplaceOwnOffersMessageComposer, MarketplaceCancelOfferResultEvent, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { LocalizeText } from '../../../../../../../api';
import { BatchUpdates, CreateMessageHook, SendMessageHook, UseMountEffect } from '../../../../../../../hooks';
import { NitroCardGridView } from '../../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../../layout/base';
import { NotificationAlertType } from '../../../../../../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../../../../../../notification-center/common/NotificationUtilities';
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
{
}
export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutMarketplaceOwnItemsViewProps> = props =>
{
const [ creditsWaiting, setCreditsWaiting ] = useState(0);
const [ offers, setOffers ] = useState(new Map<number, MarketplaceOfferData>());
UseMountEffect(() =>
{
SendMessageHook(new GetMarketplaceOwnOffersMessageComposer());
});
const onMarketPlaceOwnOffersEvent = useCallback((event: MarketplaceOwnOffersEvent) =>
{
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);
});
BatchUpdates(() =>
{
setCreditsWaiting(parser.creditsWaiting);
setOffers(latestOffers);
});
}, []);
const onMarketplaceCancelOfferResultEvent = useCallback((event:MarketplaceCancelOfferResultEvent) =>
{
const parser = event.getParser();
if(!parser) return;
if(!parser.success)
{
NotificationUtilities.simpleAlert(LocalizeText('catalog.marketplace.cancel_failed'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.marketplace.operation_failed.topic'));
return;
}
setOffers( prev =>
{
const newVal = new Map(prev);
newVal.delete(parser.offerId);
return newVal;
});
}, []);
CreateMessageHook(MarketplaceOwnOffersEvent, onMarketPlaceOwnOffersEvent);
CreateMessageHook(MarketplaceCancelOfferResultEvent, onMarketplaceCancelOfferResultEvent);
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());
}, []);
const takeItemBack = useCallback( (offerData: MarketplaceOfferData) =>
{
SendMessageHook(new CancelMarketplaceOfferMessageComposer(offerData.offerId));
}, []);
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'], [Array.from(offers.values()).filter(value => value.status === MarketPlaceOfferState.SOLD).length.toString(), creditsWaiting.toString()])}</NitroLayoutBase>}
<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'>
{
Array.from(offers.values()).map( (entry, index) => <MarketplaceItemView key={ index } offerData={ entry } type={ OWN_OFFER } onClick={takeItemBack} />)
}
</NitroCardGridView>
</>
);
}

View File

@ -0,0 +1,12 @@
.nitro-marketplace-post-offer {
width: 300px;
height: 365px;
.item-image-container {
width: 75px;
height: 75px;
background-repeat: no-repeat;
background-position: center;
overflow: hidden;
}
}

View File

@ -0,0 +1,117 @@
import { ImageResult, MakeOfferMessageComposer, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetRoomEngine, LocalizeText } from '../../../../../../../api';
import { CatalogPostMarketplaceOfferEvent } from '../../../../../../../events/catalog/CatalogPostMarketplaceOfferEvent';
import { SendMessageHook, useUiEvent } from '../../../../../../../hooks';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex } from '../../../../../../../layout';
import { FurnitureItem } from '../../../../../../inventory/common/FurnitureItem';
import { NotificationUtilities } from '../../../../../../notification-center/common/NotificationUtilities';
import { useCatalogContext } from '../../../../../context/CatalogContext';
export const MarketplacePostOfferView : FC<{}> = props =>
{
const [ item, setItem ] = useState<FurnitureItem>(null);
const [ askingPrice, setAskingPrice ] = useState(0);
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
const close = useCallback(() =>
{
setItem(null);
setAskingPrice(0);
}, []);
const onCatalogPostMarketplaceOfferEvent = useCallback( (event: CatalogPostMarketplaceOfferEvent) =>
{
setItem(event.item);
}, []);
useUiEvent(CatalogPostMarketplaceOfferEvent.POST_MARKETPLACE, onCatalogPostMarketplaceOfferEvent);
const getItemImage = useCallback( () =>
{
if(!item) return '';
let object: ImageResult;
if(!item.isWallItem)
{
object = GetRoomEngine().getFurnitureFloorImage(item.type, new Vector3d(90,0,0), 64, this, 4293848814, item.extra.toString());
}
else
{
object = GetRoomEngine().getFurnitureWallImage(item.type, new Vector3d(90,0,0), 64, this, 4293848814, item.extra.toString());
}
if(object)
{
const image = object.getImage();
if(image) return image.src;
}
return '';
}, [item]);
const getFurniTitle = useCallback( () =>
{
if(!item) return '';
const localizationKey = item.isWallItem ? 'wallItem.name.' + item.type : 'roomItem.name.' + item.type;
return LocalizeText(localizationKey);
}, [item]);
const getFurniDescription = useCallback( () =>
{
if(!item) return '';
const localizationKey = item.isWallItem ? 'wallItem.desc.' + item.type : 'roomItem.desc.' + item.type;
return LocalizeText(localizationKey);
}, [item]);
const postItem = useCallback( () =>
{
if(isNaN(askingPrice) || askingPrice <= 0 || !item) return;
NotificationUtilities.confirm(LocalizeText('inventory.marketplace.confirm_offer.info', ['furniname', 'price'], [getFurniTitle(), askingPrice.toString()]), () =>
{
SendMessageHook(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id));
setItem(null);
},
() => { setItem(null)}, null, null, LocalizeText('inventory.marketplace.confirm_offer.title'));
}, [askingPrice, getFurniTitle, item]);
return ( item &&
<NitroCardView uniqueKey="catalog-mp-post-offer" className="nitro-marketplace-post-offer" simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('inventory.marketplace.make_offer.title') } onCloseClick={ close } />
<NitroCardContentView className="text-black">
<NitroLayoutFlex>
<div className="item-image-container mx-3" style={{ backgroundImage: `url(${getItemImage()})` }} />
<div className='h-100 flex-grow-1 justify-content-center '>
<div className='fw-bold'>{getFurniTitle()}</div>
<div className='fs-6'>{getFurniDescription()}</div>
</div>
</NitroLayoutFlex>
<div className='mx-2 fst-italic text-break mb-3'>
{ LocalizeText('inventory.marketplace.make_offer.expiration_info', ['time'], [catalogState.marketplaceConfiguration.offerTime.toString()]) }
</div>
<div className="d-flex flex-row text-black mb-3">
<div className="mr-2 align-self-center fw-bold" style={ { whiteSpace: 'nowrap' } }>{ LocalizeText('inventory.marketplace.make_offer.price_request') }</div>
<input className="form-control form-control-sm" type="number" min={0} value={ askingPrice } onChange={ event => setAskingPrice(event.target.valueAsNumber) } />
</div>
<div className="alert alert-light" role="alert">
{ (askingPrice < catalogState.marketplaceConfiguration.minimumPrice || isNaN(askingPrice)) && LocalizeText('inventory.marketplace.make_offer.min_price', ['minprice'], [catalogState.marketplaceConfiguration.minimumPrice.toString()]) }
{ askingPrice > catalogState.marketplaceConfiguration.maximumPrice && !isNaN(askingPrice) &&
LocalizeText('inventory.marketplace.make_offer.max_price', ['maxprice'], [catalogState.marketplaceConfiguration.maximumPrice.toString()])
}
{ !(askingPrice < catalogState.marketplaceConfiguration.minimumPrice || askingPrice > catalogState.marketplaceConfiguration.maximumPrice || isNaN(askingPrice)) && LocalizeText('inventory.marketplace.make_offer.final_price', ['commission', 'finalprice'], [catalogState.marketplaceConfiguration.commission.toString(), (askingPrice + catalogState.marketplaceConfiguration.commission).toString()])}
</div>
<div className="btn-group btn-group-sm mt-3" role="group">
<button className='btn btn-primary' disabled={askingPrice < catalogState.marketplaceConfiguration.minimumPrice || askingPrice > catalogState.marketplaceConfiguration.maximumPrice || isNaN(askingPrice)} onClick={ postItem }>
{ LocalizeText('inventory.marketplace.make_offer.post') }
</button>
</div>
</NitroCardContentView>
</NitroCardView>
)
}

View File

@ -0,0 +1,166 @@
import { BuyMarketplaceOfferMessageComposer, GetMarketplaceOffersMessageComposer, MarketplaceBuyOfferResultEvent, 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 { NotificationAlertType } from '../../../../../../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../../../../../../notification-center/common/NotificationUtilities';
import { GetCurrencyAmount } from '../../../../../../purse/common/CurrencyHelper';
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
{
}
export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplacePublicItemsViewProps> = props =>
{
const [ searchType, setSearchType ] = useState(MarketplaceSearchType.BY_ACTIVITY);
const [ totalItemsFound, setTotalItemsFound ] = useState(0);
const [ offers, setOffers ] = useState(new Map<number, MarketplaceOfferData>());
const [ lastSearch, setLastSearch ] = useState<IMarketplaceSearchOptions>({ minPrice: -1, maxPrice: -1, query: '', type: 3 });
const requestOffers = useCallback((options: IMarketplaceSearchOptions) =>
{
setLastSearch(options);
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 purchaseItem = useCallback((offerData: MarketplaceOfferData) =>
{
if(offerData.price > GetCurrencyAmount(-1))
{
NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title'));
return;
}
const offerId = offerData.offerId;
NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_header'), () =>
{
SendMessageHook(new BuyMarketplaceOfferMessageComposer(offerId));
},
null, null, null, LocalizeText('catalog.marketplace.confirm_title'));
},[]);
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);
});
BatchUpdates(() =>
{
setTotalItemsFound(parser.totalItemsFound);
setOffers(latestOffers);
});
}, []);
const onMarketplaceBuyOfferResultEvent = useCallback( (event: MarketplaceBuyOfferResultEvent) =>
{
const parser = event.getParser();
if(!parser) return;
switch(parser.result)
{
case 1:
requestOffers(lastSearch);
break;
case 2:
setOffers(prev =>
{
const newVal = new Map(prev);
newVal.delete(parser.requestedOfferId);
return newVal;
});
NotificationUtilities.simpleAlert(LocalizeText('catalog.marketplace.not_available_header'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.marketplace.not_available_title'));
break;
case 3:
// our shit was updated
// todo: some dialogue modal
setOffers( prev =>
{
const newVal = new Map(prev);
const item = newVal.get(parser.requestedOfferId);
if(item)
{
item.offerId = parser.offerId;
item.price = parser.newPrice;
item.offerCount--;
newVal.set(item.offerId, item);
}
newVal.delete(parser.requestedOfferId);
return newVal;
});
NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_higher_header') +
'\n' + LocalizeText('catalog.marketplace.confirm_price', ['price'], [parser.newPrice.toString()]), () =>
{
SendMessageHook(new BuyMarketplaceOfferMessageComposer(parser.offerId));
},
null, null, null, LocalizeText('catalog.marketplace.confirm_higher_title'));
break;
case 4:
NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title'));
break;
}
}, [lastSearch, requestOffers]);
CreateMessageHook(MarketPlaceOffersEvent, onMarketPlaceOffersEvent);
CreateMessageHook(MarketplaceBuyOfferResultEvent, onMarketplaceBuyOfferResultEvent);
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 } onClick={purchaseItem} />)
}
</NitroCardGridView>
</>);
}

View File

@ -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>
</>
}
</>);
}

View File

@ -1,26 +1,26 @@
export class FurniCategory export class FurniCategory
{ {
public static DEFAULT: number = 1; public static DEFAULT: number = 1;
public static _Str_3639: number = 2; public static WALL_PAPER: number = 2;
public static _Str_3683: number = 3; public static FLOOR: number = 3;
public static _Str_3432: number = 4; public static LANDSCAPE: number = 4;
public static _Str_12351: number = 5; public static POST_IT: number = 5;
public static _Str_5186: number = 6; public static POSTER: number = 6;
public static _Str_21911: number = 7; public static SOUND_SET: number = 7;
public static _Str_9125: number = 8; public static TRAX_SONG: number = 8;
public static _Str_5922: number = 9; public static PRESENT: number = 9;
public static _Str_18231: number = 10; public static ECOTRON_BOX: number = 10;
public static _Str_4255: number = 11; public static TROPHY: number = 11;
public static _Str_19933: number = 12; public static CREDIT_FURNI: number = 12;
public static _Str_7696: number = 13; public static PET_SHAMPOO: number = 13;
public static _Str_7297: number = 14; public static PET_CUSTOM_PART: number = 14;
public static _Str_7954: number = 15; public static PET_CUSTOM_PART_SHAMPOO: number = 15;
public static _Str_6096: number = 16; public static PET_SADDLE: number = 16;
public static _Str_12454: number = 17; public static GUILD_FURNI: number = 17;
public static _Str_19144: number = 18; public static GAME_FURNI: number = 18;
public static MONSTERPLANT_SEED: number = 19; public static MONSTERPLANT_SEED: number = 19;
public static _Str_6915: number = 20; public static MONSTERPLANT_REVIVAL: number = 20;
public static _Str_8726: number = 21; public static MONSTERPLANT_REBREED: number = 21;
public static _Str_9449: number = 22; public static MONSTERPLANT_FERTILIZE: number = 22;
public static _Str_12534: number = 23; public static FIGURE_PURCHASABLE_SET: number = 23;
} }

View File

@ -1,6 +1,7 @@
import { FurnitureListItemParser, FurniturePlacePaintComposer, IObjectData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer'; import { FurnitureListItemParser, FurniturePlacePaintComposer, IObjectData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer';
import { GetRoomEngine } from '../../../api'; import { GetRoomEngine } from '../../../api';
import { InventoryEvent } from '../../../events'; import { InventoryEvent } from '../../../events';
import { CatalogPostMarketplaceOfferEvent } from '../../../events/catalog/CatalogPostMarketplaceOfferEvent';
import { dispatchUiEvent } from '../../../hooks/events/ui/ui-event'; import { dispatchUiEvent } from '../../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../hooks/messages/message-event';
import { FurniCategory } from './FurniCategory'; import { FurniCategory } from './FurniCategory';
@ -18,7 +19,7 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false
if(!item) return false; if(!item) return false;
if((item.category === FurniCategory._Str_3683) || (item.category === FurniCategory._Str_3639) || (item.category === FurniCategory._Str_3432)) if((item.category === FurniCategory.FLOOR) || (item.category === FurniCategory.WALL_PAPER) || (item.category === FurniCategory.LANDSCAPE))
{ {
if(flag) return false; if(flag) return false;
@ -36,7 +37,7 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false
if(item.isWallItem) category = RoomObjectCategory.WALL; if(item.isWallItem) category = RoomObjectCategory.WALL;
else category = RoomObjectCategory.FLOOR; else category = RoomObjectCategory.FLOOR;
if((item.category === FurniCategory._Str_5186)) // or external image from furnidata if((item.category === FurniCategory.POSTER)) // or external image from furnidata
{ {
isMoving = GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.INVENTORY, item.id, category, item.type, item.stuffData.getLegacyString()); isMoving = GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.INVENTORY, item.id, category, item.type, item.stuffData.getLegacyString());
} }
@ -55,6 +56,17 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false
return true; return true;
} }
export function attemptPlaceMarketplaceOffer(groupItem: GroupItem): boolean
{
const item = groupItem.getLastItem();
if(!item) return false;
if(!item.sellable) return false;
dispatchUiEvent(new CatalogPostMarketplaceOfferEvent(item));
}
function cancelRoomObjectPlacement(): void function cancelRoomObjectPlacement(): void
{ {
if(getPlacingItemId() === -1) return; if(getPlacingItemId() === -1) return;
@ -108,7 +120,7 @@ function getAllItemIds(groupItems: GroupItem[]): number[]
{ {
let totalCount = groupItem.getTotalCount(); let totalCount = groupItem.getTotalCount();
if(groupItem.category === FurniCategory._Str_12351) totalCount = 1; if(groupItem.category === FurniCategory.POST_IT) totalCount = 1;
let i = 0; let i = 0;
@ -240,7 +252,7 @@ function addGroupableFurnitureItem(set: GroupItem[], item: FurnitureItem, unseen
{ {
if((groupItem.type === item.type) && (groupItem.isWallItem === item.isWallItem) && groupItem.isGroupable) if((groupItem.type === item.type) && (groupItem.isWallItem === item.isWallItem) && groupItem.isGroupable)
{ {
if(item.category === FurniCategory._Str_5186) if(item.category === FurniCategory.POSTER)
{ {
if(groupItem.stuffData.getLegacyString() === item.stuffData.getLegacyString()) if(groupItem.stuffData.getLegacyString() === item.stuffData.getLegacyString())
{ {
@ -250,7 +262,7 @@ function addGroupableFurnitureItem(set: GroupItem[], item: FurnitureItem, unseen
} }
} }
else if(item.category === FurniCategory._Str_12454) else if(item.category === FurniCategory.GUILD_FURNI)
{ {
if(item.stuffData.compare(groupItem.stuffData)) if(item.stuffData.compare(groupItem.stuffData))
{ {
@ -309,7 +321,7 @@ export function createGroupItem(type: number, category: number, stuffData: IObje
{ {
// const iconImage: HTMLImageElement = null; // const iconImage: HTMLImageElement = null;
if(category === FurniCategory._Str_3639) if(category === FurniCategory.WALL_PAPER)
{ {
// const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_wallpaper"); // const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_wallpaper");
// if (icon != null) // if (icon != null)
@ -318,7 +330,7 @@ export function createGroupItem(type: number, category: number, stuffData: IObje
// } // }
} }
else if(category === FurniCategory._Str_3683) else if(category === FurniCategory.FLOOR)
{ {
// const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_floor"); // const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_floor");
// if (icon != null) // if (icon != null)
@ -327,7 +339,7 @@ export function createGroupItem(type: number, category: number, stuffData: IObje
// } // }
} }
else if(category === FurniCategory._Str_3432) else if(category === FurniCategory.LANDSCAPE)
{ {
// const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_landscape"); // const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_landscape");
// if (icon != null) // if (icon != null)

View File

@ -199,7 +199,7 @@ export class GroupItem
public getTotalCount(): number public getTotalCount(): number
{ {
if(this._category === FurniCategory._Str_12351) if(this._category === FurniCategory.POST_IT)
{ {
let count = 0; let count = 0;
let index = 0; let index = 0;
@ -221,7 +221,7 @@ export class GroupItem
public getUnlockedCount(): number public getUnlockedCount(): number
{ {
if(this.category === FurniCategory._Str_12351) return this.getTotalCount(); if(this.category === FurniCategory.POST_IT) return this.getTotalCount();
let count = 0; let count = 0;
let index = 0; let index = 0;
@ -318,10 +318,10 @@ export class GroupItem
switch(this._category) switch(this._category)
{ {
case FurniCategory._Str_5186: case FurniCategory.POSTER:
key = (('poster_' + k.stuffData.getLegacyString()) + '_name'); key = (('poster_' + k.stuffData.getLegacyString()) + '_name');
break; break;
case FurniCategory._Str_9125: case FurniCategory.TRAX_SONG:
this._name = 'SONG_NAME'; this._name = 'SONG_NAME';
return; return;
default: default:
@ -442,6 +442,13 @@ export class GroupItem
return (item ? item.isGroupable : false); return (item ? item.isGroupable : false);
} }
public get isSellable(): boolean
{
const item = this.getItemByIndex(0);
return (item ? item.sellable : false);
}
public get items(): FurnitureItem[] public get items(): FurnitureItem[]
{ {
return this._items; return this._items;

View File

@ -30,12 +30,12 @@ export function parseTradeItems(items: ItemDataStructure[], _arg_2: AdvancedMap<
name = ('itemid' + item.itemId); name = ('itemid' + item.itemId);
} }
if(item.category === FurniCategory._Str_5186) if(item.category === FurniCategory.POSTER)
{ {
name = (item.itemId + 'poster' + item.stuffData.getLegacyString()); name = (item.itemId + 'poster' + item.stuffData.getLegacyString());
} }
else if(item.category === FurniCategory._Str_12454) else if(item.category === FurniCategory.GUILD_FURNI)
{ {
name = ''; name = '';
} }

View File

@ -11,7 +11,7 @@ import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/
import { RarityLevelView } from '../../../shared/rarity-level/RarityLevelView'; import { RarityLevelView } from '../../../shared/rarity-level/RarityLevelView';
import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView'; import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView';
import { FurniCategory } from '../../common/FurniCategory'; import { FurniCategory } from '../../common/FurniCategory';
import { attemptItemPlacement } from '../../common/FurnitureUtilities'; import { attemptItemPlacement, attemptPlaceMarketplaceOffer } from '../../common/FurnitureUtilities';
import { GroupItem } from '../../common/GroupItem'; import { GroupItem } from '../../common/GroupItem';
import { useInventoryContext } from '../../context/InventoryContext'; import { useInventoryContext } from '../../context/InventoryContext';
import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer';
@ -76,15 +76,15 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType);
roomPreviewer.updateRoomWallsAndFloorVisibility(true, true); roomPreviewer.updateRoomWallsAndFloorVisibility(true, true);
if((furnitureItem.category === FurniCategory._Str_3639) || (furnitureItem.category === FurniCategory._Str_3683) || (furnitureItem.category === FurniCategory._Str_3432)) if((furnitureItem.category === FurniCategory.WALL_PAPER) || (furnitureItem.category === FurniCategory.FLOOR) || (furnitureItem.category === FurniCategory.LANDSCAPE))
{ {
floorType = ((furnitureItem.category === FurniCategory._Str_3683) ? groupItem.stuffData.getLegacyString() : floorType); floorType = ((furnitureItem.category === FurniCategory.FLOOR) ? groupItem.stuffData.getLegacyString() : floorType);
wallType = ((furnitureItem.category === FurniCategory._Str_3639) ? groupItem.stuffData.getLegacyString() : wallType); wallType = ((furnitureItem.category === FurniCategory.WALL_PAPER) ? groupItem.stuffData.getLegacyString() : wallType);
landscapeType = ((furnitureItem.category === FurniCategory._Str_3432) ? groupItem.stuffData.getLegacyString() : landscapeType); landscapeType = ((furnitureItem.category === FurniCategory.LANDSCAPE) ? groupItem.stuffData.getLegacyString() : landscapeType);
roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType);
if(furnitureItem.category === FurniCategory._Str_3432) if(furnitureItem.category === FurniCategory.LANDSCAPE)
{ {
const data = GetSessionDataManager().getWallItemDataByName('noob_window_double'); const data = GetSessionDataManager().getWallItemDataByName('noob_window_double');
@ -127,10 +127,15 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
{ groupItem && { groupItem &&
<NitroLayoutFlexColumn className="flex-grow-1" gap={ 2 }> <NitroLayoutFlexColumn className="flex-grow-1" gap={ 2 }>
<NitroLayoutBase className="flex-grow-1 text-black text-truncate">{ groupItem.name }</NitroLayoutBase> <NitroLayoutBase className="flex-grow-1 text-black text-truncate">{ groupItem.name }</NitroLayoutBase>
{ !!roomSession && { roomSession &&
<NitroLayoutButton variant="success" size="sm" onClick={ event => attemptItemPlacement(groupItem) }> <NitroLayoutButton variant="success" size="sm" onClick={ event => attemptItemPlacement(groupItem) }>
{ LocalizeText('inventory.furni.placetoroom') } { LocalizeText('inventory.furni.placetoroom') }
</NitroLayoutButton> } </NitroLayoutButton> }
{ (groupItem && groupItem.isSellable) &&
<NitroLayoutButton variant="primary" size="sm" onClick={ event => attemptPlaceMarketplaceOffer(groupItem) }>
{ LocalizeText('inventory.marketplace.sell') }
</NitroLayoutButton>
}
</NitroLayoutFlexColumn> } </NitroLayoutFlexColumn> }
</NitroLayoutGridColumn> </NitroLayoutGridColumn>
</NitroLayoutGrid> </NitroLayoutGrid>

View File

@ -8,6 +8,8 @@ import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCa
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn'; import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid'; import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { NotificationAlertType } from '../../../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../../../notification-center/common/NotificationUtilities';
import { FurniCategory } from '../../common/FurniCategory'; import { FurniCategory } from '../../common/FurniCategory';
import { GroupItem } from '../../common/GroupItem'; import { GroupItem } from '../../common/GroupItem';
import { IFurnitureItem } from '../../common/IFurnitureItem'; import { IFurnitureItem } from '../../common/IFurnitureItem';
@ -41,13 +43,13 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
let type = spriteId.toString(); let type = spriteId.toString();
if(category === FurniCategory._Str_5186) if(category === FurniCategory.POSTER)
{ {
type = ((type + 'poster') + stuffData.getLegacyString()); type = ((type + 'poster') + stuffData.getLegacyString());
} }
else else
{ {
if(category === FurniCategory._Str_12454) if(category === FurniCategory.GUILD_FURNI)
{ {
type = _Str_16998(spriteId, stuffData); type = _Str_16998(spriteId, stuffData);
} }
@ -113,7 +115,7 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
} }
else else
{ {
//this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}'); NotificationUtilities.simpleAlert(LocalizeText('trading.items.too_many_items.desc'), NotificationAlertType.DEFAULT, null, null, LocalizeText('trading.items.too_many_items.title'));
} }
}, [ groupItem, tradeData, canTradeItem ]); }, [ groupItem, tradeData, canTradeItem ]);

View File

@ -1,13 +1,14 @@
import { CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent, RoomEngineEvent } from '@nitrots/nitro-renderer'; import { CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent, RoomEngineEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { MODTOOLS_NEW_TICKET, PlaySound } from '../../api/utils/PlaySound'; import { MODTOOLS_NEW_TICKET, PlaySound } from '../../api/utils/PlaySound';
import { NotificationAlertEvent } from '../../events';
import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent';
import { ModToolsOpenRoomChatlogEvent } from '../../events/mod-tools/ModToolsOpenRoomChatlogEvent'; import { ModToolsOpenRoomChatlogEvent } from '../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent'; import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent';
import { ModToolsOpenUserChatlogEvent } from '../../events/mod-tools/ModToolsOpenUserChatlogEvent'; import { ModToolsOpenUserChatlogEvent } from '../../events/mod-tools/ModToolsOpenUserChatlogEvent';
import { ModToolsOpenUserInfoEvent } from '../../events/mod-tools/ModToolsOpenUserInfoEvent'; import { ModToolsOpenUserInfoEvent } from '../../events/mod-tools/ModToolsOpenUserInfoEvent';
import { CreateMessageHook, dispatchUiEvent, useRoomEngineEvent, useUiEvent } from '../../hooks'; import { CreateMessageHook, useRoomEngineEvent, useUiEvent } from '../../hooks';
import { NotificationAlertType } from '../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../notification-center/common/NotificationUtilities';
import { SetCfhCategories } from './common/GetCFHCategories'; import { SetCfhCategories } from './common/GetCFHCategories';
import { useModToolsContext } from './context/ModToolsContext'; import { useModToolsContext } from './context/ModToolsContext';
import { ModToolsActions } from './reducers/ModToolsReducer'; import { ModToolsActions } from './reducers/ModToolsReducer';
@ -38,8 +39,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
tickets: data.issues tickets: data.issues
} }
}); });
console.log(parser);
}, [dispatchModToolsState]); }, [dispatchModToolsState]);
const onIssueInfoMessageEvent = useCallback((event: IssueInfoMessageEvent) => const onIssueInfoMessageEvent = useCallback((event: IssueInfoMessageEvent) =>
@ -68,7 +68,6 @@ export const ModToolsMessageHandler: FC<{}> = props =>
} }
}); });
console.log(parser);
}, [dispatchModToolsState, tickets]); }, [dispatchModToolsState, tickets]);
const onModeratorToolPreferencesEvent = useCallback((event: ModeratorToolPreferencesEvent) => const onModeratorToolPreferencesEvent = useCallback((event: ModeratorToolPreferencesEvent) =>
@ -77,7 +76,6 @@ export const ModToolsMessageHandler: FC<{}> = props =>
if(!parser) return; if(!parser) return;
console.log(parser);
}, []); }, []);
const onIssuePickFailedMessageEvent = useCallback((event: IssuePickFailedMessageEvent) => const onIssuePickFailedMessageEvent = useCallback((event: IssuePickFailedMessageEvent) =>
@ -86,8 +84,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
if(!parser) return; if(!parser) return;
// todo: let user know it failed NotificationUtilities.simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error')
dispatchUiEvent(new NotificationAlertEvent(['Failed to pick issue'], null, null, null, 'Error', null));
}, []); }, []);
const onIssueDeletedMessageEvent = useCallback((event: IssueDeletedMessageEvent) => const onIssueDeletedMessageEvent = useCallback((event: IssueDeletedMessageEvent) =>
@ -119,11 +116,11 @@ export const ModToolsMessageHandler: FC<{}> = props =>
if(parser.success) if(parser.success)
{ {
dispatchUiEvent(new NotificationAlertEvent(['Moderation action was successfull'], null, null, null, 'Success', null)); NotificationUtilities.simpleAlert('Moderation action was successfull', NotificationAlertType.MODERATION, null, null, 'Success');
} }
else else
{ {
dispatchUiEvent(new NotificationAlertEvent(['There was a problem applying that moderation action'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('There was a problem applying tht moderation action', NotificationAlertType.MODERATION, null, null, 'Error');
} }
}, []); }, []);
@ -144,7 +141,6 @@ export const ModToolsMessageHandler: FC<{}> = props =>
SetCfhCategories(categories); SetCfhCategories(categories);
console.log(parser);
}, [dispatchModToolsState]); }, [dispatchModToolsState]);
const onCfhSanctionMessageEvent = useCallback((event: CfhSanctionMessageEvent) => const onCfhSanctionMessageEvent = useCallback((event: CfhSanctionMessageEvent) =>
@ -153,7 +149,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
if(!parser) return; if(!parser) return;
console.log(parser); // todo: update sanction data
}, []); }, []);
CreateMessageHook(ModeratorInitMessageEvent, onModeratorInitMessageEvent); CreateMessageHook(ModeratorInitMessageEvent, onModeratorInitMessageEvent);

View File

@ -1,9 +1,10 @@
import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer'; import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react'; import { FC, useCallback, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../../api'; import { LocalizeText } from '../../../../../api';
import { NotificationAlertEvent } from '../../../../../events'; import { SendMessageHook } from '../../../../../hooks';
import { dispatchUiEvent, SendMessageHook } from '../../../../../hooks';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
import { NotificationAlertType } from '../../../../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../../../../notification-center/common/NotificationUtilities';
import { useModToolsContext } from '../../../context/ModToolsContext'; import { useModToolsContext } from '../../../context/ModToolsContext';
import { ModActionDefinition } from '../../../utils/ModActionDefinition'; import { ModActionDefinition } from '../../../utils/ModActionDefinition';
import { ModToolsUserModActionViewProps } from './ModToolsUserModActionView.types'; import { ModToolsUserModActionViewProps } from './ModToolsUserModActionView.types';
@ -59,13 +60,13 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
{ {
if( (selectedTopic === -1) || (selectedAction === -1) ) if( (selectedTopic === -1) || (selectedAction === -1) )
{ {
dispatchUiEvent(new NotificationAlertEvent(['You must select a CFH topic and Sanction'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You must select a CFH topic and Sanction', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
if(!settings || !settings.cfhPermission) if(!settings || !settings.cfhPermission)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You do not have permission to do this'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You do not have permission to do this', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
@ -74,13 +75,13 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
if(!category) if(!category)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You must select a CFH topic'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You must select a CFH topic', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
if(!sanction) if(!sanction)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You must select a sanction'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You must select a sanction', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
@ -92,13 +93,13 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
if(!settings.alertPermission) if(!settings.alertPermission)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You have insufficient permissions.'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
if(message.trim().length === 0) if(message.trim().length === 0)
{ {
dispatchUiEvent(new NotificationAlertEvent(['Please write a message to user.'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('Please write a message to user', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
@ -113,7 +114,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
if(!settings.banPermission) if(!settings.banPermission)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You have insufficient permissions.'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
@ -125,7 +126,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
if(!settings.kickPermission) if(!settings.kickPermission)
{ {
dispatchUiEvent(new NotificationAlertEvent(['You have insufficient permissions.'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }
@ -144,7 +145,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
if(message.trim().length === 0) if(message.trim().length === 0)
{ {
dispatchUiEvent(new NotificationAlertEvent(['Please write a message to user.'], null, null, null, 'Error', null)); NotificationUtilities.simpleAlert('Please write a message to user', NotificationAlertType.DEFAULT, null, null, 'Error');
return; return;
} }

View File

@ -48,7 +48,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
switch(furniData.specialType) switch(furniData.specialType)
{ {
case FurniCategory._Str_7696: { case FurniCategory.PET_SHAMPOO: {
if(customParts.length < 2) return null; if(customParts.length < 2) return null;
const currentPalette = GetRoomEngine().getPetColorResult(petIndex, petFigureData.paletteId); const currentPalette = GetRoomEngine().getPetColorResult(petIndex, petFigureData.paletteId);
@ -68,7 +68,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
return <PetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } /> return <PetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } />
} }
case FurniCategory._Str_7297: { case FurniCategory.PET_CUSTOM_PART: {
if(customParts.length < 4) return null; if(customParts.length < 4) return null;
const newCustomParts: PetCustomPart[] = []; const newCustomParts: PetCustomPart[] = [];
@ -95,7 +95,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory._Str_7954: { case FurniCategory.PET_CUSTOM_PART_SHAMPOO: {
if(customParts.length < 3) return null; if(customParts.length < 3) return null;
const newCustomParts: PetCustomPart[] = []; const newCustomParts: PetCustomPart[] = [];
@ -121,7 +121,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory._Str_6096: { case FurniCategory.PET_SADDLE: {
if(customParts.length < 4) return null; if(customParts.length < 4) return null;
const newCustomParts: PetCustomPart[] = []; const newCustomParts: PetCustomPart[] = [];
@ -149,9 +149,9 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <PetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory._Str_8726: case FurniCategory.MONSTERPLANT_REBREED:
case FurniCategory._Str_6915: case FurniCategory.MONSTERPLANT_REVIVAL:
case FurniCategory._Str_9449: { case FurniCategory.MONSTERPLANT_FERTILIZE: {
let posture = 'rip'; let posture = 'rip';
const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT); const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT);
@ -190,25 +190,25 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
switch(furniData.specialType) switch(furniData.specialType)
{ {
case FurniCategory._Str_7696: case FurniCategory.PET_SHAMPOO:
mode = _Str_11906; mode = _Str_11906;
break; break;
case FurniCategory._Str_7297: case FurniCategory.PET_CUSTOM_PART:
mode = _Str_11214; mode = _Str_11214;
break; break;
case FurniCategory._Str_7954: case FurniCategory.PET_CUSTOM_PART_SHAMPOO:
mode = _Str_11733; mode = _Str_11733;
break; break;
case FurniCategory._Str_6096: case FurniCategory.PET_SADDLE:
mode = _Str_11369; mode = _Str_11369;
break; break;
case FurniCategory._Str_6915: case FurniCategory.MONSTERPLANT_REVIVAL:
mode = _Str_8759; mode = _Str_8759;
break; break;
case FurniCategory._Str_8726: case FurniCategory.MONSTERPLANT_REBREED:
mode = _Str_8432; mode = _Str_8432;
break; break;
case FurniCategory._Str_9449: case FurniCategory.MONSTERPLANT_FERTILIZE:
mode = _Str_9653; mode = _Str_9653;
break; break;
} }

View File

@ -8,14 +8,14 @@ import { ContextMenuHeaderView } from '../../../context-menu/views/header/Contex
import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView';
import { AvatarInfoUseProductViewProps } from './AvatarInfoUseProductView.types'; import { AvatarInfoUseProductViewProps } from './AvatarInfoUseProductView.types';
const _Str_2906: number = 0; const PRODUCT_PAGE_UKNOWN: number = 0;
const _Str_13718: number = 1; const PRODUCT_PAGE_SHAMPOO: number = 1;
const _Str_14146: number = 2; const PRODUCT_PAGE_CUSTOM_PART: number = 2;
const _Str_15667: number = 3; const PRODUCT_PAGE_CUSTOM_PART_SHAMPOO: number = 3;
const _Str_14658: number = 4; const PRODUCT_PAGE_SADDLE: number = 4;
const _Str_14165: number = 5; const PRODUCT_PAGE_REVIVE: number = 5;
const _Str_12577: number = 6; const PRODUCT_PAGE_REBREED: number = 6;
const _Str_14611: number = 7; const PRODUCT_PAGE_FERTILIZE: number = 7;
export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props => export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props =>
{ {
@ -31,30 +31,30 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
if(!furniData) return; if(!furniData) return;
let mode = _Str_2906; let mode = PRODUCT_PAGE_UKNOWN;
switch(furniData.specialType) switch(furniData.specialType)
{ {
case FurniCategory._Str_7696: case FurniCategory.PET_SHAMPOO:
mode = _Str_13718; mode = PRODUCT_PAGE_SHAMPOO;
break; break;
case FurniCategory._Str_7297: case FurniCategory.PET_CUSTOM_PART:
mode = _Str_14146; mode = PRODUCT_PAGE_CUSTOM_PART;
break; break;
case FurniCategory._Str_7954: case FurniCategory.PET_CUSTOM_PART_SHAMPOO:
mode = _Str_15667; mode = PRODUCT_PAGE_CUSTOM_PART_SHAMPOO;
break; break;
case FurniCategory._Str_6096: case FurniCategory.PET_SADDLE:
mode = _Str_14658; mode = PRODUCT_PAGE_SADDLE;
break; break;
case FurniCategory._Str_6915: case FurniCategory.MONSTERPLANT_REVIVAL:
mode = _Str_14165; mode = PRODUCT_PAGE_REVIVE;
break; break;
case FurniCategory._Str_8726: case FurniCategory.MONSTERPLANT_REBREED:
mode = _Str_12577; mode = PRODUCT_PAGE_REBREED;
break; break;
case FurniCategory._Str_9449: case FurniCategory.MONSTERPLANT_FERTILIZE:
mode = _Str_14611; mode = PRODUCT_PAGE_FERTILIZE;
break; break;
} }
@ -86,23 +86,23 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
<ContextMenuHeaderView> <ContextMenuHeaderView>
{ item.name } { item.name }
</ContextMenuHeaderView> </ContextMenuHeaderView>
{ (mode === _Str_2906) && { (mode === PRODUCT_PAGE_UKNOWN) &&
<ContextMenuListItemView onClick={ event => processAction('use_product') }> <ContextMenuListItemView onClick={ event => processAction('use_product') }>
{ LocalizeText('infostand.button.useproduct') } { LocalizeText('infostand.button.useproduct') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_13718) && { (mode === PRODUCT_PAGE_SHAMPOO) &&
<ContextMenuListItemView onClick={ event => processAction('use_product_shampoo') }> <ContextMenuListItemView onClick={ event => processAction('use_product_shampoo') }>
{ LocalizeText('infostand.button.useproduct_shampoo') } { LocalizeText('infostand.button.useproduct_shampoo') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_14146) && { (mode === PRODUCT_PAGE_CUSTOM_PART) &&
<ContextMenuListItemView onClick={ event => processAction('use_product_custom_part') }> <ContextMenuListItemView onClick={ event => processAction('use_product_custom_part') }>
{ LocalizeText('infostand.button.useproduct_custom_part') } { LocalizeText('infostand.button.useproduct_custom_part') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_15667) && { (mode === PRODUCT_PAGE_CUSTOM_PART_SHAMPOO) &&
<ContextMenuListItemView onClick={ event => processAction('use_product_custom_part_shampoo') }> <ContextMenuListItemView onClick={ event => processAction('use_product_custom_part_shampoo') }>
{ LocalizeText('infostand.button.useproduct_custom_part_shampoo') } { LocalizeText('infostand.button.useproduct_custom_part_shampoo') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_14658) && { (mode === PRODUCT_PAGE_SADDLE) &&
<> <>
{ item.replace && { item.replace &&
<ContextMenuListItemView onClick={ event => processAction('replace_product_saddle') }> <ContextMenuListItemView onClick={ event => processAction('replace_product_saddle') }>
@ -113,15 +113,15 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
{ LocalizeText('infostand.button.useproduct_saddle') } { LocalizeText('infostand.button.useproduct_saddle') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
</> } </> }
{ (mode === _Str_14165) && { (mode === PRODUCT_PAGE_REVIVE) &&
<ContextMenuListItemView onClick={ event => processAction('revive_monsterplant') }> <ContextMenuListItemView onClick={ event => processAction('revive_monsterplant') }>
{ LocalizeText('infostand.button.revive_monsterplant') } { LocalizeText('infostand.button.revive_monsterplant') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_12577) && { (mode === PRODUCT_PAGE_REBREED) &&
<ContextMenuListItemView onClick={ event => processAction('rebreed_monsterplant') }> <ContextMenuListItemView onClick={ event => processAction('rebreed_monsterplant') }>
{ LocalizeText('infostand.button.rebreed_monsterplant') } { LocalizeText('infostand.button.rebreed_monsterplant') }
</ContextMenuListItemView> } </ContextMenuListItemView> }
{ (mode === _Str_14611) && { (mode === PRODUCT_PAGE_FERTILIZE) &&
<ContextMenuListItemView onClick={ event => processAction('fertilize_monsterplant') }> <ContextMenuListItemView onClick={ event => processAction('fertilize_monsterplant') }>
{ LocalizeText('infostand.button.fertilize_monsterplant') } { LocalizeText('infostand.button.fertilize_monsterplant') }
</ContextMenuListItemView> } </ContextMenuListItemView> }

View File

@ -43,7 +43,7 @@ export const PurchasableClothingConfirmView: FC<PurchasableClothingConfirmViewPr
{ {
switch(furniData.specialType) switch(furniData.specialType)
{ {
case FurniCategory._Str_12534: case FurniCategory.FIGURE_PURCHASABLE_SET:
mode = MODE_PURCHASABLE_CLOTHING; mode = MODE_PURCHASABLE_CLOTHING;
const setIds = furniData.customParams.split(',').map(part => parseInt(part)); const setIds = furniData.customParams.split(',').map(part => parseInt(part));