@burdenoff/microfe-store 2026.510.113

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.
Files changed (141) hide show
  1. package/README.md +217 -0
  2. package/dist/StoreAdminRoot.d.ts +22 -0
  3. package/dist/StoreAdminRoot.js +23 -0
  4. package/dist/StoreAdminRoot.js.map +1 -0
  5. package/dist/StoreAdminRoutes.d.ts +9 -0
  6. package/dist/StoreAdminRoutes.js +69 -0
  7. package/dist/StoreAdminRoutes.js.map +1 -0
  8. package/dist/StoreRoot.d.ts +31 -0
  9. package/dist/StoreRoot.js +139 -0
  10. package/dist/StoreRoot.js.map +1 -0
  11. package/dist/StoreRoutes.d.ts +12 -0
  12. package/dist/StoreRoutes.js +285 -0
  13. package/dist/StoreRoutes.js.map +1 -0
  14. package/dist/components/InstallAppModal.d.ts +26 -0
  15. package/dist/components/InstallAppModal.js +287 -0
  16. package/dist/components/InstallAppModal.js.map +1 -0
  17. package/dist/components/RouteGuards.d.ts +17 -0
  18. package/dist/components/RouteGuards.js +26 -0
  19. package/dist/components/RouteGuards.js.map +1 -0
  20. package/dist/components/cart/CartDrawer.d.ts +35 -0
  21. package/dist/components/cart/CartDrawer.js +162 -0
  22. package/dist/components/cart/CartDrawer.js.map +1 -0
  23. package/dist/components/index.d.ts +9 -0
  24. package/dist/components/index.js +3 -0
  25. package/dist/components/marketplace/ProductCard.d.ts +18 -0
  26. package/dist/components/marketplace/ProductCard.js +2 -0
  27. package/dist/dev/main.d.ts +1 -0
  28. package/dist/generated/global-operations.d.ts +2012 -0
  29. package/dist/generated/global-operations.js +1444 -0
  30. package/dist/generated/global-operations.js.map +1 -0
  31. package/dist/generated/global-types.d.ts +20856 -0
  32. package/dist/generated/global-types.js +14 -0
  33. package/dist/generated/global-types.js.map +1 -0
  34. package/dist/generated/wspace-operations.d.ts +1 -0
  35. package/dist/generated/wspace-types.d.ts +53362 -0
  36. package/dist/hooks/index.d.ts +12 -0
  37. package/dist/hooks/useBackendCart.d.ts +73 -0
  38. package/dist/hooks/useBackendCart.js +171 -0
  39. package/dist/hooks/useBackendCart.js.map +1 -0
  40. package/dist/hooks/useCart.d.ts +62 -0
  41. package/dist/hooks/useCart.js +90 -0
  42. package/dist/hooks/useCart.js.map +1 -0
  43. package/dist/hooks/useInstallations.d.ts +43 -0
  44. package/dist/hooks/useInstallations.js +140 -0
  45. package/dist/hooks/useInstallations.js.map +1 -0
  46. package/dist/hooks/useOrders.d.ts +40 -0
  47. package/dist/hooks/useOrders.js +73 -0
  48. package/dist/hooks/useOrders.js.map +1 -0
  49. package/dist/hooks/useProductSearch.d.ts +22 -0
  50. package/dist/hooks/useProductSearch.js +59 -0
  51. package/dist/hooks/useProductSearch.js.map +1 -0
  52. package/dist/hooks/useStoreGraphQL.d.ts +475 -0
  53. package/dist/hooks/useStoreGraphQL.js +751 -0
  54. package/dist/hooks/useStoreGraphQL.js.map +1 -0
  55. package/dist/hooks/useStoreGraphQLWithContext.d.ts +48 -0
  56. package/dist/hooks/useStoreGraphQLWithContext.js +39 -0
  57. package/dist/hooks/useStoreGraphQLWithContext.js.map +1 -0
  58. package/dist/hooks/useStorePermissions.d.ts +63 -0
  59. package/dist/hooks/useStorePermissions.js +88 -0
  60. package/dist/hooks/useStorePermissions.js.map +1 -0
  61. package/dist/index.d.ts +44 -0
  62. package/dist/index.js +13 -0
  63. package/dist/pages/AdminDashboardPage.d.ts +3 -0
  64. package/dist/pages/AdminDashboardPage.js +491 -0
  65. package/dist/pages/AdminDashboardPage.js.map +1 -0
  66. package/dist/pages/AdminReviewModerationPage.d.ts +3 -0
  67. package/dist/pages/AdminReviewModerationPage.js +247 -0
  68. package/dist/pages/AdminReviewModerationPage.js.map +1 -0
  69. package/dist/pages/AdminStoresPage.d.ts +3 -0
  70. package/dist/pages/AdminStoresPage.js +442 -0
  71. package/dist/pages/AdminStoresPage.js.map +1 -0
  72. package/dist/pages/AdminSubmissionsQueuePage.d.ts +3 -0
  73. package/dist/pages/AdminSubmissionsQueuePage.js +387 -0
  74. package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -0
  75. package/dist/pages/AppDetailPage.d.ts +3 -0
  76. package/dist/pages/AppDetailPage.js +166 -0
  77. package/dist/pages/AppDetailPage.js.map +1 -0
  78. package/dist/pages/AppSettingsPage.d.ts +3 -0
  79. package/dist/pages/AppSettingsPage.js +100 -0
  80. package/dist/pages/AppSettingsPage.js.map +1 -0
  81. package/dist/pages/CartPage.d.ts +8 -0
  82. package/dist/pages/CartPage.js +259 -0
  83. package/dist/pages/CartPage.js.map +1 -0
  84. package/dist/pages/InstalledAppsPage.d.ts +8 -0
  85. package/dist/pages/InstalledAppsPage.js +290 -0
  86. package/dist/pages/InstalledAppsPage.js.map +1 -0
  87. package/dist/pages/MarketplaceHomePage.d.ts +3 -0
  88. package/dist/pages/MarketplaceHomePage.js +1118 -0
  89. package/dist/pages/MarketplaceHomePage.js.map +1 -0
  90. package/dist/pages/MyLicensesPage.d.ts +3 -0
  91. package/dist/pages/MyLicensesPage.js +146 -0
  92. package/dist/pages/MyLicensesPage.js.map +1 -0
  93. package/dist/pages/OrderConfirmationPage.d.ts +3 -0
  94. package/dist/pages/OrderConfirmationPage.js +178 -0
  95. package/dist/pages/OrderConfirmationPage.js.map +1 -0
  96. package/dist/pages/OrdersPage.d.ts +8 -0
  97. package/dist/pages/OrdersPage.js +358 -0
  98. package/dist/pages/OrdersPage.js.map +1 -0
  99. package/dist/pages/ProductCategoryPage.d.ts +3 -0
  100. package/dist/pages/ProductCategoryPage.js +83 -0
  101. package/dist/pages/ProductCategoryPage.js.map +1 -0
  102. package/dist/pages/ProductDetailPage.d.ts +8 -0
  103. package/dist/pages/ProductDetailPage.js +1205 -0
  104. package/dist/pages/ProductDetailPage.js.map +1 -0
  105. package/dist/pages/ProductReviewsPage.d.ts +3 -0
  106. package/dist/pages/ProductReviewsPage.js +86 -0
  107. package/dist/pages/ProductReviewsPage.js.map +1 -0
  108. package/dist/pages/PublisherDashboardPage.d.ts +3 -0
  109. package/dist/pages/PublisherDashboardPage.js +154 -0
  110. package/dist/pages/PublisherDashboardPage.js.map +1 -0
  111. package/dist/pages/PublisherRevenuePage.d.ts +3 -0
  112. package/dist/pages/PublisherRevenuePage.js +138 -0
  113. package/dist/pages/PublisherRevenuePage.js.map +1 -0
  114. package/dist/pages/PublisherSubmissionsPage.d.ts +3 -0
  115. package/dist/pages/PublisherSubmissionsPage.js +174 -0
  116. package/dist/pages/PublisherSubmissionsPage.js.map +1 -0
  117. package/dist/pages/PublisherSubmitPage.d.ts +3 -0
  118. package/dist/pages/PublisherSubmitPage.js +224 -0
  119. package/dist/pages/PublisherSubmitPage.js.map +1 -0
  120. package/dist/pages/SearchResultsPage.d.ts +3 -0
  121. package/dist/pages/SearchResultsPage.js +125 -0
  122. package/dist/pages/SearchResultsPage.js.map +1 -0
  123. package/dist/pages/StoresPage.d.ts +3 -0
  124. package/dist/pages/StoresPage.js +154 -0
  125. package/dist/pages/StoresPage.js.map +1 -0
  126. package/dist/providers/StoreProvider.d.ts +38 -0
  127. package/dist/providers/StoreProvider.js +51 -0
  128. package/dist/providers/StoreProvider.js.map +1 -0
  129. package/dist/store/storeStore.d.ts +69 -0
  130. package/dist/store/storeStore.js +68 -0
  131. package/dist/store/storeStore.js.map +1 -0
  132. package/dist/translations/en.d.ts +518 -0
  133. package/dist/translations/en.js +514 -0
  134. package/dist/translations/en.js.map +1 -0
  135. package/dist/types/index.d.ts +575 -0
  136. package/dist/utils/index.d.ts +67 -0
  137. package/dist/utils/index.js +114 -0
  138. package/dist/utils/index.js.map +1 -0
  139. package/dist/utils/nativeBridge.d.ts +2 -0
  140. package/dist/utils/nativeBridge.js +2 -0
  141. package/package.json +105 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstallAppModal.js","names":[],"sources":["../../src/components/InstallAppModal.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState, useEffect, useCallback } from 'react';\nimport { X, Loader2, Building2, User, CheckCircle, AlertCircle, Info } from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { useStore } from '../providers/StoreProvider';\n\n// Local type definitions for workspace operations\ninterface Workspace {\n id: string;\n name: string;\n slug: string;\n type?: string;\n status?: string;\n organizationId?: string;\n}\n\ninterface WorkspaceList {\n items: Workspace[];\n total: number;\n}\n\ninterface InstallWorkspaceAppsResult {\n successCount: number;\n failedCount: number;\n results: Array<{\n success: boolean;\n workspaceId: string;\n app?: unknown;\n error?: string;\n }>;\n}\n\n// String queries for graphqlFetch\nconst MY_WORKSPACES_STRING = `query MyWorkspaces { myWorkspaces { items { id name slug type status organizationId } total } }`;\nconst INSTALL_WORKSPACE_APPS_STRING = `mutation InstallWorkspaceApps($workspaceIds: [ID!]!, $input: InstallWorkspaceAppInput!) { installWorkspaceApps(workspaceIds: $workspaceIds, input: $input) { successCount failedCount results { success workspaceId error } } }`;\nconst RECORD_APP_INSTALLATION_STRING = `mutation RecordAppInstallation($input: RecordAppInstallationInput!) { recordAppInstallation(input: $input) { id status workspaceId version } }`;\nconst INSTALL_PURCHASED_APP_STRING = `mutation InstallPurchasedApp($orderId: ID, $productId: String!, $workspaceId: String!) { installPurchasedApp(orderId: $orderId, productId: $productId, workspaceId: $workspaceId) { success alreadyInstalled installation { id productId workspaceId status version } error message } }`;\nconst CREATE_PRODUCT_ENTITLEMENT_STRING = `mutation CreateProductEntitlement($input: CreateProductEntitlementInput!) { createProductEntitlement(input: $input) { id status productId workspaceId } }`;\nconst STORE_DISTRIBUTED_TYPES = new Set([\n 'VIBEMODULE',\n 'NODE',\n 'CONSOLE',\n 'DASHBOARD',\n 'PARSER',\n 'DATASINK',\n]);\n\nexport interface AppInfo {\n id: string;\n name: string;\n slug?: string;\n icon?: string;\n type?: string;\n version?: string;\n}\n\ninterface InstallAppModalProps {\n isOpen: boolean;\n onClose: () => void;\n app: AppInfo;\n orderId?: string | null; // For purchased apps from orders page\n purchaseState?: 'free' | 'purchased';\n onInstallSuccess?: (workspaceId: string, workspaceName: string) => void;\n onInstallError?: (error: Error) => void;\n}\n\ninterface UseWorkspacesResult {\n workspaces: Workspace[];\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n// NOTE: Inline Apollo clients removed. All GraphQL calls now use graphqlFetch\n// from fe-libs which automatically resolves gateway URLs and injects auth + locale headers.\n\n/**\n * Hook to fetch user's workspaces using graphqlFetch from fe-libs\n */\nfunction useWorkspaces(skip: boolean): UseWorkspacesResult {\n const { authToken } = useStore();\n const [workspaces, setWorkspaces] = useState<Workspace[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchWorkspaces = useCallback(async () => {\n if (skip) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await graphqlFetch<{ myWorkspaces: WorkspaceList }>({\n gateway: 'global',\n query: MY_WORKSPACES_STRING,\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'GraphQL error');\n }\n\n setWorkspaces(result.data?.myWorkspaces?.items || []);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch workspaces'));\n } finally {\n setLoading(false);\n }\n }, [authToken, skip]);\n\n useEffect(() => {\n fetchWorkspaces();\n }, [fetchWorkspaces]);\n\n return {\n workspaces,\n loading,\n error,\n refetch: fetchWorkspaces,\n };\n}\n\n/**\n * InstallAppModal component\n *\n * Modal for selecting a workspace to install an app into\n */\nexport const InstallAppModal: FC<InstallAppModalProps> = ({\n isOpen,\n onClose,\n app,\n orderId,\n purchaseState = 'free',\n onInstallSuccess,\n onInstallError,\n}) => {\n const { authToken, user } = useStore();\n const [selectedWorkspace, setSelectedWorkspace] = useState<string | null>(null);\n const [installing, setInstalling] = useState(false);\n const [installError, setInstallError] = useState<string | null>(null);\n const [installInfo, setInstallInfo] = useState<string | null>(null);\n\n const { workspaces, loading, error } = useWorkspaces(!isOpen);\n\n // Reset selection when modal opens\n useEffect(() => {\n if (isOpen) {\n setSelectedWorkspace(null);\n setInstallError(null);\n setInstallInfo(null);\n }\n }, [isOpen]);\n\n // Filter workspaces by status (only show active)\n const filteredWorkspaces = workspaces.filter((ws) => ws.status === 'ACTIVE');\n\n /**\n * Install purchased app via Store Service (NEW FLOW)\n * Used when installing from orders page or any already-purchased product\n */\n const handleInstallFromStore = async () => {\n if (!selectedWorkspace) return;\n\n const workspace = filteredWorkspaces.find((ws) => ws.id === selectedWorkspace);\n if (!workspace) return;\n const purchasedBy = user?.id;\n\n setInstalling(true);\n setInstallError(null);\n setInstallInfo(null);\n\n try {\n if (!orderId && purchaseState !== 'purchased') {\n if (!purchasedBy) {\n throw new Error('Unable to identify the current user for license creation');\n }\n\n await graphqlFetch({\n gateway: 'global',\n query: CREATE_PRODUCT_ENTITLEMENT_STRING,\n variables: {\n input: {\n productId: app.id,\n purchasedBy,\n workspaceId: workspace.id,\n metadata: {\n source: 'store-ui',\n productType: app.type,\n },\n },\n },\n authToken: authToken || undefined,\n });\n }\n\n // Call Store Service to install the purchased app\n const result = await graphqlFetch<{\n installPurchasedApp: {\n success: boolean;\n alreadyInstalled?: boolean;\n installation?: {\n id: string;\n productId: string;\n workspaceId: string;\n status: string;\n version: string;\n };\n error?: string;\n message?: string;\n };\n }>({\n gateway: 'global', // Store Service\n query: INSTALL_PURCHASED_APP_STRING,\n variables: {\n orderId: orderId ?? null,\n productId: app.id,\n workspaceId: workspace.id,\n },\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Installation failed');\n }\n\n const installResult = result.data?.installPurchasedApp;\n\n if (installResult?.success) {\n if (installResult.alreadyInstalled) {\n setInstallInfo(installResult.message || 'Already installed on this workspace');\n } else {\n onInstallSuccess?.(workspace.id, workspace.name);\n onClose();\n }\n } else {\n const errorMsg = installResult?.error || 'Installation failed';\n setInstallError(errorMsg);\n onInstallError?.(new Error(errorMsg));\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'Installation failed';\n setInstallError(errorMsg);\n onInstallError?.(new Error(errorMsg));\n } finally {\n setInstalling(false);\n }\n };\n\n /**\n * Install app via Workspace Service (LEGACY FLOW)\n * Used for free apps or when installing without order\n */\n const handleInstallViaWorkspace = async () => {\n if (!selectedWorkspace) return;\n\n const workspace = filteredWorkspaces.find((ws) => ws.id === selectedWorkspace);\n if (!workspace) return;\n\n setInstalling(true);\n setInstallError(null);\n setInstallInfo(null);\n\n try {\n // Step 1: Install to workspace service via graphqlFetch\n const installVars = {\n workspaceIds: [workspace.id],\n input: {\n appName: app.slug || app.name.toLowerCase().replace(/\\s+/g, '-'),\n displayName: app.name,\n version: app.version || '1.0.0',\n type: app.type || 'app',\n manifest: {\n productId: app.id,\n icon: app.icon,\n },\n },\n };\n\n const result = await graphqlFetch<{\n installWorkspaceApps: InstallWorkspaceAppsResult;\n }>({\n gateway: 'workspace',\n query: INSTALL_WORKSPACE_APPS_STRING,\n variables: installVars,\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Installation failed');\n }\n\n const installResult = result.data?.installWorkspaceApps;\n if (installResult?.successCount && installResult.successCount > 0) {\n // Step 2: Record installation in store service (for tracking)\n try {\n await graphqlFetch({\n gateway: 'global',\n query: RECORD_APP_INSTALLATION_STRING,\n variables: {\n input: {\n productId: app.id,\n workspaceId: workspace.id,\n workspaceName: workspace.name,\n workspaceType: workspace.type,\n organizationId: workspace.organizationId,\n version: app.version || '1.0.0',\n manifest: {\n productId: app.id,\n icon: app.icon,\n slug: app.slug,\n type: app.type,\n },\n },\n },\n authToken: authToken || undefined,\n });\n } catch (recordErr) {\n // Log but don't fail - workspace installation succeeded\n console.warn('Failed to record installation in store:', recordErr);\n }\n\n onInstallSuccess?.(workspace.id, workspace.name);\n onClose();\n } else {\n const errorMsg = installResult?.results?.[0]?.error || 'Installation failed';\n setInstallError(errorMsg);\n onInstallError?.(new Error(errorMsg));\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'Installation failed';\n setInstallError(errorMsg);\n onInstallError?.(new Error(errorMsg));\n } finally {\n setInstalling(false);\n }\n };\n\n /**\n * Main install handler - routes to appropriate install function\n */\n const handleInstall = async () => {\n const appType = app.type?.toUpperCase() ?? '';\n\n if (purchaseState === 'purchased' || orderId || STORE_DISTRIBUTED_TYPES.has(appType)) {\n // Purchased products install through the store service.\n await handleInstallFromStore();\n } else {\n // Free products install through the workspace service.\n await handleInstallViaWorkspace();\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-bg-overlay/50 backdrop-blur-sm\" onClick={onClose} />\n\n {/* Modal */}\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"install-app-modal-title\"\n className=\"relative z-10 mx-4 w-full max-w-lg rounded-2xl border border-border-default bg-bg-surface shadow-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-border-default px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n {app.icon ? (\n <img src={app.icon} alt={app.name} className=\"h-10 w-10 rounded-lg object-cover\" />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-lg font-bold text-text-muted\">\n {app.name.charAt(0)}\n </div>\n )}\n <div>\n <h2 id=\"install-app-modal-title\" className=\"text-lg font-semibold text-text-primary\">\n Install App\n </h2>\n <p className=\"text-sm text-text-muted\">{app.name}</p>\n </div>\n </div>\n <button\n onClick={onClose}\n aria-label=\"Close install dialog\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"px-6 py-4\">\n <p className=\"mb-4 text-text-secondary\">\n Select the workspace where you want to install this app:\n </p>\n\n {/* Workspace List */}\n <div className=\"max-h-72 overflow-y-auto rounded-lg border border-border-default\">\n {loading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-muted\" />\n </div>\n ) : error ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle className=\"mb-2 h-8 w-8 text-status-error-text\" />\n <p className=\"text-sm text-status-error-text\">Failed to load workspaces</p>\n <p className=\"text-xs text-text-muted mt-1\">{error.message}</p>\n </div>\n ) : filteredWorkspaces.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Building2 className=\"mb-2 h-8 w-8 text-text-muted\" />\n <p className=\"text-sm text-text-muted\">No workspaces available</p>\n </div>\n ) : (\n <div className=\"divide-y divide-border-default\">\n {filteredWorkspaces.map((workspace) => (\n <button\n key={workspace.id}\n onClick={() => setSelectedWorkspace(workspace.id)}\n className={`w-full cursor-pointer flex items-center gap-3 px-4 py-3 text-left transition-colors ${\n selectedWorkspace === workspace.id\n ? 'bg-action-primary-bg/10'\n : 'transition-colors hover:bg-bg-sunken'\n }`}\n >\n {/* Workspace Icon */}\n <div\n className={`flex h-10 w-10 items-center justify-center rounded-lg ${\n workspace.type === 'user'\n ? 'bg-status-info-bg-subtle text-status-info-text'\n : 'bg-action-primary-bg/10 text-text-link'\n }`}\n >\n {workspace.type === 'user' ? (\n <User className=\"h-5 w-5\" />\n ) : (\n <Building2 className=\"h-5 w-5\" />\n )}\n </div>\n\n {/* Workspace Info */}\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">{workspace.name}</p>\n <p className=\"text-xs text-text-muted\">\n {workspace.type === 'user' ? 'Personal' : 'Team'} workspace\n </p>\n </div>\n\n {/* Selection Indicator */}\n {selectedWorkspace === workspace.id && (\n <CheckCircle className=\"h-5 w-5 flex-shrink-0 text-action-primary-bg\" />\n )}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"border-t border-border-default px-6 py-4\">\n {/* Already-installed info */}\n {installInfo && (\n <div className=\"mb-3 flex items-center gap-2 rounded-lg bg-status-info-bg-subtle px-3 py-2 text-sm text-status-info-text\">\n <Info className=\"h-4 w-4 flex-shrink-0\" />\n <span>{installInfo}</span>\n </div>\n )}\n {/* Error message */}\n {installError && (\n <div className=\"mb-3 flex items-center gap-2 rounded-lg bg-status-error-bg-subtle/10 px-3 py-2 text-sm text-status-error-text\">\n <AlertCircle className=\"h-4 w-4 flex-shrink-0\" />\n <span>{installError}</span>\n </div>\n )}\n <div className=\"flex items-center justify-end gap-3\">\n <button\n onClick={onClose}\n disabled={installing}\n className=\"cursor-pointer rounded-lg border border-border-default px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n onClick={handleInstall}\n disabled={!selectedWorkspace || installing}\n className=\"cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-2\"\n >\n {installing ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Installing...\n </>\n ) : (\n 'Install App'\n )}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { FC, ReactNode } from 'react';
