mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Fix Group Forum buy
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { SanitizeHtml } from '../../../../../api';
|
import { FaExchangeAlt, FaSyncAlt } from 'react-icons/fa';
|
||||||
import { Column, Grid, Text } from '../../../../../common';
|
import { Column } from '../../../../../common';
|
||||||
import { useCatalogData } from '../../../../../hooks';
|
import { useCatalogData, useUserGroups } from '../../../../../hooks';
|
||||||
|
import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView';
|
||||||
import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView';
|
import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView';
|
||||||
import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView';
|
import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView';
|
||||||
import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView';
|
import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView';
|
||||||
@@ -10,40 +11,43 @@ import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget';
|
|||||||
import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView';
|
import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView';
|
||||||
import { CatalogLayoutProps } from './CatalogLayout.types';
|
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = () =>
|
||||||
{
|
{
|
||||||
const { page = null } = props;
|
const { currentOffer = null, roomPreviewer = null } = useCatalogData();
|
||||||
const { currentOffer = null } = useCatalogData();
|
const { data: groups = null } = useUserGroups();
|
||||||
|
const hasGroups = !!(groups && groups.length);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
|
||||||
<Column overflow="hidden" size={ 8 }>
|
|
||||||
<CatalogItemGridWidgetView columnMinWidth={ 36 } />
|
|
||||||
</Column>
|
|
||||||
<Column center={ !currentOffer } overflow="hidden" size={ 4 }>
|
|
||||||
{ !currentOffer &&
|
|
||||||
<>
|
<>
|
||||||
{ !!page.localization.getImage(1) && <img alt="" className="max-w-full object-contain" src={ page.localization.getImage(1) } /> }
|
<CatalogFirstProductSelectorWidgetView />
|
||||||
<Text center bold dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
<Column fullHeight gap={ 1 } overflow="hidden">
|
||||||
</> }
|
{ !!currentOffer &&
|
||||||
{ currentOffer &&
|
<div className="relative shrink-0 overflow-hidden">
|
||||||
<>
|
<button className="nitro-catalog-classic-preview-btn nitro-catalog-classic-preview-rotate" onClick={ () => roomPreviewer?.changeRoomObjectDirection() }>
|
||||||
<div className="relative overflow-hidden">
|
<FaSyncAlt />
|
||||||
<CatalogViewProductWidgetView />
|
</button>
|
||||||
<CatalogGuildBadgeWidgetView className="bottom-1 inset-e-1" position="absolute" />
|
<button className="nitro-catalog-classic-preview-btn nitro-catalog-classic-preview-state" onClick={ () => roomPreviewer?.changeRoomObjectState() }>
|
||||||
|
<FaExchangeAlt />
|
||||||
|
</button>
|
||||||
|
<CatalogViewProductWidgetView height={ 210 } />
|
||||||
|
<div className="absolute bottom-1 left-1 z-10">
|
||||||
|
<CatalogGuildBadgeWidgetView />
|
||||||
</div>
|
</div>
|
||||||
<Column grow gap={ 1 }>
|
<div className="nitro-catalog-preview-price absolute bottom-1 right-1">
|
||||||
<Text bold className="leading-tight">{ currentOffer.localizationName }</Text>
|
|
||||||
<div className="grow!">
|
|
||||||
<CatalogGuildSelectorWidgetView />
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-end">
|
|
||||||
<CatalogTotalPriceWidget alignItems="end" />
|
<CatalogTotalPriceWidget alignItems="end" />
|
||||||
</div>
|
</div>
|
||||||
<CatalogPurchaseWidgetView />
|
</div> }
|
||||||
|
<div className="grow! min-h-0 overflow-auto">
|
||||||
|
<CatalogItemGridWidgetView columnCount={ 5 } columnMinWidth={ 36 } />
|
||||||
|
</div>
|
||||||
|
{ !!currentOffer &&
|
||||||
|
<div className="flex shrink-0 flex-col gap-1">
|
||||||
|
<CatalogGuildSelectorWidgetView />
|
||||||
|
{ hasGroups &&
|
||||||
|
<CatalogPurchaseWidgetView noGiftOption={ true } /> }
|
||||||
|
</div> }
|
||||||
</Column>
|
</Column>
|
||||||
</> }
|
</>
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,16 @@ export const CatalogLayouGuildForumView: FC<CatalogLayoutProps> = props =>
|
|||||||
<Column overflow="hidden" size={ 8 }>
|
<Column overflow="hidden" size={ 8 }>
|
||||||
<div className="nitro-catalog-forum-text grow! min-h-0 overflow-auto text-black" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(1)) } } />
|
<div className="nitro-catalog-forum-text grow! min-h-0 overflow-auto text-black" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(1)) } } />
|
||||||
{ !!currentOffer &&
|
{ !!currentOffer &&
|
||||||
<Flex alignItems="center" className="shrink-0" gap={ 2 }>
|
<div className="flex shrink-0 flex-col gap-1">
|
||||||
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
<CatalogTotalPriceWidget />
|
<CatalogTotalPriceWidget />
|
||||||
<div className="grow!">
|
<div className="grow! min-w-0">
|
||||||
<CatalogGuildSelectorWidgetView />
|
<CatalogGuildSelectorWidgetView ownerOnly />
|
||||||
</div>
|
</div>
|
||||||
|
</Flex>
|
||||||
{ hasGroups &&
|
{ hasGroups &&
|
||||||
<CatalogPurchaseWidgetView noGiftOption={ true } /> }
|
<CatalogPurchaseWidgetView noGiftOption={ true } /> }
|
||||||
</Flex> }
|
</div> }
|
||||||
</Column>
|
</Column>
|
||||||
<Column alignItems="center" overflow="hidden" size={ 4 }>
|
<Column alignItems="center" overflow="hidden" size={ 4 }>
|
||||||
{ !!teaserImage &&
|
{ !!teaserImage &&
|
||||||
|
|||||||
@@ -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 { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../../api';
|
import { LocalizeText } from '../../../../../api';
|
||||||
import { Button, Flex } from '../../../../../common';
|
import { Button, Flex } from '../../../../../common';
|
||||||
import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks';
|
import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks';
|
||||||
|
|
||||||
export const CatalogGuildSelectorWidgetView: FC<{}> = props =>
|
interface CatalogGuildSelectorWidgetViewProps
|
||||||
{
|
{
|
||||||
|
ownerOnly?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CatalogGuildSelectorWidgetView: FC<CatalogGuildSelectorWidgetViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { ownerOnly = false } = props;
|
||||||
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
||||||
const { currentOffer = null } = useCatalogData();
|
const { currentOffer = null } = useCatalogData();
|
||||||
const { setPurchaseOptions = null } = useCatalogUiState();
|
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(() =>
|
const previewStuffData = useMemo(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import { BuildPurchasableClothingFigure, FurniCategory, Offer, ProductTypeEnum }
|
|||||||
import { AutoGrid, Column, LayoutGridItem, LayoutRoomPreviewerView } from '../../../../../common';
|
import { AutoGrid, Column, LayoutGridItem, LayoutRoomPreviewerView } from '../../../../../common';
|
||||||
import { useCatalogData, useCatalogUiState } from '../../../../../hooks';
|
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 { currentOffer = null, roomPreviewer = null } = useCatalogData();
|
||||||
const { purchaseOptions = null } = useCatalogUiState();
|
const { purchaseOptions = null } = useCatalogUiState();
|
||||||
const { previewStuffData = null } = purchaseOptions;
|
const { previewStuffData = null } = purchaseOptions;
|
||||||
@@ -125,5 +126,5 @@ export const CatalogViewProductWidgetView: FC<{}> = props =>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <LayoutRoomPreviewerView key={ currentOffer?.offerId } height={ 240 } roomPreviewer={ roomPreviewer } />;
|
return <LayoutRoomPreviewerView key={ currentOffer?.offerId } height={ height } roomPreviewer={ roomPreviewer } />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1354,6 +1354,16 @@
|
|||||||
line-height: 17px !important;
|
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 {
|
.nitro-catalog-swf-price-plus {
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
import { CatalogGroupsComposer, GuildMembershipsMessageEvent, HabboGroupEntryData } from '@nitrots/nitro-renderer';
|
import { CatalogGroupsComposer, GuildMembershipsMessageEvent, HabboGroupEntryData } from '@nitrots/nitro-renderer';
|
||||||
import { UseQueryResult } from '@tanstack/react-query';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useNitroQuery } from '../../api/nitro-query';
|
import { useBetween } from 'use-between';
|
||||||
|
import { SendMessageComposer } from '../../api';
|
||||||
|
import { useMessageEvent } from '../events';
|
||||||
|
|
||||||
/**
|
const useUserGroupsStore = () =>
|
||||||
* The list of guilds the current Habbo belongs to, as returned by
|
{
|
||||||
* the `CatalogGroupsComposer` → `GuildMembershipsMessageEvent`
|
const [ groups, setGroups ] = useState<HabboGroupEntryData[]>([]);
|
||||||
* request/response pair.
|
|
||||||
*
|
const onGuildMemberships = useCallback((event: GuildMembershipsMessageEvent) =>
|
||||||
* Cached at session level: the membership list is stable for the
|
{
|
||||||
* session unless the user joins/leaves a guild (in which case the
|
setGroups(event.getParser()?.groups || []);
|
||||||
* 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).
|
useMessageEvent<GuildMembershipsMessageEvent>(GuildMembershipsMessageEvent, onGuildMemberships);
|
||||||
*
|
|
||||||
* Replaces three duplicate request+listener pairs that previously
|
useEffect(() =>
|
||||||
* each issued their own CatalogGroupsComposer:
|
{
|
||||||
* - useCatalog (catalogOptions.groups)
|
SendMessageComposer(new CatalogGroupsComposer());
|
||||||
* - WiredSelectorUsersGroupView
|
}, []);
|
||||||
* - WiredConditionActorIsGroupMemberView
|
|
||||||
*/
|
return { groups };
|
||||||
export const useUserGroups = (
|
};
|
||||||
options: { enabled?: boolean } = {}
|
|
||||||
): UseQueryResult<HabboGroupEntryData[]> =>
|
export const useUserGroups = (): { data: HabboGroupEntryData[] } =>
|
||||||
useNitroQuery<GuildMembershipsMessageEvent, HabboGroupEntryData[]>({
|
{
|
||||||
key: [ 'nitro', 'user', 'groups' ],
|
const { groups } = useBetween(useUserGroupsStore);
|
||||||
request: () => new CatalogGroupsComposer(),
|
|
||||||
parser: GuildMembershipsMessageEvent,
|
return { data: groups };
|
||||||
select: event => (event.getParser().groups || []),
|
};
|
||||||
enabled: options.enabled,
|
|
||||||
staleTime: Infinity
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user