@burdenoff/microfe-store 2026.915.2 → 2026.916.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/components/cart/CartDrawer.d.ts +2 -0
- package/dist/components/cart/CartDrawer.js +24 -24
- package/dist/components/cart/CartDrawer.js.map +1 -1
- package/dist/generated/global-operations.d.ts +7 -0
- package/dist/generated/global-operations.js +7 -0
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.d.ts +1515 -46
- package/dist/generated/global-types.js.map +1 -1
- package/dist/generated/wspace-types.d.ts +42653 -21731
- package/dist/hooks/useStoreGraphQL.d.ts +1 -0
- package/dist/hooks/useStoreGraphQL.js.map +1 -1
- package/dist/pages/CartPage.js +57 -57
- package/dist/pages/CartPage.js.map +1 -1
- package/dist/pages/MarketplaceHomePage.js +329 -322
- package/dist/pages/MarketplaceHomePage.js.map +1 -1
- package/dist/pages/ProductDetailPage.js +12 -3
- package/dist/pages/ProductDetailPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStoreGraphQL.js","names":[],"sources":["../../src/hooks/useStoreGraphQL.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useStoreGraphQLWithContext } from './useStoreGraphQLWithContext';\nimport {\n BrowseStoreDocument,\n StoreProductDetailsDocument,\n HomeGroupedProductsDocument,\n} from '../generated/global-operations';\nimport { type BrowseStoreInput, type StoreProductDetailsInput } from '../generated/global-types';\n\n// Local type definitions until schema is fully defined\ntype ProductType = 'APP' | 'TEMPLATE' | 'THEME' | 'INTEGRATION' | 'WIDGET' | 'DATASET';\ntype CreateReviewInput = { productId: string; rating: number; title?: string; comment?: string };\ntype UpdateReviewInput = { rating?: number; title?: string; comment?: string };\n\n// Import generated document nodes for operations extracted to .graphql files\nimport {\n FeaturedProductsDocument,\n SearchSuggestionsDocument,\n TrendingSearchesDocument,\n FilterOptionsDocument,\n CategoriesDocument,\n ProductReviewsDocument,\n UserReviewForProductDocument,\n MyEntitlementsDocument,\n CheckEntitlementDocument,\n WorkspaceStoreOrdersDocument,\n MyPublishedProductsDocument,\n DeveloperEarningsDocument,\n CreateReviewDocument,\n UpdateReviewDocument,\n DeleteReviewDocument,\n MarkReviewHelpfulDocument,\n} from '../generated/global-operations';\n\n// ============================================================================\n// Helper to get Apollo Client\n// ============================================================================\n\n/**\n * Hook to get the store Apollo client from the shell's GatewayRoute context.\n * The Store route is wrapped with <GatewayRoute gateway=\"global\"> in the app shell,\n * so useApolloClient() returns the global gateway client.\n */\nfunction useStoreClient() {\n return useApolloClient();\n}\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\ninterface StoreProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n nature: string;\n status: string;\n description?: string;\n pricingModel: string;\n price: number;\n currency: string;\n icon?: string;\n screenshots: string[];\n rating?: number;\n reviewCount: number;\n downloads: number;\n featured: boolean;\n category?: string;\n tags?: string[];\n publishedAt?: string;\n publisher?: {\n id: string;\n name: string;\n isVerified: boolean;\n logoUrl?: string;\n };\n}\n\ninterface BrowseStoreResult {\n products: StoreProduct[];\n totalCount: number;\n hasMore: boolean;\n nextCursor?: string;\n facets?: {\n types: { value: string; count: number }[];\n subTypes: { value: string; count: number }[];\n categories: { value: string; count: number }[];\n pricingModels: { value: string; count: number }[];\n licenses: { value: string; count: number }[];\n priceRange?: { min: number; max: number };\n ratingDistribution?: {\n fiveStars: number;\n fourStars: number;\n threeStars: number;\n twoStars: number;\n oneStar: number;\n };\n };\n}\n\ninterface ProductReview {\n id: string;\n productId: string;\n userId: string;\n rating: number;\n title?: string;\n comment?: string;\n status: string;\n helpful: number;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ProductCategory {\n id: string;\n name: string;\n slug: string;\n description?: string;\n icon?: string;\n parentId?: string;\n}\n\ninterface SearchSuggestion {\n term: string;\n type: string;\n count: number;\n highlight?: string;\n}\n\ninterface GroupedProducts {\n featured: StoreProduct[];\n mostDownloaded: StoreProduct[];\n recentlyAdded: StoreProduct[];\n freeItems: StoreProduct[];\n}\n\n// GraphQL Query Result Types\ninterface StoreProductDetailsData {\n storeProductDetails?: {\n product: StoreProduct;\n publisher?: {\n id: string;\n name: string;\n isVerified: boolean;\n logoUrl?: string;\n };\n relatedProducts?: StoreProduct[];\n reviews?: ProductReview[];\n } | null;\n}\n\ninterface FilterOptionsData {\n filterOptions?: {\n types: { value: string; count: number }[];\n subTypes: { value: string; count: number }[];\n categories: { value: string; count: number }[];\n pricingModels: { value: string; count: number }[];\n licenses: { value: string; count: number }[];\n priceRange?: { min: number; max: number };\n } | null;\n}\n\ninterface CheckEntitlementData {\n checkEntitlement?: {\n hasAccess: boolean;\n entitlement?: {\n id: string;\n productId: string;\n type: string;\n status: string;\n expiresAt?: string;\n };\n } | null;\n}\n\ninterface DeveloperEarningsData {\n developerEarnings?: {\n totalEarnings: number;\n pendingPayout: number;\n periodEarnings: number;\n currency: string;\n transactions?: Array<{\n id: string;\n amount: number;\n type: string;\n status: string;\n createdAt: string;\n }>;\n } | null;\n}\n\n// ============================================================================\n// Browse & Search Hooks\n// ============================================================================\n\n/**\n * Hook to browse/search store products with filters\n * Uses Apollo Client from context\n */\nexport function useBrowseStore(input: BrowseStoreInput = {}) {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Stringify input to use as stable dependency\n const inputKey = JSON.stringify(input);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n });\n setProducts(result.data?.browseStore?.products ?? []);\n setTotalCount(result.data?.browseStore?.totalCount ?? 0);\n setHasMore(result.data?.browseStore?.hasMore ?? false);\n setFacets(result.data?.browseStore?.facets);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, inputKey]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n products,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to browse/search store products with organization context.\n * Uses organization-aware GraphQL client with automatic headers.\n * Automatically applies defaultCompatibleWith from store context\n * to the filter if not already specified in the input.\n */\nexport function useBrowseStoreWithContext(\n input: BrowseStoreInput = {},\n options?: { skip?: boolean }\n) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const { defaultCompatibleWith } = useStore();\n const [allProducts, setAllProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(!options?.skip);\n const [error, setError] = useState<Error | null>(null);\n const [currentOffset, setCurrentOffset] = useState(input.pagination?.offset ?? 0);\n\n const skip = options?.skip;\n\n // Merge defaultCompatibleWith into the input filter if not already set\n const mergedInput = useMemo(() => {\n if (!defaultCompatibleWith) return input;\n const merged = { ...input };\n if (merged.filter) {\n merged.filter = { ...merged.filter };\n if (!merged.filter.compatibleWith) {\n merged.filter.compatibleWith = defaultCompatibleWith;\n }\n } else {\n merged.filter = { compatibleWith: defaultCompatibleWith };\n }\n return merged;\n }, [input, defaultCompatibleWith]);\n\n // Stringify only filter/sort/type parts (NOT offset) as stable dependency\n // so changing offset for loadMore doesn't retrigger the effect\n const filterKey = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { pagination, ...rest } = mergedInput;\n return JSON.stringify(rest);\n }, [mergedInput]);\n\n const pageLimit = input.pagination?.limit ?? 30;\n\n const fetchData = useCallback(\n async (fetchOffset: number, append: boolean) => {\n if (skip) {\n setLoading(false);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const queryInput: BrowseStoreInput = {\n ...(JSON.parse(filterKey) as BrowseStoreInput),\n pagination: { ...mergedInput.pagination, limit: pageLimit, offset: fetchOffset },\n };\n\n let result;\n\n if (hasOrganizationContext) {\n // Use organization-aware query\n result = (await queryWithContext({\n query: BrowseStoreDocument,\n variables: { input: queryInput },\n fetchPolicy: 'network-only',\n })) as { data?: { browseStore: BrowseStoreResult } };\n } else {\n // Fallback to global client without organization context\n result = await globalClient.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input: queryInput },\n fetchPolicy: 'network-only',\n });\n }\n\n const fetched = result.data?.browseStore?.products ?? [];\n if (append) {\n setAllProducts((prev) => [...prev, ...fetched]);\n } else {\n setAllProducts(fetched);\n }\n setTotalCount(result.data?.browseStore?.totalCount ?? 0);\n setHasMore(result.data?.browseStore?.hasMore ?? false);\n setFacets(result.data?.browseStore?.facets);\n setCurrentOffset(fetchOffset + fetched.length);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [\n queryWithContext,\n globalClient,\n hasOrganizationContext,\n filterKey,\n skip,\n pageLimit,\n mergedInput.pagination,\n ]\n );\n\n // Re-fetch from offset 0 whenever filters/sort change. fetchData and pagination\n // offset are intentionally read via refs to avoid refetch loops on stable changes.\n const fetchDataRef = useRef(fetchData);\n fetchDataRef.current = fetchData;\n const offsetRef = useRef(input.pagination?.offset ?? 0);\n offsetRef.current = input.pagination?.offset ?? 0;\n useEffect(() => {\n void fetchDataRef.current(offsetRef.current, false);\n }, [filterKey, skip]);\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n void fetchData(currentOffset, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n return {\n products: allProducts,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n refetch: () => fetchData(input.pagination?.offset ?? 0, false),\n loadMore,\n };\n}\n\n/**\n * Lazy hook to browse store on demand\n */\nexport function useLazyBrowseStore() {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const browseStore = useCallback(\n async (input: BrowseStoreInput = {}) => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input },\n fetchPolicy: 'network-only',\n });\n const data = result.data?.browseStore;\n setProducts(data?.products ?? []);\n setTotalCount(data?.totalCount ?? 0);\n setHasMore(data?.hasMore ?? false);\n setFacets(data?.facets);\n return data;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n return {\n browseStore,\n products,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch product details for product page\n */\nexport function useStoreProductDetails(input: StoreProductDetailsInput) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [data, setData] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const shouldSkip = !input.id && !input.slug;\n\n // Stringify input to use as stable dependency (prevents infinite loops)\n const inputKey = JSON.stringify(input);\n\n // Track if fetch has been attempted for this input\n const fetchedRef = useRef<string | null>(null);\n\n const fetchData = useCallback(async () => {\n if (shouldSkip) {\n setLoading(false);\n return;\n }\n\n // Skip if already fetched for this input\n if (fetchedRef.current === inputKey) {\n return;\n }\n fetchedRef.current = inputKey;\n\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: StoreProductDetailsDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n })) as { data?: StoreProductDetailsData })\n : await globalClient.query<StoreProductDetailsData>({\n query: StoreProductDetailsDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n });\n setData(result.data?.storeProductDetails ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [globalClient, hasOrganizationContext, inputKey, queryWithContext, shouldSkip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n data,\n loading,\n error,\n refetch: () => {\n fetchedRef.current = null; // Reset to allow refetch\n return fetchData();\n },\n };\n}\n\n/**\n * Lazy hook to fetch product details on demand\n */\nexport function useLazyStoreProductDetails() {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [data, setData] = useState<unknown>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const getProductDetails = useCallback(\n async (input: StoreProductDetailsInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: StoreProductDetailsDocument,\n variables: { input },\n })) as { data?: StoreProductDetailsData })\n : await globalClient.query<StoreProductDetailsData>({\n query: StoreProductDetailsDocument,\n variables: { input },\n });\n const details = result.data?.storeProductDetails ?? null;\n setData(details);\n return details;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [globalClient, hasOrganizationContext, queryWithContext]\n );\n\n return {\n getProductDetails,\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch grouped products for homepage.\n */\nexport function useHomeGroupedProducts(options?: { skip?: boolean }) {\n const client = useStoreClient();\n const { defaultCompatibleWith } = useStore();\n const [data, setData] = useState<GroupedProducts | null>(null);\n const [loading, setLoading] = useState(!options?.skip);\n const [error, setError] = useState<Error | null>(null);\n\n const skip = options?.skip;\n\n const fetchData = useCallback(async () => {\n if (skip) {\n setLoading(false);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ homeGroupedProducts: GroupedProducts }>({\n query: HomeGroupedProductsDocument,\n variables: { compatibleWith: defaultCompatibleWith ?? null },\n fetchPolicy: 'cache-first',\n });\n setData(result.data?.homeGroupedProducts ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, defaultCompatibleWith, skip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n data,\n featured: data?.featured ?? [],\n mostDownloaded: data?.mostDownloaded ?? [],\n recentlyAdded: data?.recentlyAdded ?? [],\n freeItems: data?.freeItems ?? [],\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch featured products\n */\nexport function useFeaturedProducts(limit?: number) {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ featuredProducts: StoreProduct[] }>({\n query: FeaturedProductsDocument,\n variables: { limit },\n fetchPolicy: 'cache-first',\n });\n setProducts(result.data?.featuredProducts ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, limit]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n products,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch search suggestions for autocomplete\n */\nexport function useSearchSuggestions(\n query: string,\n options?: { limit?: number; types?: string[] }\n) {\n const client = useStoreClient();\n const [suggestions, setSuggestions] = useState<SearchSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const shouldSkip = query.length < 2;\n\n const fetchData = useCallback(async () => {\n if (shouldSkip) {\n setSuggestions([]);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ searchSuggestions: SearchSuggestion[] }>({\n query: SearchSuggestionsDocument,\n variables: { query, limit: options?.limit, types: options?.types },\n fetchPolicy: 'network-only',\n });\n setSuggestions(result.data?.searchSuggestions ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, query, options?.limit, options?.types, shouldSkip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n suggestions,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Lazy hook to fetch search suggestions on demand\n */\nexport function useLazySearchSuggestions() {\n const client = useStoreClient();\n const [suggestions, setSuggestions] = useState<SearchSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const getSuggestions = useCallback(\n async (query: string, options?: { limit?: number; types?: string[] }) => {\n if (query.length < 2) {\n setSuggestions([]);\n return [];\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ searchSuggestions: SearchSuggestion[] }>({\n query: SearchSuggestionsDocument,\n variables: { query, limit: options?.limit, types: options?.types },\n fetchPolicy: 'network-only',\n });\n const data = result.data?.searchSuggestions ?? [];\n setSuggestions(data);\n return data;\n } catch (err) {\n setError(err as Error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n return {\n getSuggestions,\n suggestions,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch trending search terms\n */\nexport function useTrendingSearches(options?: { limit?: number; type?: ProductType }) {\n const client = useStoreClient();\n const [terms, setTerms] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ trendingSearches: string[] }>({\n query: TrendingSearchesDocument,\n variables: { limit: options?.limit, type: options?.type },\n fetchPolicy: 'cache-first',\n });\n setTerms(result.data?.trendingSearches ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, options?.limit, options?.type]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n terms,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch filter options for dropdowns\n */\nexport function useFilterOptions(options?: { type?: ProductType; withProducts?: boolean }) {\n const client = useStoreClient();\n const [filterOptions, setFilterOptions] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<FilterOptionsData>({\n query: FilterOptionsDocument,\n variables: { type: options?.type, withProducts: options?.withProducts },\n fetchPolicy: 'cache-first',\n });\n setFilterOptions(result.data?.filterOptions ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, options?.type, options?.withProducts]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n filterOptions,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Category Hooks\n// ============================================================================\n\n/**\n * Hook to fetch all categories\n */\nexport function useCategories() {\n const client = useStoreClient();\n const [categories, setCategories] = useState<ProductCategory[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ categories: ProductCategory[] }>({\n query: CategoriesDocument,\n fetchPolicy: 'cache-first',\n });\n setCategories(result.data?.categories ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n categories,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Review Hooks\n// ============================================================================\n\n/**\n * Hook to fetch reviews for a product\n */\nexport function useProductReviews(productId: string, options?: { status?: string }) {\n const client = useStoreClient();\n const [reviews, setReviews] = useState<ProductReview[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ productReviews: ProductReview[] }>({\n query: ProductReviewsDocument,\n variables: { productId, status: options?.status },\n fetchPolicy: 'cache-first',\n });\n setReviews(result.data?.productReviews ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId, options?.status]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n reviews,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch current user's review for a product\n */\nexport function useUserReviewForProduct(productId: string) {\n const client = useStoreClient();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ userReviewForProduct: ProductReview | null }>({\n query: UserReviewForProductDocument,\n variables: { productId },\n fetchPolicy: 'network-only',\n });\n setReview(result.data?.userReviewForProduct ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n review,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to create a review\n */\nexport function useCreateReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const createReview = useCallback(\n async (input: CreateReviewInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ createReview: ProductReview }>({\n mutation: CreateReviewDocument,\n variables: { input },\n });\n const data = result.data?.createReview ?? null;\n setReview(data);\n return { data, errorMessage: null };\n } catch (err) {\n setError(err as Error);\n const apolloErr = err as { graphQLErrors?: { message: string }[]; message?: string };\n const errorMessage =\n apolloErr.graphQLErrors?.[0]?.message ??\n apolloErr.message ??\n 'We could not save your review. Please try again.';\n return { data: null, errorMessage };\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n createReview,\n review,\n loading,\n error,\n };\n}\n\n/**\n * Hook to update a review\n */\nexport function useUpdateReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const updateReview = useCallback(\n async (id: string, input: UpdateReviewInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ updateReview: ProductReview }>({\n mutation: UpdateReviewDocument,\n variables: { id, input },\n });\n const data = result.data?.updateReview ?? null;\n setReview(data);\n return data;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n updateReview,\n review,\n loading,\n error,\n };\n}\n\n/**\n * Hook to delete a review\n */\nexport function useDeleteReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const deleteReview = useCallback(\n async (id: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ deleteReview: boolean }>({\n mutation: DeleteReviewDocument,\n variables: { id },\n });\n return result.data?.deleteReview ?? false;\n } catch (err) {\n setError(err as Error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n deleteReview,\n loading,\n error,\n };\n}\n\n/**\n * Hook to mark review as helpful\n */\nexport function useMarkReviewHelpful() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const markHelpful = useCallback(\n async (id: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{\n markReviewHelpful: { id: string; helpful: number };\n }>({\n mutation: MarkReviewHelpfulDocument,\n variables: { id },\n });\n return result.data?.markReviewHelpful ?? null;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n markHelpful,\n loading,\n error,\n };\n}\n\n// ============================================================================\n// Entitlement Hooks\n// ============================================================================\n\n/**\n * Hook to fetch current user's entitlements\n */\nexport function useMyEntitlements() {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const PAGE_SIZE = 20;\n const [allEntitlements, setAllEntitlements] = useState<unknown[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [currentOffset, setCurrentOffset] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(\n async (fetchOffset = 0, append = false) => {\n setLoading(true);\n setError(null);\n try {\n const variables = { limit: PAGE_SIZE, offset: fetchOffset };\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: MyEntitlementsDocument,\n variables,\n fetchPolicy: 'network-only',\n })) as { data?: { myEntitlements: unknown[] } })\n : await globalClient.query<{ myEntitlements: unknown[] }>({\n query: MyEntitlementsDocument,\n variables,\n fetchPolicy: 'network-only',\n });\n const fetched = result.data?.myEntitlements ?? [];\n if (append) {\n setAllEntitlements((prev) => [...prev, ...fetched]);\n } else {\n setAllEntitlements(fetched);\n }\n setHasMore(fetched.length === PAGE_SIZE);\n setCurrentOffset(fetchOffset);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [globalClient, hasOrganizationContext, queryWithContext]\n );\n\n useEffect(() => {\n fetchData(0);\n }, [fetchData]);\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n fetchData(currentOffset + PAGE_SIZE, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n return {\n entitlements: allEntitlements,\n hasMore,\n loading,\n error,\n refetch: () => fetchData(0),\n loadMore,\n };\n}\n\n/**\n * Hook to check entitlement for a product\n */\nexport function useCheckEntitlement(productId: string) {\n const client = useStoreClient();\n const [entitlement, setEntitlement] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<CheckEntitlementData>({\n query: CheckEntitlementDocument,\n variables: { productId },\n fetchPolicy: 'network-only',\n });\n setEntitlement(result.data?.checkEntitlement ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n entitlement,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Order Hooks\n// ============================================================================\n\n/**\n * Hook to fetch workspace store orders\n */\nexport function useWorkspaceStoreOrders(\n billingAccountId: string,\n page: number,\n limit: number,\n options?: { status?: string; search?: string }\n) {\n const client = useStoreClient();\n const [orders, setOrders] = useState<unknown[]>([]);\n const [total, setTotal] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!billingAccountId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{\n workspaceStoreOrders: { total: number; orders: unknown[] };\n }>({\n query: WorkspaceStoreOrdersDocument,\n variables: {\n billingAccountId,\n page,\n limit,\n status: options?.status,\n search: options?.search,\n },\n fetchPolicy: 'network-only',\n });\n setOrders(result.data?.workspaceStoreOrders?.orders ?? []);\n setTotal(result.data?.workspaceStoreOrders?.total ?? 0);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, billingAccountId, page, limit, options?.status, options?.search]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n orders,\n total,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Publisher Hooks\n// ============================================================================\n\n/**\n * Hook to fetch publisher's products\n */\nexport function useMyPublishedProducts() {\n const client = useStoreClient();\n const [allProducts, setAllProducts] = useState<StoreProduct[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [currentOffset, setCurrentOffset] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const PAGE_SIZE = 20;\n\n const fetchData = useCallback(\n async (fetchOffset = 0, append = false) => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ publishedProducts: StoreProduct[] }>({\n query: MyPublishedProductsDocument,\n variables: { limit: PAGE_SIZE, offset: fetchOffset },\n fetchPolicy: 'network-only',\n });\n const fetched = result.data?.publishedProducts ?? [];\n if (append) {\n setAllProducts((prev) => [...prev, ...fetched]);\n } else {\n setAllProducts(fetched);\n }\n setHasMore(fetched.length === PAGE_SIZE);\n setCurrentOffset(fetchOffset + fetched.length);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n void fetchData(currentOffset, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n useEffect(() => {\n void fetchData(0, false);\n }, [fetchData]);\n\n return {\n products: allProducts,\n hasMore,\n loading,\n error,\n refetch: () => fetchData(0, false),\n loadMore,\n };\n}\n\n/**\n * Hook to fetch developer earnings\n */\nexport function useDeveloperEarnings(options?: {\n period?: string;\n startDate?: string;\n endDate?: string;\n}) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [earnings, setEarnings] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: DeveloperEarningsDocument,\n variables: { input: options },\n fetchPolicy: 'network-only',\n })) as { data?: DeveloperEarningsData })\n : await globalClient.query<DeveloperEarningsData>({\n query: DeveloperEarningsDocument,\n variables: { input: options },\n fetchPolicy: 'network-only',\n });\n setEarnings(result.data?.developerEarnings ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [globalClient, hasOrganizationContext, options, queryWithContext]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n earnings,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Re-export types for convenience\n// ============================================================================\n\nexport type {\n BrowseStoreInput,\n StoreProductDetailsInput,\n ProductType,\n CreateReviewInput,\n UpdateReviewInput,\n StoreProduct,\n ProductReview,\n ProductCategory,\n SearchSuggestion,\n GroupedProducts,\n BrowseStoreResult,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useStoreGraphQL.js","names":[],"sources":["../../src/hooks/useStoreGraphQL.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useStoreGraphQLWithContext } from './useStoreGraphQLWithContext';\nimport {\n BrowseStoreDocument,\n StoreProductDetailsDocument,\n HomeGroupedProductsDocument,\n} from '../generated/global-operations';\nimport { type BrowseStoreInput, type StoreProductDetailsInput } from '../generated/global-types';\n\n// Local type definitions until schema is fully defined\ntype ProductType = 'APP' | 'TEMPLATE' | 'THEME' | 'INTEGRATION' | 'WIDGET' | 'DATASET';\ntype CreateReviewInput = { productId: string; rating: number; title?: string; comment?: string };\ntype UpdateReviewInput = { rating?: number; title?: string; comment?: string };\n\n// Import generated document nodes for operations extracted to .graphql files\nimport {\n FeaturedProductsDocument,\n SearchSuggestionsDocument,\n TrendingSearchesDocument,\n FilterOptionsDocument,\n CategoriesDocument,\n ProductReviewsDocument,\n UserReviewForProductDocument,\n MyEntitlementsDocument,\n CheckEntitlementDocument,\n WorkspaceStoreOrdersDocument,\n MyPublishedProductsDocument,\n DeveloperEarningsDocument,\n CreateReviewDocument,\n UpdateReviewDocument,\n DeleteReviewDocument,\n MarkReviewHelpfulDocument,\n} from '../generated/global-operations';\n\n// ============================================================================\n// Helper to get Apollo Client\n// ============================================================================\n\n/**\n * Hook to get the store Apollo client from the shell's GatewayRoute context.\n * The Store route is wrapped with <GatewayRoute gateway=\"global\"> in the app shell,\n * so useApolloClient() returns the global gateway client.\n */\nfunction useStoreClient() {\n return useApolloClient();\n}\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\ninterface StoreProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n nature: string;\n status: string;\n description?: string;\n pricingModel: string;\n price: number;\n currency: string;\n icon?: string;\n screenshots: string[];\n rating?: number;\n reviewCount: number;\n downloads: number;\n purchaseCount: number;\n featured: boolean;\n category?: string;\n tags?: string[];\n publishedAt?: string;\n publisher?: {\n id: string;\n name: string;\n isVerified: boolean;\n logoUrl?: string;\n };\n}\n\ninterface BrowseStoreResult {\n products: StoreProduct[];\n totalCount: number;\n hasMore: boolean;\n nextCursor?: string;\n facets?: {\n types: { value: string; count: number }[];\n subTypes: { value: string; count: number }[];\n categories: { value: string; count: number }[];\n pricingModels: { value: string; count: number }[];\n licenses: { value: string; count: number }[];\n priceRange?: { min: number; max: number };\n ratingDistribution?: {\n fiveStars: number;\n fourStars: number;\n threeStars: number;\n twoStars: number;\n oneStar: number;\n };\n };\n}\n\ninterface ProductReview {\n id: string;\n productId: string;\n userId: string;\n rating: number;\n title?: string;\n comment?: string;\n status: string;\n helpful: number;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ProductCategory {\n id: string;\n name: string;\n slug: string;\n description?: string;\n icon?: string;\n parentId?: string;\n}\n\ninterface SearchSuggestion {\n term: string;\n type: string;\n count: number;\n highlight?: string;\n}\n\ninterface GroupedProducts {\n featured: StoreProduct[];\n mostDownloaded: StoreProduct[];\n recentlyAdded: StoreProduct[];\n freeItems: StoreProduct[];\n}\n\n// GraphQL Query Result Types\ninterface StoreProductDetailsData {\n storeProductDetails?: {\n product: StoreProduct;\n publisher?: {\n id: string;\n name: string;\n isVerified: boolean;\n logoUrl?: string;\n };\n relatedProducts?: StoreProduct[];\n reviews?: ProductReview[];\n } | null;\n}\n\ninterface FilterOptionsData {\n filterOptions?: {\n types: { value: string; count: number }[];\n subTypes: { value: string; count: number }[];\n categories: { value: string; count: number }[];\n pricingModels: { value: string; count: number }[];\n licenses: { value: string; count: number }[];\n priceRange?: { min: number; max: number };\n } | null;\n}\n\ninterface CheckEntitlementData {\n checkEntitlement?: {\n hasAccess: boolean;\n entitlement?: {\n id: string;\n productId: string;\n type: string;\n status: string;\n expiresAt?: string;\n };\n } | null;\n}\n\ninterface DeveloperEarningsData {\n developerEarnings?: {\n totalEarnings: number;\n pendingPayout: number;\n periodEarnings: number;\n currency: string;\n transactions?: Array<{\n id: string;\n amount: number;\n type: string;\n status: string;\n createdAt: string;\n }>;\n } | null;\n}\n\n// ============================================================================\n// Browse & Search Hooks\n// ============================================================================\n\n/**\n * Hook to browse/search store products with filters\n * Uses Apollo Client from context\n */\nexport function useBrowseStore(input: BrowseStoreInput = {}) {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Stringify input to use as stable dependency\n const inputKey = JSON.stringify(input);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n });\n setProducts(result.data?.browseStore?.products ?? []);\n setTotalCount(result.data?.browseStore?.totalCount ?? 0);\n setHasMore(result.data?.browseStore?.hasMore ?? false);\n setFacets(result.data?.browseStore?.facets);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, inputKey]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n products,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to browse/search store products with organization context.\n * Uses organization-aware GraphQL client with automatic headers.\n * Automatically applies defaultCompatibleWith from store context\n * to the filter if not already specified in the input.\n */\nexport function useBrowseStoreWithContext(\n input: BrowseStoreInput = {},\n options?: { skip?: boolean }\n) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const { defaultCompatibleWith } = useStore();\n const [allProducts, setAllProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(!options?.skip);\n const [error, setError] = useState<Error | null>(null);\n const [currentOffset, setCurrentOffset] = useState(input.pagination?.offset ?? 0);\n\n const skip = options?.skip;\n\n // Merge defaultCompatibleWith into the input filter if not already set\n const mergedInput = useMemo(() => {\n if (!defaultCompatibleWith) return input;\n const merged = { ...input };\n if (merged.filter) {\n merged.filter = { ...merged.filter };\n if (!merged.filter.compatibleWith) {\n merged.filter.compatibleWith = defaultCompatibleWith;\n }\n } else {\n merged.filter = { compatibleWith: defaultCompatibleWith };\n }\n return merged;\n }, [input, defaultCompatibleWith]);\n\n // Stringify only filter/sort/type parts (NOT offset) as stable dependency\n // so changing offset for loadMore doesn't retrigger the effect\n const filterKey = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { pagination, ...rest } = mergedInput;\n return JSON.stringify(rest);\n }, [mergedInput]);\n\n const pageLimit = input.pagination?.limit ?? 30;\n\n const fetchData = useCallback(\n async (fetchOffset: number, append: boolean) => {\n if (skip) {\n setLoading(false);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const queryInput: BrowseStoreInput = {\n ...(JSON.parse(filterKey) as BrowseStoreInput),\n pagination: { ...mergedInput.pagination, limit: pageLimit, offset: fetchOffset },\n };\n\n let result;\n\n if (hasOrganizationContext) {\n // Use organization-aware query\n result = (await queryWithContext({\n query: BrowseStoreDocument,\n variables: { input: queryInput },\n fetchPolicy: 'network-only',\n })) as { data?: { browseStore: BrowseStoreResult } };\n } else {\n // Fallback to global client without organization context\n result = await globalClient.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input: queryInput },\n fetchPolicy: 'network-only',\n });\n }\n\n const fetched = result.data?.browseStore?.products ?? [];\n if (append) {\n setAllProducts((prev) => [...prev, ...fetched]);\n } else {\n setAllProducts(fetched);\n }\n setTotalCount(result.data?.browseStore?.totalCount ?? 0);\n setHasMore(result.data?.browseStore?.hasMore ?? false);\n setFacets(result.data?.browseStore?.facets);\n setCurrentOffset(fetchOffset + fetched.length);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [\n queryWithContext,\n globalClient,\n hasOrganizationContext,\n filterKey,\n skip,\n pageLimit,\n mergedInput.pagination,\n ]\n );\n\n // Re-fetch from offset 0 whenever filters/sort change. fetchData and pagination\n // offset are intentionally read via refs to avoid refetch loops on stable changes.\n const fetchDataRef = useRef(fetchData);\n fetchDataRef.current = fetchData;\n const offsetRef = useRef(input.pagination?.offset ?? 0);\n offsetRef.current = input.pagination?.offset ?? 0;\n useEffect(() => {\n void fetchDataRef.current(offsetRef.current, false);\n }, [filterKey, skip]);\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n void fetchData(currentOffset, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n return {\n products: allProducts,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n refetch: () => fetchData(input.pagination?.offset ?? 0, false),\n loadMore,\n };\n}\n\n/**\n * Lazy hook to browse store on demand\n */\nexport function useLazyBrowseStore() {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [facets, setFacets] = useState<BrowseStoreResult['facets']>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const browseStore = useCallback(\n async (input: BrowseStoreInput = {}) => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ browseStore: BrowseStoreResult }>({\n query: BrowseStoreDocument,\n variables: { input },\n fetchPolicy: 'network-only',\n });\n const data = result.data?.browseStore;\n setProducts(data?.products ?? []);\n setTotalCount(data?.totalCount ?? 0);\n setHasMore(data?.hasMore ?? false);\n setFacets(data?.facets);\n return data;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n return {\n browseStore,\n products,\n totalCount,\n hasMore,\n facets,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch product details for product page\n */\nexport function useStoreProductDetails(input: StoreProductDetailsInput) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [data, setData] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const shouldSkip = !input.id && !input.slug;\n\n // Stringify input to use as stable dependency (prevents infinite loops)\n const inputKey = JSON.stringify(input);\n\n // Track if fetch has been attempted for this input\n const fetchedRef = useRef<string | null>(null);\n\n const fetchData = useCallback(async () => {\n if (shouldSkip) {\n setLoading(false);\n return;\n }\n\n // Skip if already fetched for this input\n if (fetchedRef.current === inputKey) {\n return;\n }\n fetchedRef.current = inputKey;\n\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: StoreProductDetailsDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n })) as { data?: StoreProductDetailsData })\n : await globalClient.query<StoreProductDetailsData>({\n query: StoreProductDetailsDocument,\n variables: { input: JSON.parse(inputKey) },\n fetchPolicy: 'network-only',\n });\n setData(result.data?.storeProductDetails ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [globalClient, hasOrganizationContext, inputKey, queryWithContext, shouldSkip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n data,\n loading,\n error,\n refetch: () => {\n fetchedRef.current = null; // Reset to allow refetch\n return fetchData();\n },\n };\n}\n\n/**\n * Lazy hook to fetch product details on demand\n */\nexport function useLazyStoreProductDetails() {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [data, setData] = useState<unknown>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const getProductDetails = useCallback(\n async (input: StoreProductDetailsInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: StoreProductDetailsDocument,\n variables: { input },\n })) as { data?: StoreProductDetailsData })\n : await globalClient.query<StoreProductDetailsData>({\n query: StoreProductDetailsDocument,\n variables: { input },\n });\n const details = result.data?.storeProductDetails ?? null;\n setData(details);\n return details;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [globalClient, hasOrganizationContext, queryWithContext]\n );\n\n return {\n getProductDetails,\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch grouped products for homepage.\n */\nexport function useHomeGroupedProducts(options?: { skip?: boolean }) {\n const client = useStoreClient();\n const { defaultCompatibleWith } = useStore();\n const [data, setData] = useState<GroupedProducts | null>(null);\n const [loading, setLoading] = useState(!options?.skip);\n const [error, setError] = useState<Error | null>(null);\n\n const skip = options?.skip;\n\n const fetchData = useCallback(async () => {\n if (skip) {\n setLoading(false);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ homeGroupedProducts: GroupedProducts }>({\n query: HomeGroupedProductsDocument,\n variables: { compatibleWith: defaultCompatibleWith ?? null },\n fetchPolicy: 'cache-first',\n });\n setData(result.data?.homeGroupedProducts ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, defaultCompatibleWith, skip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n data,\n featured: data?.featured ?? [],\n mostDownloaded: data?.mostDownloaded ?? [],\n recentlyAdded: data?.recentlyAdded ?? [],\n freeItems: data?.freeItems ?? [],\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch featured products\n */\nexport function useFeaturedProducts(limit?: number) {\n const client = useStoreClient();\n const [products, setProducts] = useState<StoreProduct[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ featuredProducts: StoreProduct[] }>({\n query: FeaturedProductsDocument,\n variables: { limit },\n fetchPolicy: 'cache-first',\n });\n setProducts(result.data?.featuredProducts ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, limit]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n products,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch search suggestions for autocomplete\n */\nexport function useSearchSuggestions(\n query: string,\n options?: { limit?: number; types?: string[] }\n) {\n const client = useStoreClient();\n const [suggestions, setSuggestions] = useState<SearchSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const shouldSkip = query.length < 2;\n\n const fetchData = useCallback(async () => {\n if (shouldSkip) {\n setSuggestions([]);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ searchSuggestions: SearchSuggestion[] }>({\n query: SearchSuggestionsDocument,\n variables: { query, limit: options?.limit, types: options?.types },\n fetchPolicy: 'network-only',\n });\n setSuggestions(result.data?.searchSuggestions ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, query, options?.limit, options?.types, shouldSkip]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n suggestions,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Lazy hook to fetch search suggestions on demand\n */\nexport function useLazySearchSuggestions() {\n const client = useStoreClient();\n const [suggestions, setSuggestions] = useState<SearchSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const getSuggestions = useCallback(\n async (query: string, options?: { limit?: number; types?: string[] }) => {\n if (query.length < 2) {\n setSuggestions([]);\n return [];\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ searchSuggestions: SearchSuggestion[] }>({\n query: SearchSuggestionsDocument,\n variables: { query, limit: options?.limit, types: options?.types },\n fetchPolicy: 'network-only',\n });\n const data = result.data?.searchSuggestions ?? [];\n setSuggestions(data);\n return data;\n } catch (err) {\n setError(err as Error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n return {\n getSuggestions,\n suggestions,\n loading,\n error,\n };\n}\n\n/**\n * Hook to fetch trending search terms\n */\nexport function useTrendingSearches(options?: { limit?: number; type?: ProductType }) {\n const client = useStoreClient();\n const [terms, setTerms] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ trendingSearches: string[] }>({\n query: TrendingSearchesDocument,\n variables: { limit: options?.limit, type: options?.type },\n fetchPolicy: 'cache-first',\n });\n setTerms(result.data?.trendingSearches ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, options?.limit, options?.type]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n terms,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch filter options for dropdowns\n */\nexport function useFilterOptions(options?: { type?: ProductType; withProducts?: boolean }) {\n const client = useStoreClient();\n const [filterOptions, setFilterOptions] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<FilterOptionsData>({\n query: FilterOptionsDocument,\n variables: { type: options?.type, withProducts: options?.withProducts },\n fetchPolicy: 'cache-first',\n });\n setFilterOptions(result.data?.filterOptions ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, options?.type, options?.withProducts]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n filterOptions,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Category Hooks\n// ============================================================================\n\n/**\n * Hook to fetch all categories\n */\nexport function useCategories() {\n const client = useStoreClient();\n const [categories, setCategories] = useState<ProductCategory[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ categories: ProductCategory[] }>({\n query: CategoriesDocument,\n fetchPolicy: 'cache-first',\n });\n setCategories(result.data?.categories ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n categories,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Review Hooks\n// ============================================================================\n\n/**\n * Hook to fetch reviews for a product\n */\nexport function useProductReviews(productId: string, options?: { status?: string }) {\n const client = useStoreClient();\n const [reviews, setReviews] = useState<ProductReview[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ productReviews: ProductReview[] }>({\n query: ProductReviewsDocument,\n variables: { productId, status: options?.status },\n fetchPolicy: 'cache-first',\n });\n setReviews(result.data?.productReviews ?? []);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId, options?.status]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n reviews,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to fetch current user's review for a product\n */\nexport function useUserReviewForProduct(productId: string) {\n const client = useStoreClient();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ userReviewForProduct: ProductReview | null }>({\n query: UserReviewForProductDocument,\n variables: { productId },\n fetchPolicy: 'network-only',\n });\n setReview(result.data?.userReviewForProduct ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n review,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n/**\n * Hook to create a review\n */\nexport function useCreateReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const createReview = useCallback(\n async (input: CreateReviewInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ createReview: ProductReview }>({\n mutation: CreateReviewDocument,\n variables: { input },\n });\n const data = result.data?.createReview ?? null;\n setReview(data);\n return { data, errorMessage: null };\n } catch (err) {\n setError(err as Error);\n const apolloErr = err as { graphQLErrors?: { message: string }[]; message?: string };\n const errorMessage =\n apolloErr.graphQLErrors?.[0]?.message ??\n apolloErr.message ??\n 'We could not save your review. Please try again.';\n return { data: null, errorMessage };\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n createReview,\n review,\n loading,\n error,\n };\n}\n\n/**\n * Hook to update a review\n */\nexport function useUpdateReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [review, setReview] = useState<ProductReview | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const updateReview = useCallback(\n async (id: string, input: UpdateReviewInput) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ updateReview: ProductReview }>({\n mutation: UpdateReviewDocument,\n variables: { id, input },\n });\n const data = result.data?.updateReview ?? null;\n setReview(data);\n return data;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n updateReview,\n review,\n loading,\n error,\n };\n}\n\n/**\n * Hook to delete a review\n */\nexport function useDeleteReview() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const deleteReview = useCallback(\n async (id: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{ deleteReview: boolean }>({\n mutation: DeleteReviewDocument,\n variables: { id },\n });\n return result.data?.deleteReview ?? false;\n } catch (err) {\n setError(err as Error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n deleteReview,\n loading,\n error,\n };\n}\n\n/**\n * Hook to mark review as helpful\n */\nexport function useMarkReviewHelpful() {\n const { mutate: mutateWithContext } = useStoreGraphQLWithContext();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const markHelpful = useCallback(\n async (id: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await mutateWithContext<{\n markReviewHelpful: { id: string; helpful: number };\n }>({\n mutation: MarkReviewHelpfulDocument,\n variables: { id },\n });\n return result.data?.markReviewHelpful ?? null;\n } catch (err) {\n setError(err as Error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [mutateWithContext]\n );\n\n return {\n markHelpful,\n loading,\n error,\n };\n}\n\n// ============================================================================\n// Entitlement Hooks\n// ============================================================================\n\n/**\n * Hook to fetch current user's entitlements\n */\nexport function useMyEntitlements() {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const PAGE_SIZE = 20;\n const [allEntitlements, setAllEntitlements] = useState<unknown[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [currentOffset, setCurrentOffset] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(\n async (fetchOffset = 0, append = false) => {\n setLoading(true);\n setError(null);\n try {\n const variables = { limit: PAGE_SIZE, offset: fetchOffset };\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: MyEntitlementsDocument,\n variables,\n fetchPolicy: 'network-only',\n })) as { data?: { myEntitlements: unknown[] } })\n : await globalClient.query<{ myEntitlements: unknown[] }>({\n query: MyEntitlementsDocument,\n variables,\n fetchPolicy: 'network-only',\n });\n const fetched = result.data?.myEntitlements ?? [];\n if (append) {\n setAllEntitlements((prev) => [...prev, ...fetched]);\n } else {\n setAllEntitlements(fetched);\n }\n setHasMore(fetched.length === PAGE_SIZE);\n setCurrentOffset(fetchOffset);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [globalClient, hasOrganizationContext, queryWithContext]\n );\n\n useEffect(() => {\n fetchData(0);\n }, [fetchData]);\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n fetchData(currentOffset + PAGE_SIZE, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n return {\n entitlements: allEntitlements,\n hasMore,\n loading,\n error,\n refetch: () => fetchData(0),\n loadMore,\n };\n}\n\n/**\n * Hook to check entitlement for a product\n */\nexport function useCheckEntitlement(productId: string) {\n const client = useStoreClient();\n const [entitlement, setEntitlement] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!productId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<CheckEntitlementData>({\n query: CheckEntitlementDocument,\n variables: { productId },\n fetchPolicy: 'network-only',\n });\n setEntitlement(result.data?.checkEntitlement ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, productId]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n entitlement,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Order Hooks\n// ============================================================================\n\n/**\n * Hook to fetch workspace store orders\n */\nexport function useWorkspaceStoreOrders(\n billingAccountId: string,\n page: number,\n limit: number,\n options?: { status?: string; search?: string }\n) {\n const client = useStoreClient();\n const [orders, setOrders] = useState<unknown[]>([]);\n const [total, setTotal] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n if (!billingAccountId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{\n workspaceStoreOrders: { total: number; orders: unknown[] };\n }>({\n query: WorkspaceStoreOrdersDocument,\n variables: {\n billingAccountId,\n page,\n limit,\n status: options?.status,\n search: options?.search,\n },\n fetchPolicy: 'network-only',\n });\n setOrders(result.data?.workspaceStoreOrders?.orders ?? []);\n setTotal(result.data?.workspaceStoreOrders?.total ?? 0);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [client, billingAccountId, page, limit, options?.status, options?.search]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n orders,\n total,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Publisher Hooks\n// ============================================================================\n\n/**\n * Hook to fetch publisher's products\n */\nexport function useMyPublishedProducts() {\n const client = useStoreClient();\n const [allProducts, setAllProducts] = useState<StoreProduct[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [currentOffset, setCurrentOffset] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const PAGE_SIZE = 20;\n\n const fetchData = useCallback(\n async (fetchOffset = 0, append = false) => {\n setLoading(true);\n setError(null);\n try {\n const result = await client.query<{ publishedProducts: StoreProduct[] }>({\n query: MyPublishedProductsDocument,\n variables: { limit: PAGE_SIZE, offset: fetchOffset },\n fetchPolicy: 'network-only',\n });\n const fetched = result.data?.publishedProducts ?? [];\n if (append) {\n setAllProducts((prev) => [...prev, ...fetched]);\n } else {\n setAllProducts(fetched);\n }\n setHasMore(fetched.length === PAGE_SIZE);\n setCurrentOffset(fetchOffset + fetched.length);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n const loadMore = useCallback(() => {\n if (!hasMore || loading) return;\n void fetchData(currentOffset, true);\n }, [fetchData, hasMore, loading, currentOffset]);\n\n useEffect(() => {\n void fetchData(0, false);\n }, [fetchData]);\n\n return {\n products: allProducts,\n hasMore,\n loading,\n error,\n refetch: () => fetchData(0, false),\n loadMore,\n };\n}\n\n/**\n * Hook to fetch developer earnings\n */\nexport function useDeveloperEarnings(options?: {\n period?: string;\n startDate?: string;\n endDate?: string;\n}) {\n const { query: queryWithContext, hasOrganizationContext } = useStoreGraphQLWithContext();\n const globalClient = useApolloClient();\n const [earnings, setEarnings] = useState<unknown>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = hasOrganizationContext\n ? ((await queryWithContext({\n query: DeveloperEarningsDocument,\n variables: { input: options },\n fetchPolicy: 'network-only',\n })) as { data?: DeveloperEarningsData })\n : await globalClient.query<DeveloperEarningsData>({\n query: DeveloperEarningsDocument,\n variables: { input: options },\n fetchPolicy: 'network-only',\n });\n setEarnings(result.data?.developerEarnings ?? null);\n } catch (err) {\n setError(err as Error);\n } finally {\n setLoading(false);\n }\n }, [globalClient, hasOrganizationContext, options, queryWithContext]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n earnings,\n loading,\n error,\n refetch: fetchData,\n };\n}\n\n// ============================================================================\n// Re-export types for convenience\n// ============================================================================\n\nexport type {\n BrowseStoreInput,\n StoreProductDetailsInput,\n ProductType,\n CreateReviewInput,\n UpdateReviewInput,\n StoreProduct,\n ProductReview,\n ProductCategory,\n SearchSuggestion,\n GroupedProducts,\n BrowseStoreResult,\n};\n"],"mappings":"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"}
|
package/dist/pages/CartPage.js
CHANGED
|
@@ -13,16 +13,16 @@ import { useEventBus as C } from "@burdenoff/fe-libs/shared/events";
|
|
|
13
13
|
import { useQuotaErrorToast as w } from "@burdenoff/fe-libs/shared/hooks";
|
|
14
14
|
//#region src/pages/CartPage.tsx
|
|
15
15
|
var T = () => {
|
|
16
|
-
let T = a(), { basePath: E } = e(), {
|
|
16
|
+
let T = a(), { basePath: E } = e(), { cart: D, cartItems: O, itemCount: k, total: A, updateQuantity: j, removeProduct: M, clearCart: N, createOrder: P } = t(), F = D?.currency || "USD", [I, L] = i(!1), [R, z] = i(null), { t: B } = o(), V = r(), H = C(), { report: U } = w(), W = O.some((e) => e.itemType === "physical"), G = async () => {
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
L(!0), z(null), H.emit("store.cart.checkout_started", {
|
|
19
19
|
cartId: "",
|
|
20
|
-
itemCount:
|
|
21
|
-
total:
|
|
20
|
+
itemCount: k,
|
|
21
|
+
total: A
|
|
22
22
|
});
|
|
23
|
-
let e = await
|
|
24
|
-
total:
|
|
25
|
-
lineItems:
|
|
23
|
+
let e = await P({
|
|
24
|
+
total: A,
|
|
25
|
+
lineItems: O.map((e) => ({
|
|
26
26
|
productId: e.productId,
|
|
27
27
|
name: e.product?.displayName || "Product",
|
|
28
28
|
quantity: e.quantity,
|
|
@@ -33,19 +33,19 @@ var T = () => {
|
|
|
33
33
|
pricingModel: e.product?.pricingModel || "PAID_ONETIME"
|
|
34
34
|
}))
|
|
35
35
|
});
|
|
36
|
-
e?.id ? (
|
|
36
|
+
e?.id ? (H.emit("store.order.placed", {
|
|
37
37
|
orderId: e.id,
|
|
38
|
-
total:
|
|
39
|
-
itemCount:
|
|
40
|
-
}),
|
|
38
|
+
total: A,
|
|
39
|
+
itemCount: k
|
|
40
|
+
}), N().catch(() => {}), T(`/billing/checkout/store/${e.id}`)) : (z(B("pages.cart.failedToCreate", { defaultValue: "Failed to create order. Please try again." })), L(!1));
|
|
41
41
|
} catch (e) {
|
|
42
42
|
if (console.error("Checkout error:", e), y(e)) {
|
|
43
|
-
|
|
43
|
+
U(e), L(!1);
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
z(e instanceof Error ? e.message : V("pages.cart.checkoutError", "An error occurred during checkout")), L(!1);
|
|
47
47
|
}
|
|
48
|
-
},
|
|
48
|
+
}, K = () => {
|
|
49
49
|
T(`${E}/marketplace`);
|
|
50
50
|
};
|
|
51
51
|
return /* @__PURE__ */ v("div", {
|
|
@@ -59,7 +59,7 @@ var T = () => {
|
|
|
59
59
|
children: [/* @__PURE__ */ _("button", {
|
|
60
60
|
type: "button",
|
|
61
61
|
onClick: () => T(-1),
|
|
62
|
-
"aria-label":
|
|
62
|
+
"aria-label": V("common.goBack", "Go back"),
|
|
63
63
|
className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary",
|
|
64
64
|
children: /* @__PURE__ */ _(s, { className: "size-5" })
|
|
65
65
|
}), /* @__PURE__ */ v("div", {
|
|
@@ -68,19 +68,19 @@ var T = () => {
|
|
|
68
68
|
/* @__PURE__ */ _(f, { className: "size-6 text-text-primary" }),
|
|
69
69
|
/* @__PURE__ */ _("h1", {
|
|
70
70
|
className: "text-xl font-bold text-text-primary",
|
|
71
|
-
children:
|
|
71
|
+
children: B("cart.title", { defaultValue: "Shopping Cart" })
|
|
72
72
|
}),
|
|
73
|
-
|
|
73
|
+
k > 0 && /* @__PURE__ */ v("span", {
|
|
74
74
|
className: "rounded-full bg-action-primary-bg px-2.5 py-0.5 text-sm font-medium text-action-primary-text",
|
|
75
75
|
children: [
|
|
76
|
-
|
|
76
|
+
k,
|
|
77
77
|
" ",
|
|
78
|
-
|
|
79
|
-
defaultValue: `${
|
|
80
|
-
count:
|
|
81
|
-
}) :
|
|
82
|
-
defaultValue: `${
|
|
83
|
-
count:
|
|
78
|
+
k === 1 ? B("pages.cart.item", {
|
|
79
|
+
defaultValue: `${k} item`,
|
|
80
|
+
count: k
|
|
81
|
+
}) : B("pages.cart.items", {
|
|
82
|
+
defaultValue: `${k} items`,
|
|
83
|
+
count: k
|
|
84
84
|
})
|
|
85
85
|
]
|
|
86
86
|
})
|
|
@@ -90,40 +90,40 @@ var T = () => {
|
|
|
90
90
|
})
|
|
91
91
|
}), /* @__PURE__ */ _("main", {
|
|
92
92
|
className: "mx-auto max-w-6xl p-6",
|
|
93
|
-
children:
|
|
93
|
+
children: O.length === 0 ? /* @__PURE__ */ _(x, {
|
|
94
94
|
illustration: "empty-generic",
|
|
95
|
-
title:
|
|
96
|
-
description:
|
|
95
|
+
title: B("cart.empty", { defaultValue: "Your cart is empty" }),
|
|
96
|
+
description: B("pages.cart.emptyDescription", { defaultValue: "Looks like you have not added any apps or products to your cart yet. Start exploring the marketplace to find something you will love!" }),
|
|
97
97
|
action: /* @__PURE__ */ v("button", {
|
|
98
98
|
type: "button",
|
|
99
|
-
onClick:
|
|
99
|
+
onClick: K,
|
|
100
100
|
className: "cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90",
|
|
101
|
-
children: [/* @__PURE__ */ _(d, { className: "size-5" }),
|
|
101
|
+
children: [/* @__PURE__ */ _(d, { className: "size-5" }), B("pages.cart.browseMarketplace", { defaultValue: "Browse Marketplace" })]
|
|
102
102
|
})
|
|
103
103
|
}) : /* @__PURE__ */ v("div", {
|
|
104
104
|
className: "mx-auto max-w-3xl",
|
|
105
105
|
children: [/* @__PURE__ */ _(S, {
|
|
106
106
|
className: "mb-6",
|
|
107
|
-
children:
|
|
107
|
+
children: V("pages.cart.purpose", "Review the apps and products you're about to buy, adjust quantities for physical items, and confirm the total before checkout. Nothing is charged until you proceed — once you do, your purchases become licenses you can install into a workspace.")
|
|
108
108
|
}), /* @__PURE__ */ v("div", { children: [
|
|
109
109
|
/* @__PURE__ */ v("div", {
|
|
110
110
|
className: "mb-4 flex items-center justify-between",
|
|
111
111
|
children: [/* @__PURE__ */ _("h2", {
|
|
112
112
|
className: "text-lg font-semibold text-text-primary",
|
|
113
|
-
children:
|
|
114
|
-
defaultValue: `Cart Items (${
|
|
115
|
-
count:
|
|
113
|
+
children: B("pages.cart.cartItems", {
|
|
114
|
+
defaultValue: `Cart Items (${k})`,
|
|
115
|
+
count: k
|
|
116
116
|
})
|
|
117
117
|
}), /* @__PURE__ */ v("button", {
|
|
118
118
|
type: "button",
|
|
119
|
-
onClick:
|
|
119
|
+
onClick: N,
|
|
120
120
|
className: "cursor-pointer flex items-center gap-1 text-sm text-text-muted transition-colors hover:text-status-error-text",
|
|
121
|
-
children: [/* @__PURE__ */ _(m, { className: "size-4" }),
|
|
121
|
+
children: [/* @__PURE__ */ _(m, { className: "size-4" }), B("cart.clearCart", { defaultValue: "Clear Cart" })]
|
|
122
122
|
})]
|
|
123
123
|
}),
|
|
124
124
|
/* @__PURE__ */ _("ul", {
|
|
125
125
|
className: "space-y-4",
|
|
126
|
-
children:
|
|
126
|
+
children: O.map((e) => /* @__PURE__ */ v("li", {
|
|
127
127
|
className: "flex gap-4 rounded-xl border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]",
|
|
128
128
|
children: [/* @__PURE__ */ _("div", {
|
|
129
129
|
className: "size-24 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken",
|
|
@@ -155,10 +155,10 @@ var T = () => {
|
|
|
155
155
|
})
|
|
156
156
|
] }), /* @__PURE__ */ _("button", {
|
|
157
157
|
type: "button",
|
|
158
|
-
onClick: () =>
|
|
158
|
+
onClick: () => M(e.id),
|
|
159
159
|
className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-status-error-bg-subtle/10 hover:text-status-error-text",
|
|
160
|
-
"aria-label":
|
|
161
|
-
title:
|
|
160
|
+
"aria-label": V("cart.removeItem", "Remove {{name}} from cart", { name: e.product?.displayName ?? V("common.item", "item") }),
|
|
161
|
+
title: V("cart.removeItemTitle", "Remove item"),
|
|
162
162
|
children: /* @__PURE__ */ _(m, { className: "size-5" })
|
|
163
163
|
})]
|
|
164
164
|
}),
|
|
@@ -166,10 +166,10 @@ var T = () => {
|
|
|
166
166
|
className: "mt-2 flex items-center gap-2",
|
|
167
167
|
children: [/* @__PURE__ */ _("span", {
|
|
168
168
|
className: "inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-muted",
|
|
169
|
-
children: e.itemType === "digital" ? /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(h, { className: "size-3" }),
|
|
169
|
+
children: e.itemType === "digital" ? /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(h, { className: "size-3" }), B("pages.cart.digital", { defaultValue: "Digital" })] }) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(p, { className: "size-3" }), B("pages.cart.physical", { defaultValue: "Physical" })] })
|
|
170
170
|
}), e.product?.pricingModel === "SUBSCRIPTION" && /* @__PURE__ */ _("span", {
|
|
171
171
|
className: "inline-flex items-center gap-1 rounded-full bg-bg-accent/10 px-2 py-0.5 text-xs font-medium text-text-link",
|
|
172
|
-
children:
|
|
172
|
+
children: B("store.pricingModels.subscription", { defaultValue: "Subscription" })
|
|
173
173
|
})]
|
|
174
174
|
}),
|
|
175
175
|
/* @__PURE__ */ v("div", {
|
|
@@ -178,13 +178,13 @@ var T = () => {
|
|
|
178
178
|
className: "flex items-center gap-3",
|
|
179
179
|
children: [/* @__PURE__ */ _("span", {
|
|
180
180
|
className: "text-sm text-text-muted",
|
|
181
|
-
children:
|
|
181
|
+
children: V("pages.cart.qty", "Qty:")
|
|
182
182
|
}), /* @__PURE__ */ v("div", {
|
|
183
183
|
className: "flex items-center rounded-lg border border-border-default",
|
|
184
184
|
children: [
|
|
185
185
|
/* @__PURE__ */ _("button", {
|
|
186
186
|
type: "button",
|
|
187
|
-
onClick: () =>
|
|
187
|
+
onClick: () => j(e.id, e.quantity - 1),
|
|
188
188
|
className: "cursor-pointer rounded-l-lg p-2 transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50",
|
|
189
189
|
disabled: e.quantity <= 1,
|
|
190
190
|
children: /* @__PURE__ */ _(l, { className: "size-4" })
|
|
@@ -195,7 +195,7 @@ var T = () => {
|
|
|
195
195
|
}),
|
|
196
196
|
/* @__PURE__ */ _("button", {
|
|
197
197
|
type: "button",
|
|
198
|
-
onClick: () =>
|
|
198
|
+
onClick: () => j(e.id, e.quantity + 1),
|
|
199
199
|
className: "cursor-pointer rounded-r-lg p-2 transition-colors hover:bg-bg-sunken",
|
|
200
200
|
children: /* @__PURE__ */ _(u, { className: "size-4" })
|
|
201
201
|
})
|
|
@@ -203,15 +203,15 @@ var T = () => {
|
|
|
203
203
|
})]
|
|
204
204
|
}) : /* @__PURE__ */ _("div", {
|
|
205
205
|
className: "text-sm text-text-muted",
|
|
206
|
-
children:
|
|
206
|
+
children: B("pages.cart.singleLicense", { defaultValue: "Single license" })
|
|
207
207
|
}), /* @__PURE__ */ v("div", {
|
|
208
208
|
className: "text-right",
|
|
209
209
|
children: [/* @__PURE__ */ _("p", {
|
|
210
210
|
className: "text-lg font-bold text-text-primary",
|
|
211
|
-
children: n(e.totalPrice)
|
|
211
|
+
children: n(e.totalPrice, F)
|
|
212
212
|
}), e.quantity > 1 && e.itemType === "physical" && /* @__PURE__ */ _("p", {
|
|
213
213
|
className: "text-xs text-text-muted",
|
|
214
|
-
children:
|
|
214
|
+
children: V("pages.cart.each", "{{price}} each", { price: n(e.unitPrice, F) })
|
|
215
215
|
})]
|
|
216
216
|
})]
|
|
217
217
|
})
|
|
@@ -222,38 +222,38 @@ var T = () => {
|
|
|
222
222
|
/* @__PURE__ */ v(b, {
|
|
223
223
|
className: "mt-8",
|
|
224
224
|
children: [
|
|
225
|
-
|
|
225
|
+
R && /* @__PURE__ */ _("div", {
|
|
226
226
|
role: "alert",
|
|
227
227
|
className: "mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
228
|
-
children:
|
|
228
|
+
children: R
|
|
229
229
|
}),
|
|
230
230
|
/* @__PURE__ */ _("p", {
|
|
231
231
|
className: "mb-3 text-xs text-text-muted",
|
|
232
|
-
children:
|
|
232
|
+
children: W ? V("pages.cart.physicalNotice", "Physical orders ship to your delivery address. Returns and refunds are handled by the seller per their store policy.") : V("pages.cart.digitalNotice", "All digital app purchases are final and non-refundable. Once an order is completed it cannot be cancelled or reversed.")
|
|
233
233
|
}),
|
|
234
234
|
/* @__PURE__ */ v("div", {
|
|
235
235
|
className: "flex items-center justify-between",
|
|
236
236
|
children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
237
237
|
className: "text-sm text-text-muted",
|
|
238
|
-
children:
|
|
238
|
+
children: V("cart.total", "Total")
|
|
239
239
|
}), /* @__PURE__ */ _("p", {
|
|
240
240
|
className: "text-2xl font-bold tabular-nums text-text-primary",
|
|
241
|
-
children: n(
|
|
241
|
+
children: n(A, F)
|
|
242
242
|
})] }), /* @__PURE__ */ _("button", {
|
|
243
243
|
type: "button",
|
|
244
|
-
onClick:
|
|
245
|
-
disabled:
|
|
244
|
+
onClick: G,
|
|
245
|
+
disabled: I,
|
|
246
246
|
className: "flex cursor-pointer items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-70",
|
|
247
|
-
children:
|
|
247
|
+
children: I ? /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(c, { className: "size-4 animate-spin" }), B("pages.cart.processing", { defaultValue: "Processing..." })] }) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(h, { className: "size-4" }), B("pages.cart.proceedToCheckout", { defaultValue: "Proceed to Checkout" })] })
|
|
248
248
|
})]
|
|
249
249
|
})
|
|
250
250
|
]
|
|
251
251
|
}),
|
|
252
252
|
/* @__PURE__ */ v("button", {
|
|
253
253
|
type: "button",
|
|
254
|
-
onClick:
|
|
254
|
+
onClick: K,
|
|
255
255
|
className: "cursor-pointer mt-4 flex items-center gap-2 text-sm font-medium text-text-link hover:underline",
|
|
256
|
-
children: [/* @__PURE__ */ _(s, { className: "size-4" }),
|
|
256
|
+
children: [/* @__PURE__ */ _(s, { className: "size-4" }), B("cart.continueShopping", { defaultValue: "Continue Shopping" })]
|
|
257
257
|
})
|
|
258
258
|
] })]
|
|
259
259
|
})
|