2
+
3
+ /**
4
+ * Loading fallback for lazy-loaded route pages
5
+ */
6
+ export declare const PageLoadingFallback: FC;
7
+ /**
8
+ * Access denied page shown when user lacks permission for a route
9
+ */
10
+ export declare const AccessDenied: FC;
11
+ /**
12
+ * Route-level permission guard that shows AccessDenied when permission check fails
13
+ */
14
+ export declare const PermissionGuard: FC<{
15
+ allowed: boolean;
16
+ children: ReactNode;
17
+ }>;
@@ -0,0 +1,26 @@
1
+ import { useI18n as e } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
2
+ import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
3
+ //#region src/components/RouteGuards.tsx
4
+ var i = () => /* @__PURE__ */ n("div", {
5
+ className: "flex h-full items-center justify-center",
6
+ children: /* @__PURE__ */ n("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-border-default border-t-accent-primary" })
7
+ }), a = () => {
8
+ let { t } = e();
9
+ return /* @__PURE__ */ n("div", {
10
+ className: "flex items-center justify-center min-h-[400px] animate-in fade-in duration-300",
11
+ children: /* @__PURE__ */ r("div", {
12
+ className: "text-center",
13
+ children: [/* @__PURE__ */ n("h1", {
14
+ className: "text-2xl font-semibold text-foreground mb-2",
15
+ children: t("common.accessDenied", { defaultValue: "Access Denied" })
16
+ }), /* @__PURE__ */ n("p", {
17
+ className: "text-muted-foreground",
18
+ children: t("common.accessDeniedDescription", { defaultValue: "You do not have permission to access this section." })
19
+ })]
20
+ })
21
+ });
22
+ }, o = ({ allowed: e, children: r }) => e ? /* @__PURE__ */ n(t, { children: r }) : /* @__PURE__ */ n(a, {});
23
+ //#endregion
24
+ export { a as AccessDenied, i as PageLoadingFallback, o as PermissionGuard };
25
+
26
+ //# sourceMappingURL=RouteGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteGuards.js","names":[],"sources":["../../src/components/RouteGuards.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n/**\n * Loading fallback for lazy-loaded route pages\n */\nexport const PageLoadingFallback: FC = () => (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-4 border-border-default border-t-accent-primary\" />\n </div>\n);\n\n/**\n * Access denied page shown when user lacks permission for a route\n */\nexport const AccessDenied: FC = () => {\n const { t } = useI18n();\n return (\n <div className=\"flex items-center justify-center min-h-[400px] animate-in fade-in duration-300\">\n <div className=\"text-center\">\n <h1 className=\"text-2xl font-semibold text-foreground mb-2\">\n {t('common.accessDenied', { defaultValue: 'Access Denied' })}\n </h1>\n <p className=\"text-muted-foreground\">\n {t('common.accessDeniedDescription', {\n defaultValue: 'You do not have permission to access this section.',\n })}\n </p>\n </div>\n </div>\n );\n};\n\n/**\n * Route-level permission guard that shows AccessDenied when permission check fails\n */\nexport const PermissionGuard: FC<{ allowed: boolean; children: ReactNode }> = ({\n allowed,\n children,\n}) => {\n if (!allowed) {\n return <AccessDenied />;\n }\n return <>{children}</>;\n};\n"],"mappings":";;;AAMA,IAAa,UACX,kBAAC,OAAD;CAAK,WAAU;WACb,kBAAC,OAAD,EAAK,WAAU,4FAA6F,CAAA;CACxG,CAAA,EAMK,UAAyB;CACpC,IAAM,EAAE,MAAM,GAAS;AACvB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAE,uBAAuB,EAAE,cAAc,iBAAiB,CAAC;IACzD,CAAA,EACL,kBAAC,KAAD;IAAG,WAAU;cACV,EAAE,kCAAkC,EACnC,cAAc,sDACf,CAAC;IACA,CAAA,CACA;;EACF,CAAA;GAOG,KAAkE,EAC7E,YACA,kBAEK,IAGE,kBAAA,GAAA,EAAG,aAAY,CAAA,GAFb,kBAAC,GAAD,EAAgB,CAAA"}
@@ -0,0 +1,35 @@
1
+ import { FC } from 'react';
2
+
3
+ /**
4
+ * Props for CartDrawer
5
+ */
6
+ interface CartDrawerProps {
7
+ isOpen: boolean;
8
+ onClose: () => void;
9
+ onCheckout: () => void;
10
+ cartItems: Array<{
11
+ id: string;
12
+ quantity: number;
13
+ subtotal: number;
14
+ productName?: string;
15
+ productIcon?: string;
16
+ variantName?: string;
17
+ product?: {
18
+ icon?: string;
19
+ name?: string;
20
+ };
21
+ }>;
22
+ itemCount: number;
23
+ subtotal: number;
24
+ tax: number;
25
+ total: number;
26
+ updateQuantity: (cartItemId: string, quantity: number) => Promise<void>;
27
+ removeProduct: (cartItemId: string) => Promise<void>;
28
+ }
29
+ /**
30
+ * CartDrawer component
31
+ *
32
+ * Sliding drawer for cart management
33
+ */
34
+ export declare const CartDrawer: FC<CartDrawerProps>;
35
+ export {};
@@ -0,0 +1,162 @@
1
+ import { formatPrice as e } from "../../utils/index.js";
2
+ import { Minus as t, Plus as n, ShoppingCart as r, Trash2 as i, X as a } from "lucide-react";
3
+ import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
4
+ //#region src/components/cart/CartDrawer.tsx
5
+ var l = ({ isOpen: l, onClose: u, onCheckout: d, cartItems: f, itemCount: p, subtotal: m, tax: h, total: g, updateQuantity: _, removeProduct: v }) => l ? /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("div", {
6
+ className: "fixed inset-0 z-40 bg-bg-overlay/50 transition-opacity",
7
+ onClick: u
8
+ }), /* @__PURE__ */ s("div", {
9
+ className: "fixed right-0 top-0 z-50 h-full w-full max-w-md bg-bg-surface shadow-xl",
10
+ children: /* @__PURE__ */ c("div", {
11
+ className: "flex h-full flex-col",
12
+ children: [
13
+ /* @__PURE__ */ c("div", {
14
+ className: "flex items-center justify-between border-b border-border-default px-6 py-4",
15
+ children: [/* @__PURE__ */ c("div", {
16
+ className: "flex items-center gap-2",
17
+ children: [
18
+ /* @__PURE__ */ s(r, { className: "h-5 w-5 text-text-primary" }),
19
+ /* @__PURE__ */ s("h2", {
20
+ className: "text-lg font-semibold text-text-primary",
21
+ children: "Shopping Cart"
22
+ }),
23
+ p > 0 && /* @__PURE__ */ s("span", {
24
+ className: "rounded-full bg-bg-accent px-2 py-0.5 text-xs font-medium text-text-link",
25
+ children: p
26
+ })
27
+ ]
28
+ }), /* @__PURE__ */ s("button", {
29
+ onClick: u,
30
+ "aria-label": "Close cart",
31
+ className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary",
32
+ children: /* @__PURE__ */ s(a, { className: "h-5 w-5" })
33
+ })]
34
+ }),
35
+ /* @__PURE__ */ s("div", {
36
+ className: "flex-1 overflow-y-auto px-6 py-4",
37
+ children: f.length === 0 ? /* @__PURE__ */ c("div", {
38
+ className: "flex h-full flex-col items-center justify-center text-center",
39
+ children: [
40
+ /* @__PURE__ */ s(r, { className: "mb-4 h-16 w-16 text-text-muted" }),
41
+ /* @__PURE__ */ s("h3", {
42
+ className: "mb-2 text-lg font-semibold text-text-primary",
43
+ children: "Your cart is empty"
44
+ }),
45
+ /* @__PURE__ */ s("p", {
46
+ className: "text-sm text-text-muted",
47
+ children: "Start shopping to add items to your cart"
48
+ })
49
+ ]
50
+ }) : /* @__PURE__ */ s("div", {
51
+ className: "space-y-4",
52
+ children: f.map((a) => /* @__PURE__ */ c("div", {
53
+ className: "flex gap-4 rounded-lg border border-border-default p-4",
54
+ children: [/* @__PURE__ */ s("div", {
55
+ className: "h-20 w-20 flex-shrink-0 overflow-hidden rounded bg-bg-sunken",
56
+ children: a.productIcon || a.product?.icon ? /* @__PURE__ */ s("img", {
57
+ src: a.productIcon || a.product?.icon,
58
+ alt: a.productName || a.product?.name,
59
+ className: "h-full w-full object-cover"
60
+ }) : /* @__PURE__ */ s("div", {
61
+ className: "flex h-full w-full items-center justify-center",
62
+ children: /* @__PURE__ */ s(r, { className: "h-8 w-8 text-text-muted" })
63
+ })
64
+ }), /* @__PURE__ */ c("div", {
65
+ className: "flex flex-1 flex-col",
66
+ children: [
67
+ /* @__PURE__ */ s("h4", {
68
+ className: "mb-1 font-semibold text-text-primary",
69
+ children: a.productName || a.product?.name || "Product"
70
+ }),
71
+ a.variantName && /* @__PURE__ */ s("p", {
72
+ className: "mb-2 text-xs text-text-muted",
73
+ children: a.variantName
74
+ }),
75
+ /* @__PURE__ */ c("div", {
76
+ className: "flex items-center gap-3",
77
+ children: [/* @__PURE__ */ c("div", {
78
+ className: "flex items-center rounded border border-border-default",
79
+ children: [
80
+ /* @__PURE__ */ s("button", {
81
+ onClick: () => _(a.id, a.quantity - 1),
82
+ className: "cursor-pointer p-1.5 transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50",
83
+ disabled: a.quantity <= 1,
84
+ children: /* @__PURE__ */ s(t, { className: "h-4 w-4" })
85
+ }),
86
+ /* @__PURE__ */ s("span", {
87
+ className: "min-w-[2rem] text-center text-sm font-medium",
88
+ children: a.quantity
89
+ }),
90
+ /* @__PURE__ */ s("button", {
91
+ onClick: () => _(a.id, a.quantity + 1),
92
+ className: "cursor-pointer p-1.5 transition-colors hover:bg-bg-sunken",
93
+ children: /* @__PURE__ */ s(n, { className: "h-4 w-4" })
94
+ })
95
+ ]
96
+ }), /* @__PURE__ */ s("button", {
97
+ onClick: () => v(a.id),
98
+ className: "cursor-pointer ml-auto text-status-error-text transition-colors hover:text-status-error-text-emphasis",
99
+ children: /* @__PURE__ */ s(i, { className: "h-4 w-4" })
100
+ })]
101
+ }),
102
+ /* @__PURE__ */ s("div", {
103
+ className: "mt-2 text-right",
104
+ children: /* @__PURE__ */ s("span", {
105
+ className: "font-semibold text-text-primary",
106
+ children: e(a.subtotal)
107
+ })
108
+ })
109
+ ]
110
+ })]
111
+ }, a.id))
112
+ })
113
+ }),
114
+ f.length > 0 && /* @__PURE__ */ c("div", {
115
+ className: "border-t border-border-default bg-bg-sunken px-6 py-4",
116
+ children: [/* @__PURE__ */ c("div", {
117
+ className: "space-y-2",
118
+ children: [
119
+ /* @__PURE__ */ c("div", {
120
+ className: "flex justify-between text-sm",
121
+ children: [/* @__PURE__ */ s("span", {
122
+ className: "text-text-muted",
123
+ children: "Subtotal"
124
+ }), /* @__PURE__ */ s("span", {
125
+ className: "font-medium text-text-primary",
126
+ children: e(m)
127
+ })]
128
+ }),
129
+ /* @__PURE__ */ c("div", {
130
+ className: "flex justify-between text-sm",
131
+ children: [/* @__PURE__ */ s("span", {
132
+ className: "text-text-muted",
133
+ children: "Tax"
134
+ }), /* @__PURE__ */ s("span", {
135
+ className: "font-medium text-text-primary",
136
+ children: e(h)
137
+ })]
138
+ }),
139
+ /* @__PURE__ */ c("div", {
140
+ className: "flex justify-between border-t border-border-default pt-2",
141
+ children: [/* @__PURE__ */ s("span", {
142
+ className: "font-semibold text-text-primary",
143
+ children: "Total"
144
+ }), /* @__PURE__ */ s("span", {
145
+ className: "text-lg font-bold text-text-primary",
146
+ children: e(g)
147
+ })]
148
+ })
149
+ ]
150
+ }), /* @__PURE__ */ s("button", {
151
+ onClick: d,
152
+ className: "cursor-pointer mt-4 w-full rounded-lg bg-action-primary-bg py-3 font-bold text-action-primary-text shadow-lg transition-all hover:opacity-90 hover:shadow-xl active:scale-[0.98]",
153
+ children: "Proceed to Checkout"
154
+ })]
155
+ })
156
+ ]
157
+ })
158
+ })] }) : null;
159
+ //#endregion
160
+ export { l as CartDrawer };
161
+
162
+ //# sourceMappingURL=CartDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CartDrawer.js","names":[],"sources":["../../../src/components/cart/CartDrawer.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { X, ShoppingCart, Trash2, Plus, Minus } from 'lucide-react';\nimport { formatPrice } from '../../utils';\n\n/**\n * Props for CartDrawer\n */\ninterface CartDrawerProps {\n isOpen: boolean;\n onClose: () => void;\n onCheckout: () => void;\n cartItems: Array<{\n id: string;\n quantity: number;\n subtotal: number;\n productName?: string;\n productIcon?: string;\n variantName?: string;\n product?: { icon?: string; name?: string };\n }>;\n itemCount: number;\n subtotal: number;\n tax: number;\n total: number;\n updateQuantity: (cartItemId: string, quantity: number) => Promise<void>;\n removeProduct: (cartItemId: string) => Promise<void>;\n}\n\n/**\n * CartDrawer component\n *\n * Sliding drawer for cart management\n */\nexport const CartDrawer: FC<CartDrawerProps> = ({\n isOpen,\n onClose,\n onCheckout,\n cartItems,\n itemCount,\n subtotal,\n tax,\n total,\n updateQuantity,\n removeProduct,\n}) => {\n if (!isOpen) return null;\n\n return (\n <>\n {/* Backdrop */}\n <div className=\"fixed inset-0 z-40 bg-bg-overlay/50 transition-opacity\" onClick={onClose} />\n\n {/* Drawer */}\n <div className=\"fixed right-0 top-0 z-50 h-full w-full max-w-md bg-bg-surface shadow-xl\">\n <div className=\"flex h-full flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-border-default px-6 py-4\">\n <div className=\"flex items-center gap-2\">\n <ShoppingCart className=\"h-5 w-5 text-text-primary\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Shopping Cart</h2>\n {itemCount > 0 && (\n <span className=\"rounded-full bg-bg-accent px-2 py-0.5 text-xs font-medium text-text-link\">\n {itemCount}\n </span>\n )}\n </div>\n <button\n onClick={onClose}\n aria-label=\"Close cart\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n {/* Cart Items */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {cartItems.length === 0 ? (\n <div className=\"flex h-full flex-col items-center justify-center text-center\">\n <ShoppingCart className=\"mb-4 h-16 w-16 text-text-muted\" />\n <h3 className=\"mb-2 text-lg font-semibold text-text-primary\">Your cart is empty</h3>\n <p className=\"text-sm text-text-muted\">Start shopping to add items to your cart</p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {cartItems.map((item) => (\n <div\n key={item.id}\n className=\"flex gap-4 rounded-lg border border-border-default p-4\"\n >\n {/* Product Image */}\n <div className=\"h-20 w-20 flex-shrink-0 overflow-hidden rounded bg-bg-sunken\">\n {item.productIcon || item.product?.icon ? (\n <img\n src={item.productIcon || item.product?.icon}\n alt={item.productName || item.product?.name}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center\">\n <ShoppingCart className=\"h-8 w-8 text-text-muted\" />\n </div>\n )}\n </div>\n\n {/* Product Info */}\n <div className=\"flex flex-1 flex-col\">\n <h4 className=\"mb-1 font-semibold text-text-primary\">\n {item.productName || item.product?.name || 'Product'}\n </h4>\n {item.variantName && (\n <p className=\"mb-2 text-xs text-text-muted\">{item.variantName}</p>\n )}\n\n {/* Quantity Controls */}\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center rounded border border-border-default\">\n <button\n onClick={() => updateQuantity(item.id, item.quantity - 1)}\n className=\"cursor-pointer p-1.5 transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50\"\n disabled={item.quantity <= 1}\n >\n <Minus className=\"h-4 w-4\" />\n </button>\n <span className=\"min-w-[2rem] text-center text-sm font-medium\">\n {item.quantity}\n </span>\n <button\n onClick={() => updateQuantity(item.id, item.quantity + 1)}\n className=\"cursor-pointer p-1.5 transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" />\n </button>\n </div>\n\n <button\n onClick={() => removeProduct(item.id)}\n className=\"cursor-pointer ml-auto text-status-error-text transition-colors hover:text-status-error-text-emphasis\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n\n {/* Price */}\n <div className=\"mt-2 text-right\">\n <span className=\"font-semibold text-text-primary\">\n {formatPrice(item.subtotal)}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer with Summary */}\n {cartItems.length > 0 && (\n <div className=\"border-t border-border-default bg-bg-sunken px-6 py-4\">\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-muted\">Subtotal</span>\n <span className=\"font-medium text-text-primary\">{formatPrice(subtotal)}</span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-muted\">Tax</span>\n <span className=\"font-medium text-text-primary\">{formatPrice(tax)}</span>\n </div>\n <div className=\"flex justify-between border-t border-border-default pt-2\">\n <span className=\"font-semibold text-text-primary\">Total</span>\n <span className=\"text-lg font-bold text-text-primary\">{formatPrice(total)}</span>\n </div>\n </div>\n\n <button\n onClick={onCheckout}\n className=\"cursor-pointer mt-4 w-full rounded-lg bg-action-primary-bg py-3 font-bold text-action-primary-text shadow-lg transition-all hover:opacity-90 hover:shadow-xl active:scale-[0.98]\"\n >\n Proceed to Checkout\n </button>\n </div>\n )}\n </div>\n </div>\n </>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Store Components
3
+ *
4
+ * Re-exports all store UI components
5
+ */
6
+ export { ProductCard } from './marketplace/ProductCard';
7
+ export { CartDrawer } from './cart/CartDrawer';
8
+ export { InstallAppModal } from './InstallAppModal';
9
+ export type { AppInfo } from './InstallAppModal';
@@ -0,0 +1,3 @@
1
+ import "./cart/CartDrawer.js";
2
+ import "./marketplace/ProductCard.js";
3
+ import "./InstallAppModal.js";
@@ -0,0 +1,18 @@
1
+ import { FC } from 'react';
2
+ import { Product } from '../../types';
3
+
4
+ /**
5
+ * Props for ProductCard
6
+ */
7
+ interface ProductCardProps {
8
+ product: Product;
9
+ onSelect: (product: Product) => void;
10
+ onAddToCart: (product: Product) => void;
11
+ }
12
+ /**
13
+ * ProductCard component
14
+ *
15
+ * Displays a product in grid view with key information and actions
16
+ */
17
+ export declare const ProductCard: FC<ProductCardProps>;
18
+ export {};
@@ -0,0 +1,2 @@
1
+ import "lucide-react";
2
+ import "react/jsx-runtime";
@@ -0,0 +1 @@
1
+ export {};