@burdenoff/microfe-coolandlovely 2026.1031.2 → 2026.1101.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coolandlovely/CoolAndLovelyRoot.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoot.js +16 -4
- package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +19 -15
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/ActivityTrail.js +1 -1
- package/dist/coolandlovely/components/ActivityTrail.js.map +1 -1
- package/dist/coolandlovely/components/ActorName.js.map +1 -1
- package/dist/coolandlovely/components/AddToCartPanel.js.map +1 -1
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
- package/dist/coolandlovely/components/BrandCard.js.map +1 -1
- package/dist/coolandlovely/components/BrandCover.js.map +1 -1
- package/dist/coolandlovely/components/BrandCreatorAvatars.js.map +1 -1
- package/dist/coolandlovely/components/CollaborationFeeCard.js.map +1 -1
- package/dist/coolandlovely/components/CollectionCard.js.map +1 -1
- package/dist/coolandlovely/components/ColourSwatchRow.js.map +1 -1
- package/dist/coolandlovely/components/Comments.js.map +1 -1
- package/dist/coolandlovely/components/EmptyState.js.map +1 -1
- package/dist/coolandlovely/components/FeedbackWidget.js.map +1 -1
- package/dist/coolandlovely/components/Field.js.map +1 -1
- package/dist/coolandlovely/components/FileImage.js.map +1 -1
- package/dist/coolandlovely/components/FollowButton.js.map +1 -1
- package/dist/coolandlovely/components/FulfilmentTimeline.js.map +1 -1
- package/dist/coolandlovely/components/ImageUploadField.js +3 -1
- package/dist/coolandlovely/components/ImageUploadField.js.map +1 -1
- package/dist/coolandlovely/components/LookCard.js.map +1 -1
- package/dist/coolandlovely/components/LookbookCard.js.map +1 -1
- package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
- package/dist/coolandlovely/components/PageLayout.js.map +1 -1
- package/dist/coolandlovely/components/PayForOrder.js.map +1 -1
- package/dist/coolandlovely/components/RefundPanel.js +1 -1
- package/dist/coolandlovely/components/RefundPanel.js.map +1 -1
- package/dist/coolandlovely/components/ReturnRequests.js +1 -1
- package/dist/coolandlovely/components/ReturnRequests.js.map +1 -1
- package/dist/coolandlovely/components/ShopItemCard.js.map +1 -1
- package/dist/coolandlovely/components/StateViews.js.map +1 -1
- package/dist/coolandlovely/components/StatusBadge.js +1 -1
- package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
- package/dist/coolandlovely/components/StepTracker.js.map +1 -1
- package/dist/coolandlovely/components/StockEditor.js.map +1 -1
- package/dist/coolandlovely/components/StoreListingCard.js.map +1 -1
- package/dist/coolandlovely/components/TagList.js.map +1 -1
- package/dist/coolandlovely/components/Thumbnail.js +1 -1
- package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
- package/dist/coolandlovely/components/VisibilityChip.js.map +1 -1
- package/dist/coolandlovely/components/WardrobeItemCard.js.map +1 -1
- package/dist/coolandlovely/components/index.js +2 -1
- package/dist/coolandlovely/context/CoolAndLovelyContext.js +2 -1
- package/dist/coolandlovely/context/CoolAndLovelyContext.js.map +1 -1
- package/dist/coolandlovely/context/index.js +2 -1
- package/dist/coolandlovely/hooks/index.js +4 -3
- package/dist/coolandlovely/hooks/useActivity.d.ts +1 -1
- package/dist/coolandlovely/hooks/useActivity.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useActivity.js.map +1 -1
- package/dist/coolandlovely/hooks/useAssistantEntity.js.map +1 -1
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts +4 -4
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useBrandOrdersApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useCatalogImport.js.map +1 -1
- package/dist/coolandlovely/hooks/useComments.d.ts +1 -1
- package/dist/coolandlovely/hooks/useComments.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useComments.js.map +1 -1
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts +7 -7
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCommerceApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts +24 -24
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useEditorialApi.d.ts +95 -0
- package/dist/coolandlovely/hooks/useEditorialApi.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useEditorialApi.js +107 -0
- package/dist/coolandlovely/hooks/useEditorialApi.js.map +1 -0
- package/dist/coolandlovely/hooks/useFiles.js.map +1 -1
- package/dist/coolandlovely/hooks/useInventoryApi.d.ts +1 -1
- package/dist/coolandlovely/hooks/useInventoryApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useInventoryApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useTr.js.map +1 -1
- package/dist/coolandlovely/index.js +6 -5
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/admin/AdminBrandsPage.js.map +1 -1
- package/dist/coolandlovely/pages/admin/AdminCollaborationsPage.js.map +1 -1
- package/dist/coolandlovely/pages/admin/AdminFeaturedItemsPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/ImportCatalogPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/CartPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/OrdersPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
- package/dist/coolandlovely/pages/editorial/EditorialPage.d.ts +2 -0
- package/dist/coolandlovely/pages/editorial/EditorialPage.d.ts.map +1 -0
- package/dist/coolandlovely/pages/editorial/EditorialPage.js +486 -0
- package/dist/coolandlovely/pages/editorial/EditorialPage.js.map +1 -0
- package/dist/coolandlovely/pages/items/StoreListedPieceView.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- package/dist/coolandlovely/store/coolandlovelyStore.js.map +1 -1
- package/dist/coolandlovely/store/index.js +2 -1
- package/dist/coolandlovely/types/commerce.d.ts.map +1 -1
- package/dist/coolandlovely/types/index.d.ts.map +1 -1
- package/dist/coolandlovely/utils/cn.js +1 -1
- package/dist/coolandlovely/utils/cn.js.map +1 -1
- package/dist/coolandlovely/utils/formatters.js.map +1 -1
- package/dist/coolandlovely/utils/icons.js.map +1 -1
- package/dist/coolandlovely/utils/index.js +2 -1
- package/dist/coolandlovely/utils/navigation.js.map +1 -1
- package/dist/coolandlovely/utils/paymentProviders.js +22 -22
- package/dist/coolandlovely/utils/paymentProviders.js.map +1 -1
- package/dist/coolandlovely/utils/sparkline.js +13 -15
- package/dist/coolandlovely/utils/sparkline.js.map +1 -1
- package/dist/node_modules/clsx/dist/clsx.js +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +225 -146
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/stories/DiscoverPage.stories.d.ts.map +1 -1
- package/dist/utils/pageContext.js +1 -1
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiscoverPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"sourcesContent":["/**\n * Discover Page\n * @module coolandlovely/pages/discover\n *\n * A profile-tuned discovery feed plus a first-class search experience over the\n * catalogue (`cooSearchStyleItems`) and published looks (`cooSearchLooks`).\n *\n * The \"For you\" tab ranks the real catalogue + social lists against the\n * caller's style profile — no fabricated recommendations, no black-box \"AI\"\n * (that is roadmap). The \"Items\" / \"Looks\" tabs drive server-side search with\n * filters and pagination.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Compass,\n Sparkles,\n Heart,\n ShoppingBag,\n UserCheck,\n Users,\n Search,\n Shirt,\n X,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { LookCard } from '../../components/LookCard';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useMyStyleProfile,\n useLooks,\n useStyleItems,\n useMyFollowing,\n useSearchStyleItems,\n useSearchLooks,\n useTr,\n} from '../../hooks';\nimport type {\n CooLook,\n CooStyleCategory,\n CooStyleItem,\n CooStyleItemStatus,\n CooLookOccasion,\n} from '../../types';\nimport { categoryIcon, STYLE_CATEGORIES } from '../../utils/icons';\nimport { formatPrice, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\n\n/** Lower-cased token set used for overlap scoring. */\nfunction tokenSet(values: string[]): Set<string> {\n return new Set(values.map((v) => v.trim().toLowerCase()).filter(Boolean));\n}\n\n/**\n * The candidate values that literally appear in the taste set.\n *\n * This is the ranker's own reason for a match, returned as the ORIGINAL\n * strings so the \"Why this matched\" chips quote the catalogue's words rather\n * than a normalised token. Nothing here is inferred: a value is only listed\n * when the shopper declared it and the record carries it.\n */\nfunction matches(candidate: string[], taste: Set<string>): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const value of candidate) {\n const key = value.trim().toLowerCase();\n if (!key || seen.has(key) || !taste.has(key)) continue;\n seen.add(key);\n out.push(value.trim());\n }\n return out;\n}\n\n/** A ranked feed row carrying the concrete reasons it ranked where it did. */\ninterface Scored<T> {\n row: T;\n score: number;\n reasons: string[];\n}\n\ninterface SectionProps {\n title: string;\n icon: ReactNode;\n children: ReactNode;\n sublabel?: string;\n}\n\nconst Section: FC<SectionProps> = ({ title, icon, sublabel, children }) => (\n <section className=\"mt-8\">\n <div className=\"mb-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n {icon} {title}\n </h2>\n {sublabel ? <p className=\"mt-0.5 text-sm text-text-secondary\">{sublabel}</p> : null}\n </div>\n {children}\n </section>\n);\n\ninterface TasteGroupProps {\n label: string;\n values: string[];\n withSwatches?: boolean;\n}\n\n/**\n * One declared-taste list off the shopper's own style profile\n * (`cooMyStyleProfile`). Renders nothing when that list is empty — an\n * undeclared palette stays visibly undeclared instead of getting a placeholder.\n */\nconst TasteGroup: FC<TasteGroupProps> = ({ label, values, withSwatches }) => {\n if (values.length === 0) return null;\n return (\n <div className=\"min-w-0 rounded-lg bg-bg-sunken p-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">{label}</p>\n {withSwatches ? <ColourSwatchRow colours={values} max={6} /> : null}\n </div>\n <TagList tags={values} max={8} tone=\"accent\" className=\"mt-2\" />\n </div>\n );\n};\n\n/**\n * The concrete overlaps that put this card in the feed — the same values the\n * ranker scored on, never a generated rationale. Hidden when there were none.\n */\nconst MatchReasons: FC<{ reasons: string[] }> = ({ reasons }) => {\n if (reasons.length === 0) return null;\n return (\n <div className=\"mt-2\">\n <p className=\"text-xs font-medium text-text-secondary\">Why this matched</p>\n <TagList tags={reasons} max={3} tone=\"accent\" className=\"mt-1\" />\n </div>\n );\n};\n\ntype DiscoverTab = 'for-you' | 'items' | 'looks';\n\nconst ITEM_STATUS_ORDER: CooStyleItemStatus[] = ['ACTIVE', 'DRAFT', 'OUT_OF_STOCK', 'RETIRED'];\nconst LOOK_OCCASION_ORDER: CooLookOccasion[] = [\n 'EVERYDAY',\n 'WORK',\n 'EVENING',\n 'WEDDING_GUEST',\n 'VACATION',\n 'PARTY',\n 'ACTIVE',\n 'OTHER',\n];\n\nconst PAGE_SIZE = 24;\n\n/**\n * How long the search box must be idle before a search is sent. Each search is\n * metered against the workspace's `coolandlovely.searches.count` quota, so one\n * request per settled query (not one per keystroke) is what the shopper pays.\n */\nconst SEARCH_DEBOUNCE_MS = 350;\n\n/** `value`, updated only after it has stopped changing for `delayMs`. */\nconst useDebouncedValue = <T,>(value: T, delayMs: number): T => {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const handle = window.setTimeout(() => setDebounced(value), delayMs);\n return () => window.clearTimeout(handle);\n }, [value, delayMs]);\n return debounced;\n};\n\nfunction formatStatusLabel(status: string): string {\n return status.replace(/_/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nexport function DiscoverPage() {\n const { navigateTo, apiGatewayUrl, authToken, workspaceId } = useCoolAndLovely();\n const tr = useTr();\n const profile = useMyStyleProfile();\n\n const tabs: Array<{ value: DiscoverTab; label: string; icon: ReactNode }> = [\n {\n value: 'for-you',\n label: tr('coolandlovely.discover.forYou', 'For you'),\n icon: <Compass className=\"h-4 w-4\" />,\n },\n {\n value: 'items',\n label: tr('coolandlovely.discover.items', 'Items'),\n icon: <ShoppingBag className=\"h-4 w-4\" />,\n },\n {\n value: 'looks',\n label: tr('coolandlovely.discover.looks', 'Looks'),\n icon: <Sparkles className=\"h-4 w-4\" />,\n },\n ];\n\n const itemStatusOptions = [\n { value: 'ALL' as const, label: tr('coolandlovely.filters.all', 'All') },\n ...ITEM_STATUS_ORDER.map((value) => ({\n value,\n label: tr(`coolandlovely.status.${value.toLowerCase()}`, formatStatusLabel(value)),\n })),\n ];\n\n const lookOccasionOptions = [\n { value: 'ALL' as const, label: tr('coolandlovely.filters.all', 'All') },\n ...LOOK_OCCASION_ORDER.map((value) => ({\n value,\n label: tr(`coolandlovely.occasion.${value.toLowerCase()}`, titleCase(value)),\n })),\n ];\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const following = useMyFollowing();\n\n const [activeTab, setActiveTab] = useState<DiscoverTab>('for-you');\n const [query, setQuery] = useState('');\n const [itemOffset, setItemOffset] = useState(0);\n const [lookOffset, setLookOffset] = useState(0);\n\n // Item search filters\n const [itemCategories, setItemCategories] = useState<CooStyleCategory[]>([]);\n const [itemStatus, setItemStatus] = useState<CooStyleItemStatus | 'ALL'>('ALL');\n\n // Look search filters\n const [lookOccasion, setLookOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n\n const debouncedQuery = useDebouncedValue(query.trim(), SEARCH_DEBOUNCE_MS);\n\n // Only the visible results tab searches: the \"For you\" feed is built from the\n // plain list queries, and a search fired for a hidden tab would spend the\n // workspace's search quota (and, once that quota is spent or not yet\n // provisioned, its 429 would take the feed's batched list queries down too).\n const itemSearch = useSearchStyleItems({\n enabled: activeTab === 'items',\n input: {\n query: debouncedQuery || undefined,\n categories: itemCategories.length > 0 ? itemCategories : undefined,\n status: itemStatus === 'ALL' ? undefined : itemStatus,\n },\n pagination: { limit: PAGE_SIZE, offset: itemOffset },\n });\n\n const lookSearch = useSearchLooks({\n enabled: activeTab === 'looks',\n input: {\n query: debouncedQuery || undefined,\n occasion: lookOccasion === 'ALL' ? undefined : lookOccasion,\n },\n pagination: { limit: PAGE_SIZE, offset: lookOffset },\n });\n\n const isForYouLoading = profile.isLoading || looks.isLoading || items.isLoading;\n const isForYouError = looks.isError && items.isError;\n\n const feed = useMemo(() => {\n const p = profile.data;\n const lookRows = looks.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const followingOwners = new Set((following.data ?? []).map((f) => f.ownerId));\n\n // Taste = declared style preferences ∪ palette ∪ favourite brands.\n const taste = tokenSet([\n ...(p?.stylePreferences ?? []),\n ...(p?.palette ?? []),\n ...(p?.favouriteBrands ?? []),\n ]);\n const paletteTokens = tokenSet(p?.palette ?? []);\n const brandTokens = tokenSet(p?.favouriteBrands ?? []);\n\n const scoreLook = (l: CooLook): Scored<CooLook> => {\n const tagHits = matches(l.tags, taste);\n const occasionHit = taste.has(l.occasion.toLowerCase());\n return {\n row: l,\n score: tagHits.length * 2 + (occasionHit ? 1 : 0) + l.likeCount * 0.05 + l.saveCount * 0.05,\n reasons: occasionHit ? [...tagHits, titleCase(l.occasion)] : tagHits,\n };\n };\n\n const scoreItem = (it: CooStyleItem): Scored<CooStyleItem> => {\n const colourHits = matches(it.colours, paletteTokens);\n const tagHits = matches(it.tags, taste);\n const categoryHit = taste.has(it.category.toLowerCase());\n // The brand hit reads the item's OWN federated brand name rather than\n // guessing from its tags, so a favourite brand is credited even when the\n // catalogue entry was never tagged with it.\n const brandName = it.brand?.name?.trim();\n const brandHit = brandName && brandTokens.has(brandName.toLowerCase()) ? brandName : null;\n return {\n row: it,\n score:\n tagHits.length * 2 + colourHits.length * 2 + (categoryHit ? 1 : 0) + (brandHit ? 1 : 0),\n reasons: [\n ...colourHits,\n ...tagHits,\n ...(categoryHit ? [titleCase(it.category)] : []),\n ...(brandHit ? [brandHit] : []),\n ],\n };\n };\n\n const hasTaste = taste.size > 0;\n\n // \"Made for you\": when the shopper has taste, rank by match then engagement;\n // otherwise fall back to most-loved looks so the feed is never empty.\n const madeForYou = lookRows\n .map(scoreLook)\n .sort((a, b) =>\n hasTaste\n ? b.score - a.score\n : b.row.likeCount + b.row.saveCount - (a.row.likeCount + a.row.saveCount)\n )\n .slice(0, 8);\n\n const inYourPalette = itemRows\n .map(scoreItem)\n .filter((scored) => (hasTaste ? scored.score > 0 : true))\n .sort((a, b) => b.score - a.score)\n .slice(0, 8);\n\n const fromFollowing = lookRows\n .filter((l) => followingOwners.has(l.authorId))\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 8);\n\n return {\n hasProfile: Boolean(p),\n hasTaste,\n // The shopper's own declared taste, straight off cooMyStyleProfile — the\n // exact three lists the ranking above is computed from.\n palette: p?.palette ?? [],\n aesthetics: p?.stylePreferences ?? [],\n favouriteBrands: p?.favouriteBrands ?? [],\n madeForYou,\n inYourPalette,\n fromFollowing,\n followingProfiles: following.data ?? [],\n };\n }, [profile.data, looks.data, items.data, following.data]);\n\n // Look authors resolved ONCE for the whole feed (one batched lookup, 5-minute\n // fe-libs cache) rather than one lookup per card.\n const authorActors = useMemo<ActorInput[]>(() => {\n const ids = new Set<string>();\n for (const scored of feed.madeForYou) ids.add(scored.row.authorId);\n for (const look of feed.fromFollowing) ids.add(look.authorId);\n return [...ids].map((actorId) => ({ actorId, actorType: 'user' }));\n }, [feed]);\n const authorProfiles = useActorProfiles(authorActors, {\n apiGatewayUrl,\n authToken,\n workspaceId,\n });\n\n /** A real display name, or null while it is unresolved — never a raw id. */\n const authorLabel = (authorId: string): string | null => {\n const profile = authorProfiles[authorId];\n return profile?.resolved ? profile.displayName : null;\n };\n\n const toggleCategory = (category: CooStyleCategory) => {\n setItemCategories((prev) =>\n prev.includes(category) ? prev.filter((c) => c !== category) : [...prev, category]\n );\n setItemOffset(0);\n };\n\n const clearFilters = () => {\n setQuery('');\n setItemCategories([]);\n setItemStatus('ALL');\n setLookOccasion('ALL');\n setItemOffset(0);\n setLookOffset(0);\n };\n\n const renderForYou = () => {\n if (isForYouLoading) {\n return <LoadingView label={tr('coolandlovely.loading.feed', 'Curating your feed…')} />;\n }\n\n if (isForYouError) {\n return (\n <ErrorView\n onRetry={() => {\n void looks.refetch();\n void items.refetch();\n }}\n />\n );\n }\n\n return (\n <>\n {!feed.hasProfile ? (\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.discover.buildProfileTitle', 'Build your style profile')}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.discover.buildProfileDescription',\n 'Tell us your aesthetics, palette and favourite brands and this feed tunes itself to you.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <Sparkles className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.discover.createProfile', 'Create profile')}\n </button>\n </div>\n </EmphasisPanel>\n ) : null}\n\n {feed.hasTaste ? (\n <section className=\"mb-6 rounded-lg border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-sm font-semibold text-text-primary\">\n {tr('coolandlovely.discover.declaredTaste', 'Your declared taste')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n {tr('coolandlovely.discover.editProfile', 'Edit profile')}{' '}\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'coolandlovely.discover.rankedAgainst',\n 'Everything below is ranked against these lists.'\n )}\n </p>\n <div className=\"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <TasteGroup\n label={tr('coolandlovely.profile.palette', 'Palette')}\n values={feed.palette}\n withSwatches\n />\n <TasteGroup\n label={tr('coolandlovely.profile.aesthetics', 'Aesthetics')}\n values={feed.aesthetics}\n />\n <TasteGroup\n label={tr('coolandlovely.profile.favouriteBrands', 'Favourite brands')}\n values={feed.favouriteBrands}\n />\n </div>\n </section>\n ) : null}\n\n <Section\n title={tr('coolandlovely.discover.madeForYou', 'Made for you')}\n icon={<Compass className=\"h-5 w-5\" />}\n sublabel={\n feed.hasTaste\n ? tr('coolandlovely.discover.madeForYouTuned', 'Ranked to match your style profile')\n : tr('coolandlovely.discover.madeForYouFallback', 'Most-loved looks on the platform')\n }\n >\n {feed.madeForYou.length === 0 ? (\n <EmptyState\n title={tr('coolandlovely.empty.looksTitle', 'No looks yet')}\n description={tr(\n 'coolandlovely.discover.madeForYouEmpty',\n 'Once looks are published they will appear here, tuned to your taste.'\n )}\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.madeForYou.map(({ row: look, reasons }) => {\n const author = authorLabel(look.authorId);\n return (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n {author ? (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{author}</p>\n ) : null}\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n `coolandlovely.occasion.${look.occasion.toLowerCase()}`,\n titleCase(look.occasion)\n )}\n </p>\n <span className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n {feed.hasTaste ? <MatchReasons reasons={reasons} /> : null}\n </div>\n </button>\n );\n })}\n </div>\n )}\n </Section>\n\n {feed.inYourPalette.length > 0 ? (\n <Section\n title={tr('coolandlovely.discover.inYourPalette', 'In your palette')}\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n sublabel={tr(\n 'coolandlovely.discover.inYourPaletteSub',\n 'Pieces that match your colours, categories and tags'\n )}\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.inYourPalette.map(({ row: item, reasons }) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<ShoppingBag className=\"h-6 w-6\" />}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name ? (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n ) : null}\n <p className=\"mt-0.5 flex items-baseline gap-2 text-xs text-text-secondary\">\n <span className=\"font-medium text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"truncate\">\n {tr(\n `coolandlovely.category.${item.category.toLowerCase()}`,\n titleCase(item.category)\n )}\n {item.materials.length > 0 ? ` · ${item.materials.join(', ')}` : ''}\n </span>\n </p>\n <ColourSwatchRow colours={item.colours} max={5} className=\"mt-2\" />\n {feed.hasTaste ? <MatchReasons reasons={reasons} /> : null}\n </div>\n </button>\n ))}\n </div>\n </Section>\n ) : null}\n\n <Section\n title={tr('coolandlovely.discover.fromFollowing', 'From people you follow')}\n icon={<UserCheck className=\"h-5 w-5\" />}\n sublabel={\n feed.followingProfiles.length === 0\n ? tr(\n 'coolandlovely.discover.followPrompt',\n 'Follow creators and shoppers to see their looks here'\n )\n : tr('coolandlovely.discover.followCount', 'You follow {{count}} {{people}}', {\n count: feed.followingProfiles.length,\n people:\n feed.followingProfiles.length === 1\n ? tr('coolandlovely.common.person', 'person')\n : tr('coolandlovely.common.people', 'people'),\n })\n }\n >\n {feed.followingProfiles.length === 0 ? (\n <EmptyState\n title={tr(\n 'coolandlovely.discover.noFollowingTitle',\n 'You are not following anyone yet'\n )}\n description={tr(\n 'coolandlovely.discover.noFollowingDescription',\n 'Open a look or a style profile and tap Follow to build a feed from people whose taste you love.'\n )}\n icon={<Users className=\"h-8 w-8\" />}\n />\n ) : feed.fromFollowing.length === 0 ? (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.discover.followingEmpty',\n 'The people you follow have not published looks visible to you yet.'\n )}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.fromFollowing.map((look) => {\n const author = authorLabel(look.authorId);\n return (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n {author ? (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{author}</p>\n ) : null}\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n `coolandlovely.occasion.${look.occasion.toLowerCase()}`,\n titleCase(look.occasion)\n )}\n </p>\n </div>\n </button>\n );\n })}\n </div>\n )}\n </Section>\n </>\n );\n };\n\n const renderItemResults = () => {\n const data = itemSearch.data;\n const rows = data?.items ?? [];\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n return (\n <div className=\"space-y-4\">\n {/* Category filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {STYLE_CATEGORIES.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => toggleCategory(c)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n itemCategories.includes(c)\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {categoryIcon(c, 14)} {tr(`coolandlovely.category.${c.toLowerCase()}`, titleCase(c))}\n </button>\n ))}\n </div>\n\n {/* Status filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {itemStatusOptions.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setItemStatus(opt.value);\n setItemOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n itemStatus === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {itemSearch.isLoading ? (\n <LoadingView label={tr('coolandlovely.loading.searchItems', 'Searching items…')} />\n ) : itemSearch.isError ? (\n <ErrorView onRetry={() => void itemSearch.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shirt className=\"h-10 w-10\" />}\n title={tr('coolandlovely.empty.itemsTitle', 'No items found')}\n description={tr(\n 'coolandlovely.empty.searchFilters',\n 'Try a different query or filters.'\n )}\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {rows.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <div className=\"relative\">\n <Thumbnail\n icon={categoryIcon(item.category, 32)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[3/4] w-full\"\n />\n <div className=\"absolute right-2 top-2\">\n <StatusBadge status={item.status} className=\"shadow-sm\" />\n </div>\n </div>\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n )}\n <div className=\"mt-1.5 flex items-center justify-between gap-2\">\n <span className=\"text-sm font-semibold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"text-xs text-text-secondary\">\n {tr(\n `coolandlovely.category.${item.category.toLowerCase()}`,\n titleCase(item.category)\n )}\n </span>\n </div>\n {item.colours.length > 0 && (\n <ColourSwatchRow colours={item.colours} max={5} className=\"mt-2\" />\n )}\n </div>\n </button>\n ))}\n </div>\n\n {(itemOffset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={itemOffset === 0}\n onClick={() => setItemOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.pagination.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.pagination.page', 'Page {{page}}', {\n page: itemOffset / PAGE_SIZE + 1,\n })}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setItemOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {tr('coolandlovely.pagination.next', 'Next')} <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n };\n\n const renderLookResults = () => {\n const data = lookSearch.data;\n const rows = data?.items ?? [];\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n return (\n <div className=\"space-y-4\">\n {/* Occasion filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {lookOccasionOptions.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setLookOccasion(opt.value);\n setLookOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n lookOccasion === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {lookSearch.isLoading ? (\n <LoadingView label={tr('coolandlovely.loading.searchLooks', 'Searching looks…')} />\n ) : lookSearch.isError ? (\n <ErrorView onRetry={() => void lookSearch.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title={tr('coolandlovely.empty.looksSearchTitle', 'No looks found')}\n description={tr(\n 'coolandlovely.empty.looksSearchDescription',\n 'Try a different query or occasion.'\n )}\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {rows.map((look) => (\n <div key={look.id} className=\"relative\">\n <LookCard\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n {look.isFeatured && (\n <div className=\"pointer-events-none absolute left-2 top-2 z-10\">\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur\">\n <Sparkles className=\"h-3 w-3\" />{' '}\n {tr('coolandlovely.filters.featured', 'Featured')}\n </span>\n </div>\n )}\n </div>\n ))}\n </div>\n\n {(lookOffset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={lookOffset === 0}\n onClick={() => setLookOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.pagination.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.pagination.page', 'Page {{page}}', {\n page: lookOffset / PAGE_SIZE + 1,\n })}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setLookOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {tr('coolandlovely.pagination.next', 'Next')} <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n };\n\n return (\n <PageLayout\n title={tr('coolandlovely.page.discoverTitle', 'Discover')}\n description={tr(\n 'coolandlovely.page.discoverSubtitle',\n 'Find looks and pieces tuned to your taste'\n )}\n hero\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'coolandlovely.discover.purpose',\n 'Your personalised feed, computed live from your style profile, plus search across every piece and look on the platform.'\n )}\n </PagePurpose>\n\n {/* Search bar */}\n <div className=\"mb-4 flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n value={query}\n onChange={(e) => {\n const next = e.target.value;\n setQuery(next);\n setItemOffset(0);\n setLookOffset(0);\n // Typing a query on the feed means the shopper wants results.\n if (next.trim() && activeTab === 'for-you') setActiveTab('items');\n }}\n placeholder={tr(\n 'coolandlovely.discover.searchPlaceholder',\n 'Search style items and looks…'\n )}\n className=\"w-full rounded-lg border border-border-seam bg-bg-surface py-2.5 pl-9 pr-9 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 rounded p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"mb-6 flex items-center gap-1 border-b border-border-seam\">\n {tabs.map((tab) => (\n <button\n key={tab.value}\n type=\"button\"\n onClick={() => setActiveTab(tab.value)}\n className={cn(\n 'inline-flex items-center gap-1.5 border-b-2 px-3 py-2.5 text-sm font-medium transition-colors',\n activeTab === tab.value\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.icon} {tab.label}\n </button>\n ))}\n {(query || itemCategories.length > 0 || itemStatus !== 'ALL' || lookOccasion !== 'ALL') && (\n <button\n type=\"button\"\n onClick={clearFilters}\n className=\"ml-auto inline-flex items-center gap-1 rounded-full px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-3.5 w-3.5\" /> {tr('coolandlovely.filters.clear', 'Clear')}\n </button>\n )}\n </div>\n\n {activeTab === 'for-you' && renderForYou()}\n {activeTab === 'items' && renderItemResults()}\n {activeTab === 'looks' && renderLookResults()}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DiscoverPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"sourcesContent":["/**\n * Discover Page\n * @module coolandlovely/pages/discover\n *\n * A profile-tuned discovery feed plus a first-class search experience over the\n * catalogue (`cooSearchStyleItems`) and published looks (`cooSearchLooks`).\n *\n * The \"For you\" tab ranks the real catalogue + social lists against the\n * caller's style profile — no fabricated recommendations, no black-box \"AI\"\n * (that is roadmap). The \"Items\" / \"Looks\" tabs drive server-side search with\n * filters and pagination.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Compass,\n Sparkles,\n Heart,\n ShoppingBag,\n UserCheck,\n Users,\n Search,\n Shirt,\n X,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { LookCard } from '../../components/LookCard';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useMyStyleProfile,\n useLooks,\n useStyleItems,\n useMyFollowing,\n useSearchStyleItems,\n useSearchLooks,\n useTr,\n} from '../../hooks';\nimport type {\n CooLook,\n CooStyleCategory,\n CooStyleItem,\n CooStyleItemStatus,\n CooLookOccasion,\n} from '../../types';\nimport { categoryIcon, STYLE_CATEGORIES } from '../../utils/icons';\nimport { formatPrice, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\n\n/** Lower-cased token set used for overlap scoring. */\nfunction tokenSet(values: string[]): Set<string> {\n return new Set(values.map((v) => v.trim().toLowerCase()).filter(Boolean));\n}\n\n/**\n * The candidate values that literally appear in the taste set.\n *\n * This is the ranker's own reason for a match, returned as the ORIGINAL\n * strings so the \"Why this matched\" chips quote the catalogue's words rather\n * than a normalised token. Nothing here is inferred: a value is only listed\n * when the shopper declared it and the record carries it.\n */\nfunction matches(candidate: string[], taste: Set<string>): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const value of candidate) {\n const key = value.trim().toLowerCase();\n if (!key || seen.has(key) || !taste.has(key)) continue;\n seen.add(key);\n out.push(value.trim());\n }\n return out;\n}\n\n/** A ranked feed row carrying the concrete reasons it ranked where it did. */\ninterface Scored<T> {\n row: T;\n score: number;\n reasons: string[];\n}\n\ninterface SectionProps {\n title: string;\n icon: ReactNode;\n children: ReactNode;\n sublabel?: string;\n}\n\nconst Section: FC<SectionProps> = ({ title, icon, sublabel, children }) => (\n <section className=\"mt-8\">\n <div className=\"mb-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n {icon} {title}\n </h2>\n {sublabel ? <p className=\"mt-0.5 text-sm text-text-secondary\">{sublabel}</p> : null}\n </div>\n {children}\n </section>\n);\n\ninterface TasteGroupProps {\n label: string;\n values: string[];\n withSwatches?: boolean;\n}\n\n/**\n * One declared-taste list off the shopper's own style profile\n * (`cooMyStyleProfile`). Renders nothing when that list is empty — an\n * undeclared palette stays visibly undeclared instead of getting a placeholder.\n */\nconst TasteGroup: FC<TasteGroupProps> = ({ label, values, withSwatches }) => {\n if (values.length === 0) return null;\n return (\n <div className=\"min-w-0 rounded-lg bg-bg-sunken p-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">{label}</p>\n {withSwatches ? <ColourSwatchRow colours={values} max={6} /> : null}\n </div>\n <TagList tags={values} max={8} tone=\"accent\" className=\"mt-2\" />\n </div>\n );\n};\n\n/**\n * The concrete overlaps that put this card in the feed — the same values the\n * ranker scored on, never a generated rationale. Hidden when there were none.\n */\nconst MatchReasons: FC<{ reasons: string[] }> = ({ reasons }) => {\n if (reasons.length === 0) return null;\n return (\n <div className=\"mt-2\">\n <p className=\"text-xs font-medium text-text-secondary\">Why this matched</p>\n <TagList tags={reasons} max={3} tone=\"accent\" className=\"mt-1\" />\n </div>\n );\n};\n\ntype DiscoverTab = 'for-you' | 'items' | 'looks';\n\nconst ITEM_STATUS_ORDER: CooStyleItemStatus[] = ['ACTIVE', 'DRAFT', 'OUT_OF_STOCK', 'RETIRED'];\nconst LOOK_OCCASION_ORDER: CooLookOccasion[] = [\n 'EVERYDAY',\n 'WORK',\n 'EVENING',\n 'WEDDING_GUEST',\n 'VACATION',\n 'PARTY',\n 'ACTIVE',\n 'OTHER',\n];\n\nconst PAGE_SIZE = 24;\n\n/**\n * How long the search box must be idle before a search is sent. Each search is\n * metered against the workspace's `coolandlovely.searches.count` quota, so one\n * request per settled query (not one per keystroke) is what the shopper pays.\n */\nconst SEARCH_DEBOUNCE_MS = 350;\n\n/** `value`, updated only after it has stopped changing for `delayMs`. */\nconst useDebouncedValue = <T,>(value: T, delayMs: number): T => {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const handle = window.setTimeout(() => setDebounced(value), delayMs);\n return () => window.clearTimeout(handle);\n }, [value, delayMs]);\n return debounced;\n};\n\nfunction formatStatusLabel(status: string): string {\n return status.replace(/_/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nexport function DiscoverPage() {\n const { navigateTo, apiGatewayUrl, authToken, workspaceId } = useCoolAndLovely();\n const tr = useTr();\n const profile = useMyStyleProfile();\n\n const tabs: Array<{ value: DiscoverTab; label: string; icon: ReactNode }> = [\n {\n value: 'for-you',\n label: tr('coolandlovely.discover.forYou', 'For you'),\n icon: <Compass className=\"h-4 w-4\" />,\n },\n {\n value: 'items',\n label: tr('coolandlovely.discover.items', 'Items'),\n icon: <ShoppingBag className=\"h-4 w-4\" />,\n },\n {\n value: 'looks',\n label: tr('coolandlovely.discover.looks', 'Looks'),\n icon: <Sparkles className=\"h-4 w-4\" />,\n },\n ];\n\n const itemStatusOptions = [\n { value: 'ALL' as const, label: tr('coolandlovely.filters.all', 'All') },\n ...ITEM_STATUS_ORDER.map((value) => ({\n value,\n label: tr(`coolandlovely.status.${value.toLowerCase()}`, formatStatusLabel(value)),\n })),\n ];\n\n const lookOccasionOptions = [\n { value: 'ALL' as const, label: tr('coolandlovely.filters.all', 'All') },\n ...LOOK_OCCASION_ORDER.map((value) => ({\n value,\n label: tr(`coolandlovely.occasion.${value.toLowerCase()}`, titleCase(value)),\n })),\n ];\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const following = useMyFollowing();\n\n const [activeTab, setActiveTab] = useState<DiscoverTab>('for-you');\n const [query, setQuery] = useState('');\n const [itemOffset, setItemOffset] = useState(0);\n const [lookOffset, setLookOffset] = useState(0);\n\n // Item search filters\n const [itemCategories, setItemCategories] = useState<CooStyleCategory[]>([]);\n const [itemStatus, setItemStatus] = useState<CooStyleItemStatus | 'ALL'>('ALL');\n\n // Look search filters\n const [lookOccasion, setLookOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n\n const debouncedQuery = useDebouncedValue(query.trim(), SEARCH_DEBOUNCE_MS);\n\n // Only the visible results tab searches: the \"For you\" feed is built from the\n // plain list queries, and a search fired for a hidden tab would spend the\n // workspace's search quota (and, once that quota is spent or not yet\n // provisioned, its 429 would take the feed's batched list queries down too).\n const itemSearch = useSearchStyleItems({\n enabled: activeTab === 'items',\n input: {\n query: debouncedQuery || undefined,\n categories: itemCategories.length > 0 ? itemCategories : undefined,\n status: itemStatus === 'ALL' ? undefined : itemStatus,\n },\n pagination: { limit: PAGE_SIZE, offset: itemOffset },\n });\n\n const lookSearch = useSearchLooks({\n enabled: activeTab === 'looks',\n input: {\n query: debouncedQuery || undefined,\n occasion: lookOccasion === 'ALL' ? undefined : lookOccasion,\n },\n pagination: { limit: PAGE_SIZE, offset: lookOffset },\n });\n\n const isForYouLoading = profile.isLoading || looks.isLoading || items.isLoading;\n const isForYouError = looks.isError && items.isError;\n\n const feed = useMemo(() => {\n const p = profile.data;\n const lookRows = looks.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const followingOwners = new Set((following.data ?? []).map((f) => f.ownerId));\n\n // Taste = declared style preferences ∪ palette ∪ favourite brands.\n const taste = tokenSet([\n ...(p?.stylePreferences ?? []),\n ...(p?.palette ?? []),\n ...(p?.favouriteBrands ?? []),\n ]);\n const paletteTokens = tokenSet(p?.palette ?? []);\n const brandTokens = tokenSet(p?.favouriteBrands ?? []);\n\n const scoreLook = (l: CooLook): Scored<CooLook> => {\n const tagHits = matches(l.tags, taste);\n const occasionHit = taste.has(l.occasion.toLowerCase());\n return {\n row: l,\n score: tagHits.length * 2 + (occasionHit ? 1 : 0) + l.likeCount * 0.05 + l.saveCount * 0.05,\n reasons: occasionHit ? [...tagHits, titleCase(l.occasion)] : tagHits,\n };\n };\n\n const scoreItem = (it: CooStyleItem): Scored<CooStyleItem> => {\n const colourHits = matches(it.colours, paletteTokens);\n const tagHits = matches(it.tags, taste);\n const categoryHit = taste.has(it.category.toLowerCase());\n // The brand hit reads the item's OWN federated brand name rather than\n // guessing from its tags, so a favourite brand is credited even when the\n // catalogue entry was never tagged with it.\n const brandName = it.brand?.name?.trim();\n const brandHit = brandName && brandTokens.has(brandName.toLowerCase()) ? brandName : null;\n return {\n row: it,\n score:\n tagHits.length * 2 + colourHits.length * 2 + (categoryHit ? 1 : 0) + (brandHit ? 1 : 0),\n reasons: [\n ...colourHits,\n ...tagHits,\n ...(categoryHit ? [titleCase(it.category)] : []),\n ...(brandHit ? [brandHit] : []),\n ],\n };\n };\n\n const hasTaste = taste.size > 0;\n\n // \"Made for you\": when the shopper has taste, rank by match then engagement;\n // otherwise fall back to most-loved looks so the feed is never empty.\n const madeForYou = lookRows\n .map(scoreLook)\n .sort((a, b) =>\n hasTaste\n ? b.score - a.score\n : b.row.likeCount + b.row.saveCount - (a.row.likeCount + a.row.saveCount)\n )\n .slice(0, 8);\n\n const inYourPalette = itemRows\n .map(scoreItem)\n .filter((scored) => (hasTaste ? scored.score > 0 : true))\n .sort((a, b) => b.score - a.score)\n .slice(0, 8);\n\n const fromFollowing = lookRows\n .filter((l) => followingOwners.has(l.authorId))\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 8);\n\n return {\n hasProfile: Boolean(p),\n hasTaste,\n // The shopper's own declared taste, straight off cooMyStyleProfile — the\n // exact three lists the ranking above is computed from.\n palette: p?.palette ?? [],\n aesthetics: p?.stylePreferences ?? [],\n favouriteBrands: p?.favouriteBrands ?? [],\n madeForYou,\n inYourPalette,\n fromFollowing,\n followingProfiles: following.data ?? [],\n };\n }, [profile.data, looks.data, items.data, following.data]);\n\n // Look authors resolved ONCE for the whole feed (one batched lookup, 5-minute\n // fe-libs cache) rather than one lookup per card.\n const authorActors = useMemo<ActorInput[]>(() => {\n const ids = new Set<string>();\n for (const scored of feed.madeForYou) ids.add(scored.row.authorId);\n for (const look of feed.fromFollowing) ids.add(look.authorId);\n return [...ids].map((actorId) => ({ actorId, actorType: 'user' }));\n }, [feed]);\n const authorProfiles = useActorProfiles(authorActors, {\n apiGatewayUrl,\n authToken,\n workspaceId,\n });\n\n /** A real display name, or null while it is unresolved — never a raw id. */\n const authorLabel = (authorId: string): string | null => {\n const profile = authorProfiles[authorId];\n return profile?.resolved ? profile.displayName : null;\n };\n\n const toggleCategory = (category: CooStyleCategory) => {\n setItemCategories((prev) =>\n prev.includes(category) ? prev.filter((c) => c !== category) : [...prev, category]\n );\n setItemOffset(0);\n };\n\n const clearFilters = () => {\n setQuery('');\n setItemCategories([]);\n setItemStatus('ALL');\n setLookOccasion('ALL');\n setItemOffset(0);\n setLookOffset(0);\n };\n\n const renderForYou = () => {\n if (isForYouLoading) {\n return <LoadingView label={tr('coolandlovely.loading.feed', 'Curating your feed…')} />;\n }\n\n if (isForYouError) {\n return (\n <ErrorView\n onRetry={() => {\n void looks.refetch();\n void items.refetch();\n }}\n />\n );\n }\n\n return (\n <>\n {!feed.hasProfile ? (\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('coolandlovely.discover.buildProfileTitle', 'Build your style profile')}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.discover.buildProfileDescription',\n 'Tell us your aesthetics, palette and favourite brands and this feed tunes itself to you.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <Sparkles className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.discover.createProfile', 'Create profile')}\n </button>\n </div>\n </EmphasisPanel>\n ) : null}\n\n {feed.hasTaste ? (\n <section className=\"mb-6 rounded-lg border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-sm font-semibold text-text-primary\">\n {tr('coolandlovely.discover.declaredTaste', 'Your declared taste')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n {tr('coolandlovely.discover.editProfile', 'Edit profile')}{' '}\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'coolandlovely.discover.rankedAgainst',\n 'Everything below is ranked against these lists.'\n )}\n </p>\n <div className=\"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <TasteGroup\n label={tr('coolandlovely.profile.palette', 'Palette')}\n values={feed.palette}\n withSwatches\n />\n <TasteGroup\n label={tr('coolandlovely.profile.aesthetics', 'Aesthetics')}\n values={feed.aesthetics}\n />\n <TasteGroup\n label={tr('coolandlovely.profile.favouriteBrands', 'Favourite brands')}\n values={feed.favouriteBrands}\n />\n </div>\n </section>\n ) : null}\n\n <Section\n title={tr('coolandlovely.discover.madeForYou', 'Made for you')}\n icon={<Compass className=\"h-5 w-5\" />}\n sublabel={\n feed.hasTaste\n ? tr('coolandlovely.discover.madeForYouTuned', 'Ranked to match your style profile')\n : tr('coolandlovely.discover.madeForYouFallback', 'Most-loved looks on the platform')\n }\n >\n {feed.madeForYou.length === 0 ? (\n <EmptyState\n title={tr('coolandlovely.empty.looksTitle', 'No looks yet')}\n description={tr(\n 'coolandlovely.discover.madeForYouEmpty',\n 'Once looks are published they will appear here, tuned to your taste.'\n )}\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.madeForYou.map(({ row: look, reasons }) => {\n const author = authorLabel(look.authorId);\n return (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n {author ? (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{author}</p>\n ) : null}\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n `coolandlovely.occasion.${look.occasion.toLowerCase()}`,\n titleCase(look.occasion)\n )}\n </p>\n <span className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n {feed.hasTaste ? <MatchReasons reasons={reasons} /> : null}\n </div>\n </button>\n );\n })}\n </div>\n )}\n </Section>\n\n {feed.inYourPalette.length > 0 ? (\n <Section\n title={tr('coolandlovely.discover.inYourPalette', 'In your palette')}\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n sublabel={tr(\n 'coolandlovely.discover.inYourPaletteSub',\n 'Pieces that match your colours, categories and tags'\n )}\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.inYourPalette.map(({ row: item, reasons }) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<ShoppingBag className=\"h-6 w-6\" />}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name ? (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n ) : null}\n <p className=\"mt-0.5 flex items-baseline gap-2 text-xs text-text-secondary\">\n <span className=\"font-medium text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"truncate\">\n {tr(\n `coolandlovely.category.${item.category.toLowerCase()}`,\n titleCase(item.category)\n )}\n {item.materials.length > 0 ? ` · ${item.materials.join(', ')}` : ''}\n </span>\n </p>\n <ColourSwatchRow colours={item.colours} max={5} className=\"mt-2\" />\n {feed.hasTaste ? <MatchReasons reasons={reasons} /> : null}\n </div>\n </button>\n ))}\n </div>\n </Section>\n ) : null}\n\n <Section\n title={tr('coolandlovely.discover.fromFollowing', 'From people you follow')}\n icon={<UserCheck className=\"h-5 w-5\" />}\n sublabel={\n feed.followingProfiles.length === 0\n ? tr(\n 'coolandlovely.discover.followPrompt',\n 'Follow creators and shoppers to see their looks here'\n )\n : tr('coolandlovely.discover.followCount', 'You follow {{count}} {{people}}', {\n count: feed.followingProfiles.length,\n people:\n feed.followingProfiles.length === 1\n ? tr('coolandlovely.common.person', 'person')\n : tr('coolandlovely.common.people', 'people'),\n })\n }\n >\n {feed.followingProfiles.length === 0 ? (\n <EmptyState\n title={tr(\n 'coolandlovely.discover.noFollowingTitle',\n 'You are not following anyone yet'\n )}\n description={tr(\n 'coolandlovely.discover.noFollowingDescription',\n 'Open a look or a style profile and tap Follow to build a feed from people whose taste you love.'\n )}\n icon={<Users className=\"h-8 w-8\" />}\n />\n ) : feed.fromFollowing.length === 0 ? (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n {tr(\n 'coolandlovely.discover.followingEmpty',\n 'The people you follow have not published looks visible to you yet.'\n )}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.fromFollowing.map((look) => {\n const author = authorLabel(look.authorId);\n return (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n {author ? (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{author}</p>\n ) : null}\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n `coolandlovely.occasion.${look.occasion.toLowerCase()}`,\n titleCase(look.occasion)\n )}\n </p>\n </div>\n </button>\n );\n })}\n </div>\n )}\n </Section>\n </>\n );\n };\n\n const renderItemResults = () => {\n const data = itemSearch.data;\n const rows = data?.items ?? [];\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n return (\n <div className=\"space-y-4\">\n {/* Category filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {STYLE_CATEGORIES.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => toggleCategory(c)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n itemCategories.includes(c)\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {categoryIcon(c, 14)} {tr(`coolandlovely.category.${c.toLowerCase()}`, titleCase(c))}\n </button>\n ))}\n </div>\n\n {/* Status filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {itemStatusOptions.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setItemStatus(opt.value);\n setItemOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n itemStatus === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {itemSearch.isLoading ? (\n <LoadingView label={tr('coolandlovely.loading.searchItems', 'Searching items…')} />\n ) : itemSearch.isError ? (\n <ErrorView onRetry={() => void itemSearch.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shirt className=\"h-10 w-10\" />}\n title={tr('coolandlovely.empty.itemsTitle', 'No items found')}\n description={tr(\n 'coolandlovely.empty.searchFilters',\n 'Try a different query or filters.'\n )}\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {rows.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <div className=\"relative\">\n <Thumbnail\n icon={categoryIcon(item.category, 32)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[3/4] w-full\"\n />\n <div className=\"absolute right-2 top-2\">\n <StatusBadge status={item.status} className=\"shadow-sm\" />\n </div>\n </div>\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n )}\n <div className=\"mt-1.5 flex items-center justify-between gap-2\">\n <span className=\"text-sm font-semibold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"text-xs text-text-secondary\">\n {tr(\n `coolandlovely.category.${item.category.toLowerCase()}`,\n titleCase(item.category)\n )}\n </span>\n </div>\n {item.colours.length > 0 && (\n <ColourSwatchRow colours={item.colours} max={5} className=\"mt-2\" />\n )}\n </div>\n </button>\n ))}\n </div>\n\n {(itemOffset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={itemOffset === 0}\n onClick={() => setItemOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.pagination.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.pagination.page', 'Page {{page}}', {\n page: itemOffset / PAGE_SIZE + 1,\n })}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setItemOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {tr('coolandlovely.pagination.next', 'Next')} <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n };\n\n const renderLookResults = () => {\n const data = lookSearch.data;\n const rows = data?.items ?? [];\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n return (\n <div className=\"space-y-4\">\n {/* Occasion filter */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {lookOccasionOptions.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setLookOccasion(opt.value);\n setLookOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n lookOccasion === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {lookSearch.isLoading ? (\n <LoadingView label={tr('coolandlovely.loading.searchLooks', 'Searching looks…')} />\n ) : lookSearch.isError ? (\n <ErrorView onRetry={() => void lookSearch.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title={tr('coolandlovely.empty.looksSearchTitle', 'No looks found')}\n description={tr(\n 'coolandlovely.empty.looksSearchDescription',\n 'Try a different query or occasion.'\n )}\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {rows.map((look) => (\n <div key={look.id} className=\"relative\">\n <LookCard\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n {look.isFeatured && (\n <div className=\"pointer-events-none absolute left-2 top-2 z-10\">\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur\">\n <Sparkles className=\"h-3 w-3\" />{' '}\n {tr('coolandlovely.filters.featured', 'Featured')}\n </span>\n </div>\n )}\n </div>\n ))}\n </div>\n\n {(lookOffset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={lookOffset === 0}\n onClick={() => setLookOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.pagination.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.pagination.page', 'Page {{page}}', {\n page: lookOffset / PAGE_SIZE + 1,\n })}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setLookOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {tr('coolandlovely.pagination.next', 'Next')} <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n };\n\n return (\n <PageLayout\n title={tr('coolandlovely.page.discoverTitle', 'Discover')}\n description={tr(\n 'coolandlovely.page.discoverSubtitle',\n 'Find looks and pieces tuned to your taste'\n )}\n hero\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'coolandlovely.discover.purpose',\n 'Your personalised feed, computed live from your style profile, plus search across every piece and look on the platform.'\n )}\n </PagePurpose>\n\n {/* Search bar */}\n <div className=\"mb-4 flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n value={query}\n onChange={(e) => {\n const next = e.target.value;\n setQuery(next);\n setItemOffset(0);\n setLookOffset(0);\n // Typing a query on the feed means the shopper wants results.\n if (next.trim() && activeTab === 'for-you') setActiveTab('items');\n }}\n placeholder={tr(\n 'coolandlovely.discover.searchPlaceholder',\n 'Search style items and looks…'\n )}\n className=\"w-full rounded-lg border border-border-seam bg-bg-surface py-2.5 pl-9 pr-9 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 rounded p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"mb-6 flex items-center gap-1 border-b border-border-seam\">\n {tabs.map((tab) => (\n <button\n key={tab.value}\n type=\"button\"\n onClick={() => setActiveTab(tab.value)}\n className={cn(\n 'inline-flex items-center gap-1.5 border-b-2 px-3 py-2.5 text-sm font-medium transition-colors',\n activeTab === tab.value\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.icon} {tab.label}\n </button>\n ))}\n {(query || itemCategories.length > 0 || itemStatus !== 'ALL' || lookOccasion !== 'ALL') && (\n <button\n type=\"button\"\n onClick={clearFilters}\n className=\"ml-auto inline-flex items-center gap-1 rounded-full px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-3.5 w-3.5\" /> {tr('coolandlovely.filters.clear', 'Clear')}\n </button>\n )}\n </div>\n\n {activeTab === 'for-you' && renderForYou()}\n {activeTab === 'items' && renderItemResults()}\n {activeTab === 'looks' && renderLookResults()}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorialPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/editorial/EditorialPage.tsx"],"names":[],"mappings":"AA2FA,wBAAgB,aAAa,gCAma5B"}
|