diff --git a/src/views/catalog/CatalogMessageHandler.tsx b/src/views/catalog/CatalogMessageHandler.tsx index e536a6a9..836de880 100644 --- a/src/views/catalog/CatalogMessageHandler.tsx +++ b/src/views/catalog/CatalogMessageHandler.tsx @@ -1,4 +1,4 @@ -import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceConfigurationEvent, MarketplaceMakeOfferResult, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent, UserSubscriptionEvent } from '@nitrots/nitro-renderer'; +import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, 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 { FC, useCallback } from 'react'; import { LocalizeText } from '../../api'; @@ -204,6 +204,20 @@ export const CatalogMessageHandler: FC = props => }); }, [dispatchCatalogState]); + const onClubGiftInfoEvent = useCallback((event: ClubGiftInfoEvent) => + { + const parser = event.getParser(); + + if(!parser) return; + + dispatchCatalogState({ + type: CatalogActions.SET_CLUB_GIFTS, + payload: { + clubGifts: parser + } + }); + }, [dispatchCatalogState]); + CreateMessageHook(CatalogPagesListEvent, onCatalogPagesListEvent); CreateMessageHook(CatalogPageMessageEvent, onCatalogPageMessageEvent); CreateMessageHook(PurchaseOKMessageEvent, onPurchaseOKMessageEvent); @@ -219,6 +233,7 @@ export const CatalogMessageHandler: FC = props => CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent); CreateMessageHook(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent); CreateMessageHook(GiftWrappingConfigurationEvent, onGiftWrappingConfigurationEvent); + CreateMessageHook(ClubGiftInfoEvent, onClubGiftInfoEvent); CreateMessageHook(MarketplaceMakeOfferResult, onMarketplaceMakeOfferResult); CreateMessageHook(MarketplaceConfigurationEvent, onMarketplaceConfigurationEvent); diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index 739f126d..44df2707 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -1,4 +1,4 @@ -import { GetCatalogIndexComposer, GetCatalogPageComposer, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer'; +import { GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { CREDITS, PlaySound } from '../../api/utils/PlaySound'; @@ -193,6 +193,7 @@ export const CatalogView: FC = props => { SendMessageHook(new GetMarketplaceConfigurationMessageComposer()); SendMessageHook(new GetGiftWrappingConfigurationComposer()); + SendMessageHook(new GetClubGiftInfo()); }); const currentNavigationPage = ((searchResult && searchResult.page) || currentTab); diff --git a/src/views/catalog/reducers/CatalogReducer.tsx b/src/views/catalog/reducers/CatalogReducer.tsx index 87eba150..9747147d 100644 --- a/src/views/catalog/reducers/CatalogReducer.tsx +++ b/src/views/catalog/reducers/CatalogReducer.tsx @@ -1,4 +1,4 @@ -import { CatalogPageMessageOfferData, CatalogPageMessageParser, ClubOfferData, GiftWrappingConfigurationParser, INodeData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; +import { CatalogPageMessageOfferData, CatalogPageMessageParser, ClubGiftInfoParser, ClubOfferData, GiftWrappingConfigurationParser, INodeData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData'; import { Reducer } from 'react'; import { CatalogPetPalette } from '../common/CatalogPetPalette'; @@ -17,6 +17,7 @@ export interface ICatalogState groups: HabboGroupEntryData[]; petPalettes: CatalogPetPalette[]; clubOffers: ClubOfferData[]; + clubGifts: ClubGiftInfoParser; subscriptionInfo: SubscriptionInfo; giftConfiguration: GiftWrappingConfiguration; marketplaceConfiguration: MarketplaceConfigurationMessageParser; @@ -35,6 +36,7 @@ export interface ICatalogAction groups?: HabboGroupEntryData[]; petPalette?: CatalogPetPalette; clubOffers?: ClubOfferData[]; + clubGifts?: ClubGiftInfoParser; subscriptionInfo?: SubscriptionInfo; giftConfiguration?: GiftWrappingConfigurationParser; marketplaceConfiguration?: MarketplaceConfigurationMessageParser; @@ -54,6 +56,7 @@ export class CatalogActions public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT'; public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO'; public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION'; + public static SET_CLUB_GIFTS: string = 'CA_SET_CLUB_GIFTS'; public static SET_MARKETPLACE_CONFIGURATION: string = 'CA_SET_MARKETPLACE_CONFIGURATION'; } @@ -67,6 +70,7 @@ export const initialCatalog: ICatalogState = { groups: [], petPalettes: [], clubOffers: null, + clubGifts: null, subscriptionInfo: new SubscriptionInfo(), giftConfiguration: null, marketplaceConfiguration: null @@ -164,8 +168,13 @@ export const CatalogReducer: Reducer = (state, ac return { ...state, giftConfiguration }; } + case CatalogActions.SET_CLUB_GIFTS: { + const clubGifts = (action.payload.clubGifts || state.clubGifts || null); + + return { ...state, clubGifts }; + } case CatalogActions.SET_MARKETPLACE_CONFIGURATION: { - let marketplaceConfiguration = (action.payload.marketplaceConfiguration || state.marketplaceConfiguration || null); + const marketplaceConfiguration = (action.payload.marketplaceConfiguration || state.marketplaceConfiguration || null); return { ...state, marketplaceConfiguration } } diff --git a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx index bbef91a1..d5411cf0 100644 --- a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx +++ b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx @@ -1,5 +1,6 @@ import { CatalogPageMessageParser, RoomPreviewer } from '@nitrots/nitro-renderer'; import { CatalogLayoutBadgeDisplayView } from './badge-display/CatalogLayoutBadgeDisplayView'; +import { CatalogLayoutColorGroupingView } from './color-grouping/CatalogLayoutColorGroupingView'; import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView'; import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View'; import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLayoutGuildCustomFurniView'; @@ -15,6 +16,7 @@ import { CatalogLayoutSingleBundleView } from './single-bundle/CatalogLayoutSing import { CatalogLayoutSpacesView } from './spaces-new/CatalogLayoutSpacesView'; import { CatalogLayoutTrophiesView } from './trophies/CatalogLayoutTrophiesView'; import { CatalogLayoutVipBuyView } from './vip-buy/CatalogLayoutVipBuyView'; +import { CatalogLayoutVipGiftsView } from './vip-gifts/CatalogLayoutVipGiftsView'; export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPreviewer: RoomPreviewer) => { @@ -41,7 +43,7 @@ export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPrevi case 'search_results': return null; case 'club_gifts': - return null; + return ; case 'marketplace_own_items': return ; case 'marketplace': @@ -56,6 +58,8 @@ export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPrevi return ; case 'badge_display': return ; + case 'default_3x3_color_grouping': + return ; case 'bots': case 'default_3x3': default: diff --git a/src/views/catalog/views/page/layout/color-grouping/CatalogLayoutColorGroupingView.tsx b/src/views/catalog/views/page/layout/color-grouping/CatalogLayoutColorGroupingView.tsx new file mode 100644 index 00000000..258893fe --- /dev/null +++ b/src/views/catalog/views/page/layout/color-grouping/CatalogLayoutColorGroupingView.tsx @@ -0,0 +1,12 @@ +import { FC } from 'react'; +import { CatalogLayoutProps } from '../CatalogLayout.types'; + +export interface CatalogLayoutColorGroupViewProps extends CatalogLayoutProps +{ + +} + +export const CatalogLayoutColorGroupingView : FC = props => +{ + return null; +} diff --git a/src/views/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx b/src/views/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx new file mode 100644 index 00000000..be60d347 --- /dev/null +++ b/src/views/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx @@ -0,0 +1,73 @@ +import { SelectClubGiftComposer } from '@nitrots/nitro-renderer'; +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../../api'; +import { SendMessageHook } from '../../../../../../hooks'; +import { NitroCardGridView } from '../../../../../../layout'; +import { NitroLayoutBase } from '../../../../../../layout/base'; +import { NotificationUtilities } from '../../../../../notification-center/common/NotificationUtilities'; +import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogActions } from '../../../../reducers/CatalogReducer'; +import { CatalogLayoutProps } from '../CatalogLayout.types'; +import { VipGiftItem } from './gift-item/VipGiftItemView'; + +export interface CatalogLayoutVipGiftsViewProps extends CatalogLayoutProps +{ + +} + +export const CatalogLayoutVipGiftsView: FC = props => +{ + const { catalogState, dispatchCatalogState } = useCatalogContext(); + + const giftsAvailable = useCallback(() => + { + const clubGifts = catalogState.clubGifts; + + if(!clubGifts) return ''; + + if(clubGifts.giftsAvailable > 0) + { + return LocalizeText('catalog.club_gift.available', ['amount'], [clubGifts.giftsAvailable.toString()]); + } + + if(clubGifts.daysUntilNextGift > 0) + { + return LocalizeText('catalog.club_gift.days_until_next', ['days'], [clubGifts.daysUntilNextGift.toString()]); + } + + if(catalogState.subscriptionInfo.isVip) + { + return LocalizeText('catalog.club_gift.not_available'); + } + + return LocalizeText('catalog.club_gift.no_club'); + + }, [catalogState.clubGifts, catalogState.subscriptionInfo.isVip]); + + const selectGift = useCallback((localizationId: string) => + { + NotificationUtilities.confirm(LocalizeText('catalog.club_gift.confirm'), () => + { + SendMessageHook(new SelectClubGiftComposer(localizationId)); + const prev = catalogState.clubGifts; + + prev.giftsAvailable--; + + dispatchCatalogState({ + type: CatalogActions.SET_CLUB_GIFTS, + payload: { + clubGifts: prev + } + }); + }, null); + }, [catalogState.clubGifts, dispatchCatalogState]); + + return ( + <> + {giftsAvailable()} + + { catalogState.clubGifts && catalogState.clubGifts.offers.map( (offer, index) => 0} onSelect={selectGift}/>)} + + + ) +} diff --git a/src/views/catalog/views/page/layout/vip-gifts/gift-item/VipGiftItemView.tsx b/src/views/catalog/views/page/layout/vip-gifts/gift-item/VipGiftItemView.tsx new file mode 100644 index 00000000..2bb32ba0 --- /dev/null +++ b/src/views/catalog/views/page/layout/vip-gifts/gift-item/VipGiftItemView.tsx @@ -0,0 +1,61 @@ +import { CatalogPageMessageOfferData } from '@nitrots/nitro-renderer'; +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../../../api'; +import { NitroCardGridItemView } from '../../../../../../../layout'; +import { ProductImageUtility } from '../../../../../../notification-center/common/ProductImageUtility'; + +export interface VipGiftItemViewProps +{ + offer: CatalogPageMessageOfferData; + isAvailable: boolean; + onSelect(localizationId: string): void; +} + +export const VipGiftItem : FC = props => +{ + const { offer = null, isAvailable = false, onSelect = null } = props; + + const getImageUrlForOffer = useCallback( () => + { + if(!offer || !offer.products.length) return ''; + + const productData = offer.products[0]; + + return ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam); + }, [offer]); + + const getItemTitle = useCallback(() => + { + if(!offer || !offer.products.length) return ''; + + const productData = offer.products[0]; + + const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.name.' + productData.furniClassId : 'roomItem.name.' + productData.furniClassId; + + return LocalizeText(localizationKey); + }, [offer]); + + const getItemDesc = useCallback( () => + { + if(!offer || !offer.products.length) return ''; + + const productData = offer.products[0]; + + const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.desc.' + productData.furniClassId : 'roomItem.desc.' + productData.furniClassId ; + + return LocalizeText(localizationKey); + }, [offer]); + + return ( + + +
+
{getItemTitle()}
+
{getItemDesc()}
+
+
+ +
+
+ ) +} diff --git a/src/views/notification-center/common/ProductImageUtility.ts b/src/views/notification-center/common/ProductImageUtility.ts index 9078754c..a05dd13f 100644 --- a/src/views/notification-center/common/ProductImageUtility.ts +++ b/src/views/notification-center/common/ProductImageUtility.ts @@ -41,7 +41,7 @@ export class ProductImageUtility return imageUrl; } - private static getProductCategory(productType: string, furniClassId: number): number + public static getProductCategory(productType: string, furniClassId: number): number { if(productType === CatalogPageMessageProductData.S) return 1;