diff --git a/src/App.tsx b/src/App.tsx index b6106abb..59094326 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -127,6 +127,7 @@ export const App: FC<{}> = props => return (
+
{ (!isReady || isError) && } diff --git a/src/api/nitro/room/widgets/handlers/RoomWidgetAvatarInfoHandler.ts b/src/api/nitro/room/widgets/handlers/RoomWidgetAvatarInfoHandler.ts index 43b8ade2..6cbd73af 100644 --- a/src/api/nitro/room/widgets/handlers/RoomWidgetAvatarInfoHandler.ts +++ b/src/api/nitro/room/widgets/handlers/RoomWidgetAvatarInfoHandler.ts @@ -136,24 +136,24 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler { 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 figurePart = (figureParts.length ? parseInt(figureParts[0]) : -1); if(figurePart === part) { - if(specialType === FurniCategory._Str_6915) + if(specialType === FurniCategory.MONSTERPLANT_REVIVAL) { if(!userData.canRevive) continue; } - if(specialType === FurniCategory._Str_8726) + if(specialType === FurniCategory.MONSTERPLANT_REBREED) { 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; } diff --git a/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts b/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts index 9e6f234b..b286dd1a 100644 --- a/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts +++ b/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts @@ -1,9 +1,10 @@ import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer'; import { GetConfiguration, GetNitroInstance } from '../../..'; -import { GetRoomEngine, GetSessionDataManager } from '../../../..'; +import { GetRoomEngine, GetSessionDataManager, LocalizeText } from '../../../..'; import { FloorplanEditorEvent } from '../../../../../events/floorplan-editor/FloorplanEditorEvent'; import { dispatchUiEvent } from '../../../../../hooks'; import { SendMessageHook } from '../../../../../hooks/messages'; +import { NotificationUtilities } from '../../../../../views/notification-center/common/NotificationUtilities'; import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events'; import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages'; import { RoomWidgetHandler } from './RoomWidgetHandler'; @@ -127,10 +128,11 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler newWindow.document.write(image.outerHTML); return null; case ':pickall': - // this.container.notificationService.alertWithConfirm('${room.confirm.pick_all}', '${generic.alert.title}', () => - // { - // GetSessionDataManager().sendSpecialCommandMessage(':pickall'); - // }); + NotificationUtilities.confirm(LocalizeText('room.confirm.pick_all'), () => + { + GetSessionDataManager().sendSpecialCommandMessage(':pickall'); + }, + null, null, null, LocalizeText('generic.alert.title')); return null; case ':furni': diff --git a/src/components/inventory/common/FurniCategory.ts b/src/components/inventory/common/FurniCategory.ts index c4175ab1..65289472 100644 --- a/src/components/inventory/common/FurniCategory.ts +++ b/src/components/inventory/common/FurniCategory.ts @@ -1,26 +1,26 @@ export class FurniCategory { public static DEFAULT: number = 1; - public static _Str_3639: number = 2; - public static _Str_3683: number = 3; - public static _Str_3432: number = 4; - public static _Str_12351: number = 5; - public static _Str_5186: number = 6; - public static _Str_21911: number = 7; - public static _Str_9125: number = 8; - public static _Str_5922: number = 9; - public static _Str_18231: number = 10; - public static _Str_4255: number = 11; - public static _Str_19933: number = 12; - public static _Str_7696: number = 13; - public static _Str_7297: number = 14; - public static _Str_7954: number = 15; - public static _Str_6096: number = 16; - public static _Str_12454: number = 17; - public static _Str_19144: number = 18; + public static WALL_PAPER: number = 2; + public static FLOOR: number = 3; + public static LANDSCAPE: number = 4; + public static POST_IT: number = 5; + public static POSTER: number = 6; + public static SOUND_SET: number = 7; + public static TRAX_SONG: number = 8; + public static PRESENT: number = 9; + public static ECOTRON_BOX: number = 10; + public static TROPHY: number = 11; + public static CREDIT_FURNI: number = 12; + public static PET_SHAMPOO: number = 13; + public static PET_CUSTOM_PART: number = 14; + public static PET_CUSTOM_PART_SHAMPOO: number = 15; + public static PET_SADDLE: number = 16; + public static GUILD_FURNI: number = 17; + public static GAME_FURNI: number = 18; public static MONSTERPLANT_SEED: number = 19; - public static _Str_6915: number = 20; - public static _Str_8726: number = 21; - public static _Str_9449: number = 22; - public static _Str_12534: number = 23; -} \ No newline at end of file + public static MONSTERPLANT_REVIVAL: number = 20; + public static MONSTERPLANT_REBREED: number = 21; + public static MONSTERPLANT_FERTILIZE: number = 22; + public static FIGURE_PURCHASABLE_SET: number = 23; +} diff --git a/src/components/inventory/common/FurnitureUtilities.ts b/src/components/inventory/common/FurnitureUtilities.ts index 96dc07b3..46ba4b7d 100644 --- a/src/components/inventory/common/FurnitureUtilities.ts +++ b/src/components/inventory/common/FurnitureUtilities.ts @@ -1,6 +1,7 @@ import { FurnitureListItemParser, FurniturePlacePaintComposer, IObjectData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer'; import { GetRoomEngine } from '../../../api'; import { InventoryEvent } from '../../../events'; +import { CatalogPostMarketplaceOfferEvent } from '../../../events/catalog/CatalogPostMarketplaceOfferEvent'; import { dispatchUiEvent } from '../../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../../hooks/messages/message-event'; import { FurniCategory } from './FurniCategory'; @@ -18,7 +19,7 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = 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; @@ -36,7 +37,7 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false if(item.isWallItem) category = RoomObjectCategory.WALL; 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()); } @@ -55,6 +56,17 @@ export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false 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 { if(getPlacingItemId() === -1) return; @@ -108,7 +120,7 @@ function getAllItemIds(groupItems: GroupItem[]): number[] { let totalCount = groupItem.getTotalCount(); - if(groupItem.category === FurniCategory._Str_12351) totalCount = 1; + if(groupItem.category === FurniCategory.POST_IT) totalCount = 1; 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(item.category === FurniCategory._Str_5186) + if(item.category === FurniCategory.POSTER) { 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)) { @@ -309,7 +321,7 @@ export function createGroupItem(type: number, category: number, stuffData: IObje { // const iconImage: HTMLImageElement = null; - if(category === FurniCategory._Str_3639) + if(category === FurniCategory.WALL_PAPER) { // const icon = this._windowManager.assets.getAssetByName("inventory_furni_icon_wallpaper"); // 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"); // 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"); // if (icon != null) diff --git a/src/components/inventory/common/GroupItem.ts b/src/components/inventory/common/GroupItem.ts index 8eb40644..2b3598a4 100644 --- a/src/components/inventory/common/GroupItem.ts +++ b/src/components/inventory/common/GroupItem.ts @@ -199,7 +199,7 @@ export class GroupItem public getTotalCount(): number { - if(this._category === FurniCategory._Str_12351) + if(this._category === FurniCategory.POST_IT) { let count = 0; let index = 0; @@ -221,7 +221,7 @@ export class GroupItem 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 index = 0; @@ -318,10 +318,10 @@ export class GroupItem switch(this._category) { - case FurniCategory._Str_5186: + case FurniCategory.POSTER: key = (('poster_' + k.stuffData.getLegacyString()) + '_name'); break; - case FurniCategory._Str_9125: + case FurniCategory.TRAX_SONG: this._name = 'SONG_NAME'; return; default: @@ -442,6 +442,13 @@ export class GroupItem return (item ? item.isGroupable : false); } + public get isSellable(): boolean + { + const item = this.getItemByIndex(0); + + return (item ? item.sellable : false); + } + public get items(): FurnitureItem[] { return this._items; diff --git a/src/components/inventory/common/TradingUtilities.ts b/src/components/inventory/common/TradingUtilities.ts index 9e6e9204..dbf12e4b 100644 --- a/src/components/inventory/common/TradingUtilities.ts +++ b/src/components/inventory/common/TradingUtilities.ts @@ -30,12 +30,12 @@ export function parseTradeItems(items: ItemDataStructure[], _arg_2: AdvancedMap< name = ('itemid' + item.itemId); } - if(item.category === FurniCategory._Str_5186) + if(item.category === FurniCategory.POSTER) { name = (item.itemId + 'poster' + item.stuffData.getLegacyString()); } - else if(item.category === FurniCategory._Str_12454) + else if(item.category === FurniCategory.GUILD_FURNI) { name = ''; } diff --git a/src/components/inventory/views/furniture/InventoryFurnitureView.tsx b/src/components/inventory/views/furniture/InventoryFurnitureView.tsx index f025f5e1..f745d952 100644 --- a/src/components/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/components/inventory/views/furniture/InventoryFurnitureView.tsx @@ -10,7 +10,7 @@ import { LimitedEditionCompactPlateView } from '../../../../views/shared/limited import { RarityLevelView } from '../../../../views/shared/rarity-level/RarityLevelView'; import { RoomPreviewerView } from '../../../../views/shared/room-previewer/RoomPreviewerView'; import { FurniCategory } from '../../common/FurniCategory'; -import { attemptItemPlacement } from '../../common/FurnitureUtilities'; +import { attemptItemPlacement, attemptPlaceMarketplaceOffer } from '../../common/FurnitureUtilities'; import { GroupItem } from '../../common/GroupItem'; import { useInventoryContext } from '../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; @@ -80,15 +80,15 @@ export const InventoryFurnitureView: FC = props => roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); 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); - wallType = ((furnitureItem.category === FurniCategory._Str_3639) ? groupItem.stuffData.getLegacyString() : wallType); - landscapeType = ((furnitureItem.category === FurniCategory._Str_3432) ? groupItem.stuffData.getLegacyString() : landscapeType); + floorType = ((furnitureItem.category === FurniCategory.FLOOR) ? groupItem.stuffData.getLegacyString() : floorType); + wallType = ((furnitureItem.category === FurniCategory.WALL_PAPER) ? groupItem.stuffData.getLegacyString() : wallType); + landscapeType = ((furnitureItem.category === FurniCategory.LANDSCAPE) ? groupItem.stuffData.getLegacyString() : landscapeType); roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); - if(furnitureItem.category === FurniCategory._Str_3432) + if(furnitureItem.category === FurniCategory.LANDSCAPE) { const data = GetSessionDataManager().getWallItemDataByName('noob_window_double'); @@ -133,6 +133,11 @@ export const InventoryFurnitureView: FC = props => } + { (groupItem && groupItem.isSellable) && + + } } diff --git a/src/components/inventory/views/trade/InventoryTradeView.tsx b/src/components/inventory/views/trade/InventoryTradeView.tsx index 73ad1642..5bc8b551 100644 --- a/src/components/inventory/views/trade/InventoryTradeView.tsx +++ b/src/components/inventory/views/trade/InventoryTradeView.tsx @@ -10,6 +10,7 @@ import { Grid } from '../../../../common/Grid'; import { LayoutGridItem } from '../../../../common/layout/LayoutGridItem'; import { Text } from '../../../../common/Text'; import { SendMessageHook } from '../../../../hooks/messages'; +import { NotificationAlertType } from '../../../../views/notification-center/common/NotificationAlertType'; import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities'; import { FurniCategory } from '../../common/FurniCategory'; import { GroupItem } from '../../common/GroupItem'; @@ -49,13 +50,13 @@ export const InventoryTradeView: FC = props => let type = spriteId.toString(); - if(category === FurniCategory._Str_5186) + if(category === FurniCategory.POSTER) { type = ((type + 'poster') + stuffData.getLegacyString()); } else { - if(category === FurniCategory._Str_12454) + if(category === FurniCategory.GUILD_FURNI) { type = _Str_16998(spriteId, stuffData); } @@ -121,7 +122,7 @@ export const InventoryTradeView: FC = props => } 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 ]); @@ -157,6 +158,7 @@ export const InventoryTradeView: FC = props => case TradeState.TRADING_STATE_RUNNING: if(!tradeData.otherUser.itemCount && !tradeData.ownUser.accepts) { + // eslint-disable-next-line no-template-curly-in-string NotificationUtilities.simpleAlert(LocalizeText('${inventory.trading.warning.other_not_offering}'), null, null, null); } diff --git a/src/events/catalog/CatalogPostMarketplaceOfferEvent.ts b/src/events/catalog/CatalogPostMarketplaceOfferEvent.ts new file mode 100644 index 00000000..75e7abea --- /dev/null +++ b/src/events/catalog/CatalogPostMarketplaceOfferEvent.ts @@ -0,0 +1,20 @@ +import { CatalogEvent } from '.'; +import { FurnitureItem } from '../../components/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; + } +} diff --git a/src/events/notification-center/NotificationConfirmEvent.ts b/src/events/notification-center/NotificationConfirmEvent.ts new file mode 100644 index 00000000..6dc1638b --- /dev/null +++ b/src/events/notification-center/NotificationConfirmEvent.ts @@ -0,0 +1,62 @@ +import { NitroEvent } from '@nitrots/nitro-renderer'; + +export class NotificationConfirmEvent extends NitroEvent +{ + public static CONFIRM: string = 'NCE_CONFIRM'; + + private _confirmType: string; + private _message: string; + private _onConfirm: Function; + private _onCancel: Function; + private _confirmText: string; + private _cancelText: string; + private _title: string; + + constructor(confirmType: string, message: string, onConfirm: Function, onCancel: Function, confirmText: string, cancelText: string, title: string) + { + super(NotificationConfirmEvent.CONFIRM); + + this._confirmType = confirmType; + this._message = message; + this._onConfirm = onConfirm; + this._onCancel = onCancel; + this._confirmText = confirmText; + this._cancelText = cancelText; + this._title = title; + } + + public get confirmType(): string + { + return this._confirmType; + } + + public get message(): string + { + return this._message; + } + + public get onConfirm(): Function + { + return this._onConfirm; + } + + public get onCancel(): Function + { + return this._onCancel; + } + + public get confirmText(): string + { + return this._confirmText; + } + + public get cancelText(): string + { + return this._cancelText; + } + + public get title(): string + { + return this._title; + } +} diff --git a/src/events/notification-center/index.ts b/src/events/notification-center/index.ts index cac7d708..7eaa0ab2 100644 --- a/src/events/notification-center/index.ts +++ b/src/events/notification-center/index.ts @@ -2,3 +2,4 @@ export * from './NotificationAlertEvent'; export * from './NotificationBubbleEvent'; export * from './NotificationCenterAlertEvent'; export * from './NotificationCenterEvent'; +export * from './NotificationConfirmEvent'; diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index 850dc1bb..ff833840 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -16,6 +16,7 @@ import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer'; import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView'; import { CatalogPageView } from './views/page/CatalogPageView'; +import { MarketplacePostOfferView } from './views/page/layout/marketplace/post-offer/MarketplacePostOfferView'; export const CatalogView: FC = props => { @@ -224,6 +225,7 @@ export const CatalogView: FC = props => } + ); } diff --git a/src/views/catalog/views/page/layout/CatalogLayout.scss b/src/views/catalog/views/page/layout/CatalogLayout.scss index d71c9f8a..3302b3b8 100644 --- a/src/views/catalog/views/page/layout/CatalogLayout.scss +++ b/src/views/catalog/views/page/layout/CatalogLayout.scss @@ -1,3 +1,5 @@ @import './frontpage4/CatalogLayoutFrontpage4View'; @import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss'; @import './vip-buy/CatalogLayoutVipBuyView'; +@import './marketplace/marketplace-item/MarketplaceItemView'; +@import './marketplace/post-offer/MarketplacePostOfferView'; diff --git a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx index 8fe64187..bbef91a1 100644 --- a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx +++ b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx @@ -6,6 +6,8 @@ import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLa import { CatalogLayouGuildForumView } from './guild-forum/CatalogLayoutGuildForumView'; import { CatalogLayouGuildFrontpageView } from './guild-frontpage/CatalogLayoutGuildFrontpageView'; 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 { CatalogLayoutPets2View } from './pets2/CatalogLayoutPets2View'; import { CatalogLayoutPets3View } from './pets3/CatalogLayoutPets3View'; @@ -41,9 +43,9 @@ export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPrevi case 'club_gifts': return null; case 'marketplace_own_items': - return null; + return ; case 'marketplace': - return null; + return ; case 'single_bundle': return ; case 'spaces_new': diff --git a/src/views/catalog/views/page/layout/marketplace/common/IMarketplaceSearchOptions.ts b/src/views/catalog/views/page/layout/marketplace/common/IMarketplaceSearchOptions.ts new file mode 100644 index 00000000..77734c3a --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/common/IMarketplaceSearchOptions.ts @@ -0,0 +1,6 @@ +export interface IMarketplaceSearchOptions { + query: string; + type: number; + minPrice: number; + maxPrice: number; +} diff --git a/src/views/catalog/views/page/layout/marketplace/common/MarketplaceConfirmType.ts b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceConfirmType.ts new file mode 100644 index 00000000..dbc17f2a --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceConfirmType.ts @@ -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; +} diff --git a/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferData.ts b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferData.ts new file mode 100644 index 00000000..ba1fa88b --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferData.ts @@ -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)); + } +} diff --git a/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferState.ts b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferState.ts new file mode 100644 index 00000000..20c0e45b --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceOfferState.ts @@ -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; +} diff --git a/src/views/catalog/views/page/layout/marketplace/common/MarketplaceSearchType.ts b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceSearchType.ts new file mode 100644 index 00000000..ac7a7019 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/common/MarketplaceSearchType.ts @@ -0,0 +1,6 @@ +export class MarketplaceSearchType +{ + public static readonly BY_ACTIVITY = 1; + public static readonly BY_VALUE = 2; + public static readonly ADVANCED = 3; +} diff --git a/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.scss b/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.scss new file mode 100644 index 00000000..be2f5222 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.scss @@ -0,0 +1,4 @@ +.marketplace-item { + max-height: 70px; + height: 70px; +} diff --git a/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.tsx b/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.tsx new file mode 100644 index 00000000..db086b2a --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/marketplace-item/MarketplaceItemView.tsx @@ -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 = 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 ( + + +
+
{getMarketplaceOfferTitle()}
+
{getMarketplaceOfferDescription()}
+ + { type === OWN_OFFER && <> +
{ LocalizeText('catalog.marketplace.offer.price_own_item', ['price'], [offerData.price.toString()])}
+
{ offerTime() }
+ + } + { type === PUBLIC_OFFER && <> +
{ LocalizeText('catalog.marketplace.offer.price_public_item', ['price', 'average'], [offerData.price.toString(), offerData.averagePrice.toString() ]) }
+
{ LocalizeText('catalog.marketplace.offer_count', ['count'], [offerData.offerCount.toString()]) }
+ + } +
+
+ { (type === OWN_OFFER && offerData.status !== MarketPlaceOfferState.SOLD) && } + { type === PUBLIC_OFFER && <> + + + } +
+
) +} diff --git a/src/views/catalog/views/page/layout/marketplace/own-items/CatalogLayoutMarketplaceOwnItemsView.tsx b/src/views/catalog/views/page/layout/marketplace/own-items/CatalogLayoutMarketplaceOwnItemsView.tsx new file mode 100644 index 00000000..d76ae6f3 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/own-items/CatalogLayoutMarketplaceOwnItemsView.tsx @@ -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 = props => +{ + const [ creditsWaiting, setCreditsWaiting ] = useState(0); + const [ offers, setOffers ] = useState(new Map()); + + UseMountEffect(() => + { + SendMessageHook(new GetMarketplaceOwnOffersMessageComposer()); + }); + + const onMarketPlaceOwnOffersEvent = useCallback((event: MarketplaceOwnOffersEvent) => + { + const parser = event.getParser(); + + if(!parser) return; + + const latestOffers = new Map(); + 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) && {LocalizeText('catalog.marketplace.redeem.no_sold_items')}} + + { (creditsWaiting > 0) && {LocalizeText('catalog.marketplace.redeem.get_credits', ['count', 'credits'], [Array.from(offers.values()).filter(value => value.status === MarketPlaceOfferState.SOLD).length.toString(), creditsWaiting.toString()])}} + + + +
{LocalizeText('catalog.marketplace.items_found', ['count'], [offers.size.toString()])}
+ + { + Array.from(offers.values()).map( (entry, index) => ) + } + + + ); +} diff --git a/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.scss b/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.scss new file mode 100644 index 00000000..46306202 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.scss @@ -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; + } +} diff --git a/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.tsx b/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.tsx new file mode 100644 index 00000000..cef4fae5 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/post-offer/MarketplacePostOfferView.tsx @@ -0,0 +1,111 @@ +import { ImageResult, MakeOfferMessageComposer, Vector3d } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { GetRoomEngine, LocalizeText } from '../../../../../../../api'; +import { FurnitureItem } from '../../../../../../../components/inventory/common/FurnitureItem'; +import { CatalogPostMarketplaceOfferEvent } from '../../../../../../../events/catalog/CatalogPostMarketplaceOfferEvent'; +import { SendMessageHook, useUiEvent } from '../../../../../../../hooks'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex } from '../../../../../../../layout'; +import { NotificationUtilities } from '../../../../../../notification-center/common/NotificationUtilities'; + +export const MarketplacePostOfferView : FC<{}> = props => +{ + const [ item, setItem ] = useState(null); + const [ askingPrice, setAskingPrice ] = useState(0); + + 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 && + + + + +
+
+
{getFurniTitle()}
+
{getFurniDescription()}
+
+ +
+ { LocalizeText('inventory.marketplace.make_offer.expiration_info') } +
+
+
{ LocalizeText('inventory.marketplace.make_offer.price_request') }
+ setAskingPrice(event.target.valueAsNumber) } /> +
+
+ { askingPrice <= 0 || isNaN(askingPrice) ? LocalizeText('inventory.marketplace.make_offer.min_price', ['minprice'], ['1']) : LocalizeText('inventory.marketplace.make_offer.final_price', ['commission', 'finalprice'], ['1', (askingPrice + 1).toString()])} +
+
+ +
+ + + ) +} diff --git a/src/views/catalog/views/page/layout/marketplace/public-items/CatalogLayoutMarketplacePublicItemsView.tsx b/src/views/catalog/views/page/layout/marketplace/public-items/CatalogLayoutMarketplacePublicItemsView.tsx new file mode 100644 index 00000000..69af4473 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/public-items/CatalogLayoutMarketplacePublicItemsView.tsx @@ -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 = props => +{ + const [ searchType, setSearchType ] = useState(MarketplaceSearchType.BY_ACTIVITY); + const [ totalItemsFound, setTotalItemsFound ] = useState(0); + const [ offers, setOffers ] = useState(new Map()); + const [ lastSearch, setLastSearch ] = useState({ 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(); + 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 (<> +
+ + + +
+ + + +
{LocalizeText('catalog.marketplace.items_found', ['count'], [offers.size.toString()])}
+ + { + Array.from(offers.values()).map( (entry, index) => ) + } + + ); +} diff --git a/src/views/catalog/views/page/layout/marketplace/public-items/SearchFormView.tsx b/src/views/catalog/views/page/layout/marketplace/public-items/SearchFormView.tsx new file mode 100644 index 00000000..3fe0d3e6 --- /dev/null +++ b/src/views/catalog/views/page/layout/marketplace/public-items/SearchFormView.tsx @@ -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 = 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 (<> +
+
{ LocalizeText('catalog.marketplace.sort_order') }
+ +
+ { searchType === MarketplaceSearchType.ADVANCED && <> +
+
{ LocalizeText('catalog.marketplace.search_name') }
+ setSearchQuery(event.target.value)}/> +
+ +
+
{ LocalizeText('catalog.marketplace.search_price') }
+ setMin(event.target.valueAsNumber) } /> + setMax(event.target.valueAsNumber) } /> +
+ + + + } + ); +} diff --git a/src/views/mod-tools/ModToolsMessageHandler.tsx b/src/views/mod-tools/ModToolsMessageHandler.tsx index 3357aef8..3863bdb7 100644 --- a/src/views/mod-tools/ModToolsMessageHandler.tsx +++ b/src/views/mod-tools/ModToolsMessageHandler.tsx @@ -1,13 +1,14 @@ import { CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent, RoomEngineEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; import { MODTOOLS_NEW_TICKET, PlaySound } from '../../api/utils/PlaySound'; -import { NotificationAlertEvent } from '../../events'; import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; import { ModToolsOpenRoomChatlogEvent } from '../../events/mod-tools/ModToolsOpenRoomChatlogEvent'; import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent'; import { ModToolsOpenUserChatlogEvent } from '../../events/mod-tools/ModToolsOpenUserChatlogEvent'; 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 { useModToolsContext } from './context/ModToolsContext'; import { ModToolsActions } from './reducers/ModToolsReducer'; @@ -38,8 +39,7 @@ export const ModToolsMessageHandler: FC<{}> = props => tickets: data.issues } }); - - console.log(parser); + }, [dispatchModToolsState]); const onIssueInfoMessageEvent = useCallback((event: IssueInfoMessageEvent) => @@ -68,7 +68,6 @@ export const ModToolsMessageHandler: FC<{}> = props => } }); - console.log(parser); }, [dispatchModToolsState, tickets]); const onModeratorToolPreferencesEvent = useCallback((event: ModeratorToolPreferencesEvent) => @@ -77,7 +76,6 @@ export const ModToolsMessageHandler: FC<{}> = props => if(!parser) return; - console.log(parser); }, []); const onIssuePickFailedMessageEvent = useCallback((event: IssuePickFailedMessageEvent) => @@ -86,8 +84,7 @@ export const ModToolsMessageHandler: FC<{}> = props => if(!parser) return; - // todo: let user know it failed - dispatchUiEvent(new NotificationAlertEvent(['Failed to pick issue'], null, null, null, 'Error', null)); + NotificationUtilities.simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error') }, []); const onIssueDeletedMessageEvent = useCallback((event: IssueDeletedMessageEvent) => @@ -119,11 +116,11 @@ export const ModToolsMessageHandler: FC<{}> = props => 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 { - 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); - console.log(parser); }, [dispatchModToolsState]); const onCfhSanctionMessageEvent = useCallback((event: CfhSanctionMessageEvent) => @@ -153,7 +149,7 @@ export const ModToolsMessageHandler: FC<{}> = props => if(!parser) return; - console.log(parser); + // todo: update sanction data }, []); CreateMessageHook(ModeratorInitMessageEvent, onModeratorInitMessageEvent); diff --git a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx b/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx index 09454bdc..88bcbac1 100644 --- a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx +++ b/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx @@ -1,9 +1,10 @@ import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; import { LocalizeText } from '../../../../../api'; -import { NotificationAlertEvent } from '../../../../../events'; -import { dispatchUiEvent, SendMessageHook } from '../../../../../hooks'; +import { SendMessageHook } from '../../../../../hooks'; 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 { ModActionDefinition } from '../../../utils/ModActionDefinition'; import { ModToolsUserModActionViewProps } from './ModToolsUserModActionView.types'; @@ -59,13 +60,13 @@ export const ModToolsUserModActionView: FC = pro { 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; } 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; } @@ -74,13 +75,13 @@ export const ModToolsUserModActionView: FC = pro 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; } 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; } @@ -92,13 +93,13 @@ export const ModToolsUserModActionView: FC = pro 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; } 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; } @@ -113,7 +114,7 @@ export const ModToolsUserModActionView: FC = pro 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; } @@ -125,7 +126,7 @@ export const ModToolsUserModActionView: FC = pro 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; } @@ -144,7 +145,7 @@ export const ModToolsUserModActionView: FC = pro 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; } diff --git a/src/views/notification-center/NotificationCenterView.tsx b/src/views/notification-center/NotificationCenterView.tsx index 0367b604..8f74f251 100644 --- a/src/views/notification-center/NotificationCenterView.tsx +++ b/src/views/notification-center/NotificationCenterView.tsx @@ -1,20 +1,23 @@ import { FC, ReactNode, useCallback, useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; -import { NotificationAlertEvent } from '../../events'; +import { NotificationAlertEvent, NotificationConfirmEvent } from '../../events'; import { NotificationBubbleEvent } from '../../events/notification-center/NotificationBubbleEvent'; import { useUiEvent } from '../../hooks/events'; import { NotificationAlertItem } from './common/NotificationAlertItem'; import { NotificationBubbleItem } from './common/NotificationBubbleItem'; import { NotificationBubbleType } from './common/NotificationBubbleType'; +import { NotificationConfirmItem } from './common/NotificationConfirmItem'; import { NotificationCenterMessageHandler } from './NotificationCenterMessageHandler'; import { NotificationCenterViewProps } from './NotificationCenterView.types'; import { GetAlertLayout } from './views/alert-layouts/GetAlertLayout'; import { GetBubbleLayout } from './views/bubble-layouts/GetBubbleLayout'; +import { GetConfirmLayout } from './views/confirm-layouts/GetConfirmLayout'; export const NotificationCenterView: FC = props => { const [ alerts, setAlerts ] = useState([]); const [ bubbleAlerts, setBubbleAlerts ] = useState([]); + const [ confirms, setConfirms ] = useState([]); const onNotificationAlertEvent = useCallback((event: NotificationAlertEvent) => { @@ -36,6 +39,15 @@ export const NotificationCenterView: FC = props => useUiEvent(NotificationBubbleEvent.NEW_BUBBLE, onNotificationBubbleEvent); + const onNotificationConfirmEvent = useCallback((event: NotificationConfirmEvent) => + { + const confirmItem = new NotificationConfirmItem(event.type, event.message, event.onConfirm, event.onCancel, event.confirmText, event.cancelText, event.title); + + setConfirms(prevValue => [ confirmItem, ...prevValue ]); + }, []); + + useUiEvent(NotificationConfirmEvent.CONFIRM, onNotificationConfirmEvent); + const closeAlert = useCallback((alert: NotificationAlertItem) => { setAlerts(prevValue => @@ -62,6 +74,19 @@ export const NotificationCenterView: FC = props => }) }, []); + const closeConfirm = useCallback((item: NotificationConfirmItem) => + { + setConfirms(prevValue => + { + const newConfirms = [ ...prevValue ]; + const index = newConfirms.findIndex(value => (item === value)); + + if(index >= 0) newConfirms.splice(index, 1); + + return newConfirms; + }) + }, []); + const getAlerts = useMemo(() => { if(!alerts || !alerts.length) return null; @@ -101,6 +126,22 @@ export const NotificationCenterView: FC = props => return elements; }, [ bubbleAlerts, closeBubbleAlert ]); + const getConfirms = useMemo(() => + { + if(!confirms || !confirms.length) return null; + + const elements: ReactNode[] = []; + + for(const confirm of confirms) + { + const element = GetConfirmLayout(confirm, () => closeConfirm(confirm)); + + elements.push(element); + } + + return elements; + }, [ confirms, closeConfirm ]); + return ( <> @@ -108,6 +149,7 @@ export const NotificationCenterView: FC = props => { getBubbleAlerts }
{ createPortal(getAlerts, document.getElementById('nitro-alerts-container')) } + { createPortal(getConfirms, document.getElementById('nitro-confirms-container')) } ); } diff --git a/src/views/notification-center/common/NotificationConfirmItem.ts b/src/views/notification-center/common/NotificationConfirmItem.ts new file mode 100644 index 00000000..04556626 --- /dev/null +++ b/src/views/notification-center/common/NotificationConfirmItem.ts @@ -0,0 +1,67 @@ +export class NotificationConfirmItem +{ + private static ITEM_ID: number = -1; + + private _id: number; + private _confirmType: string; + private _message: string; + private _onConfirm: Function; + private _onCancel: Function; + private _confirmText: string; + private _cancelText: string; + private _title: string; + + constructor(confirmType: string, message: string, onConfirm: Function, onCancel: Function, confirmText: string, cancelText: string, title: string) + { + NotificationConfirmItem.ITEM_ID += 1; + + this._id = NotificationConfirmItem.ITEM_ID; + this._confirmType = confirmType; + this._message = message; + this._onConfirm = onConfirm; + this._onCancel = onCancel; + this._confirmText = confirmText; + this._cancelText = cancelText; + this._title = title; + } + + public get id(): number + { + return this._id; + } + + public get confirmType(): string + { + return this._confirmType; + } + + public get message(): string + { + return this._message; + } + + public get onConfirm(): Function + { + return this._onConfirm; + } + + public get onCancel(): Function + { + return this._onCancel; + } + + public get confirmText(): string + { + return this._confirmText; + } + + public get cancelText(): string + { + return this._cancelText; + } + + public get title(): string + { + return this._title; + } +} diff --git a/src/views/notification-center/common/NotificationConfirmType.ts b/src/views/notification-center/common/NotificationConfirmType.ts new file mode 100644 index 00000000..533ca053 --- /dev/null +++ b/src/views/notification-center/common/NotificationConfirmType.ts @@ -0,0 +1,4 @@ +export class NotificationConfirmType +{ + public static DEFAULT: string = 'default'; +} diff --git a/src/views/notification-center/common/NotificationUtilities.ts b/src/views/notification-center/common/NotificationUtilities.ts index 1ee727d0..c14dda6a 100644 --- a/src/views/notification-center/common/NotificationUtilities.ts +++ b/src/views/notification-center/common/NotificationUtilities.ts @@ -1,6 +1,6 @@ import { HabboWebTools, RoomEnterEffect } from '@nitrots/nitro-renderer'; import { CreateLinkEvent, GetConfiguration, GetNitroInstance, LocalizeText } from '../../../api'; -import { NotificationAlertEvent } from '../../../events'; +import { NotificationAlertEvent, NotificationConfirmEvent } from '../../../events'; import { NotificationBubbleEvent } from '../../../events/notification-center/NotificationBubbleEvent'; import { dispatchUiEvent } from '../../../hooks'; import { CatalogPageName } from '../../catalog/common/CatalogPageName'; @@ -112,7 +112,18 @@ export class NotificationUtilities dispatchUiEvent(new NotificationAlertEvent(messages, NotificationAlertType.MOTD, null, null, LocalizeText('notifications.motd.title'))); } - public static simpleAlert(message: string, type: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void + public static confirm(message: string, onConfirm: Function, onCancel: Function, confirmText: string = null, cancelText: string = null, title: string = null, type: string = null): void + { + if(!confirmText || !confirmText.length) confirmText = LocalizeText('generic.confirm'); + + if(!cancelText || !cancelText.length) cancelText = LocalizeText('generic.cancel'); + + if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); + + dispatchUiEvent(new NotificationConfirmEvent(type, this.cleanText(message), onConfirm, onCancel, confirmText, cancelText, title)); + } + + public static simpleAlert(message: string, type: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void { if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); diff --git a/src/views/notification-center/views/confirm-layouts/GetConfirmLayout.tsx b/src/views/notification-center/views/confirm-layouts/GetConfirmLayout.tsx new file mode 100644 index 00000000..5a34a2db --- /dev/null +++ b/src/views/notification-center/views/confirm-layouts/GetConfirmLayout.tsx @@ -0,0 +1,15 @@ +import { NotificationConfirmItem } from '../../common/NotificationConfirmItem'; +import { NotificationDefaultConfirmView } from './default/NotificationDefaultConfirmView'; + +export const GetConfirmLayout = (item: NotificationConfirmItem, close: () => void) => +{ + if(!item) return null; + + const props = { key: item.id, item, close }; + + switch(item.confirmType) + { + default: + return + } +} diff --git a/src/views/notification-center/views/confirm-layouts/NotificationConfirmLayoutView.types.ts b/src/views/notification-center/views/confirm-layouts/NotificationConfirmLayoutView.types.ts new file mode 100644 index 00000000..fbddeb27 --- /dev/null +++ b/src/views/notification-center/views/confirm-layouts/NotificationConfirmLayoutView.types.ts @@ -0,0 +1,7 @@ +import { NotificationConfirmItem } from '../../common/NotificationConfirmItem'; + +export interface NotificationConfirmLayoutViewProps +{ + item: NotificationConfirmItem; + close: () => void; +} diff --git a/src/views/notification-center/views/confirm-layouts/default/NotificationDefaultConfirmView.tsx b/src/views/notification-center/views/confirm-layouts/default/NotificationDefaultConfirmView.tsx new file mode 100644 index 00000000..8446562d --- /dev/null +++ b/src/views/notification-center/views/confirm-layouts/default/NotificationDefaultConfirmView.tsx @@ -0,0 +1,38 @@ +import { DetailsHTMLAttributes, FC } from 'react'; +import { NotificationAlertView } from '../../../../../layout'; +import { NotificationConfirmLayoutViewProps } from '../NotificationConfirmLayoutView.types'; + +export interface NotificationDefaultConfirmViewProps extends NotificationConfirmLayoutViewProps, DetailsHTMLAttributes +{ + +} + +export const NotificationDefaultConfirmView: FC = props => +{ + const { item = null, close = null, ...rest } = props; + const { message = null, onConfirm = null, onCancel = null, confirmText = null, cancelText = null, title = null } = item; + + const confirm = () => + { + if(onConfirm) onConfirm(); + + close(); + } + + const cancel = () => + { + if(onCancel) onCancel(); + + close(); + } + + return ( + + { message } +
+ + +
+
+ ); +} diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx index 1ec6cae4..3f06e3c9 100644 --- a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx @@ -48,7 +48,7 @@ export const AvatarInfoUseProductConfirmView: FC } - case FurniCategory._Str_7297: { + case FurniCategory.PET_CUSTOM_PART: { if(customParts.length < 4) return null; const newCustomParts: PetCustomPart[] = []; @@ -95,7 +95,7 @@ export const AvatarInfoUseProductConfirmView: FC; } - case FurniCategory._Str_7954: { + case FurniCategory.PET_CUSTOM_PART_SHAMPOO: { if(customParts.length < 3) return null; const newCustomParts: PetCustomPart[] = []; @@ -121,7 +121,7 @@ export const AvatarInfoUseProductConfirmView: FC; } - case FurniCategory._Str_6096: { + case FurniCategory.PET_SADDLE: { if(customParts.length < 4) return null; const newCustomParts: PetCustomPart[] = []; @@ -149,9 +149,9 @@ export const AvatarInfoUseProductConfirmView: FC; } - case FurniCategory._Str_8726: - case FurniCategory._Str_6915: - case FurniCategory._Str_9449: { + case FurniCategory.MONSTERPLANT_REBREED: + case FurniCategory.MONSTERPLANT_REVIVAL: + case FurniCategory.MONSTERPLANT_FERTILIZE: { let posture = 'rip'; const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT); @@ -190,25 +190,25 @@ export const AvatarInfoUseProductConfirmView: FC = props => { @@ -31,30 +31,30 @@ export const AvatarInfoUseProductView: FC = props if(!furniData) return; - let mode = _Str_2906; + let mode = PRODUCT_PAGE_UKNOWN; switch(furniData.specialType) { - case FurniCategory._Str_7696: - mode = _Str_13718; + case FurniCategory.PET_SHAMPOO: + mode = PRODUCT_PAGE_SHAMPOO; break; - case FurniCategory._Str_7297: - mode = _Str_14146; + case FurniCategory.PET_CUSTOM_PART: + mode = PRODUCT_PAGE_CUSTOM_PART; break; - case FurniCategory._Str_7954: - mode = _Str_15667; + case FurniCategory.PET_CUSTOM_PART_SHAMPOO: + mode = PRODUCT_PAGE_CUSTOM_PART_SHAMPOO; break; - case FurniCategory._Str_6096: - mode = _Str_14658; + case FurniCategory.PET_SADDLE: + mode = PRODUCT_PAGE_SADDLE; break; - case FurniCategory._Str_6915: - mode = _Str_14165; + case FurniCategory.MONSTERPLANT_REVIVAL: + mode = PRODUCT_PAGE_REVIVE; break; - case FurniCategory._Str_8726: - mode = _Str_12577; + case FurniCategory.MONSTERPLANT_REBREED: + mode = PRODUCT_PAGE_REBREED; break; - case FurniCategory._Str_9449: - mode = _Str_14611; + case FurniCategory.MONSTERPLANT_FERTILIZE: + mode = PRODUCT_PAGE_FERTILIZE; break; } @@ -86,23 +86,23 @@ export const AvatarInfoUseProductView: FC = props { item.name } - { (mode === _Str_2906) && + { (mode === PRODUCT_PAGE_UKNOWN) && processAction('use_product') }> { LocalizeText('infostand.button.useproduct') } } - { (mode === _Str_13718) && + { (mode === PRODUCT_PAGE_SHAMPOO) && processAction('use_product_shampoo') }> { LocalizeText('infostand.button.useproduct_shampoo') } } - { (mode === _Str_14146) && + { (mode === PRODUCT_PAGE_CUSTOM_PART) && processAction('use_product_custom_part') }> { LocalizeText('infostand.button.useproduct_custom_part') } } - { (mode === _Str_15667) && + { (mode === PRODUCT_PAGE_CUSTOM_PART_SHAMPOO) && processAction('use_product_custom_part_shampoo') }> { LocalizeText('infostand.button.useproduct_custom_part_shampoo') } } - { (mode === _Str_14658) && + { (mode === PRODUCT_PAGE_SADDLE) && <> { item.replace && processAction('replace_product_saddle') }> @@ -113,15 +113,15 @@ export const AvatarInfoUseProductView: FC = props { LocalizeText('infostand.button.useproduct_saddle') } } } - { (mode === _Str_14165) && + { (mode === PRODUCT_PAGE_REVIVE) && processAction('revive_monsterplant') }> { LocalizeText('infostand.button.revive_monsterplant') } } - { (mode === _Str_12577) && + { (mode === PRODUCT_PAGE_REBREED) && processAction('rebreed_monsterplant') }> { LocalizeText('infostand.button.rebreed_monsterplant') } } - { (mode === _Str_14611) && + { (mode === PRODUCT_PAGE_FERTILIZE) && processAction('fertilize_monsterplant') }> { LocalizeText('infostand.button.fertilize_monsterplant') } } diff --git a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx index bdb93aec..01cf94c2 100644 --- a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx +++ b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx @@ -43,7 +43,7 @@ export const PurchasableClothingConfirmView: FC parseInt(part));