@fluid-app/portal-sdk 0.1.149 → 0.1.150
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/{ContactsScreen-DtABz7O7.mjs → ContactsScreen--c03aFBb.mjs} +2 -2
- package/dist/{ContactsScreen-DtABz7O7.mjs.map → ContactsScreen--c03aFBb.mjs.map} +1 -1
- package/dist/{ContactsScreen-DuKE5ruf.cjs → ContactsScreen-BRLqZ5Aj.cjs} +2 -2
- package/dist/{ContactsScreen-psnV3fcP.cjs → ContactsScreen-C-wNg4uQ.cjs} +2 -2
- package/dist/{ContactsScreen-psnV3fcP.cjs.map → ContactsScreen-C-wNg4uQ.cjs.map} +1 -1
- package/dist/{OrdersScreen-CR2NZAGm.cjs → OrdersScreen-CCpGsP-L.cjs} +2 -2
- package/dist/{OrdersScreen-BXlGNk8k.cjs → OrdersScreen-CeyfnOeb.cjs} +2 -2
- package/dist/{OrdersScreen-BXlGNk8k.cjs.map → OrdersScreen-CeyfnOeb.cjs.map} +1 -1
- package/dist/{OrdersScreen-B4xeL-Kg.mjs → OrdersScreen-DZ0sgSHZ.mjs} +2 -2
- package/dist/{OrdersScreen-B4xeL-Kg.mjs.map → OrdersScreen-DZ0sgSHZ.mjs.map} +1 -1
- package/dist/{ProductsScreen-IbgDLX51.mjs → ProductsScreen-C5BF7B4b.mjs} +0 -5
- package/dist/{ShareablesScreen-C2zLeoy7.mjs → ShareablesScreen-DutWYuKD.mjs} +0 -6
- package/dist/{ShopScreen-DGQuhCjL.cjs → ShopScreen-5PBOI4UO.cjs} +1 -1
- package/dist/{ShopScreen-gE3t8H83.mjs → ShopScreen-DMVWsOB-.mjs} +2 -2
- package/dist/ShopScreen-DMVWsOB-.mjs.map +1 -0
- package/dist/{ShopScreen-BVD2rPsc.cjs → ShopScreen-a3P0O4WA.cjs} +2 -2
- package/dist/ShopScreen-a3P0O4WA.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-OkgAzsMr.cjs → SubscriptionsScreen-B6Wy4na9.cjs} +3 -3
- package/dist/SubscriptionsScreen-B6Wy4na9.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-CU49ip-B.cjs → SubscriptionsScreen-BITwBKgB.cjs} +2 -2
- package/dist/{SubscriptionsScreen-B5uCnkDP.mjs → SubscriptionsScreen-DzfYCz8K.mjs} +3 -3
- package/dist/SubscriptionsScreen-DzfYCz8K.mjs.map +1 -0
- package/dist/index.cjs +13 -13
- package/dist/index.mjs +17 -17
- package/dist/{order-status-badge-CDdk0tyF.cjs → order-status-badge-CAO-R9SO.cjs} +2 -2
- package/dist/order-status-badge-CAO-R9SO.cjs.map +1 -0
- package/dist/{order-status-badge-CCK76FjJ.mjs → order-status-badge-Dy8w7xHm.mjs} +2 -2
- package/dist/order-status-badge-Dy8w7xHm.mjs.map +1 -0
- package/package.json +12 -12
- package/dist/ShopScreen-BVD2rPsc.cjs.map +0 -1
- package/dist/ShopScreen-gE3t8H83.mjs.map +0 -1
- package/dist/SubscriptionsScreen-B5uCnkDP.mjs.map +0 -1
- package/dist/SubscriptionsScreen-OkgAzsMr.cjs.map +0 -1
- package/dist/order-status-badge-CCK76FjJ.mjs.map +0 -1
- package/dist/order-status-badge-CDdk0tyF.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShopScreen-DMVWsOB-.mjs","names":["defaultRenderImage"],"sources":["../../../products/core/src/products-api-context.tsx","../../../products/core/src/portal-products-api-context.tsx","../../../products/core/src/hooks/use-debounce.ts","../../../products/core/src/hooks/use-portal-products.ts","../../../products/core/src/hooks/use-portal-product-catalog.ts","../../../products/core/src/hooks/use-portal-product-detail.ts","../../../products/core/src/utils/subscription-plans.ts","../../../products/core/src/stores/use-product-store.ts","../../../products/core/src/stores/use-draft-store.ts","../../../products/core/src/utils/product-helpers.ts","../../../products/core/src/utils/product-price.ts","../../../shop/ui/src/utils/media-helpers.ts","../../../shop/ui/src/components/product-card.tsx","../../../shop/ui/src/components/image-gallery.tsx","../../../shop/ui/src/components/quantity-selector.tsx","../../../shop/ui/src/components/shop-app.tsx","../../../cart/ui/src/components/cart-script.tsx","../../../cart/ui/src/components/cart-widget.tsx","../../../cart/ui/src/components/cart-button.tsx","../../../cart/ui/src/components/shop-container.tsx","../src/screens/ShopScreen.tsx"],"sourcesContent":["import { createContext, useContext, type JSX, type ReactNode } from \"react\";\nimport type { ProductsApi } from \"./products-api\";\n\ninterface ProductsCoreConfig {\n api: ProductsApi;\n}\n\nconst ProductsCoreContext = createContext<ProductsCoreConfig | null>(null);\n\nexport function ProductsCoreProvider({\n api,\n children,\n}: ProductsCoreConfig & { children: ReactNode }): JSX.Element {\n return (\n <ProductsCoreContext.Provider value={{ api }}>\n {children}\n </ProductsCoreContext.Provider>\n );\n}\n\nexport function useProductsApi(): ProductsApi {\n const ctx = useContext(ProductsCoreContext);\n if (!ctx) {\n throw new Error(\n \"useProductsApi must be used within a <ProductsCoreProvider>\",\n );\n }\n return ctx.api;\n}\n","import { createContext, useContext, type JSX, type ReactNode } from \"react\";\nimport type { PortalProductsApi } from \"./portal-products-api\";\n\ninterface PortalProductsCoreConfig {\n api: PortalProductsApi;\n}\n\nconst PortalProductsCoreContext =\n createContext<PortalProductsCoreConfig | null>(null);\n\nexport function PortalProductsCoreProvider({\n api,\n children,\n}: PortalProductsCoreConfig & { children: ReactNode }): JSX.Element {\n return (\n <PortalProductsCoreContext.Provider value={{ api }}>\n {children}\n </PortalProductsCoreContext.Provider>\n );\n}\n\nexport function usePortalProductsApi(): PortalProductsApi {\n const ctx = useContext(PortalProductsCoreContext);\n if (!ctx) {\n throw new Error(\n \"usePortalProductsApi must be used within a <PortalProductsCoreProvider>\",\n );\n }\n return ctx.api;\n}\n","import { useState, useEffect } from \"react\";\n\nexport function useDebounce<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebouncedValue(value);\n }, delay);\n\n return () => {\n clearTimeout(timer);\n };\n }, [value, delay]);\n\n return debouncedValue;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport type { portalProducts } from \"../portal-products-api\";\nimport { usePortalProductsApi } from \"../portal-products-api-context\";\n\nconst portalProductKeys = {\n all: [\"portal-products\"] as const,\n list: (params?: portalProducts.CursorPaginationParams) =>\n [...portalProductKeys.all, \"list\", params] as const,\n detail: (id: string | number) =>\n [...portalProductKeys.all, \"detail\", String(id)] as const,\n search: (query: string, params?: portalProducts.CursorPaginationParams) =>\n [...portalProductKeys.all, \"search\", query, params] as const,\n media: (productId: string | number) =>\n [...portalProductKeys.all, \"media\", String(productId)] as const,\n};\n\nexport { portalProductKeys };\n\nexport function usePortalProducts(\n params?: portalProducts.CursorPaginationParams,\n) {\n const api = usePortalProductsApi();\n return useQuery({\n queryKey: portalProductKeys.list(params),\n queryFn: () => api.listProducts(params),\n });\n}\n\nexport function usePortalProduct(\n id: string | number,\n options?: { enabled?: boolean },\n) {\n const api = usePortalProductsApi();\n return useQuery({\n queryKey: portalProductKeys.detail(id),\n queryFn: () => api.getProduct(id),\n enabled: options?.enabled,\n });\n}\n\nexport function usePortalProductSearch(\n query: string,\n params?: portalProducts.CursorPaginationParams & { enabled?: boolean },\n) {\n const api = usePortalProductsApi();\n const { enabled, ...paginationParams } = params ?? {};\n return useQuery({\n queryKey: portalProductKeys.search(query, paginationParams),\n queryFn: () => api.searchProducts(query, paginationParams),\n enabled: enabled ?? query.length > 0,\n });\n}\n\nexport function usePortalProductMedia(\n productId: string | number,\n options?: { enabled?: boolean },\n) {\n const api = usePortalProductsApi();\n return useQuery({\n queryKey: portalProductKeys.media(productId),\n queryFn: () => api.getProductMedia(productId),\n enabled: options?.enabled,\n });\n}\n","import { useState, useMemo, useCallback } from \"react\";\nimport type { portalProducts } from \"../portal-products-api\";\nimport { usePortalProductsApi } from \"../portal-products-api-context\";\nimport { useDebounce } from \"./use-debounce\";\n\nexport interface UsePortalProductCatalogParams {\n perPage?: number;\n}\n\n/** Page param is a cursor string from the BFF, or undefined for the first page. */\nexport type PortalProductPageParam = string | undefined;\n\nexport function usePortalProductCatalog({\n perPage = 25,\n}: UsePortalProductCatalogParams = {}) {\n const api = usePortalProductsApi();\n const [searchTerm, setSearchTerm] = useState(\"\");\n const debouncedSearchTerm = useDebounce(searchTerm, 300);\n\n const fetchProducts = useCallback(\n async (\n pageParam?: PortalProductPageParam,\n ): Promise<portalProducts.PortalProductsResponse> => {\n const cursor = pageParam;\n\n if (debouncedSearchTerm) {\n return api.searchProducts(debouncedSearchTerm, {\n cursor,\n limit: perPage,\n });\n }\n return api.listProducts({ cursor, limit: perPage });\n },\n [api, debouncedSearchTerm, perPage],\n );\n\n const getNextPageParam = useCallback(\n (\n lastPage: portalProducts.PortalProductsResponse,\n _allPages: portalProducts.PortalProductsResponse[],\n lastPageParam: PortalProductPageParam,\n ): PortalProductPageParam => {\n const nextCursor = lastPage.meta?.pagination?.next_cursor ?? undefined;\n // Stop if the API returned the same cursor we just sent (prevents\n // infinite refetch loops when the backend doesn't advance).\n if (nextCursor != null && nextCursor === lastPageParam) {\n return undefined;\n }\n return nextCursor;\n },\n [],\n );\n\n const queryKey = useMemo(\n () => [\"portal-product-catalog\", debouncedSearchTerm || \"\", perPage],\n [debouncedSearchTerm, perPage],\n );\n\n return {\n searchTerm,\n setSearchTerm,\n debouncedSearchTerm,\n fetchProducts,\n getNextPageParam,\n queryKey,\n perPage,\n };\n}\n","import { useMemo } from \"react\";\nimport { usePortalProduct } from \"./use-portal-products\";\n\nexport interface UsePortalProductDetailParams {\n productId: string;\n}\n\nexport function usePortalProductDetail({\n productId,\n}: UsePortalProductDetailParams) {\n const {\n data: productResponse,\n isLoading,\n error,\n } = usePortalProduct(productId);\n\n const product = productResponse?.product;\n\n const images = useMemo(() => {\n if (!product?.images) return [];\n return product.images.map((img, idx) => ({\n id: idx,\n url: img.url ?? \"\",\n alt: img.alt ?? null,\n }));\n }, [product?.images]);\n\n return {\n product,\n isLoading,\n error,\n images,\n };\n}\n","import type { products } from \"../types\";\n\nexport function ensureDefaultSubscriptionPlan(\n plans: readonly products.ProductSubscriptionPlan[],\n): products.ProductSubscriptionPlan[] {\n const activePlans = plans.filter((plan) => plan.active !== false);\n\n if (activePlans.length === 0) {\n return plans.map((plan) => ({ ...plan, default: false }));\n }\n\n const hasActiveDefault = activePlans.some((plan) => plan.default === true);\n\n if (!hasActiveDefault) {\n const planWithLowestId = activePlans.reduce((lowest, current) => {\n const lowestId = lowest.subscription_plan?.id || Infinity;\n const currentId = current.subscription_plan?.id || Infinity;\n return currentId < lowestId ? current : lowest;\n });\n\n return plans.map((plan) => ({\n ...plan,\n default:\n plan.subscription_plan?.id === planWithLowestId.subscription_plan?.id &&\n plan.active !== false,\n }));\n }\n\n return plans.map((plan) => ({\n ...plan,\n default: plan.active !== false ? plan.default : false,\n }));\n}\n\nexport function plansToAttributes(\n plans: readonly products.ProductSubscriptionPlan[],\n): products.ProductSubscriptionPlanAttribute[] {\n return plans.map((plan) => ({\n id: plan.id ?? undefined,\n subscription_plan_id: plan.subscription_plan.id,\n default: plan.default || false,\n active: plan.active !== false,\n }));\n}\n","import { create, type StateCreator } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport type { products } from \"../types\";\nimport {\n ensureDefaultSubscriptionPlan,\n plansToAttributes,\n} from \"../utils/subscription-plans\";\n\n// Default state\nconst defaultState = {\n id: undefined,\n title: \"\",\n description: \"\",\n introduction: \"\",\n stripped: \"\",\n feature_text: \"\",\n sku: \"\",\n slug: \"\",\n canonical_url: null as string | null,\n image_url: \"\",\n image_path: undefined,\n status: \"draft\",\n publish_at: null,\n price: \"0\",\n commission: 0,\n public: true,\n no_index: false,\n show_reviews: true,\n publish_to_retail_store: true,\n publish_to_rep_store: true,\n publish_to_share_tab: true,\n collection_ids: [],\n tag_ids: [],\n images_attributes: [],\n product_subscription_plans_attributes: [],\n product_subscription_plans: [],\n variants_attributes: [],\n bundle: false,\n track_inventory_on_bundle_items: false,\n product_bundles_attributes: [],\n option_attrs: [],\n options: [],\n metafields_attributes: [],\n metadata: {},\n search_engine_optimizer_attributes: {\n title: \"\",\n description: \"\",\n image_url: \"\",\n image_path: \"\",\n block_crawler: false,\n },\n};\n\ntype ValidationErrors = Partial<Record<string, string>>;\n\nexport type TranslationData = {\n title?: string;\n introduction?: string;\n description?: string;\n feature_text?: string;\n};\n\ntype LanguageTranslations = Record<string, TranslationData>;\ntype TranslationLoadingState = Record<string, boolean>;\n\ninterface UpdateFieldOptions {\n shouldValidate?: boolean;\n shouldClearError?: boolean;\n markDirty?: boolean;\n}\n\ntype ArrayItemType<T> = T extends (infer U)[] ? U : unknown;\n\ntype ProductStoreFields = products.UpdateProduct & {\n product_subscription_plans: products.ProductSubscriptionPlan[];\n track_inventory_on_bundle_items: boolean;\n canonical_url: string | null;\n publish_at: string | null;\n};\n\nexport type ProductStoreState = ProductStoreFields & {\n errors: ValidationErrors;\n isValid: boolean;\n isDirty: boolean;\n translations: LanguageTranslations;\n editedTranslations: LanguageTranslations;\n translationErrors: Record<string, Record<string, string | undefined>>;\n translationLoading: TranslationLoadingState;\n translationsFetched: boolean;\n\n setProduct: (productData: products.Product) => void;\n updateField: <K extends keyof ProductStoreFields>(\n key: K,\n value: ProductStoreFields[K],\n options?: UpdateFieldOptions,\n ) => void;\n updatePartial: (updates: Partial<ProductStoreFields>) => void;\n updateSlug: (slug: string, isManual?: boolean) => void;\n updateSEO: (seo: {\n title?: string;\n description?: string;\n image_url?: string;\n image_path?: string;\n block_crawler?: boolean;\n }) => void;\n updateArrayItem: <K extends keyof ProductStoreFields>(\n arrayKey: K,\n itemId: number | string,\n updatedItem: ArrayItemType<ProductStoreFields[K]>,\n idField?: string,\n ) => void;\n reset: () => void;\n validateField: (field: string) => void;\n validateRequired: () => boolean;\n clearErrors: () => void;\n clearFieldError: (field: string) => void;\n markClean: () => void;\n\n setTranslationLoading: (languageIso: string, loading: boolean) => void;\n setTranslationData: (languageIso: string, data: TranslationData) => void;\n updateTranslationField: (\n languageIso: string,\n field: keyof TranslationData,\n value: string,\n ) => void;\n getOriginalTranslation: (\n languageIso: string,\n field: keyof TranslationData,\n ) => string | undefined;\n getEditedTranslation: (\n languageIso: string,\n field: keyof TranslationData,\n ) => string | undefined;\n setTranslationError: (\n languageIso: string,\n field: keyof TranslationData,\n error?: string,\n ) => void;\n getTranslationError: (\n languageIso: string,\n field: keyof TranslationData,\n ) => string | undefined;\n getTranslation: (\n languageIso: string,\n field: keyof TranslationData,\n ) => string | undefined;\n isTranslationLoading: (languageIso: string) => boolean;\n resetTranslations: () => void;\n setTranslationsFetched: (fetched: boolean) => void;\n};\n\nfunction syncSubscriptionPlans(plans: products.ProductSubscriptionPlan[]): {\n product_subscription_plans: products.ProductSubscriptionPlan[];\n product_subscription_plans_attributes: products.ProductSubscriptionPlanAttribute[];\n} {\n const activePlans = plans.filter((plan) => plan.active !== false);\n const plansWithDefault =\n activePlans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;\n return {\n product_subscription_plans: plansWithDefault,\n product_subscription_plans_attributes: plansToAttributes(plansWithDefault),\n };\n}\n\nconst extractFilenameFromUrl = (imageUrl: string): string => {\n try {\n const url = new URL(imageUrl);\n return url.pathname.split(\"/\").pop() || \"\";\n } catch {\n return imageUrl.split(\"/\").pop()?.split(\"?\")[0] || \"\";\n }\n};\n\nconst createProductStore: StateCreator<ProductStoreState> = (set, get) => ({\n ...defaultState,\n track_inventory_on_bundle_items: false,\n translations: {},\n editedTranslations: {},\n translationErrors: {},\n translationLoading: {},\n translationsFetched: false,\n errors: {},\n isValid: false,\n isDirty: false,\n\n setProduct: (productData: products.Product) => {\n const transformedData: ProductStoreFields = {\n id: productData.id || undefined,\n title: productData.title || \"\",\n description: productData.description || \"\",\n introduction: productData.introduction || \"\",\n stripped: productData.stripped || \"\",\n feature_text: productData.feature_text || \"\",\n sku: productData.sku || \"\",\n slug: productData.slug || \"\",\n canonical_url: productData.canonical_url || null,\n custom_slug: productData.custom_slug || false,\n image_url: productData.image_url || \"\",\n image_path:\n productData.image_path && !productData.image_path.includes(\"undefined\")\n ? productData.image_path\n : productData.image_url\n ? extractFilenameFromUrl(productData.image_url)\n : undefined,\n status: productData.status || \"draft\",\n publish_at: productData.publish_at || null,\n commission:\n typeof productData.commission === \"string\"\n ? parseFloat(productData.commission)\n : productData.commission || 0,\n public: productData.public ?? true,\n no_index: productData.no_index ?? false,\n show_reviews: productData.show_reviews ?? true,\n publish_to_retail_store: productData.publish_to_retail_store,\n publish_to_rep_store: productData.publish_to_rep_store,\n publish_to_share_tab: productData.publish_to_share_tab,\n ...(productData.tax_category_id && {\n tax_category_id: productData.tax_category_id,\n }),\n international_tax_type: productData.international_tax_type || undefined,\n category_id: productData.category_id\n ? parseInt(productData.category_id)\n : productData.category?.id\n ? productData.category.id\n : undefined,\n application_theme_template_id:\n productData.application_theme_template_id || undefined,\n collection_ids: (\n productData.collections as Array<{ id: number }> | undefined\n )?.map((collection) => collection.id),\n tag_ids: Array.isArray(productData.tags)\n ? (productData.tags as Array<{ id: number } | number>)\n .map((tag) => (typeof tag === \"number\" ? tag : tag?.id))\n .filter(Boolean)\n : [],\n search_engine_optimizer_attributes: {\n id: productData.search_engine_optimizer?.id,\n title:\n productData.search_engine_optimizer?.title ||\n productData.title ||\n undefined,\n description: productData.search_engine_optimizer?.description || \"\",\n image_url:\n productData.search_engine_optimizer?.image_url ||\n productData.image_url ||\n \"\",\n image_path:\n productData.search_engine_optimizer?.image_path ||\n productData.image_path ||\n \"\",\n block_crawler:\n productData.search_engine_optimizer?.block_crawler ?? false,\n },\n images_attributes:\n (productData.images as products.ImageAttribute[] | undefined)?.map(\n (img) => ({\n id: img.id,\n position: img.position || 0,\n image_url: img.image_url,\n image_path:\n img.image_path && !img.image_path.includes(\"undefined\")\n ? img.image_path\n : img.image_url\n ? extractFilenameFromUrl(img.image_url)\n : undefined,\n _destroy: false,\n }),\n ) || [],\n ...(productData.images &&\n productData.images.length > 0 && {\n image_path: (() => {\n if (\n productData.image_path &&\n typeof productData.image_path === \"string\" &&\n !productData.image_path.includes(\"undefined\")\n ) {\n return productData.image_path;\n }\n const firstImage = (\n productData.images as products.ImageAttribute[]\n ).find((img) => img.position === 0);\n if (\n firstImage?.image_path &&\n typeof firstImage.image_path === \"string\" &&\n !firstImage.image_path.includes(\"undefined\")\n ) {\n return firstImage.image_path;\n }\n return productData.image_url\n ? extractFilenameFromUrl(productData.image_url)\n : undefined;\n })(),\n }),\n product_subscription_plans: (() => {\n const plans =\n productData?.product_subscription_plans?.map(\n (plan: products.ProductSubscriptionPlan) => ({\n ...plan,\n active: plan?.active,\n }),\n ) || [];\n return plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;\n })(),\n product_subscription_plans_attributes: (() => {\n const plans =\n productData?.product_subscription_plans?.map(\n (plan: products.ProductSubscriptionPlan) => ({\n ...plan,\n active: plan?.active,\n }),\n ) || [];\n const finalPlans =\n plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;\n return plansToAttributes(finalPlans);\n })(),\n variants_attributes: productData?.variants\n ?.filter(\n (\n variant: products.Variant,\n ): variant is products.Variant & { id: number } =>\n variant.id !== null && variant.id !== undefined,\n )\n .map((variant) => ({\n id: variant.id,\n title: variant.title ?? productData?.title ?? \"Untitled Variant\",\n option_attrs: variant.option_attrs || [],\n sku: variant.sku || undefined,\n price: variant.price,\n track_quantity: variant.track_quantity ?? false,\n keep_selling: variant.keep_selling ?? false,\n bar_code: variant.bar_code ?? \"\",\n limit_subscription: variant.limit_subscription,\n subscription_max_qty: variant.subscription_max_qty ?? 0,\n customer_limit: variant.customer_limit ?? 0,\n is_master: variant.is_master,\n _destroy: false,\n images_attributes: variant?.images?.map(\n (image: { id?: number; position: number; image_url: string }) => ({\n id: image.id,\n position: image.position || 0,\n image_url: image.image_url,\n _destroy: false,\n }),\n ),\n inventory_levels_attributes: variant?.inventory_levels\n ?.filter(\n (level: products.InventoryLevel) =>\n (level.warehouse_id ?? level.warehouse?.id) != null,\n )\n .map((level: products.InventoryLevel) => ({\n id: level.id,\n available: level.available,\n committed: level.committed,\n on_hand: level.on_hand,\n unavailable: level.unavailable,\n warehouse_id: level.warehouse?.id || 0,\n _destroy: false,\n })),\n variant_countries_attributes: variant?.variant_countries\n ? Object.entries(\n variant.variant_countries as Record<\n string,\n products.VariantCountry\n >,\n ).map(([iso, country]) => ({\n id: country.id ?? 0,\n active: country.active ?? true,\n country_id: country.country_id,\n country_name: country.country_name ?? \"\",\n country_iso: iso,\n price: Number(country.price) || 0,\n subscription_price: Number(country.subscription_price) || 0,\n wholesale: Number(country.wholesale) || 0,\n wholesale_subscription_price:\n Number(country.wholesale_subscription_price) || 0,\n compare_price: Number(country.compare_price) || 0,\n cv: Number(country.cv) || 0,\n qv: Number(country.qv) || 0,\n pc_cv: Number(country.pc_cv) || 0,\n pc_qv: Number(country.pc_qv) || 0,\n cost_of_goods_sold: Number(country.cost_of_goods_sold) || 0,\n currency_code: country.currency_code || null,\n shipping: Number(country.shipping) || 0,\n points: country.points,\n }))\n : [],\n })),\n bundle:\n productData.product_bundles && productData.product_bundles.length > 0,\n track_inventory_on_bundle_items:\n productData.track_inventory_on_bundle_items ?? false,\n product_bundles_attributes: (productData.product_bundles || []).map(\n (bundle: products.ProductBundle) => ({\n id: bundle.id,\n bundled_variant_id: bundle.bundled_variant?.id || 0,\n bundled_variant: {\n title: bundle.bundled_variant?.title || \"\",\n sku: bundle.bundled_variant?.sku || null,\n price: String(bundle.bundled_variant?.price || \"0\"),\n price_in_currency: bundle.bundled_variant?.price_in_currency || \"\",\n currency_code: bundle.bundled_variant?.currency_code,\n product: {\n id: bundle.bundled_variant?.product.id || 0,\n title: bundle.bundled_variant?.product.title || \"\",\n image_url: bundle.bundled_variant?.product.image_url || \"\",\n price: bundle.bundled_variant?.product.price || \"0\",\n price_in_currency:\n bundle.bundled_variant?.product.price_in_currency || \"\",\n cv: bundle.bundled_variant?.product.cv || 0,\n qv: bundle.bundled_variant?.product.qv || 0,\n },\n },\n cv: bundle.cv || 0,\n qv: bundle.qv || 0,\n quantity: bundle.quantity,\n display_externally: bundle.display_externally ?? true,\n _destroy: false,\n }),\n ),\n option_attrs: productData.option_attrs || [],\n options: productData.options || [],\n metafields_attributes: (productData.metafields || []).map(\n (metafield: products.Metafield) => ({\n id: metafield.id,\n namespace: metafield.namespace,\n key: metafield.key,\n value: metafield.value,\n value_type: metafield.value_type,\n _destroy: false,\n }),\n ),\n metadata: productData.metadata || {},\n };\n\n set({\n ...transformedData,\n errors: {},\n isValid: false,\n isDirty: false,\n });\n },\n\n updateSlug: (slug, isManual = true) => {\n set((state: ProductStoreState) => ({\n slug,\n custom_slug: isManual,\n search_engine_optimizer_attributes: {\n ...state.search_engine_optimizer_attributes,\n title: state.search_engine_optimizer_attributes?.title || \"\",\n description:\n state.search_engine_optimizer_attributes?.description || \"\",\n image_url: state.search_engine_optimizer_attributes?.image_url || \"\",\n image_path: state.search_engine_optimizer_attributes?.image_path || \"\",\n block_crawler:\n state.search_engine_optimizer_attributes?.block_crawler ?? false,\n },\n isDirty: true,\n }));\n },\n\n updateSEO: (seo) => {\n set((state: ProductStoreState) => ({\n search_engine_optimizer_attributes: {\n ...state.search_engine_optimizer_attributes,\n title:\n seo.title !== undefined\n ? seo.title\n : state.search_engine_optimizer_attributes?.title || \"\",\n description:\n seo.description !== undefined\n ? seo.description\n : state.search_engine_optimizer_attributes?.description || \"\",\n image_url:\n seo.image_url !== undefined\n ? seo.image_url\n : state.search_engine_optimizer_attributes?.image_url || \"\",\n image_path:\n seo.image_path !== undefined\n ? seo.image_path\n : state.search_engine_optimizer_attributes?.image_path || \"\",\n block_crawler:\n seo.block_crawler !== undefined\n ? seo.block_crawler\n : (state.search_engine_optimizer_attributes?.block_crawler ??\n false),\n },\n isDirty: true,\n }));\n },\n\n updateField: <K extends keyof ProductStoreFields>(\n key: K,\n value: ProductStoreFields[K],\n options?: UpdateFieldOptions,\n ) => {\n const {\n shouldValidate = false,\n shouldClearError = true,\n markDirty = true,\n } = options || {};\n\n set((state: ProductStoreState) => {\n if (key === \"product_subscription_plans\") {\n return {\n ...state,\n ...syncSubscriptionPlans(value as products.ProductSubscriptionPlan[]),\n errors: shouldClearError\n ? { ...state.errors, [key]: undefined }\n : state.errors,\n isDirty: markDirty ? true : state.isDirty,\n };\n }\n\n return {\n ...state,\n [key]: value,\n errors: shouldClearError\n ? { ...state.errors, [key]: undefined }\n : state.errors,\n isDirty: markDirty ? true : state.isDirty,\n };\n });\n\n if (shouldValidate) {\n get().validateField(key as string);\n }\n },\n\n updatePartial: (updates: Partial<ProductStoreFields>) => {\n set((state: ProductStoreState) => {\n if (updates.product_subscription_plans) {\n return {\n ...state,\n ...updates,\n ...syncSubscriptionPlans(updates.product_subscription_plans),\n errors: {\n ...state.errors,\n ...Object.keys(updates).reduce(\n (acc, key) => {\n acc[key] = undefined;\n return acc;\n },\n {} as Record<string, undefined>,\n ),\n },\n isDirty: true,\n };\n }\n\n return {\n ...state,\n ...updates,\n errors: {\n ...state.errors,\n ...Object.keys(updates).reduce(\n (acc, key) => {\n acc[key] = undefined;\n return acc;\n },\n {} as Record<string, undefined>,\n ),\n },\n isDirty: true,\n };\n });\n },\n\n updateArrayItem: <K extends keyof ProductStoreFields>(\n arrayKey: K,\n itemId: number | string,\n updatedItem: ArrayItemType<ProductStoreFields[K]>,\n idField: string = \"id\",\n ) => {\n set((state: ProductStoreState) => {\n const currentArray = Array.isArray(state[arrayKey])\n ? (state[arrayKey] as unknown[])\n : [];\n\n const updatedArray = currentArray.map((item) => {\n if (\n typeof item === \"object\" &&\n item !== null &&\n idField in item &&\n (item as Record<string, unknown>)[idField] === itemId\n ) {\n return updatedItem;\n }\n return item;\n });\n\n if (arrayKey === \"product_subscription_plans\") {\n return {\n ...state,\n ...syncSubscriptionPlans(\n updatedArray as products.ProductSubscriptionPlan[],\n ),\n errors: { ...state.errors, [arrayKey]: undefined },\n isDirty: true,\n };\n }\n\n return {\n ...state,\n [arrayKey]: updatedArray,\n errors: { ...state.errors, [arrayKey]: undefined },\n isDirty: true,\n };\n });\n },\n\n reset: () => {\n set({\n ...defaultState,\n track_inventory_on_bundle_items: false,\n custom_slug: false,\n errors: {},\n isValid: false,\n isDirty: false,\n });\n },\n\n // Validation methods — these provide basic field-level validation.\n // For full schema validation (e.g. Zod), the consumer should call\n // their own validation function against the store state.\n validateField: (field: string) => {\n const fieldValue = get()[field as keyof ProductStoreState];\n const hasValue =\n fieldValue !== undefined && fieldValue !== null && fieldValue !== \"\";\n\n set((state: ProductStoreState) => ({\n errors: {\n ...state.errors,\n [field]: hasValue ? undefined : `${field} is required`,\n },\n isValid:\n hasValue &&\n Object.keys(state.errors).every(\n (key) => key === field || !state.errors[key],\n ),\n }));\n },\n\n validateRequired: () => {\n // Basic validation: check that title exists\n const state = get();\n const errors: ValidationErrors = {};\n\n if (!state.title) {\n errors.title = \"Title is required\";\n }\n\n if (Object.keys(errors).length > 0) {\n set({ errors, isValid: false });\n return false;\n }\n\n set({ errors: {}, isValid: true });\n return true;\n },\n\n clearErrors: () => {\n set({ errors: {}, isValid: false });\n },\n\n clearFieldError: (field: string) => {\n set((state: ProductStoreState) => ({\n errors: { ...state.errors, [field]: undefined },\n }));\n },\n\n markClean: () => {\n set({ isDirty: false });\n },\n\n // Translation methods\n setTranslationLoading: (languageIso: string, loading: boolean) => {\n set((state: ProductStoreState) => ({\n translationLoading: {\n ...state.translationLoading,\n [languageIso]: loading,\n },\n }));\n },\n\n setTranslationData: (languageIso: string, data: TranslationData) => {\n set((state: ProductStoreState) => ({\n translations: {\n ...state.translations,\n [languageIso]: data,\n },\n translationLoading: {\n ...state.translationLoading,\n [languageIso]: false,\n },\n }));\n },\n\n updateTranslationField: (\n languageIso: string,\n field: keyof TranslationData,\n value: string,\n ) => {\n set((state: ProductStoreState) => {\n const originalValue = state.translations[languageIso]?.[field];\n let error: string | undefined;\n\n if (\n field === \"title\" &&\n value === \"\" &&\n originalValue &&\n originalValue.trim() !== \"\"\n ) {\n error = \"Title is required\";\n }\n\n return {\n editedTranslations: {\n ...state.editedTranslations,\n [languageIso]: {\n ...state.editedTranslations[languageIso],\n [field]: value,\n },\n },\n translationErrors: {\n ...state.translationErrors,\n [languageIso]: {\n ...state.translationErrors[languageIso],\n [field]: error,\n },\n },\n };\n });\n },\n\n getTranslation: (languageIso: string, field: keyof TranslationData) => {\n const state = get();\n return (\n state.editedTranslations[languageIso]?.[field] ??\n state.translations[languageIso]?.[field]\n );\n },\n\n getOriginalTranslation: (\n languageIso: string,\n field: keyof TranslationData,\n ) => {\n return get().translations[languageIso]?.[field];\n },\n\n getEditedTranslation: (languageIso: string, field: keyof TranslationData) => {\n return get().editedTranslations[languageIso]?.[field];\n },\n\n setTranslationError: (\n languageIso: string,\n field: keyof TranslationData,\n error?: string,\n ) => {\n set((state: ProductStoreState) => ({\n translationErrors: {\n ...state.translationErrors,\n [languageIso]: {\n ...state.translationErrors[languageIso],\n [field]: error,\n },\n },\n }));\n },\n\n getTranslationError: (languageIso: string, field: keyof TranslationData) => {\n return get().translationErrors[languageIso]?.[field];\n },\n\n isTranslationLoading: (languageIso: string) => {\n return get().translationLoading[languageIso] ?? false;\n },\n\n resetTranslations: () => {\n set({\n translations: {},\n editedTranslations: {},\n translationErrors: {},\n translationLoading: {},\n translationsFetched: false,\n });\n },\n\n setTranslationsFetched: (fetched: boolean) => {\n set({ translationsFetched: fetched });\n },\n});\n\nexport const useProductStore =\n process.env.NODE_ENV === \"development\"\n ? create<ProductStoreState>()(\n devtools(createProductStore, { name: \"product-store\" }),\n )\n : create<ProductStoreState>()(createProductStore);\n","import { create } from \"zustand\";\n\ninterface DraftStore {\n draftData: unknown | null;\n isFromSettings: boolean;\n navigationTarget: string | null;\n\n saveDraft: (data: unknown) => void;\n getDraft: () => unknown | null;\n clearDraft: () => void;\n setFromSettings: (value: boolean) => void;\n setNavigationTarget: (target: string | null) => void;\n reset: () => void;\n}\n\nexport const useDraftStore = create<DraftStore>()((set, get) => ({\n draftData: null,\n isFromSettings: false,\n navigationTarget: null,\n\n saveDraft: (data: unknown) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const formData = data as any;\n const hasContent =\n formData?.title ||\n formData?.description ||\n formData?.sku ||\n (formData?.product_subscription_plans &&\n formData.product_subscription_plans.length > 0);\n\n if (hasContent) {\n set({ draftData: data });\n }\n },\n\n getDraft: () => {\n const { draftData, isFromSettings, navigationTarget } = get();\n\n if (!draftData) {\n return null;\n }\n\n if (isFromSettings && navigationTarget) {\n return draftData;\n }\n\n set({ draftData: null });\n return null;\n },\n\n clearDraft: () => {\n const { draftData } = get();\n if (draftData) {\n set({ draftData: null });\n }\n },\n\n setFromSettings: (value: boolean) => {\n set({ isFromSettings: value });\n },\n\n setNavigationTarget: (target: string | null) => {\n set({ navigationTarget: target });\n },\n\n reset: () => {\n set({ draftData: null, isFromSettings: false, navigationTarget: null });\n },\n}));\n","import type { products } from \"../types\";\n\nexport function createSlug(title: string): string {\n return title\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nexport function stripHtmlTags(html: string): string {\n return html\n .replace(/<[^>]*>/g, \"\")\n .replace(/&[^;]+;/g, \" \")\n .trim();\n}\n\nexport function getVariantImageUrl(\n variant?: {\n primary_image?: string | null;\n image_url?: string | null;\n images?: Array<{ image_url: string }> | null;\n } | null,\n product?: { image_url?: string | null } | null,\n): string {\n if (!variant) return product?.image_url || \"\";\n if (variant.primary_image) return variant.primary_image;\n if (variant.image_url) return variant.image_url;\n if (Array.isArray(variant.images) && variant.images.length > 0) {\n const firstImage = variant.images[0];\n if (firstImage?.image_url) return firstImage.image_url;\n }\n return product?.image_url || \"\";\n}\n\nexport function getProductImageUrl(\n product?: {\n image_url?: string | null;\n images?: Array<{ image_url: string; position?: number }> | null;\n } | null,\n): string | null {\n if (!product) return null;\n if (Array.isArray(product.images) && product.images.length > 0) {\n const sortedImages = [...product.images].sort(\n (a, b) => (a.position ?? 0) - (b.position ?? 0),\n );\n const primaryImage = sortedImages[0];\n if (primaryImage?.image_url) return primaryImage.image_url;\n }\n return product.image_url ?? null;\n}\n\nexport function sanitizeBundleData<\n T extends products.CreateProduct | products.UpdateProduct,\n>(productData: T): T {\n const activeVariants = (productData.variants_attributes || []).filter(\n (variant) => !variant._destroy,\n );\n const hasMultipleVariants = activeVariants.length > 1;\n\n const activeOptions = (productData.options || []).filter(\n (opt) => !opt._destroy,\n );\n const derivedOptionAttrs = [\n ...new Set(activeOptions.map((opt) => opt.title.toLowerCase())),\n ];\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { options, option_attrs, ...restProductData } = productData;\n\n // We spread the original data and override specific fields, preserving the\n // runtime shape. The cast to T is safe because we only narrow/replace fields\n // that exist on the base type.\n if (hasMultipleVariants) {\n return {\n ...productData,\n options: undefined,\n option_attrs: derivedOptionAttrs,\n bundle: false,\n product_bundles_attributes: [],\n track_inventory_on_bundle_items: false,\n } as T;\n }\n\n return {\n ...productData,\n options: undefined,\n option_attrs: derivedOptionAttrs,\n } as T;\n}\n\nexport interface ApiErrorShape {\n message?: string;\n error_message?: string;\n status?: number;\n data?: unknown;\n errors?: Record<string, string[]>;\n}\n\nfunction getErrorsFromApiError(\n error: ApiErrorShape,\n): Record<string, string[]> | undefined {\n if (error?.errors && typeof error.errors === \"object\") {\n return error.errors;\n }\n if (error?.data && typeof error.data === \"object\") {\n const data = error.data as Record<string, unknown>;\n const firstKey = Object.keys(data)[0];\n if (firstKey && Array.isArray(data[firstKey])) {\n return data as Record<string, string[]>;\n }\n }\n return undefined;\n}\n\nfunction formatFieldName(fieldName: string): string {\n const SEO_FIELD_LABELS: Record<string, string> = {\n \"search_engine_optimizer.title\": \"SEO Title\",\n \"search_engine_optimizer.description\": \"SEO Description\",\n \"search_engine_optimizer.image_url\": \"SEO Image\",\n };\n\n if (SEO_FIELD_LABELS[fieldName]) return SEO_FIELD_LABELS[fieldName];\n\n const parts = fieldName.split(\".\");\n if (parts.length > 1) {\n return parts\n .map((part, index) =>\n part\n .split(\"_\")\n .map((word, wordIndex) => {\n if (\n (index === 0 && wordIndex === 0) ||\n (index > 0 && wordIndex > 0)\n )\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n return word.toLowerCase();\n })\n .join(\" \"),\n )\n .join(\" \");\n }\n\n return fieldName\n .split(\"_\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\nexport function getErrorMessage(\n error: ApiErrorShape,\n fallbackMessage: string,\n): string {\n if (error?.message && error.message !== \"unprocessable entity\") {\n return error.message;\n }\n\n const errorsObj = getErrorsFromApiError(error);\n if (errorsObj) {\n const firstField = Object.keys(errorsObj)[0];\n if (firstField && errorsObj[firstField]) {\n const fieldErrors = errorsObj[firstField];\n if (\n Array.isArray(fieldErrors) &&\n fieldErrors.length > 0 &&\n fieldErrors[0]\n ) {\n return `${formatFieldName(firstField)} ${fieldErrors[0]}`;\n }\n }\n }\n\n return fallbackMessage;\n}\n\nexport function isSeoError(fieldName: string): boolean {\n return (\n fieldName.startsWith(\"search_engine_optimizer\") || fieldName === \"slug\"\n );\n}\n\nexport function extractSeoErrors(\n error: ApiErrorShape,\n): Array<{ field: string; message: string }> {\n const seoErrors: Array<{ field: string; message: string }> = [];\n const errorsObj = getErrorsFromApiError(error);\n if (errorsObj) {\n for (const fieldName of Object.keys(errorsObj)) {\n if (isSeoError(fieldName) && errorsObj[fieldName]) {\n const fieldErrors = errorsObj[fieldName];\n if (\n Array.isArray(fieldErrors) &&\n fieldErrors.length > 0 &&\n fieldErrors[0]\n ) {\n seoErrors.push({\n field: fieldName,\n message: `${formatFieldName(fieldName)} ${fieldErrors[0].charAt(0).toUpperCase() + fieldErrors[0].slice(1)}`,\n });\n }\n }\n }\n }\n return seoErrors;\n}\n","import type { products } from \"../types\";\n\ntype ProductPriceInput = products.Product | products.ShopProduct;\n\nfunction stripParentheticalText(text: string | undefined): string | null {\n if (!text) return null;\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\nfunction isShopVariantCountry(\n vc: products.VariantCountry | products.ShopVariantCountry | undefined,\n): vc is products.ShopVariantCountry {\n return vc !== undefined && \"display_wholesale_subscription_price\" in vc;\n}\n\nfunction isAdminProduct(\n product: ProductPriceInput,\n): product is products.Product {\n return \"display_price\" in product;\n}\n\nfunction isVariantCountriesRecord(\n vc: unknown,\n): vc is Record<string, products.VariantCountry> {\n return vc !== null && typeof vc === \"object\" && !Array.isArray(vc);\n}\n\nexport function determineProductPrice(\n product: ProductPriceInput,\n countryIso: string,\n): { repPrice: string | null | undefined; price?: string | null } {\n const { variants } = product;\n\n // Get the first active variant for the country, or fall back to first variant\n const selectedVariant =\n variants?.find((v) => {\n if (isVariantCountriesRecord(v.variant_countries)) {\n return v.variant_countries[countryIso]?.active;\n }\n return false;\n }) ||\n variants?.[0] ||\n null;\n\n let variantCountry:\n | products.VariantCountry\n | products.ShopVariantCountry\n | undefined;\n if (countryIso && selectedVariant?.variant_countries) {\n const variantCountries = selectedVariant.variant_countries;\n\n if (Array.isArray(variantCountries)) {\n variantCountry = variantCountries.find(\n (v: products.ShopVariantCountry) => v?.country?.iso === countryIso,\n );\n } else if (isVariantCountriesRecord(variantCountries)) {\n variantCountry = variantCountries[countryIso];\n }\n }\n\n if (selectedVariant?.subscription_only)\n return {\n repPrice: isShopVariantCountry(variantCountry)\n ? variantCountry.display_wholesale_subscription_price\n : undefined,\n };\n\n const price = isShopVariantCountry(variantCountry)\n ? variantCountry.display_price\n : isAdminProduct(product)\n ? product.display_price\n : undefined;\n\n const repPrice = isShopVariantCountry(variantCountry)\n ? variantCountry.display_wholesale\n : undefined;\n return {\n repPrice: stripParentheticalText(repPrice),\n price: price === repPrice ? null : stripParentheticalText(price),\n };\n}\n\nexport function extractPriceFromString(priceString: string): number | null {\n if (!priceString) return null;\n const strippedString = priceString.replace(/[^\\d.]/g, \"\");\n return parseFloat(strippedString);\n}\n","const VIDEO_EXTENSIONS = [\n \".mp4\",\n \".webm\",\n \".mov\",\n \".avi\",\n \".m4v\",\n \".mkv\",\n \".ogv\",\n \".ogg\",\n \".wmv\",\n \".flv\",\n \".3gp\",\n];\n\nconst IMAGE_EXTENSIONS = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\",\n \".svg\",\n \".bmp\",\n \".ico\",\n \".tiff\",\n \".tif\",\n];\n\nexport function isVideoUrl(url: string | undefined | null): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return VIDEO_EXTENSIONS.some((ext) => lowerUrl.includes(ext));\n}\n\nexport function isImageUrl(url: string | undefined | null): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return IMAGE_EXTENSIONS.some((ext) => lowerUrl.includes(ext));\n}\n\nexport function getMediaTypeFromUrl(\n url: string | undefined | null,\n): \"video\" | \"image\" | \"unknown\" {\n if (isVideoUrl(url)) return \"video\";\n if (isImageUrl(url)) return \"image\";\n return \"unknown\";\n}\n\nexport function getVideoThumbnailUrl(videoUrl: string): string {\n if (videoUrl.includes(\"ik.imagekit.io\")) {\n return `${videoUrl}/ik-thumbnail.jpg`;\n }\n return videoUrl;\n}\n\nexport function ensureImageIsFeatured<\n T extends { image_url: string; position?: number },\n>(items: T[]): T[] {\n if (items.length === 0) return items;\n\n const firstItem = items[0];\n if (!firstItem || !isVideoUrl(firstItem.image_url)) {\n return items;\n }\n\n const firstImageIndex = items.findIndex(\n (item) => !isVideoUrl(item.image_url),\n );\n\n if (firstImageIndex === -1) {\n return items;\n }\n\n const reordered = [...items];\n const [imageToMove] = reordered.splice(firstImageIndex, 1);\n if (imageToMove) {\n reordered.unshift(imageToMove);\n }\n\n return reordered;\n}\n","import type React from \"react\";\nimport { useState, type ReactNode } from \"react\";\nimport type { products, portalProducts } from \"@fluid-app/products-core\";\nimport {\n determineProductPrice,\n getProductImageUrl,\n} from \"@fluid-app/products-core\";\nimport { Card } from \"@fluid-app/ui-primitives\";\nimport { CirclePlay } from \"lucide-react\";\nimport { getVideoThumbnailUrl, isVideoUrl } from \"../utils/media-helpers\";\n\ntype LegacyProduct = (products.Product | products.ShopProduct) & {\n kind?: string;\n video_url?: string;\n};\n\nexport interface RenderImageProps {\n src: string;\n alt: string;\n fill?: boolean;\n className?: string;\n onError?: (e: React.SyntheticEvent<HTMLImageElement>) => void;\n unoptimized?: boolean;\n}\n\ntype TaggedPortalProduct = portalProducts.Product & {\n readonly __portalProduct: true;\n};\n\nexport type ProductCardProduct = LegacyProduct | TaggedPortalProduct;\n\ninterface ProductCardProps {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n showShareModal?: boolean;\n setShareModalOpen?: (open: boolean) => void;\n setSelectedProduct?: (product: LegacyProduct) => void;\n renderLink?: (props: { href: string; children: ReactNode }) => ReactNode;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onClick?: () => void;\n}\n\nexport function tagPortalProduct(\n product: portalProducts.Product,\n): TaggedPortalProduct {\n return { ...product, __portalProduct: true as const };\n}\n\nfunction isPortalProduct(\n product: ProductCardProduct,\n): product is TaggedPortalProduct {\n return \"__portalProduct\" in product && product.__portalProduct === true;\n}\n\nfunction getPortalProductCoverImage(\n product: portalProducts.Product,\n): string | null {\n if (product.images && product.images.length > 0) {\n return product.images[0]?.url ?? null;\n }\n return null;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nfunction formatPortalPrice(\n price: string | undefined,\n currency: string | undefined,\n): string | null {\n if (!price) return null;\n const numericPrice = Number(price);\n if (Number.isNaN(numericPrice)) return `${currency ?? \"\"}${price}`;\n try {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: currency || \"USD\",\n }).format(numericPrice);\n } catch {\n return `$${price}`;\n }\n}\n\nfunction ProductCardContent({\n product,\n countryIso,\n companyLogoUrl,\n renderImage = defaultRenderImage,\n}: {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n\n const isPortal = isPortalProduct(product);\n const coverImage = isPortal\n ? getPortalProductCoverImage(product)\n : getProductImageUrl(product as Parameters<typeof getProductImageUrl>[0]);\n const isVideo = isVideoUrl(coverImage);\n const productName = isPortal\n ? product.name || \"No title available\"\n : (product as LegacyProduct).title || \"No title available\";\n\n let repPrice: string | null | undefined = null;\n let price: string | null | undefined = null;\n if (isPortal) {\n repPrice = formatPortalPrice(product.price, product.currency);\n } else if (countryIso) {\n const prices = determineProductPrice(product, countryIso);\n repPrice = prices.repPrice;\n price = prices.price;\n }\n\n return (\n <>\n {/* Image/Video container */}\n <div\n className=\"bg-muted relative aspect-square overflow-hidden\"\n onMouseEnter={() => isVideo && setIsHovered(true)}\n onMouseLeave={() => isVideo && setIsHovered(false)}\n >\n {isVideo && isHovered ? (\n <video\n src={coverImage || \"\"}\n className=\"absolute inset-0 h-full w-full object-cover\"\n autoPlay\n muted\n loop\n playsInline\n />\n ) : (\n renderImage({\n src:\n isVideo && coverImage\n ? getVideoThumbnailUrl(coverImage)\n : coverImage ||\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\",\n alt: productName,\n fill: true,\n className:\n \"object-cover transition-transform group-hover:scale-105\",\n onError: (e) => {\n e.currentTarget.src =\n companyLogoUrl ||\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Video play indicator */}\n {isVideo && !isHovered && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm\">\n <CirclePlay className=\"h-12 w-12 text-white\" />\n </div>\n </div>\n )}\n </div>\n\n {/* Product info */}\n <div className=\"px-3 pt-2 pb-4\">\n <h3 className=\"text-foreground line-clamp-1 text-sm font-bold\">\n {productName}\n </h3>\n\n <div className=\"flex items-center gap-2\">\n {repPrice && (\n <span className=\"text-foreground text-sm font-bold\">\n {repPrice}\n </span>\n )}\n {price && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {price}\n </span>\n )}\n </div>\n\n {!isPortal && countryIso && (\n <div className=\"text-muted-foreground text-sm\">\n CV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"cv\",\n ) || \"-\"}{\" \"}\n | QV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"qv\",\n ) || \"-\"}\n </div>\n )}\n </div>\n </>\n );\n}\n\nfunction getSelectedVariant(\n product: LegacyProduct,\n): products.Variant | products.ShopVariant | null {\n if (!product.variants || product.variants.length === 0) return null;\n\n const masterVariant = product.variants.find(\n (v: products.Variant | products.ShopVariant) => {\n return \"is_master\" in v && v.is_master;\n },\n );\n if (masterVariant) return masterVariant;\n\n return product.variants[0] || null;\n}\n\nfunction getVariantCountryValue(\n variant: products.Variant | products.ShopVariant | null,\n countryIso: string,\n field: \"cv\" | \"qv\",\n): number | null {\n if (!variant || !variant.variant_countries) return null;\n\n if (\n typeof variant.variant_countries === \"object\" &&\n !Array.isArray(variant.variant_countries)\n ) {\n const countryData = variant.variant_countries[countryIso] as\n | products.VariantCountry\n | undefined;\n return countryData?.[field] ?? null;\n }\n\n if (Array.isArray(variant.variant_countries)) {\n const countryData = variant.variant_countries.find(\n (vc: products.ShopVariantCountry) => vc.country_iso === countryIso,\n );\n return countryData?.[field] ?? null;\n }\n\n return null;\n}\n\nexport default function ProductCard({\n product,\n countryIso,\n companyLogoUrl,\n showShareModal = false,\n setShareModalOpen,\n setSelectedProduct,\n renderLink,\n renderImage,\n onClick,\n}: ProductCardProps): React.JSX.Element {\n const cardContent = (\n <ProductCardContent\n product={product}\n countryIso={countryIso}\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n />\n );\n\n const cardClassName = \"overflow-hidden border-0 shadow-none pt-0 gap-0\";\n\n if (showShareModal && !isPortalProduct(product)) {\n const handleShareClick = () => {\n if (setSelectedProduct && setShareModalOpen) {\n setSelectedProduct(product);\n setShareModalOpen(true);\n }\n };\n return (\n <Card className={cardClassName}>\n <button\n onClick={handleShareClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n if (onClick) {\n return (\n <Card className={cardClassName}>\n <button\n onClick={onClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n const href = `/portal/shop/${product.id}`;\n\n if (renderLink) {\n return (\n <Card className={cardClassName}>\n {renderLink({ href, children: cardContent })}\n </Card>\n );\n }\n\n return (\n <Card className={cardClassName}>\n <a href={href} className=\"group block cursor-pointer\">\n {cardContent}\n </a>\n </Card>\n );\n}\n","import type React from \"react\";\nimport { useState, useEffect, useMemo, type ReactNode } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { isVideoUrl } from \"../utils/media-helpers\";\nimport type { RenderImageProps } from \"./product-card\";\n\ninterface ImageGalleryProps {\n images: Array<{\n id: number;\n image_url: string;\n image_path: string | null;\n position: number;\n }>;\n fallbackImageUrl: string;\n productTitle: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nexport default function ImageGallery({\n images,\n fallbackImageUrl,\n productTitle,\n renderImage = defaultRenderImage,\n}: ImageGalleryProps): React.JSX.Element {\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n const [isImageHovered, setIsImageHovered] = useState(false);\n const [hoverSide, setHoverSide] = useState<\"left\" | \"right\" | null>(null);\n\n const hasMultipleImages = images && images.length > 0;\n const displayImages = useMemo(\n () =>\n hasMultipleImages\n ? [...images].sort((a, b) => a.position - b.position)\n : [{ id: 0, image_url: fallbackImageUrl, position: 0 }],\n [images, hasMultipleImages, fallbackImageUrl],\n );\n\n // Reset to first image when the images array changes (e.g. variant switch)\n useEffect(() => {\n setCurrentImageIndex(0);\n }, [displayImages]);\n\n const nextImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex((prev) => (prev + 1) % displayImages.length);\n }\n };\n\n const prevImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex(\n (prev) => (prev - 1 + displayImages.length) % displayImages.length,\n );\n }\n };\n\n return (\n <div className=\"space-y-4\">\n {/* Main Image */}\n <div\n className=\"relative aspect-square overflow-hidden rounded-sm bg-gray-100\"\n onMouseEnter={() => setIsImageHovered(true)}\n onMouseLeave={() => {\n setIsImageHovered(false);\n setHoverSide(null);\n }}\n onMouseMove={(e) => {\n const bounds = e.currentTarget.getBoundingClientRect();\n const x = e.clientX - bounds.left;\n if (x < bounds.width / 4) {\n setHoverSide(\"left\");\n } else if (x > (bounds.width * 3) / 4) {\n setHoverSide(\"right\");\n } else {\n setHoverSide(null);\n }\n }}\n >\n {isVideoUrl(displayImages[currentImageIndex]?.image_url) ? (\n <video\n key={displayImages[currentImageIndex]?.id}\n src={displayImages[currentImageIndex]?.image_url}\n className=\"absolute inset-0 h-full w-full object-cover\"\n controls\n loop\n playsInline\n />\n ) : (\n renderImage({\n src:\n displayImages[currentImageIndex]?.image_url || fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-cover group-hover:scale-105\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Navigation click areas and icons */}\n {displayImages.length > 1 && isImageHovered && (\n <>\n {/* Left quarter clickable area and icon */}\n <div\n className=\"absolute top-0 left-0 z-10 h-full w-1/4 cursor-pointer\"\n onClick={prevImage}\n style={{ pointerEvents: \"auto\" }}\n >\n {hoverSide === \"left\" && (\n <span className=\"absolute top-1/2 left-8 z-20 -translate-y-1/2 select-none\">\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-white\">\n <ChevronLeft className=\"h-5 w-5 text-black\" />\n </span>\n </span>\n )}\n </div>\n {/* Right quarter clickable area and icon */}\n <div\n className=\"absolute top-0 right-0 z-10 h-full w-1/4 cursor-pointer\"\n onClick={nextImage}\n style={{ pointerEvents: \"auto\" }}\n >\n {hoverSide === \"right\" && (\n <span className=\"absolute top-1/2 right-8 z-20 -translate-y-1/2 select-none\">\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-white\">\n <ChevronRight className=\"h-5 w-5 text-black\" />\n </span>\n </span>\n )}\n </div>\n </>\n )}\n\n {/* Page Indicators - Bottom Center */}\n {displayImages.length > 1 && (\n <div className=\"absolute bottom-3 left-1/2 flex -translate-x-1/2 gap-3\">\n {displayImages.map((_, index) => (\n <div\n key={index}\n className={`h-1.5 w-6 rounded-lg transition-colors ${\n index === currentImageIndex ? \"bg-gray-800\" : \"bg-gray-400\"\n }`}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\n\ninterface QuantitySelectorProps {\n quantity: number;\n setQuantity: (quantity: number) => void;\n}\n\nexport default function QuantitySelector({\n quantity,\n setQuantity,\n}: QuantitySelectorProps): React.JSX.Element {\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center rounded-lg\">\n <Button\n variant=\"default\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n className=\"border-0 px-3 py-2 shadow-none\"\n >\n −\n </Button>\n <span className=\"text-foreground min-w-8 px-4 py-2 text-center text-sm font-medium\">\n {quantity}\n </span>\n <Button\n variant=\"default\"\n onClick={() => setQuantity(quantity + 1)}\n className=\"border-0 px-3 py-2 shadow-none\"\n >\n +\n </Button>\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport {\n useState,\n useMemo,\n useEffect,\n useRef,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport {\n usePortalProductCatalog,\n usePortalProductDetail,\n type PortalProductPageParam,\n} from \"@fluid-app/products-core\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { Button, Skeleton } from \"@fluid-app/ui-primitives\";\nimport { SearchSort } from \"@fluid-app/ui-components/components/SearchSort\";\nimport { ArrowLeft, ShoppingCart } from \"lucide-react\";\nimport ProductCard, {\n tagPortalProduct,\n type RenderImageProps,\n} from \"./product-card\";\nimport ImageGallery from \"./image-gallery\";\nimport QuantitySelector from \"./quantity-selector\";\n\ninterface ShopAppProps {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n /** When provided, controls which product detail to show (URL-driven routing) */\n productId?: string | null;\n /** Called when a product is selected from the listing */\n onSelectProduct?: (productId: string) => void;\n /** Called when user navigates back from product detail */\n onBack?: () => void;\n /** Optional cart button to render in the header area */\n cartButton?: ReactNode;\n}\n\nconst PAGE_SIZE = 25;\n\nfunction sanitizeHtml(html: string): string {\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n for (const el of doc.querySelectorAll(\n \"script, iframe, object, embed, form, base, meta, link, style\",\n )) {\n el.remove();\n }\n for (const el of doc.querySelectorAll(\"*\")) {\n for (const attr of [...el.attributes]) {\n if (\n attr.name.toLowerCase().startsWith(\"on\") ||\n attr.value.toLowerCase().trim().startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n}\n\nconst GRID_CLASS =\n \"grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4\";\n\nfunction SkeletonGrid({ count = 8 }: { count?: number }) {\n return (\n <div className={GRID_CLASS}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n );\n}\n\nfunction ProductListing({\n companyLogoUrl,\n renderImage,\n onSelectProduct,\n cartButton,\n}: {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n cartButton?: ReactNode;\n}) {\n const observerTarget = useRef<HTMLDivElement>(null);\n\n const catalog = usePortalProductCatalog({ perPage: PAGE_SIZE });\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n error,\n isFetched,\n } = useInfiniteQuery({\n queryKey: catalog.queryKey,\n queryFn: ({ pageParam }) => catalog.fetchProducts(pageParam),\n getNextPageParam: catalog.getNextPageParam,\n initialPageParam: undefined as PortalProductPageParam,\n });\n\n const handleIntersect = useCallback(\n (entries: IntersectionObserverEntry[]) => {\n if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) {\n fetchNextPage();\n }\n },\n [hasNextPage, isFetchingNextPage, fetchNextPage],\n );\n\n useEffect(() => {\n const target = observerTarget.current;\n if (!target) return;\n\n const observer = new IntersectionObserver(handleIntersect, {\n threshold: 0.1,\n rootMargin: \"200px\",\n });\n observer.observe(target);\n return () => observer.disconnect();\n }, [handleIntersect]);\n\n const allProducts = data?.pages.flatMap((page) => page.products) ?? [];\n\n return (\n <div className=\"h-full overflow-auto\">\n <div className=\"mx-auto px-2 md:px-10\">\n {/* Search */}\n <div className=\"flex items-center justify-end gap-2 py-4\">\n <div className=\"w-full max-w-sm\">\n <SearchSort\n searchValue={catalog.searchTerm}\n onSearchChange={catalog.setSearchTerm}\n placeholder=\"Search products...\"\n />\n </div>\n {cartButton && (\n <div className=\"flex shrink-0 items-center gap-3\">{cartButton}</div>\n )}\n </div>\n </div>\n\n {/* Product Grid */}\n <div className=\"mx-auto space-y-8 px-2 md:px-10 md:py-8\">\n {isLoading ? (\n <SkeletonGrid />\n ) : error ? (\n <p className=\"mx-auto my-6 rounded-lg bg-red-100 px-3 py-2 text-red-500\">\n Error: {error.message}\n </p>\n ) : isFetched && allProducts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-muted-foreground text-sm\">\n {catalog.searchTerm\n ? `No products match \"${catalog.searchTerm}\". Try a different search term.`\n : \"There are no products available at the moment.\"}\n </p>\n </div>\n ) : (\n <>\n <div className={GRID_CLASS}>\n {allProducts.map((product) => (\n <ProductCard\n key={product.id}\n product={tagPortalProduct(product)}\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n onClick={() => onSelectProduct(String(product.id))}\n />\n ))}\n </div>\n <div ref={observerTarget} />\n {isFetchingNextPage && <SkeletonGrid count={4} />}\n </>\n )}\n </div>\n </div>\n );\n}\n\nfunction ProductDetail({\n productId,\n renderImage,\n onBack,\n cartButton,\n}: {\n productId: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onBack: () => void;\n cartButton?: ReactNode;\n}) {\n const [quantity, setQuantity] = useState(1);\n const { product, isLoading, error, images } = usePortalProductDetail({\n productId,\n });\n\n const coverImage = images[0]?.url ?? null;\n\n const galleryImages = useMemo(\n () =>\n images.map((img, idx) => ({\n id: img.id ?? idx,\n image_url: img.url,\n image_path: null as string | null,\n position: idx,\n })),\n [images],\n );\n\n if (isLoading) {\n return (\n <div className=\"mx-auto max-w-7xl py-8 pr-4 pl-0 md:pr-6 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <div className=\"space-y-4 pl-20\">\n <Skeleton className=\"h-8 w-3/4\" />\n <Skeleton className=\"h-5 w-1/4\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-10 w-1/2\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n Unable to load product\n </h3>\n <p className=\"text-muted-foreground\">\n Something went wrong. Please try again later.\n </p>\n </div>\n </div>\n );\n }\n\n if (!product) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n Product not found\n </h3>\n <p className=\"text-muted-foreground\">\n The product you're looking for doesn't exist.\n </p>\n </div>\n </div>\n );\n }\n\n const title = product.name || \"Product\";\n const displayPrice = (() => {\n if (!product.price) return null;\n const numericPrice = Number(product.price);\n if (Number.isNaN(numericPrice))\n return `${product.currency ?? \"\"}${product.price}`;\n try {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: product.currency || \"USD\",\n }).format(numericPrice);\n } catch {\n return `$${product.price}`;\n }\n })();\n\n return (\n <div className=\"h-full overflow-auto pb-5 pl-8\">\n {/* Back button and cart */}\n <div className=\"flex items-center justify-between px-2 pt-4 md:px-10\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onBack} className=\"gap-1\">\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Shop\n </Button>\n {cartButton}\n </div>\n\n <div className=\"mx-auto max-w-7xl py-8 pr-4 pl-0 md:pr-6 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n {/* Image Gallery */}\n <ImageGallery\n images={galleryImages}\n fallbackImageUrl={\n coverImage ??\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\"\n }\n productTitle={title}\n renderImage={renderImage}\n />\n\n {/* Product Info */}\n <div className=\"max-w-lg pl-20\">\n <h1 className=\"text-foreground text-3xl font-bold\">{title}</h1>\n\n {displayPrice && (\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-sm\">{displayPrice}</span>\n </div>\n )}\n\n {/* Product Description */}\n <div className=\"pt-2\">\n <h3 className=\"text-foreground mb-1 text-sm font-medium\">\n Product Description\n </h3>\n <div\n className=\"text-foreground mb-3 text-[12px]\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtml(product.description ?? \"\"),\n }}\n />\n </div>\n\n {/* Quantity and Add to Cart */}\n <div className=\"mb-3\" />\n <div className=\"flex items-center gap-3 pb-3\">\n <QuantitySelector quantity={quantity} setQuantity={setQuantity} />\n\n <Button\n variant=\"default\"\n className=\"flex-1 gap-2 py-2 text-base font-medium\"\n data-fluid-add-to-cart={String(product.id ?? \"\")}\n data-fluid-quantity={quantity}\n data-fluid-open-cart-after-add=\"false\"\n >\n <ShoppingCart className=\"h-4 w-4\" />\n Add to Cart\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function ShopApp({\n companyLogoUrl,\n renderImage,\n productId: controlledProductId,\n onSelectProduct: onSelectProductProp,\n onBack: onBackProp,\n cartButton,\n}: ShopAppProps): React.JSX.Element {\n // Internal state used only when navigation is not controlled externally\n const [internalProductId, setInternalProductId] = useState<string | null>(\n null,\n );\n\n const isControlled = controlledProductId !== undefined;\n const activeProductId = isControlled\n ? controlledProductId\n : internalProductId;\n\n const handleSelectProduct = onSelectProductProp ?? setInternalProductId;\n const handleBack = onBackProp ?? (() => setInternalProductId(null));\n\n if (activeProductId) {\n return (\n <ProductDetail\n productId={activeProductId}\n renderImage={renderImage}\n onBack={handleBack}\n cartButton={cartButton}\n />\n );\n }\n\n return (\n <ProductListing\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n onSelectProduct={handleSelectProduct}\n cartButton={cartButton}\n />\n );\n}\n","import { useEffect, useRef } from \"react\";\n\ninterface CartScriptProps {\n subdomain: string;\n authJwt?: string;\n /** Enable BFF mode — uses portal session cookies instead of JWT for cart auth. */\n bffMode?: boolean;\n}\n\nconst SCRIPT_ID = \"fluid-cdn-script\";\nconst LEAD_CAPTURE_ID = \"fluid-lead-capture-suppress\";\nconst SCRIPT_SRC =\n \"https://assets.fluid.app/scripts/fluid-sdk/latest/web-widgets/index.js\";\n\nexport default function CartScript({\n subdomain,\n authJwt,\n bffMode,\n}: CartScriptProps): React.ReactNode {\n // Use a ref so the script is injected once with the initial values.\n // ES modules are cached by URL — re-inserting the same script won't\n // re-execute it, so changing props after the first load has no effect.\n const authJwtRef = useRef(authJwt);\n authJwtRef.current = authJwt;\n\n useEffect(() => {\n if (!subdomain) return;\n\n // Don't add a duplicate script\n if (document.getElementById(SCRIPT_ID)) return;\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.src = SCRIPT_SRC;\n script.type = \"module\";\n script.crossOrigin = \"anonymous\";\n script.dataset.fluidShop = subdomain;\n if (bffMode) {\n script.dataset.bffMode = \"true\";\n } else if (authJwtRef.current) {\n script.dataset.authJwt = authJwtRef.current;\n }\n document.head.appendChild(script);\n\n // Suppress the SDK's auto-injected lead capture widget.\n // The SDK skips injection when it finds an existing element with hide-widget.\n const leadCapture = document.createElement(\"fluid-lead-capture-widget\");\n leadCapture.id = LEAD_CAPTURE_ID;\n leadCapture.setAttribute(\"hide-widget\", \"true\");\n document.body.appendChild(leadCapture);\n\n return () => {\n const existing = document.getElementById(SCRIPT_ID);\n if (existing) existing.remove();\n const existingLeadCapture = document.getElementById(LEAD_CAPTURE_ID);\n if (existingLeadCapture) existingLeadCapture.remove();\n };\n }, [subdomain, bffMode]);\n\n return null;\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface CartWidgetProps {\n theme?: Record<string, string>;\n}\n\nexport default function CartWidget({\n theme,\n}: CartWidgetProps): React.ReactNode {\n const [mounted, setMounted] = useState(false);\n const widgetRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n const el = widgetRef.current;\n if (!el) return;\n if (theme) {\n el.setAttribute(\"theme\", JSON.stringify(theme));\n } else {\n el.removeAttribute(\"theme\");\n }\n }, [theme, mounted]);\n\n const widget = React.createElement(\"fluid-cart-widget\", {\n ref: (el: HTMLElement | null) => {\n widgetRef.current = el;\n },\n \"data-fluid-widget\": \"true\",\n \"hide-widget\": \"true\",\n \"is-primary\": \"true\",\n });\n\n // Portal to document.body so the cart drawer escapes any\n // overflow-hidden / isolation stacking contexts in the layout.\n if (mounted) {\n return createPortal(widget, document.body);\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ShoppingCart } from \"lucide-react\";\nimport React, { useEffect, useCallback, useState } from \"react\";\n\ndeclare global {\n interface Window {\n FluidCommerceSDK?: {\n getCheckoutUrl: () => string;\n setOnCheckout: (callback: () => void) => void;\n };\n FairShareSDK?: {\n getCartItemCount: () => number;\n isBffMode: () => boolean;\n updateLocaleSettings: (options: {\n language?: string;\n country?: string;\n }) => Promise<void>;\n };\n fluidCart?: {\n open: () => void;\n };\n }\n}\n\ninterface CartButtonProps {\n onCheckout?: (checkoutUrl: string) => void;\n}\n\nconst MAX_SDK_POLL_ATTEMPTS = 50; // 5 seconds at 100ms intervals\n\nexport function CartButton({ onCheckout }: CartButtonProps): React.ReactNode {\n const [initialCount, setInitialCount] = useState(0);\n\n const navigateToCheckout = useCallback(() => {\n if (!window.FluidCommerceSDK) {\n console.error(\"FluidCommerceSDK not available\");\n return;\n }\n\n try {\n const checkoutUrl = window.FluidCommerceSDK.getCheckoutUrl();\n if (!checkoutUrl) {\n console.error(\"No checkout URL available\");\n return;\n }\n onCheckout?.(checkoutUrl);\n } catch (error) {\n console.error(\"Error getting checkout URL:\", error);\n }\n }, [onCheckout]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let attempts = 0;\n let cancelled = false;\n\n const setupSDK = () => {\n if (cancelled) return;\n if (window.FluidCommerceSDK) {\n if (onCheckout) {\n window.FluidCommerceSDK.setOnCheckout(navigateToCheckout);\n }\n const count = window.FairShareSDK?.getCartItemCount?.();\n if (count != null) {\n setInitialCount(count);\n }\n } else if (attempts < MAX_SDK_POLL_ATTEMPTS) {\n attempts++;\n timeoutId = setTimeout(setupSDK, 100);\n }\n };\n\n setupSDK();\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [navigateToCheckout, onCheckout]);\n\n return (\n <Button\n className=\"bg-primary text-primary-foreground hover:bg-primary-700 relative flex items-center gap-4 rounded-sm px-4 py-1.5\"\n onClick={() => {\n window.fluidCart?.open();\n }}\n >\n <div className=\"relative\">\n <ShoppingCart className=\"size-5\" />\n <span\n id=\"fluid-cart-count\"\n className=\"bg-primary-foreground text-primary absolute -top-1 -right-2 flex h-4 w-4 items-center justify-center rounded-full text-[8px] font-bold\"\n >\n {initialCount}\n </span>\n </div>\n <span>Cart</span>\n </Button>\n );\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ShopContainerProps {\n children: React.ReactNode;\n className?: string;\n cartScript?: React.ReactNode;\n cartWidget?: React.ReactNode;\n}\n\nexport default function ShopContainer({\n children,\n className = \"\",\n cartScript,\n cartWidget,\n}: ShopContainerProps): React.ReactNode {\n const containerRef = useRef<HTMLDivElement>(null);\n const [portalContainer, setPortalContainer] = useState<HTMLDivElement | null>(\n null,\n );\n\n useEffect(() => {\n const currentContainer = containerRef.current;\n if (!currentContainer) return;\n\n const reactContentWrapper = document.createElement(\"div\");\n reactContentWrapper.id = \"react-content-wrapper\";\n reactContentWrapper.style.cssText = `\n position: relative;\n `;\n reactContentWrapper.className = \"min-h-full\";\n\n currentContainer.appendChild(reactContentWrapper);\n\n setPortalContainer(reactContentWrapper);\n\n return () => {\n if (currentContainer && reactContentWrapper) {\n try {\n currentContainer.removeChild(reactContentWrapper);\n } catch (e) {\n console.warn(\"Failed to cleanup isolated container:\", e);\n }\n }\n setPortalContainer(null);\n };\n }, []);\n\n return (\n <>\n <div\n ref={containerRef}\n className={`isolated-shop-wrapper ${className} h-full`}\n >\n {portalContainer &&\n createPortal(\n <>\n {cartScript}\n {cartWidget}\n {children}\n </>,\n portalContainer,\n )}\n </div>\n </>\n );\n}\n","import { type ComponentProps, useEffect, useMemo } from \"react\";\nimport ShopApp from \"@fluid-app/shop-ui/components/shop-app\";\nimport { PortalProductsCoreProvider } from \"@fluid-app/products-core\";\nimport {\n CartButton,\n CartScript,\n CartWidget,\n ShopContainer,\n} from \"@fluid-app/cart-ui\";\nimport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbPage,\n} from \"@fluid-app/ui-primitives\";\nimport {\n useScreenHeaderBreadcrumbs,\n useScreenHeaderActions,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useCurrentUser } from \"../hooks/use-current-user\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { usePortalProductsClient } from \"../products/use-portal-products-client\";\n\ntype ShopScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function ShopScreen({\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ShopScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const portalProductsApi = usePortalProductsClient();\n const { data: userData } = useCurrentUser();\n const { currentSlug, navigate } = useAppNavigation();\n const countryCode = config.countryIso ?? userData?.country?.iso ?? \"US\";\n const subdomain = userData?.company?.subdomain;\n\n const headerBreadcrumbs = useMemo(\n () => (\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">Shop</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n ),\n [],\n );\n useScreenHeaderBreadcrumbs(headerBreadcrumbs);\n\n const headerActions = useMemo(\n () => (\n <div className=\"flex items-center gap-4\">\n <CartButton />\n </div>\n ),\n [],\n );\n useScreenHeaderActions(headerActions);\n\n // Sync country to FairShare SDK so the cart uses the correct country.\n // The SDK loads asynchronously via a script tag, so we poll until it's available.\n useEffect(() => {\n if (!countryCode) return;\n type FairShareWindow = {\n FairShareSDK?: {\n updateLocaleSettings: (opts: { country: string }) => void;\n };\n };\n const sdk = () => (window as FairShareWindow).FairShareSDK;\n\n if (sdk()) {\n sdk()!.updateLocaleSettings({ country: countryCode });\n return;\n }\n\n let attempts = 0;\n const id = setInterval(() => {\n attempts++;\n if (sdk()) {\n sdk()!.updateLocaleSettings({ country: countryCode });\n clearInterval(id);\n } else if (attempts >= 50) {\n clearInterval(id);\n }\n }, 100);\n\n return () => clearInterval(id);\n }, [countryCode]);\n\n // Parse product ID from slug: \"shop/{productId}\"\n const parts = currentSlug.split(\"/\");\n const productId = parts[1] ?? null;\n\n return (\n <div {...divProps} className={`h-full ${divProps.className ?? \"\"}`}>\n <ShopContainer\n cartScript={\n subdomain ? <CartScript subdomain={subdomain} bffMode /> : null\n }\n cartWidget={<CartWidget />}\n >\n <PortalProductsCoreProvider api={portalProductsApi}>\n <ShopApp\n companyLogoUrl={userData?.company?.logo_url}\n productId={productId}\n onSelectProduct={(id) => navigate(`shop/${id}`)}\n onBack={() => navigate(\"shop\")}\n />\n </PortalProductsCoreProvider>\n </ShopContainer>\n </div>\n );\n}\n\nexport const shopScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ShopScreen\",\n displayName: \"Shop Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ let zustand = require("zustand");
|
|
|
16
16
|
let zustand_middleware = require("zustand/middleware");
|
|
17
17
|
(0, react.createContext)(null);
|
|
18
18
|
//#endregion
|
|
19
|
-
//#region ../../products/core/src/portal-context.tsx
|
|
19
|
+
//#region ../../products/core/src/portal-products-api-context.tsx
|
|
20
20
|
const PortalProductsCoreContext = (0, react.createContext)(null);
|
|
21
21
|
function PortalProductsCoreProvider({ api, children }) {
|
|
22
22
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PortalProductsCoreContext.Provider, {
|
|
@@ -1509,4 +1509,4 @@ Object.defineProperty(exports, "shopScreenPropertySchema", {
|
|
|
1509
1509
|
}
|
|
1510
1510
|
});
|
|
1511
1511
|
|
|
1512
|
-
//# sourceMappingURL=ShopScreen-
|
|
1512
|
+
//# sourceMappingURL=ShopScreen-a3P0O4WA.cjs.map
|