diff --git a/CLAUDE.md b/CLAUDE.md index 6a3981f..982ba69 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -259,15 +259,14 @@ into `configurePreviewServer` so `yarn preview` keeps working. | `useNitroQuery` + `useNitroEventInvalidator` | `OfferView`, `CatalogLayoutRoomAdsView`, `ModToolsChatlogView`, `CfhChatlogView`, `useGiftConfiguration`, `useUserGroups`, `useClubOffers(windowId)`, `useSellablePetPalette(breed)`, `useMarketplaceConfiguration`, `useClubGifts` (with invalidator) | | Zustand | `NavigatorRoomCreatorView` (`useRoomCreatorStore`) | | God-hook split (state + actions + shim) | `doorbell`, `poll`, `furni-chooser`, `user-chooser`, `friend-request`, `chat-input` | -| God-hook split (`useBetween` singleton + state filter + actions filter + shim) | `wired-tools`, `translation`, `notification`, `friends`, `catalog` (three-way: `useCatalogData` / `useCatalogUiState` / `useCatalogActions`, plus the `useCatalog` shim) | +| God-hook split (`useBetween` singleton + state filter + actions filter + shim) | `wired-tools`, `translation`, `notification`, `friends`, `catalog` (three-way: `useCatalogData` / `useCatalogUiState` / `useCatalogActions` — all 48 consumers migrated, deprecated `useCatalog` shim removed) | | `WidgetErrorBoundary` | `RoomWidgetsView` umbrella | -| Vitest | 163/163 cases — pure helpers + Zustand store + 2 component-/hook-level pilots (WidgetErrorBoundary, useDoorbellState) on top of the renderer-SDK mock at `tests/mocks/renderer-mock.ts`, 34 cases on the catalog pure helpers, 5 contract cases on the catalog filters | +| Vitest | 162/162 cases — pure helpers + Zustand store + 2 component-/hook-level pilots (WidgetErrorBoundary, useDoorbellState) on top of the renderer-SDK mock at `tests/mocks/renderer-mock.ts`, 34 cases on the catalog pure helpers, 4 contract cases on the catalog filters | | Form Actions | Login / Register / Forgot (LoginView.tsx) | | Cherry-picked from `duckietm` PR #126 | `UserAccountSettingsView` (reset password / email / username under user settings), plus the wear-badge popup `canShowWearButton` gating | | Not yet | Notes | |---|---| -| Migrate the 48 `useCatalog()` consumers to the new filters | The split is done: pure helpers in `useCatalog.helpers.ts`, three filters (`useCatalogData` / `useCatalogUiState` / `useCatalogActions`) plus the deprecated `useCatalog` shim. Three pilot consumers already migrated (`CatalogBuildersClubStatusView`, `CatalogBreadcrumbView`, `CatalogNavigationItemView`). The remaining 45 still hit the shim — incremental work, each migration is mechanical: split the destructure into 2-3 filter calls based on which keys are read. | | Split `useChatWidget` / `useAvatarInfoWidget` | Both state-driven via events with no clean imperative actions to extract — skip-motivated. Already touched today for the InfoStand listener move. | | Split `usePetPackageWidget` / `useWordQuizWidget` / `useChatCommandSelector` | Their "actions" mutate internal state or are tightly interdependent — skip-motivated. | | Hoist Wired Creator Tools shared state to a Zustand slice | Would remove ~25 props passed to the 3 tab sub-components. (Wired-tools split done as singleton-filter; Zustand slice is the next step.) | @@ -331,8 +330,9 @@ Fix shapes documented; both are reasonable PRs on their own. `getNodesByOfferIdFromMap`, `getOfferProductKeys`, `normalizeCatalogType`, `resolveBuilderFurniPlaceableStatus`) - Catalog three-way filter split: `useCatalogData` / - `useCatalogUiState` / `useCatalogActions` (with the deprecated - `useCatalog` shim) in `src/hooks/catalog/useCatalog.ts` + `useCatalogUiState` / `useCatalogActions` in + `src/hooks/catalog/useCatalog.ts` (all 48 consumers migrated; + deprecated `useCatalog` shim removed) - Renderer-SDK mock for Vitest: `tests/mocks/renderer-mock.ts` (aliased over `@nitrots/nitro-renderer` via `vitest.config.mts`). Hosts the explicit `NitroLogger` mock, the `mockEventDispatcher` / diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8eafc58..57fca54 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -502,15 +502,11 @@ filters built on top of the same `useBetween` singleton: `getBuilderFurniPlaceableStatus`). The internal store is named `useCatalogStore` and is **not exported**; -the four public entry points (`useCatalogData` / `useCatalogUiState` -/ `useCatalogActions` / `useCatalog`) all funnel into the same -`useBetween` instance, so listeners + state register once. The -deprecated `useCatalog` shim continues to expose the full historical -return shape so the 48 existing consumers compile unchanged; they -should be incrementally migrated to the specific filters as PRs -touch them. Three pilot migrations already landed in -`CatalogBuildersClubStatusView`, `CatalogBreadcrumbView`, and -`CatalogNavigationItemView`. +the three public entry points (`useCatalogData` / `useCatalogUiState` +/ `useCatalogActions`) all funnel into the same `useBetween` +instance, so listeners + state register once. All 48 historical +consumers have been migrated to the targeted filters; the deprecated +`useCatalog` shim has been removed. Pure helpers in `useCatalog.helpers.ts`: @@ -569,7 +565,7 @@ empty-map / partial-bucket branches of the offer lookup). the partial-visible fallback), `buildCatalogNodeTree` (tree depth + offerId index), and the full decision tree of `resolveBuilderFurniPlaceableStatus`. - - `useCatalog.filters.test.tsx` (5) — contract tests for the + - `useCatalog.filters.test.tsx` (4) — contract tests for the three-way singleton-filter split. Stubs `use-between` so the filters share one fake store, asserts each filter exposes exactly the keys it owns (no leak across slices), and pins diff --git a/src/components/catalog/CatalogAdminContext.tsx b/src/components/catalog/CatalogAdminContext.tsx index 2d27597..29e1f84 100644 --- a/src/components/catalog/CatalogAdminContext.tsx +++ b/src/components/catalog/CatalogAdminContext.tsx @@ -1,7 +1,7 @@ import { CatalogAdminCreateOfferComposer, CatalogAdminCreatePageComposer, CatalogAdminDeleteOfferComposer, CatalogAdminDeletePageComposer, CatalogAdminMoveOfferComposer, CatalogAdminMovePageComposer, CatalogAdminPublishComposer, CatalogAdminResultEvent, CatalogAdminSaveOfferComposer, CatalogAdminSavePageComposer } from '@nitrots/nitro-renderer'; import { createContext, FC, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react'; import { ICatalogNode, IPurchasableOffer, NotificationAlertType, SendMessageComposer } from '../../api'; -import { useCatalog, useMessageEvent, useNotification } from '../../hooks'; +import { useCatalogUiState, useMessageEvent, useNotification } from '../../hooks'; export interface IPageEditData { @@ -76,7 +76,7 @@ export const useCatalogAdmin = () => useContext(CatalogAdminContext); export const CatalogAdminProvider: FC<{ children: ReactNode }> = ({ children }) => { - const { currentType } = useCatalog(); + const { currentType } = useCatalogUiState(); const [ adminMode, setAdminMode ] = useState(false); const [ editingOffer, setEditingOffer ] = useState(null); const [ editingPageData, setEditingPageData ] = useState(false); diff --git a/src/components/catalog/CatalogClassicView.tsx b/src/components/catalog/CatalogClassicView.tsx index 2a49735..9c3111c 100644 --- a/src/components/catalog/CatalogClassicView.tsx +++ b/src/components/catalog/CatalogClassicView.tsx @@ -3,7 +3,7 @@ import { FC, useEffect } from 'react'; import { FaCog, FaEdit, FaEye, FaEyeSlash, FaPlus, FaTrash } from 'react-icons/fa'; import { CatalogType, GetConfigurationValue, LocalizeText } from '../../api'; import { Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; -import { useCatalog } from '../../hooks'; +import { useCatalogActions, useCatalogData, useCatalogUiState } from '../../hooks'; import { CatalogAdminProvider, useCatalogAdmin } from './CatalogAdminContext'; import { CatalogAdminOfferEditView } from './views/admin/CatalogAdminOfferEditView'; import { CatalogAdminPageEditView } from './views/admin/CatalogAdminPageEditView'; @@ -16,7 +16,9 @@ import { MarketplacePostOfferView } from './views/page/layout/marketplace/Market const CatalogClassicViewInner: FC<{}> = () => { - const { isVisible = false, setIsVisible = null, rootNode = null, currentPage = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], searchResult = null, setSearchResult = null, openPageByName = null, openPageByOfferId = null, activateNode = null, openCatalogByType = null, toggleCatalogByType = null, currentType = CatalogType.NORMAL } = useCatalog(); + const { rootNode = null, currentPage = null, searchResult = null } = useCatalogData(); + const { isVisible = false, setIsVisible = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], setSearchResult = null, currentType = CatalogType.NORMAL } = useCatalogUiState(); + const { openPageByName = null, openPageByOfferId = null, activateNode = null, openCatalogByType = null, toggleCatalogByType = null } = useCatalogActions(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; const setAdminMode = catalogAdmin?.setAdminMode ?? (() => diff --git a/src/components/catalog/CatalogModernView.tsx b/src/components/catalog/CatalogModernView.tsx index 5e56267..12b8ac1 100644 --- a/src/components/catalog/CatalogModernView.tsx +++ b/src/components/catalog/CatalogModernView.tsx @@ -3,7 +3,7 @@ import { FC, useEffect, useState } from 'react'; import { FaCog, FaEdit, FaEye, FaEyeSlash, FaHeart, FaPlus, FaStar, FaTrash } from 'react-icons/fa'; import { CatalogType, LocalizeText } from '../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; -import { useCatalog, useCatalogFavorites } from '../../hooks'; +import { useCatalogActions, useCatalogData, useCatalogFavorites, useCatalogUiState } from '../../hooks'; import { CatalogAdminProvider, useCatalogAdmin } from './CatalogAdminContext'; import { CatalogAdminOfferEditView } from './views/admin/CatalogAdminOfferEditView'; import { CatalogAdminPageEditView } from './views/admin/CatalogAdminPageEditView'; @@ -18,7 +18,9 @@ import { MarketplacePostOfferView } from './views/page/layout/marketplace/Market const CatalogModernViewInner: FC<{}> = () => { - const { isVisible = false, setIsVisible = null, rootNode = null, currentPage = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], searchResult = null, setSearchResult = null, openPageByName = null, openPageByOfferId = null, activateNode = null, openCatalogByType = null, toggleCatalogByType = null, currentType = CatalogType.NORMAL } = useCatalog(); + const { rootNode = null, currentPage = null, searchResult = null } = useCatalogData(); + const { isVisible = false, setIsVisible = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], setSearchResult = null, currentType = CatalogType.NORMAL } = useCatalogUiState(); + const { openPageByName = null, openPageByOfferId = null, activateNode = null, openCatalogByType = null, toggleCatalogByType = null } = useCatalogActions(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; const setAdminMode = catalogAdmin?.setAdminMode ?? (() => diff --git a/src/components/catalog/CatalogView.tsx b/src/components/catalog/CatalogView.tsx index a7ea8f1..2652fd6 100644 --- a/src/components/catalog/CatalogView.tsx +++ b/src/components/catalog/CatalogView.tsx @@ -1,12 +1,12 @@ import { FC } from 'react'; import { GetConfigurationValue } from '../../api'; -import { useCatalog } from '../../hooks'; +import { useCatalogData } from '../../hooks'; import { CatalogClassicView } from './CatalogClassicView'; import { CatalogModernView } from './CatalogModernView'; export const CatalogView: FC<{}> = () => { - const { catalogLocalizationVersion = 0 } = useCatalog(); + const { catalogLocalizationVersion = 0 } = useCatalogData(); const useNewStyle = GetConfigurationValue('catalog.style.new', false); if(useNewStyle) return ( diff --git a/src/components/catalog/views/admin/CatalogAdminOfferEditView.tsx b/src/components/catalog/views/admin/CatalogAdminOfferEditView.tsx index 32fec7f..c61c14b 100644 --- a/src/components/catalog/views/admin/CatalogAdminOfferEditView.tsx +++ b/src/components/catalog/views/admin/CatalogAdminOfferEditView.tsx @@ -2,12 +2,12 @@ import { FC, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { FaSave, FaSpinner, FaTimes, FaTrash } from 'react-icons/fa'; import { LocalizeText } from '../../../../api'; -import { useCatalog } from '../../../../hooks'; +import { useCatalogData } from '../../../../hooks'; import { IOfferEditData, useCatalogAdmin } from '../../CatalogAdminContext'; export const CatalogAdminOfferEditView: FC<{}> = () => { - const { currentPage = null } = useCatalog(); + const { currentPage = null } = useCatalogData(); const catalogAdmin = useCatalogAdmin(); const editingOffer = catalogAdmin?.editingOffer ?? null; const setEditingOffer = catalogAdmin?.setEditingOffer; diff --git a/src/components/catalog/views/admin/CatalogAdminPageEditView.tsx b/src/components/catalog/views/admin/CatalogAdminPageEditView.tsx index 037af96..457a301 100644 --- a/src/components/catalog/views/admin/CatalogAdminPageEditView.tsx +++ b/src/components/catalog/views/admin/CatalogAdminPageEditView.tsx @@ -1,7 +1,7 @@ import { FC, useEffect, useState } from 'react'; import { FaSave, FaSpinner, FaTimes, FaTrash } from 'react-icons/fa'; import { CatalogType, LocalizeText } from '../../../../api'; -import { useCatalog } from '../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../hooks'; import { IPageEditData, useCatalogAdmin } from '../../CatalogAdminContext'; const LAYOUT_OPTIONS = [ @@ -21,7 +21,8 @@ const MODE_OPTIONS = [ export const CatalogAdminPageEditView: FC<{}> = () => { - const { currentPage = null, activeNodes = [], rootNode = null, currentType = CatalogType.NORMAL } = useCatalog(); + const { currentPage = null, rootNode = null } = useCatalogData(); + const { activeNodes = [], currentType = CatalogType.NORMAL } = useCatalogUiState(); const catalogAdmin = useCatalogAdmin(); const editingPageData = catalogAdmin?.editingPageData ?? false; const editingRootPage = catalogAdmin?.editingRootPage ?? false; diff --git a/src/components/catalog/views/favorites/CatalogFavoritesView.tsx b/src/components/catalog/views/favorites/CatalogFavoritesView.tsx index 6b403d3..0de88c5 100644 --- a/src/components/catalog/views/favorites/CatalogFavoritesView.tsx +++ b/src/components/catalog/views/favorites/CatalogFavoritesView.tsx @@ -1,7 +1,7 @@ import { FC, useMemo } from 'react'; import { FaHeart, FaStar, FaTimes } from 'react-icons/fa'; import { ICatalogNode, LocalizeText } from '../../../../api'; -import { useCatalog, useCatalogFavorites } from '../../../../hooks'; +import { useCatalogActions, useCatalogData, useCatalogFavorites } from '../../../../hooks'; import { CatalogIconView } from '../catalog-icon/CatalogIconView'; interface CatalogFavoritesViewProps @@ -13,7 +13,8 @@ export const CatalogFavoritesView: FC = props => { const { onClose } = props; const { favoriteOffers, favoritePageIds, toggleFavoritePage, toggleFavoriteOffer } = useCatalogFavorites(); - const { offersToNodes, activateNode, openPageByOfferId, rootNode } = useCatalog(); + const { offersToNodes, rootNode } = useCatalogData(); + const { activateNode, openPageByOfferId } = useCatalogActions(); const favoritePages = useMemo(() => { diff --git a/src/components/catalog/views/navigation/CatalogNavigationView.tsx b/src/components/catalog/views/navigation/CatalogNavigationView.tsx index 777c5fd..97907f6 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { ICatalogNode } from '../../../../api'; -import { useCatalog } from '../../../../hooks'; +import { useCatalogData } from '../../../../hooks'; import { CatalogNavigationItemView } from './CatalogNavigationItemView'; import { CatalogNavigationSetView } from './CatalogNavigationSetView'; @@ -12,7 +12,7 @@ export interface CatalogNavigationViewProps export const CatalogNavigationView: FC = props => { const { node = null } = props; - const { searchResult = null } = useCatalog(); + const { searchResult = null } = useCatalogData(); return (
diff --git a/src/components/catalog/views/page/common/CatalogGridOfferView.tsx b/src/components/catalog/views/page/common/CatalogGridOfferView.tsx index a634705..660f1ef 100644 --- a/src/components/catalog/views/page/common/CatalogGridOfferView.tsx +++ b/src/components/catalog/views/page/common/CatalogGridOfferView.tsx @@ -3,7 +3,7 @@ import { FC, MouseEvent, useMemo, useState } from 'react'; import { FaHeart } from 'react-icons/fa'; import { CatalogType, IPurchasableOffer, Offer, ProductTypeEnum } from '../../../../../api'; import { LayoutAvatarImageView, LayoutGridItem, LayoutGridItemProps } from '../../../../../common'; -import { useCatalog, useCatalogFavorites, useInventoryFurni } from '../../../../../hooks'; +import { useCatalogActions, useCatalogFavorites, useCatalogUiState, useInventoryFurni } from '../../../../../hooks'; interface CatalogGridOfferViewProps extends LayoutGridItemProps { @@ -15,7 +15,8 @@ export const CatalogGridOfferView: FC = props => { const { offer = null, selectOffer = null, itemActive = false, ...rest } = props; const [ isMouseDown, setMouseDown ] = useState(false); - const { requestOfferToMover = null, currentType = CatalogType.NORMAL } = useCatalog(); + const { requestOfferToMover = null } = useCatalogActions(); + const { currentType = CatalogType.NORMAL } = useCatalogUiState(); const { isVisible = false } = useInventoryFurni(); const { isFavoriteOffer, toggleFavoriteOffer } = useCatalogFavorites(); const isFav = offer ? isFavoriteOffer(offer.offerId) : false; diff --git a/src/components/catalog/views/page/common/CatalogSearchView.tsx b/src/components/catalog/views/page/common/CatalogSearchView.tsx index bb8583c..5fd9dca 100644 --- a/src/components/catalog/views/page/common/CatalogSearchView.tsx +++ b/src/components/catalog/views/page/common/CatalogSearchView.tsx @@ -2,12 +2,13 @@ import { GetSessionDataManager, IFurnitureData } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { FaSearch, FaTimes } from 'react-icons/fa'; import { CatalogPage, CatalogType, FilterCatalogNode, FurnitureOffer, ICatalogNode, ICatalogPage, IPurchasableOffer, LocalizeText, PageLocalization, SearchResult } from '../../../../../api'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; export const CatalogSearchView: FC<{}> = () => { const [ searchValue, setSearchValue ] = useState(''); - const { currentType = null, rootNode = null, searchResult = null, setSearchResult = null, setCurrentPage = null } = useCatalog(); + const { rootNode = null, searchResult = null } = useCatalogData(); + const { currentType = null, setSearchResult = null, setCurrentPage = null } = useCatalogUiState(); const normalizeSearchText = (value: string) => (value || '') .toLocaleLowerCase() diff --git a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx index ee82e6e..d2ef2af 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; import { LocalizeText, SanitizeHtml } from '../../../../../api'; import { Column, Grid, Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { CatalogBadgeSelectorWidgetView } from '../widgets/CatalogBadgeSelectorWidgetView'; import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -14,7 +14,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutBadgeDisplayView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); return ( <> diff --git a/src/components/catalog/views/page/layout/CatalogLayoutBuildersClubBuyView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutBuildersClubBuyView.tsx index 19e8c2c..9c458fe 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutBuildersClubBuyView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutBuildersClubBuyView.tsx @@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { CatalogPurchaseState, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../api'; import { Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, LayoutLoadingSpinnerView, Text } from '../../../../../common'; import { CatalogEvent, CatalogPurchaseFailureEvent, CatalogPurchasedEvent } from '../../../../../events'; -import { useCatalog, useClubOffers, usePurse, useUiEvent } from '../../../../../hooks'; +import { useCatalogData, useClubOffers, usePurse, useUiEvent } from '../../../../../hooks'; import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView'; import { CatalogLayoutProps } from './CatalogLayout.types'; @@ -14,7 +14,7 @@ export const CatalogLayoutBuildersClubBuyView: FC = () => { const [ pendingOffer, setPendingOffer ] = useState(null); const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE); - const { currentPage = null } = useCatalog(); + const { currentPage = null } = useCatalogData(); const { getCurrencyAmount = null } = usePurse(); const isPurchasingRef = useRef(false); const isAddonLayout = (currentPage?.layoutCode === 'builders_club_addons'); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutColorGroupingView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutColorGroupingView.tsx index 4c1944c..cb4c53a 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutColorGroupingView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutColorGroupingView.tsx @@ -3,7 +3,7 @@ import { FC, useMemo, useState } from 'react'; import { FaFillDrip } from 'react-icons/fa'; import { IPurchasableOffer, SanitizeHtml } from '../../../../../api'; import { AutoGrid, Button, Column, Grid, LayoutGridItem, Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; import { CatalogGridOfferView } from '../common/CatalogGridOfferView'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView'; @@ -22,7 +22,8 @@ export const CatalogLayoutColorGroupingView: FC>(new Map()); - const { currentOffer = null, setCurrentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { setCurrentOffer = null } = useCatalogUiState(); const [ colorsShowing, setColorsShowing ] = useState(false); const sortByColorIndex = (a: IPurchasableOffer, b: IPurchasableOffer) => diff --git a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx index e9417ab..f01401f 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import { FaEdit, FaPlus } from 'react-icons/fa'; import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SanitizeHtml } from '../../../../../api'; import { Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { useCatalogAdmin } from '../../../CatalogAdminContext'; import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; @@ -17,7 +17,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutDefaultView: FC = props => { const { page = null } = props; - const { currentOffer = null, currentPage = null } = useCatalog(); + const { currentOffer = null, currentPage = null } = useCatalogData(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx index cb8b6fa..6d28e1e 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; import { SanitizeHtml } from '../../../../../api'; import { Column, Grid, Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -13,7 +13,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayouGuildCustomFurniView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); return ( diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx index b7d9cf9..58baa3a 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx @@ -1,7 +1,7 @@ import { FC, useState } from 'react'; import { SanitizeHtml } from '../../../../../api'; import { Column, Grid, Text } from '../../../../../common'; -import { useCatalog, useUserGroups } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks'; import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; @@ -12,7 +12,8 @@ export const CatalogLayouGuildForumView: FC = props => { const { page = null } = props; const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, setCurrentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { setCurrentOffer = null } = useCatalogUiState(); const { data: groups = null } = useUserGroups(); return ( diff --git a/src/components/catalog/views/page/layout/CatalogLayoutRoomAdsView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutRoomAdsView.tsx index d9c6c87..8016c40 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutRoomAdsView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutRoomAdsView.tsx @@ -3,7 +3,7 @@ import { FC, useEffect, useState } from 'react'; import { LocalizeText, SendMessageComposer } from '../../../../../api'; import { useNitroQuery } from '../../../../../api/nitro-query'; import { Button, Column, Text } from '../../../../../common'; -import { useCatalog, useNavigator, useRoomPromote } from '../../../../../hooks'; +import { useCatalogUiState, useNavigator, useRoomPromote } from '../../../../../hooks'; import { NitroInput } from '../../../../../layout'; import { CatalogLayoutProps } from './CatalogLayout.types'; @@ -18,7 +18,7 @@ export const CatalogLayoutRoomAdsView: FC = props => const [ extended, setExtended ] = useState(false); const [ categoryId, setCategoryId ] = useState(1); const { categories = null } = useNavigator(); - const { setIsVisible = null } = useCatalog(); + const { setIsVisible = null } = useCatalogUiState(); const { promoteInformation, isExtended, setIsExtended } = useRoomPromote(); const { data: availableRooms = [] } = useNitroQuery({ diff --git a/src/components/catalog/views/page/layout/CatalogLayoutSoundMachineView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutSoundMachineView.tsx index 0aa131e..e6c12f4 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutSoundMachineView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutSoundMachineView.tsx @@ -2,7 +2,7 @@ import { GetOfficialSongIdMessageComposer, GetSoundManager, MusicPriorities, Off import { FC, useEffect, useState } from 'react'; import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SanitizeHtml, SendMessageComposer } from '../../../../../api'; import { Button, Column, Grid, LayoutImage, Text } from '../../../../../common'; -import { useCatalog, useMessageEvent } from '../../../../../hooks'; +import { useCatalogData, useMessageEvent } from '../../../../../hooks'; import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -18,7 +18,7 @@ export const CatalogLayoutSoundMachineView: FC = props => const { page = null } = props; const [ songId, setSongId ] = useState(-1); const [ officialSongId, setOfficialSongId ] = useState(''); - const { currentOffer = null, currentPage = null } = useCatalog(); + const { currentOffer = null, currentPage = null } = useCatalogData(); const previewSong = (previewSongId: number) => GetSoundManager().musicController?.playSong(previewSongId, MusicPriorities.PRIORITY_PURCHASE_PREVIEW, 15, 0, 0, 0); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx index 9cd18b6..3d5ccfe 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx @@ -1,7 +1,7 @@ import { FC, useEffect } from 'react'; import { SanitizeHtml } from '../../../../../api'; import { Column, Grid, Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; import { CatalogSpacesWidgetView } from '../widgets/CatalogSpacesWidgetView'; import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; @@ -11,7 +11,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutSpacesView: FC = props => { const { page = null } = props; - const { currentOffer = null, roomPreviewer = null } = useCatalog(); + const { currentOffer = null, roomPreviewer = null } = useCatalogData(); useEffect(() => { diff --git a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx index 1e1c174..31299a0 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx @@ -2,7 +2,7 @@ import { FC, useEffect, useState } from 'react'; import { FaEdit, FaPen, FaPlus, FaTrophy } from 'react-icons/fa'; import { LocalizeText, ProductTypeEnum, SanitizeHtml } from '../../../../../api'; import { Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; import { useCatalogAdmin } from '../../../CatalogAdminContext'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -15,7 +15,8 @@ export const CatalogLayoutTrophiesView: FC = props => { const { page = null } = props; const [ trophyText, setTrophyText ] = useState(''); - const { currentOffer = null, setPurchaseOptions = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { setPurchaseOptions = null } = useCatalogUiState(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; diff --git a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx index b63f4f6..09202de 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx @@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { CatalogPurchaseState, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../api'; import { AutoGrid, Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, LayoutLoadingSpinnerView, Text } from '../../../../../common'; import { CatalogEvent, CatalogPurchaseFailureEvent, CatalogPurchasedEvent } from '../../../../../events'; -import { useCatalog, useClubOffers, usePurse, useUiEvent } from '../../../../../hooks'; +import { useCatalogData, useClubOffers, usePurse, useUiEvent } from '../../../../../hooks'; import { CatalogLayoutProps } from './CatalogLayout.types'; const VIP_WINDOW_ID = 1; @@ -12,7 +12,7 @@ export const CatalogLayoutVipBuyView: FC = props => { const [ pendingOffer, setPendingOffer ] = useState(null); const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE); - const { currentPage = null } = useCatalog(); + const { currentPage = null } = useCatalogData(); const { purse = null, getCurrencyAmount = null } = usePurse(); const { data: offers = null } = useClubOffers(VIP_WINDOW_ID); const isPurchasingRef = useRef(false); diff --git a/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx b/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx index a7e74b2..29ead13 100644 --- a/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx +++ b/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx @@ -1,7 +1,7 @@ import { CreateLinkEvent, FrontPageItem } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect } from 'react'; import { Column, Grid } from '../../../../../../common'; -import { useCatalog } from '../../../../../../hooks'; +import { useCatalogData } from '../../../../../../hooks'; import { CatalogRedeemVoucherView } from '../../common/CatalogRedeemVoucherView'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView'; @@ -9,7 +9,7 @@ import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView export const CatalogLayoutFrontpage4View: FC = props => { const { page = null, hideNavigation = null } = props; - const { frontPageItems = [] } = useCatalog(); + const { frontPageItems = [] } = useCatalogData(); const selectItem = useCallback((item: FrontPageItem) => { diff --git a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx index 589d6bb..7081428 100644 --- a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx +++ b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx @@ -4,7 +4,7 @@ import { FaCheck, FaEdit, FaFillDrip, FaPaw, FaPlus, FaTimes } from 'react-icons import { DispatchUiEvent, GetPetAvailableColors, GetPetIndexFromLocalization, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../../api'; import { LayoutGridItem, LayoutPetImageView } from '../../../../../../common'; import { CatalogPurchaseFailureEvent } from '../../../../../../events'; -import { useCatalog, useMessageEvent, useSellablePetPalette } from '../../../../../../hooks'; +import { useCatalogData, useCatalogUiState, useMessageEvent, useSellablePetPalette } from '../../../../../../hooks'; import { useCatalogAdmin } from '../../../../CatalogAdminContext'; import { CatalogAddOnBadgeWidgetView } from '../../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogTotalPriceWidget } from '../../widgets/CatalogTotalPriceWidget'; @@ -23,7 +23,8 @@ export const CatalogLayoutPetView: FC = props => const [ petName, setPetName ] = useState(''); const [ approvalPending, setApprovalPending ] = useState(true); const [ approvalResult, setApprovalResult ] = useState(-1); - const { currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null, roomPreviewer = null } = useCatalog(); + const { currentOffer = null, roomPreviewer = null } = useCatalogData(); + const { setCurrentOffer = null, setPurchaseOptions = null } = useCatalogUiState(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; const breed: string = (currentOffer?.product?.productData?.type as unknown as string) ?? ''; diff --git a/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx index fd3b652..657729b 100644 --- a/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { BaseProps, LayoutBadgeImageView } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; interface CatalogAddOnBadgeWidgetViewProps extends BaseProps { @@ -10,7 +10,7 @@ interface CatalogAddOnBadgeWidgetViewProps extends BaseProps export const CatalogAddOnBadgeWidgetView: FC = props => { const { ...rest } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); if(!currentOffer || !currentOffer.badgeCode || !currentOffer.badgeCode.length) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx index 625b39f..8ef5c4d 100644 --- a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx @@ -1,7 +1,7 @@ import { StringDataType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { AutoGrid, AutoGridProps, LayoutBadgeImageView, LayoutGridItem } from '../../../../../common'; -import { useCatalog, useInventoryBadges } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState, useInventoryBadges } from '../../../../../hooks'; const EXCLUDED_BADGE_CODES: string[] = []; @@ -15,7 +15,8 @@ export const CatalogBadgeSelectorWidgetView: FC(null); - const { currentOffer = null, setPurchaseOptions = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { setPurchaseOptions = null } = useCatalogUiState(); const { badgeCodes = [], activate = null, deactivate = null } = useInventoryBadges(); const previewStuffData = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx index a5cffce..cf77622 100644 --- a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx @@ -1,6 +1,6 @@ import { FC, useEffect, useRef } from 'react'; import { AutoGrid, AutoGridProps, LayoutGridItem } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; interface CatalogBundleGridWidgetViewProps extends AutoGridProps { @@ -10,7 +10,7 @@ interface CatalogBundleGridWidgetViewProps extends AutoGridProps export const CatalogBundleGridWidgetView: FC = props => { const { columnCount = 5, children = null, ...rest } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); const elementRef = useRef(null); useEffect(() => diff --git a/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx index 855a175..c5e9542 100644 --- a/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx @@ -1,9 +1,10 @@ import { FC, useEffect } from 'react'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; export const CatalogFirstProductSelectorWidgetView: FC<{}> = props => { - const { currentPage = null, setCurrentOffer = null } = useCatalog(); + const { currentPage = null } = useCatalogData(); + const { setCurrentOffer = null } = useCatalogUiState(); useEffect(() => { diff --git a/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx index d56958e..c69c895 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx @@ -1,7 +1,7 @@ import { StringDataType } from '@nitrots/nitro-renderer'; import { FC, useMemo } from 'react'; import { BaseProps, LayoutBadgeImageView } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; interface CatalogGuildBadgeWidgetViewProps extends BaseProps { @@ -11,7 +11,8 @@ interface CatalogGuildBadgeWidgetViewProps extends BaseProps export const CatalogGuildBadgeWidgetView: FC = props => { const { ...rest } = props; - const { currentOffer = null, purchaseOptions = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { purchaseOptions = null } = useCatalogUiState(); const { previewStuffData = null } = purchaseOptions; const badgeCode = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx index d98ba4c..3d9e4a4 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx @@ -2,12 +2,13 @@ import { StringDataType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { LocalizeText } from '../../../../../api'; import { Button, Flex } from '../../../../../common'; -import { useCatalog, useUserGroups } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks'; export const CatalogGuildSelectorWidgetView: FC<{}> = props => { const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, setPurchaseOptions = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { setPurchaseOptions = null } = useCatalogUiState(); const { data: groups = null } = useUserGroups(); const previewStuffData = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx index 5b627c7..deff50a 100644 --- a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx @@ -1,7 +1,7 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { IPurchasableOffer } from '../../../../../api'; import { AutoGrid, AutoGridProps } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogActions, useCatalogData } from '../../../../../hooks'; import { useCatalogAdmin } from '../../../CatalogAdminContext'; import { CatalogGridOfferView } from '../common/CatalogGridOfferView'; @@ -13,7 +13,8 @@ interface CatalogItemGridWidgetViewProps extends AutoGridProps export const CatalogItemGridWidgetView: FC = props => { const { columnCount = 5, children = null, ...rest } = props; - const { currentOffer = null, currentPage = null, selectCatalogOffer = null } = useCatalog(); + const { currentOffer = null, currentPage = null } = useCatalogData(); + const { selectCatalogOffer = null } = useCatalogActions(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; const elementRef = useRef(null); diff --git a/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx index b2c85e8..faf02a2 100644 --- a/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx @@ -1,11 +1,11 @@ import { FC } from 'react'; import { Offer } from '../../../../../api'; import { LayoutLimitedEditionCompletePlateView } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; export const CatalogLimitedItemWidgetView: FC = props => { - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); if(!currentOffer || (currentOffer.pricingModel !== Offer.PRICING_MODEL_SINGLE) || !currentOffer.product.isUniqueLimitedItem) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx index 718eb2e..a83a981 100644 --- a/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import { FaPlus } from 'react-icons/fa'; import { IPurchasableOffer } from '../../../../../api'; import { LayoutCurrencyIcon, Text } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogUiState } from '../../../../../hooks'; interface CatalogPriceDisplayWidgetViewProps { @@ -13,7 +13,7 @@ interface CatalogPriceDisplayWidgetViewProps export const CatalogPriceDisplayWidgetView: FC = props => { const { offer = null, separator = false } = props; - const { purchaseOptions = null } = useCatalog(); + const { purchaseOptions = null } = useCatalogUiState(); const { quantity = 1 } = purchaseOptions; if(!offer) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index b329fa7..d5321e0 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { BuilderFurniPlaceableStatus, CatalogPurchaseState, CatalogType, DispatchUiEvent, GetClubMemberLevel, LocalStorageKeys, LocalizeText, NotificationBubbleType, Offer, ProductTypeEnum, SendMessageComposer } from '../../../../../api'; import { Button, LayoutLoadingSpinnerView, Text } from '../../../../../common'; import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogPurchasedEvent } from '../../../../../events'; -import { useCatalog, useLocalStorage, useNotification, usePurse, useUiEvent } from '../../../../../hooks'; +import { useCatalogActions, useCatalogData, useCatalogUiState, useLocalStorage, useNotification, usePurse, useUiEvent } from '../../../../../hooks'; interface CatalogPurchaseWidgetViewProps { @@ -20,7 +20,9 @@ export const CatalogPurchaseWidgetView: FC = pro const [ purchaseWillBeGift, setPurchaseWillBeGift ] = useState(false); const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE); const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useLocalStorage(LocalStorageKeys.CATALOG_SKIP_PURCHASE_CONFIRMATION, false); - const { currentOffer = null, currentPage = null, currentType = CatalogType.NORMAL, purchaseOptions = null, setPurchaseOptions = null, requestOfferToMover = null, setCatalogPlaceMultipleObjects = null, getBuilderFurniPlaceableStatus = null } = useCatalog(); + const { currentOffer = null, currentPage = null } = useCatalogData(); + const { currentType = CatalogType.NORMAL, purchaseOptions = null, setPurchaseOptions = null, setCatalogPlaceMultipleObjects = null } = useCatalogUiState(); + const { requestOfferToMover = null, getBuilderFurniPlaceableStatus = null } = useCatalogActions(); const { getCurrencyAmount = null } = usePurse(); const { showSingleBubble = null } = useNotification(); diff --git a/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx index bd82411..c34fe4a 100644 --- a/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx @@ -1,10 +1,10 @@ import { FC } from 'react'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { CatalogPriceDisplayWidgetView } from './CatalogPriceDisplayWidgetView'; export const CatalogSimplePriceWidgetView: FC<{}> = props => { - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); return (
diff --git a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx index 722589c..b100cbe 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx @@ -1,7 +1,7 @@ import { FC, useEffect, useRef, useState } from 'react'; import { IPurchasableOffer, LocalizeText, Offer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, AutoGridProps, Button } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; import { CatalogGridOfferView } from '../common/CatalogGridOfferView'; interface CatalogSpacesWidgetViewProps extends AutoGridProps @@ -17,7 +17,8 @@ export const CatalogSpacesWidgetView: FC = props = const [ groupedOffers, setGroupedOffers ] = useState(null); const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(-1); const [ selectedOfferForGroup, setSelectedOfferForGroup ] = useState(null); - const { currentPage = null, currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null } = useCatalog(); + const { currentPage = null, currentOffer = null } = useCatalogData(); + const { setCurrentOffer = null, setPurchaseOptions = null } = useCatalogUiState(); const elementRef = useRef(null); const setSelectedOffer = (offer: IPurchasableOffer) => diff --git a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx index 6b543a1..573465e 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx @@ -1,14 +1,15 @@ import { FC } from 'react'; import { FaMinus, FaPlus } from 'react-icons/fa'; import { LocalizeText } from '../../../../../api'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; const MIN_VALUE: number = 1; const MAX_VALUE: number = 99; export const CatalogSpinnerWidgetView: FC<{}> = props => { - const { currentOffer = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); + const { purchaseOptions = null, setPurchaseOptions = null } = useCatalogUiState(); const { quantity = 1 } = purchaseOptions; const updateQuantity = (value: number) => diff --git a/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx b/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx index 365bdf6..2ad6129 100644 --- a/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx +++ b/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { Column, ColumnProps } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData } from '../../../../../hooks'; import { CatalogPriceDisplayWidgetView } from './CatalogPriceDisplayWidgetView'; interface CatalogSimplePriceWidgetViewProps extends ColumnProps @@ -10,7 +10,7 @@ interface CatalogSimplePriceWidgetViewProps extends ColumnProps export const CatalogTotalPriceWidget: FC = props => { const { gap = 1, ...rest } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null } = useCatalogData(); return ( diff --git a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx index 14b4516..027aa36 100644 --- a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx @@ -2,11 +2,12 @@ import { GetAvatarRenderManager, GetSessionDataManager, Vector3d } from '@nitrot import { FC, useEffect } from 'react'; import { BuildPurchasableClothingFigure, FurniCategory, Offer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, Column, LayoutGridItem, LayoutRoomPreviewerView } from '../../../../../common'; -import { useCatalog } from '../../../../../hooks'; +import { useCatalogData, useCatalogUiState } from '../../../../../hooks'; export const CatalogViewProductWidgetView: FC<{}> = props => { - const { currentOffer = null, roomPreviewer = null, purchaseOptions = null } = useCatalog(); + const { currentOffer = null, roomPreviewer = null } = useCatalogData(); + const { purchaseOptions = null } = useCatalogUiState(); const { previewStuffData = null } = purchaseOptions; useEffect(() => diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts index 67d3054..0214cf5 100644 --- a/src/hooks/catalog/useCatalog.ts +++ b/src/hooks/catalog/useCatalog.ts @@ -1060,11 +1060,3 @@ export const useCatalogActions = () => }; }; -/** - * Deprecated. Kept so the 48 existing consumers compile unchanged — - * incrementally migrate them to `useCatalogData` / `useCatalogUiState` - * / `useCatalogActions` and remove this shim once the call sites are - * gone. Mirrors the same `useBetween` singleton, so behavior is - * identical. - */ -export const useCatalog = () => useBetween(useCatalogStore); diff --git a/src/hooks/catalog/useCatalogFavorites.ts b/src/hooks/catalog/useCatalogFavorites.ts index 5fc4d9e..2eb1854 100644 --- a/src/hooks/catalog/useCatalogFavorites.ts +++ b/src/hooks/catalog/useCatalogFavorites.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useBetween } from 'use-between'; import { CatalogType } from '../../api'; -import { useCatalog } from './useCatalog'; +import { useCatalogUiState } from './useCatalog'; import { getOffersStorageKey, getPagesStorageKey, IFavoriteOffer, LEGACY_STORAGE_KEY_OFFERS, LEGACY_STORAGE_KEY_PAGES, normalizeCatalogType, parseOffers, parsePages } from './useCatalogFavorites.helpers'; export type { IFavoriteOffer } from './useCatalogFavorites.helpers'; @@ -66,7 +66,7 @@ const writePages = (catalogType: string, ids: number[]) => const useCatalogFavoritesState = () => { - const { currentType = CatalogType.NORMAL } = useCatalog(); + const { currentType = CatalogType.NORMAL } = useCatalogUiState(); const catalogType = normalizeCatalogType(currentType); const [ favoriteOffersByType, setFavoriteOffersByType ] = useState>({ [CatalogType.NORMAL]: [], diff --git a/tests/useCatalog.filters.test.tsx b/tests/useCatalog.filters.test.tsx index a44eb56..4164e1c 100644 --- a/tests/useCatalog.filters.test.tsx +++ b/tests/useCatalog.filters.test.tsx @@ -75,7 +75,7 @@ vi.mock('use-between', () => ({ // Import AFTER the mock is set up. The hooks resolve `useBetween` at // import time via the module graph, so the order matters. -import { useCatalog, useCatalogActions, useCatalogData, useCatalogUiState } from '../src/hooks/catalog/useCatalog'; +import { useCatalogActions, useCatalogData, useCatalogUiState } from '../src/hooks/catalog/useCatalog'; describe('useCatalog filter contract', () => { @@ -160,47 +160,23 @@ describe('useCatalog filter contract', () => expect(result.current.openCatalogByType).toBe(fakeStore.openCatalogByType); }); - it('all four hooks observe the same singleton — refs are ===', () => + it('all three filters observe the same singleton — refs are ===', () => { const { result } = renderHook(() => ({ data: useCatalogData(), ui: useCatalogUiState(), - actions: useCatalogActions(), - full: useCatalog() + actions: useCatalogActions() })); - // The shim and the slices reach the same fakeStore. Any - // accidental copy would break this `===` check. - expect(result.current.full.activateNode).toBe(result.current.actions.activateNode); - expect(result.current.full.openCatalogByType).toBe(result.current.actions.openCatalogByType); - expect(result.current.full.setIsVisible).toBe(result.current.ui.setIsVisible); - expect(result.current.full.setCurrentPage).toBe(result.current.ui.setCurrentPage); - expect(result.current.full.rootNode).toBe(result.current.data.rootNode); - expect(result.current.full.furniCount).toBe(result.current.data.furniCount); - expect(result.current.full.roomPreviewer).toBe(result.current.data.roomPreviewer); - }); - - it('useCatalog (deprecated shim) preserves the full historical surface', () => - { - const { result } = renderHook(() => useCatalog()); - - // Sample one field from each slice, including the setters - // that the 48 existing consumers still destructure straight - // out of `useCatalog()`. If a setter or callback ever stops - // being forwarded, the shim breaks and those consumers - // silently fail. - const required = [ - 'rootNode', 'offersToNodes', 'currentPage', 'currentOffer', 'frontPageItems', - 'isVisible', 'setIsVisible', 'pageId', 'previousPageId', 'currentType', - 'setCurrentPage', 'setCurrentOffer', 'setSearchResult', - 'openCatalogByType', 'toggleCatalogByType', 'activateNode', - 'openPageById', 'openPageByName', 'openPageByOfferId', - 'requestOfferToMover', 'selectCatalogOffer', - 'getNodeById', 'getNodeByName', 'getBuilderFurniPlaceableStatus', - 'furniCount', 'furniLimit', 'secondsLeft', 'updateTime' - ]; - - for(const key of required) expect(result.current).toHaveProperty(key); + // Each slice reaches the same fakeStore via useBetween. Any + // accidental copy would break these `===` checks. + expect(result.current.actions.activateNode).toBe(fakeStore.activateNode); + expect(result.current.actions.openCatalogByType).toBe(fakeStore.openCatalogByType); + expect(result.current.ui.setIsVisible).toBe(fakeStore.setIsVisible); + expect(result.current.ui.setCurrentPage).toBe(fakeStore.setCurrentPage); + expect(result.current.data.rootNode).toBe(fakeStore.rootNode); + expect(result.current.data.furniCount).toBe(fakeStore.furniCount); + expect(result.current.data.roomPreviewer).toBe(fakeStore.roomPreviewer); }); });