diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx index 145620d..863b39e 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx @@ -1,7 +1,8 @@ import { FC } from 'react'; -import { SanitizeHtml } from '../../../../../api'; -import { Column, Grid, Text } from '../../../../../common'; -import { useCatalogData } from '../../../../../hooks'; +import { FaExchangeAlt, FaSyncAlt } from 'react-icons/fa'; +import { Column } from '../../../../../common'; +import { useCatalogData, useUserGroups } from '../../../../../hooks'; +import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -10,40 +11,43 @@ import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; -export const CatalogLayouGuildCustomFurniView: FC = props => +export const CatalogLayouGuildCustomFurniView: FC = () => { - const { page = null } = props; - const { currentOffer = null } = useCatalogData(); + const { currentOffer = null, roomPreviewer = null } = useCatalogData(); + const { data: groups = null } = useUserGroups(); + const hasGroups = !!(groups && groups.length); return ( - - - - - - { !currentOffer && - <> - { !!page.localization.getImage(1) && } - - } - { currentOffer && - <> -
- - + <> + + + { !!currentOffer && +
+ + + +
+
- - { currentOffer.localizationName } -
- -
-
- -
- -
- } +
+ +
+
} +
+ +
+ { !!currentOffer && +
+ + { hasGroups && + } +
}
- + ); }; + diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx index bfbe7e5..0145230 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx @@ -25,14 +25,16 @@ export const CatalogLayouGuildForumView: FC = props =>
{ !!currentOffer && - - -
- -
+
+ + +
+ +
+
{ hasGroups && } - } +
} { !!teaserImage && diff --git a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx index 2168c81..a5424c9 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx @@ -1,15 +1,38 @@ -import { CreateLinkEvent, StringDataType } from '@nitrots/nitro-renderer'; +import { CreateLinkEvent, GetSessionDataManager, StringDataType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { LocalizeText } from '../../../../../api'; import { Button, Flex } from '../../../../../common'; import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks'; -export const CatalogGuildSelectorWidgetView: FC<{}> = props => +interface CatalogGuildSelectorWidgetViewProps { + ownerOnly?: boolean; +} + +export const CatalogGuildSelectorWidgetView: FC = props => +{ + const { ownerOnly = false } = props; const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); const { currentOffer = null } = useCatalogData(); const { setPurchaseOptions = null } = useCatalogUiState(); - const { data: groups = null } = useUserGroups(); + const { data: allGroups = null } = useUserGroups(); + + const groups = useMemo(() => + { + if(!allGroups || !ownerOnly) return allGroups; + + const ownerId = GetSessionDataManager().userId; + const hasOwnerData = allGroups.some(group => typeof (group as { ownerId?: number }).ownerId === 'number'); + + if(!hasOwnerData) return allGroups; + + return allGroups.filter(group => (group as { ownerId?: number }).ownerId === ownerId); + }, [ allGroups, ownerOnly ]); + + useEffect(() => + { + if(groups && (selectedGroupIndex >= groups.length)) setSelectedGroupIndex(0); + }, [ groups, selectedGroupIndex ]); const previewStuffData = useMemo(() => { diff --git a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx index 46c0184..c1ade7a 100644 --- a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx @@ -4,8 +4,9 @@ import { BuildPurchasableClothingFigure, FurniCategory, Offer, ProductTypeEnum } import { AutoGrid, Column, LayoutGridItem, LayoutRoomPreviewerView } from '../../../../../common'; import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; -export const CatalogViewProductWidgetView: FC<{}> = props => +export const CatalogViewProductWidgetView: FC<{ height?: number }> = props => { + const { height = 240 } = props; const { currentOffer = null, roomPreviewer = null } = useCatalogData(); const { purchaseOptions = null } = useCatalogUiState(); const { previewStuffData = null } = purchaseOptions; @@ -125,5 +126,5 @@ export const CatalogViewProductWidgetView: FC<{}> = props => ); } - return ; + return ; }; diff --git a/src/css/catalog/CatalogClassicView.css b/src/css/catalog/CatalogClassicView.css index d42744c..5f602b3 100644 --- a/src/css/catalog/CatalogClassicView.css +++ b/src/css/catalog/CatalogClassicView.css @@ -1354,6 +1354,16 @@ line-height: 17px !important; } +.nitro-catalog-classic-window .nitro-catalog-preview-price .nitro-catalog-swf-price-text { + color: #ffffff !important; + text-shadow: + 0 0 2px #000, + 1px 1px 1px #000, + -1px 1px 1px #000, + 1px -1px 1px #000, + -1px -1px 1px #000 !important; +} + .nitro-catalog-swf-price-plus { width: 7px; height: 7px; diff --git a/src/hooks/groups/useUserGroups.ts b/src/hooks/groups/useUserGroups.ts index 470e55c..1ae768b 100644 --- a/src/hooks/groups/useUserGroups.ts +++ b/src/hooks/groups/useUserGroups.ts @@ -1,32 +1,31 @@ import { CatalogGroupsComposer, GuildMembershipsMessageEvent, HabboGroupEntryData } from '@nitrots/nitro-renderer'; -import { UseQueryResult } from '@tanstack/react-query'; -import { useNitroQuery } from '../../api/nitro-query'; +import { useCallback, useEffect, useState } from 'react'; +import { useBetween } from 'use-between'; +import { SendMessageComposer } from '../../api'; +import { useMessageEvent } from '../events'; -/** - * The list of guilds the current Habbo belongs to, as returned by - * the `CatalogGroupsComposer` → `GuildMembershipsMessageEvent` - * request/response pair. - * - * Cached at session level: the membership list is stable for the - * session unless the user joins/leaves a guild (in which case the - * relevant flow should invalidate the `['nitro', 'user', 'groups']` - * query key, which today nobody does — re-mounting the consumer - * refetches via React Query's default behavior). - * - * Replaces three duplicate request+listener pairs that previously - * each issued their own CatalogGroupsComposer: - * - useCatalog (catalogOptions.groups) - * - WiredSelectorUsersGroupView - * - WiredConditionActorIsGroupMemberView - */ -export const useUserGroups = ( - options: { enabled?: boolean } = {} -): UseQueryResult => - useNitroQuery({ - key: [ 'nitro', 'user', 'groups' ], - request: () => new CatalogGroupsComposer(), - parser: GuildMembershipsMessageEvent, - select: event => (event.getParser().groups || []), - enabled: options.enabled, - staleTime: Infinity - }); +const useUserGroupsStore = () => +{ + const [ groups, setGroups ] = useState([]); + + const onGuildMemberships = useCallback((event: GuildMembershipsMessageEvent) => + { + setGroups(event.getParser()?.groups || []); + }, []); + + useMessageEvent(GuildMembershipsMessageEvent, onGuildMemberships); + + useEffect(() => + { + SendMessageComposer(new CatalogGroupsComposer()); + }, []); + + return { groups }; +}; + +export const useUserGroups = (): { data: HabboGroupEntryData[] } => +{ + const { groups } = useBetween(useUserGroupsStore); + + return { data: groups }; +};