mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
0f9fa1203b
Replaces every direct call to the deprecated useCatalog() shim with the targeted filter(s) (useCatalogData / useCatalogUiState / useCatalogActions). Each consumer now subscribes only to the slice it actually reads, which restores React Compiler memoization and stops catalog-wide re-renders whenever an unrelated key changes. Removes the now-unused useCatalog shim from useCatalog.ts and the shim-specific case in tests/useCatalog.filters.test.tsx. The "all four hooks observe the same singleton" test becomes "all three filters", since there is no shim left to compare against. useCatalogFavorites swaps its internal useCatalog() call for useCatalogUiState() (currentType lives in the UI slice). Updates CLAUDE.md and docs/ARCHITECTURE.md to reflect that all 48 historical consumers are migrated and the shim is gone. Vitest: 162/162 (was 163 — minus the deprecated-shim contract case).
108 lines
6.5 KiB
TypeScript
108 lines
6.5 KiB
TypeScript
import { FC } from 'react';
|
|
import { FaEdit, FaPlus } from 'react-icons/fa';
|
|
import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SanitizeHtml } from '../../../../../api';
|
|
import { Text } from '../../../../../common';
|
|
import { useCatalogData } from '../../../../../hooks';
|
|
import { useCatalogAdmin } from '../../../CatalogAdminContext';
|
|
import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView';
|
|
import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView';
|
|
import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView';
|
|
import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView';
|
|
import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView';
|
|
import { CatalogSpinnerWidgetView } from '../widgets/CatalogSpinnerWidgetView';
|
|
import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget';
|
|
import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView';
|
|
import { CatalogLayoutProps } from './CatalogLayout.types';
|
|
|
|
export const CatalogLayoutDefaultView: FC<CatalogLayoutProps> = props =>
|
|
{
|
|
const { page = null } = props;
|
|
const { currentOffer = null, currentPage = null } = useCatalogData();
|
|
const catalogAdmin = useCatalogAdmin();
|
|
const adminMode = catalogAdmin?.adminMode ?? false;
|
|
|
|
return (
|
|
<div className="flex flex-col h-full gap-2">
|
|
{ /* Admin: quick actions */ }
|
|
{ adminMode && !catalogAdmin.editingPageData &&
|
|
<div className="flex gap-2">
|
|
<button
|
|
className="flex items-center gap-1 text-[10px] text-primary hover:text-dark transition-colors cursor-pointer"
|
|
onClick={ () =>
|
|
{
|
|
catalogAdmin.setEditingPageNode(null); catalogAdmin.setEditingRootPage(false); catalogAdmin.setEditingPageData(true);
|
|
} }
|
|
>
|
|
<FaEdit className="text-[10px]" /> { LocalizeText('catalog.admin.edit.page') }
|
|
</button>
|
|
<button
|
|
className="flex items-center gap-1 text-[10px] text-success hover:text-green-800 transition-colors cursor-pointer"
|
|
onClick={ () => catalogAdmin.setEditingOffer({ offerId: -1, product: { productClassId: 0, productType: 'i', productCount: 1, extraParam: '' } } as any) }
|
|
>
|
|
<FaPlus className="text-[10px]" /> { LocalizeText('catalog.admin.offer.new') }
|
|
</button>
|
|
</div> }
|
|
|
|
{ /* Product detail card */ }
|
|
{ currentOffer &&
|
|
<div className="flex gap-0 bg-white rounded border-2 border-card-grid-item-border overflow-hidden">
|
|
{ /* Preview area */ }
|
|
<div className="w-[140px] min-w-[140px] bg-card-grid-item relative flex items-center justify-center border-r-2 border-card-grid-item-border">
|
|
{ (currentOffer.product.productType !== ProductTypeEnum.BADGE) &&
|
|
<>
|
|
<CatalogViewProductWidgetView />
|
|
<CatalogAddOnBadgeWidgetView className="bg-muted rounded bottom-1 right-1 absolute" />
|
|
</> }
|
|
{ (currentOffer.product.productType === ProductTypeEnum.BADGE) &&
|
|
<CatalogAddOnBadgeWidgetView className="scale-2" /> }
|
|
</div>
|
|
{ /* Product info + purchase */ }
|
|
<div className="flex flex-col flex-1 min-w-0 p-2.5 gap-2">
|
|
{ /* Title row */ }
|
|
<div>
|
|
<div className="flex items-start justify-between gap-2">
|
|
<Text className="text-[13px]! font-bold text-dark leading-tight">{ currentOffer.localizationName }</Text>
|
|
{ adminMode &&
|
|
<FaEdit
|
|
className="text-primary text-[11px] cursor-pointer hover:text-dark transition-colors shrink-0 mt-0.5"
|
|
title={ LocalizeText('catalog.admin.offer.edit') }
|
|
onClick={ () => catalogAdmin.setEditingOffer(currentOffer) }
|
|
/> }
|
|
</div>
|
|
{ adminMode &&
|
|
<div className="flex items-center gap-1 mt-1 flex-wrap">
|
|
<span className="text-[8px] font-mono text-white bg-gray-600 px-1 py-px rounded">ID: { currentOffer.product.productClassId }</span>
|
|
<span className="text-[8px] font-mono text-white bg-primary px-1 py-px rounded">Offer: { currentOffer.offerId }</span>
|
|
<span className="text-[8px] font-mono text-white bg-secondary px-1 py-px rounded">{ currentOffer.product.productType.toUpperCase() }</span>
|
|
</div> }
|
|
<CatalogLimitedItemWidgetView />
|
|
</div>
|
|
{ /* Price */ }
|
|
<CatalogTotalPriceWidget />
|
|
{ /* Spinner */ }
|
|
<CatalogSpinnerWidgetView />
|
|
{ /* Actions */ }
|
|
<div className="flex gap-1.5 mt-auto">
|
|
<CatalogPurchaseWidgetView />
|
|
</div>
|
|
</div>
|
|
</div> }
|
|
|
|
{ /* Welcome/description card */ }
|
|
{ !currentOffer &&
|
|
<div className="flex items-center gap-3 p-2.5 bg-white rounded border-2 border-card-grid-item-border">
|
|
{ !!page.localization.getImage(1) &&
|
|
<img className="w-[70px] h-[70px] object-contain rounded shrink-0" src={ page.localization.getImage(1) } /> }
|
|
<Text className="text-[11px]! text-muted" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
|
</div> }
|
|
|
|
{ /* Item grid */ }
|
|
<div className="flex-1 overflow-auto min-h-0">
|
|
{ GetConfigurationValue('catalog.headers') &&
|
|
<CatalogHeaderView imageUrl={ currentPage.localization.getImage(0) } /> }
|
|
<CatalogItemGridWidgetView columnCount={ 7 } columnMinHeight={ 50 } columnMinWidth={ 50 } />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|