@burdenoff/microfe-store 2026.625.3 → 2026.625.5

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 (184) hide show
  1. package/dist/StoreRoutes.js +3 -3
  2. package/dist/StoreRoutes.js.map +1 -1
  3. package/dist/components/AccessDenied.js +3 -3
  4. package/dist/components/AccessDenied.js.map +1 -1
  5. package/dist/components/InstallAppModal.js +255 -175
  6. package/dist/components/InstallAppModal.js.map +1 -1
  7. package/dist/components/cart/CartDrawer.js +10 -10
  8. package/dist/components/cart/CartDrawer.js.map +1 -1
  9. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/errors/CombinedGraphQLErrors.js +1 -1
  10. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js.map +1 -0
  11. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/errors/utils.js +1 -1
  12. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/errors/utils.js.map +1 -0
  13. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/link/core/ApolloLink.js +2 -2
  14. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/link/core/ApolloLink.js.map +1 -0
  15. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/link/subscriptions/index.js +2 -2
  16. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/link/subscriptions/index.js.map +1 -0
  17. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/link/utils/createOperation.js +1 -1
  18. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/link/utils/createOperation.js.map +1 -0
  19. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/caching/sizes.js.map +1 -0
  20. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/graphql/print.js +1 -1
  21. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/graphql/print.js.map +1 -0
  22. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/caches.js +2 -2
  23. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/caches.js.map +1 -0
  24. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/checkDocument.js +1 -1
  25. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/checkDocument.js.map +1 -0
  26. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/getMainDefinition.js +1 -1
  27. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getMainDefinition.js.map +1 -0
  28. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getMemoryInternals.js +9 -0
  29. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getMemoryInternals.js.map +1 -0
  30. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/getOperationDefinition.js +1 -1
  31. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getOperationDefinition.js.map +1 -0
  32. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getOperationName.js +8 -0
  33. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/getOperationName.js.map +1 -0
  34. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/globals/global.js +1 -1
  35. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/globals/global.js.map +1 -0
  36. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/globals/maybe.js +10 -0
  37. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/globals/maybe.js.map +1 -0
  38. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/isNonNullObject.js +8 -0
  39. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/isNonNullObject.js.map +1 -0
  40. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/makeUniqueId.js +1 -1
  41. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/makeUniqueId.js.map +1 -0
  42. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/memoize.js +2 -2
  43. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/memoize.js.map +1 -0
  44. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/internal/stringifyForDisplay.js +1 -1
  45. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/internal/stringifyForDisplay.js.map +1 -0
  46. package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/invariant/index.js +1 -1
  47. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/utilities/invariant/index.js.map +1 -0
  48. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/version.js +6 -0
  49. package/dist/node_modules/.bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo/client/version.js.map +1 -0
  50. package/dist/node_modules/{@wry → .bun/@wry_caches@1.0.1/node_modules/@wry}/caches/lib/weak.js +1 -1
  51. package/dist/node_modules/.bun/@wry_caches@1.0.1/node_modules/@wry/caches/lib/weak.js.map +1 -0
  52. package/dist/node_modules/{@wry → .bun/@wry_trie@0.5.0/node_modules/@wry}/trie/lib/index.js +1 -1
  53. package/dist/node_modules/.bun/@wry_trie@0.5.0/node_modules/@wry/trie/lib/index.js.map +1 -0
  54. package/dist/node_modules/{graphql-ws → .bun/graphql-ws@6.0.8_796ebe57c2b0ffe0/node_modules/graphql-ws}/dist/client.js +1 -1
  55. package/dist/node_modules/.bun/graphql-ws@6.0.8_796ebe57c2b0ffe0/node_modules/graphql-ws/dist/client.js.map +1 -0
  56. package/dist/node_modules/{graphql-ws → .bun/graphql-ws@6.0.8_796ebe57c2b0ffe0/node_modules/graphql-ws}/dist/common-CGW11Fyb.js +1 -1
  57. package/dist/node_modules/.bun/graphql-ws@6.0.8_796ebe57c2b0ffe0/node_modules/graphql-ws/dist/common-CGW11Fyb.js.map +1 -0
  58. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/NotificationFactories.js +1 -1
  59. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/NotificationFactories.js.map +1 -0
  60. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/Observable.js +1 -1
  61. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/Observable.js.map +1 -0
  62. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/Subscriber.js +2 -2
  63. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/Subscriber.js.map +1 -0
  64. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/Subscription.js +2 -2
  65. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/Subscription.js.map +1 -0
  66. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/config.js +1 -1
  67. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/config.js.map +1 -0
  68. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/observable/empty.js +1 -1
  69. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/observable/empty.js.map +1 -0
  70. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/scheduler/timeoutProvider.js +2 -2
  71. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/scheduler/timeoutProvider.js.map +1 -0
  72. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/symbol/observable.js +1 -1
  73. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/symbol/observable.js.map +1 -0
  74. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/util/UnsubscriptionError.js +1 -1
  75. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/UnsubscriptionError.js.map +1 -0
  76. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/arrRemove.js +11 -0
  77. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/arrRemove.js.map +1 -0
  78. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/util/createErrorClass.js +1 -1
  79. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/createErrorClass.js.map +1 -0
  80. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/util/errorContext.js +1 -1
  81. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/errorContext.js.map +1 -0
  82. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/identity.js +8 -0
  83. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/identity.js.map +1 -0
  84. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/isFunction.js +8 -0
  85. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/isFunction.js.map +1 -0
  86. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/noop.js +6 -0
  87. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/noop.js.map +1 -0
  88. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/util/pipe.js +1 -1
  89. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/pipe.js.map +1 -0
  90. package/dist/node_modules/{rxjs → .bun/rxjs@7.8.2/node_modules/rxjs}/dist/esm5/internal/util/reportUnhandledError.js +1 -1
  91. package/dist/node_modules/.bun/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/util/reportUnhandledError.js.map +1 -0
  92. package/dist/node_modules/{rxjs → .bun/tslib@2.8.1}/node_modules/tslib/tslib.es6.js +1 -1
  93. package/dist/node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.es6.js.map +1 -0
  94. package/dist/pages/AdminDashboardPage.js +89 -90
  95. package/dist/pages/AdminDashboardPage.js.map +1 -1
  96. package/dist/pages/AdminReviewModerationPage.js +56 -58
  97. package/dist/pages/AdminReviewModerationPage.js.map +1 -1
  98. package/dist/pages/AdminStoresPage.js +372 -391
  99. package/dist/pages/AdminStoresPage.js.map +1 -1
  100. package/dist/pages/AdminSubmissionsQueuePage.js +148 -134
  101. package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -1
  102. package/dist/pages/AppDetailPage.js +120 -123
  103. package/dist/pages/AppDetailPage.js.map +1 -1
  104. package/dist/pages/AppSettingsPage.js +297 -70
  105. package/dist/pages/AppSettingsPage.js.map +1 -1
  106. package/dist/pages/CartPage.js +76 -65
  107. package/dist/pages/CartPage.js.map +1 -1
  108. package/dist/pages/InstalledAppsPage.js +315 -106
  109. package/dist/pages/InstalledAppsPage.js.map +1 -1
  110. package/dist/pages/MarketplaceHomePage.js +378 -368
  111. package/dist/pages/MarketplaceHomePage.js.map +1 -1
  112. package/dist/pages/MyLicensesPage.js +75 -67
  113. package/dist/pages/MyLicensesPage.js.map +1 -1
  114. package/dist/pages/OrderConfirmationPage.js +37 -38
  115. package/dist/pages/OrderConfirmationPage.js.map +1 -1
  116. package/dist/pages/OrdersPage.js +64 -53
  117. package/dist/pages/OrdersPage.js.map +1 -1
  118. package/dist/pages/ProductDetailPage.js +213 -215
  119. package/dist/pages/ProductDetailPage.js.map +1 -1
  120. package/dist/pages/ProductReviewsPage.js +2 -2
  121. package/dist/pages/ProductReviewsPage.js.map +1 -1
  122. package/dist/pages/PublisherDashboardPage.js +92 -93
  123. package/dist/pages/PublisherDashboardPage.js.map +1 -1
  124. package/dist/pages/PublisherRevenuePage.js +60 -61
  125. package/dist/pages/PublisherRevenuePage.js.map +1 -1
  126. package/dist/pages/PublisherSubmissionsPage.js +96 -97
  127. package/dist/pages/PublisherSubmissionsPage.js.map +1 -1
  128. package/dist/pages/PublisherSubmitPage.js +184 -189
  129. package/dist/pages/PublisherSubmitPage.js.map +1 -1
  130. package/dist/providers/StoreProvider.js +3 -3
  131. package/package.json +2 -2
  132. package/dist/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js.map +0 -1
  133. package/dist/node_modules/@apollo/client/errors/utils.js.map +0 -1
  134. package/dist/node_modules/@apollo/client/link/core/ApolloLink.js.map +0 -1
  135. package/dist/node_modules/@apollo/client/link/subscriptions/index.js.map +0 -1
  136. package/dist/node_modules/@apollo/client/link/utils/createOperation.js.map +0 -1
  137. package/dist/node_modules/@apollo/client/utilities/caching/sizes.js.map +0 -1
  138. package/dist/node_modules/@apollo/client/utilities/graphql/print.js.map +0 -1
  139. package/dist/node_modules/@apollo/client/utilities/internal/caches.js.map +0 -1
  140. package/dist/node_modules/@apollo/client/utilities/internal/checkDocument.js.map +0 -1
  141. package/dist/node_modules/@apollo/client/utilities/internal/getMainDefinition.js.map +0 -1
  142. package/dist/node_modules/@apollo/client/utilities/internal/getMemoryInternals.js +0 -9
  143. package/dist/node_modules/@apollo/client/utilities/internal/getMemoryInternals.js.map +0 -1
  144. package/dist/node_modules/@apollo/client/utilities/internal/getOperationDefinition.js.map +0 -1
  145. package/dist/node_modules/@apollo/client/utilities/internal/getOperationName.js +0 -8
  146. package/dist/node_modules/@apollo/client/utilities/internal/getOperationName.js.map +0 -1
  147. package/dist/node_modules/@apollo/client/utilities/internal/globals/global.js.map +0 -1
  148. package/dist/node_modules/@apollo/client/utilities/internal/globals/maybe.js +0 -10
  149. package/dist/node_modules/@apollo/client/utilities/internal/globals/maybe.js.map +0 -1
  150. package/dist/node_modules/@apollo/client/utilities/internal/isNonNullObject.js +0 -8
  151. package/dist/node_modules/@apollo/client/utilities/internal/isNonNullObject.js.map +0 -1
  152. package/dist/node_modules/@apollo/client/utilities/internal/makeUniqueId.js.map +0 -1
  153. package/dist/node_modules/@apollo/client/utilities/internal/memoize.js.map +0 -1
  154. package/dist/node_modules/@apollo/client/utilities/internal/stringifyForDisplay.js.map +0 -1
  155. package/dist/node_modules/@apollo/client/utilities/invariant/index.js.map +0 -1
  156. package/dist/node_modules/@apollo/client/version.js +0 -6
  157. package/dist/node_modules/@apollo/client/version.js.map +0 -1
  158. package/dist/node_modules/@wry/caches/lib/weak.js.map +0 -1
  159. package/dist/node_modules/@wry/trie/lib/index.js.map +0 -1
  160. package/dist/node_modules/graphql-ws/dist/client.js.map +0 -1
  161. package/dist/node_modules/graphql-ws/dist/common-CGW11Fyb.js.map +0 -1
  162. package/dist/node_modules/rxjs/dist/esm5/internal/NotificationFactories.js.map +0 -1
  163. package/dist/node_modules/rxjs/dist/esm5/internal/Observable.js.map +0 -1
  164. package/dist/node_modules/rxjs/dist/esm5/internal/Subscriber.js.map +0 -1
  165. package/dist/node_modules/rxjs/dist/esm5/internal/Subscription.js.map +0 -1
  166. package/dist/node_modules/rxjs/dist/esm5/internal/config.js.map +0 -1
  167. package/dist/node_modules/rxjs/dist/esm5/internal/observable/empty.js.map +0 -1
  168. package/dist/node_modules/rxjs/dist/esm5/internal/scheduler/timeoutProvider.js.map +0 -1
  169. package/dist/node_modules/rxjs/dist/esm5/internal/symbol/observable.js.map +0 -1
  170. package/dist/node_modules/rxjs/dist/esm5/internal/util/UnsubscriptionError.js.map +0 -1
  171. package/dist/node_modules/rxjs/dist/esm5/internal/util/arrRemove.js +0 -11
  172. package/dist/node_modules/rxjs/dist/esm5/internal/util/arrRemove.js.map +0 -1
  173. package/dist/node_modules/rxjs/dist/esm5/internal/util/createErrorClass.js.map +0 -1
  174. package/dist/node_modules/rxjs/dist/esm5/internal/util/errorContext.js.map +0 -1
  175. package/dist/node_modules/rxjs/dist/esm5/internal/util/identity.js +0 -8
  176. package/dist/node_modules/rxjs/dist/esm5/internal/util/identity.js.map +0 -1
  177. package/dist/node_modules/rxjs/dist/esm5/internal/util/isFunction.js +0 -8
  178. package/dist/node_modules/rxjs/dist/esm5/internal/util/isFunction.js.map +0 -1
  179. package/dist/node_modules/rxjs/dist/esm5/internal/util/noop.js +0 -6
  180. package/dist/node_modules/rxjs/dist/esm5/internal/util/noop.js.map +0 -1
  181. package/dist/node_modules/rxjs/dist/esm5/internal/util/pipe.js.map +0 -1
  182. package/dist/node_modules/rxjs/dist/esm5/internal/util/reportUnhandledError.js.map +0 -1
  183. package/dist/node_modules/rxjs/node_modules/tslib/tslib.es6.js.map +0 -1
  184. /package/dist/node_modules/{@apollo → .bun/@apollo_client@4.1.9_e571b0b00fd00a97/node_modules/@apollo}/client/utilities/caching/sizes.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"AdminDashboardPage.js","names":[],"sources":["../../src/pages/AdminDashboardPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport {\n LayoutDashboard,\n PackageCheck,\n Store as StoreIcon,\n MessageSquareWarning,\n Users,\n Check,\n X,\n ExternalLink,\n CheckCircle,\n XCircle,\n RefreshCw,\n ChevronDown,\n ChevronUp,\n} from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { GlassCard, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\nimport { formatPriceForModel } from '../utils';\n\ntype RecentProduct = {\n id: string;\n slug: string;\n name: string;\n type: string;\n nature?: string | null;\n category?: string | null;\n icon?: string | null;\n price: number;\n currency: string;\n pricingModel: string;\n description?: string | null;\n submittedAt?: string | null;\n submittedBy?: string | null;\n publisher?: { name: string; email: string } | null;\n};\n\ntype ActivityProduct = {\n id: string;\n slug: string;\n name: string;\n icon?: string | null;\n status: string;\n publishedAt?: string | null;\n reviewedAt?: string | null;\n reviewedBy?: string | null;\n rejectedReason?: string | null;\n};\n\ntype DashboardState = {\n pendingCount: number;\n totalStores: number;\n recentPending: RecentProduct[];\n recentPublished: ActivityProduct[];\n recentRejected: ActivityProduct[];\n loading: boolean;\n error: string | null;\n};\n\nconst DASHBOARD_QUERY = /* GraphQL */ `\n query AdminDashboardData {\n recentPending: pendingReviewProducts(limit: 5) {\n totalCount\n products {\n id\n slug\n name\n type\n nature\n category\n icon\n price\n currency\n pricingModel\n description\n submittedAt\n submittedBy\n publisher {\n name\n email\n }\n }\n }\n stores {\n id\n }\n recentPublished: products(filter: { status: PUBLISHED }, limit: 5) {\n id\n slug\n name\n icon\n status\n publishedAt\n reviewedBy\n }\n recentRejected: products(filter: { status: REJECTED }, limit: 5) {\n id\n slug\n name\n icon\n status\n reviewedAt\n rejectedReason\n }\n }\n`;\n\nconst APPROVE_MUTATION = /* GraphQL */ `\n mutation ApproveProduct($id: ID!) {\n approveProduct(id: $id) {\n id\n status\n }\n }\n`;\n\nconst REJECT_MUTATION = /* GraphQL */ `\n mutation RejectProduct($id: ID!, $reason: String!) {\n rejectProduct(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\nexport const AdminDashboardPage: FC = () => {\n const navigate = useNavigate();\n const { authToken, basePath } = useStore();\n\n const [state, setState] = useState<DashboardState>({\n pendingCount: 0,\n totalStores: 0,\n recentPending: [],\n recentPublished: [],\n recentRejected: [],\n loading: true,\n error: null,\n });\n const [actingId, setActingId] = useState<string | null>(null);\n const [rejectingId, setRejectingId] = useState<string | null>(null);\n const [rejectReason, setRejectReason] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n const [viewingId, setViewingId] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n try {\n const result = await graphqlFetch<{\n recentPending: { totalCount: number; products: RecentProduct[] };\n stores: Array<{ id: string }>;\n recentPublished: ActivityProduct[];\n recentRejected: ActivityProduct[];\n }>({\n gateway: 'global',\n query: DASHBOARD_QUERY,\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to load dashboard');\n }\n setState({\n pendingCount: result.data?.recentPending.totalCount ?? 0,\n totalStores: result.data?.stores.length ?? 0,\n recentPending: result.data?.recentPending.products ?? [],\n recentPublished: result.data?.recentPublished ?? [],\n recentRejected: result.data?.recentRejected ?? [],\n loading: false,\n error: null,\n });\n } catch (err) {\n setState((prev) => ({\n ...prev,\n loading: false,\n error: err instanceof Error ? err.message : 'Failed to load dashboard',\n }));\n }\n }, [authToken]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const approve = async (id: string) => {\n setActingId(id);\n setActionError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: APPROVE_MUTATION,\n variables: { id },\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Approval failed');\n }\n await load();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Approval failed');\n } finally {\n setActingId(null);\n }\n };\n\n const reject = async (id: string) => {\n if (!rejectReason.trim()) return;\n setActingId(id);\n setActionError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: REJECT_MUTATION,\n variables: { id, reason: rejectReason.trim() },\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Rejection failed');\n }\n setRejectingId(null);\n setRejectReason('');\n await load();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Rejection failed');\n } finally {\n setActingId(null);\n }\n };\n\n const formatDate = (iso?: string | null) => {\n if (!iso) return '—';\n return new Date(iso).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const kpiTiles = [\n {\n label: 'Pending submissions',\n value: state.pendingCount,\n icon: PackageCheck,\n href: `${basePath}/submissions`,\n },\n {\n label: 'Stores in registry',\n value: state.totalStores,\n icon: StoreIcon,\n href: `${basePath}/stores`,\n },\n {\n label: 'Review queue',\n value: '—',\n icon: MessageSquareWarning,\n href: `${basePath}/reviews`,\n },\n {\n label: 'Publishers',\n value: '—',\n icon: Users,\n href: `${basePath}/dashboard`,\n },\n ];\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-seam bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <LayoutDashboard className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Store admin dashboard</h1>\n </div>\n <button\n type=\"button\"\n onClick={() => void load()}\n disabled={state.loading}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover disabled:opacity-60\"\n >\n <RefreshCw className={`size-4 ${state.loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Manage store submissions, multi-store registry, and review moderation.\n </p>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl space-y-6 p-6\">\n {state.error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {state.error}\n </div>\n )}\n\n {/* KPI tiles */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {kpiTiles.map((tile) => {\n const Icon = tile.icon;\n return (\n <button\n key={tile.label}\n type=\"button\"\n onClick={() => navigate(tile.href)}\n className=\"rounded-card border border-border-seam bg-bg-surface bg-accent-wash p-4 text-left shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tile.label}\n </span>\n <Icon className=\"size-4 text-text-tertiary\" />\n </div>\n <div className=\"mt-2 text-3xl font-semibold tabular-nums text-text-primary\">\n {state.loading ? '…' : tile.value}\n </div>\n </button>\n );\n })}\n </div>\n\n {/* Recent Submissions */}\n <EmphasisPanel>\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Recent Submissions</h2>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/submissions`)}\n className=\"inline-flex items-center gap-1 text-xs text-text-accent hover:underline\"\n >\n View all\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n\n {actionError && (\n <div\n role=\"alert\"\n className=\"mb-3 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-2 text-sm text-text-danger\"\n >\n {actionError}\n </div>\n )}\n\n {state.loading ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised py-10 text-center text-sm text-text-secondary\">\n Loading…\n </div>\n ) : state.recentPending.length === 0 ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised py-10 text-center text-sm text-text-secondary\">\n No pending submissions.\n </div>\n ) : (\n <ul className=\"space-y-2\">\n {state.recentPending.map((p) => (\n <li\n key={p.id}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-surface-raised transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-10 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-10 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n {p.type.slice(0, 2)}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {p.publisher?.name ?? 'Unknown publisher'} ·{' '}\n {formatPriceForModel(p.price, p.currency, p.pricingModel)} ·{' '}\n {formatDate(p.submittedAt)}\n </p>\n </div>\n <div className=\"flex flex-shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setViewingId(viewingId === p.id ? null : p.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-3 py-1.5 text-xs text-text-secondary hover:bg-surface-hover\"\n >\n {viewingId === p.id ? (\n <ChevronUp className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n Details\n </button>\n <button\n type=\"button\"\n onClick={() => void approve(p.id)}\n disabled={actingId === p.id}\n className=\"inline-flex items-center gap-1 rounded-md bg-surface-success px-3 py-1.5 text-xs font-medium text-text-on-success hover:bg-surface-success-hover disabled:opacity-60\"\n >\n <Check className=\"size-3.5\" />\n Approve\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setRejectingId(p.id);\n setRejectReason('');\n setActionError(null);\n }}\n disabled={actingId === p.id}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-danger bg-surface-danger-muted px-3 py-1.5 text-xs font-medium text-text-danger hover:bg-surface-danger hover:text-text-on-danger disabled:opacity-60\"\n >\n <X className=\"size-3.5\" />\n Reject\n </button>\n </div>\n </div>\n\n {viewingId === p.id && (\n <div className=\"border-t border-border-seam bg-surface-muted p-4\">\n <dl className=\"grid grid-cols-2 gap-x-6 gap-y-3 text-xs sm:grid-cols-3\">\n <div>\n <dt className=\"font-medium text-text-secondary\">Slug</dt>\n <dd className=\"mt-0.5 font-mono text-text-primary\">{p.slug}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-text-secondary\">Type</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.type}</dd>\n </div>\n {p.nature && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Nature</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.nature}</dd>\n </div>\n )}\n {p.category && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Category</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.category}</dd>\n </div>\n )}\n <div>\n <dt className=\"font-medium text-text-secondary\">Pricing</dt>\n <dd className=\"mt-0.5 text-text-primary\">\n {formatPriceForModel(p.price, p.currency, p.pricingModel)}{' '}\n <span className=\"text-text-tertiary\">({p.pricingModel})</span>\n </dd>\n </div>\n <div>\n <dt className=\"font-medium text-text-secondary\">Publisher</dt>\n <dd className=\"mt-0.5 text-text-primary\">\n {p.publisher?.name ?? '—'}\n {p.publisher?.email && (\n <span className=\"block text-text-tertiary\">{p.publisher.email}</span>\n )}\n </dd>\n </div>\n {p.submittedBy && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Submitted by</dt>\n <dd className=\"mt-0.5 font-mono text-text-primary\">{p.submittedBy}</dd>\n </div>\n )}\n <div>\n <dt className=\"font-medium text-text-secondary\">Submitted at</dt>\n <dd className=\"mt-0.5 text-text-primary\">{formatDate(p.submittedAt)}</dd>\n </div>\n {p.description && (\n <div className=\"col-span-2 sm:col-span-3\">\n <dt className=\"font-medium text-text-secondary\">Description</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.description}</dd>\n </div>\n )}\n </dl>\n </div>\n )}\n\n {rejectingId === p.id && (\n <div className=\"border-t border-border-seam bg-surface-muted px-4 py-3\">\n <label\n htmlFor={`reject-reason-${p.id}`}\n className=\"block text-xs font-medium text-text-secondary\"\n >\n Rejection reason (required)\n </label>\n <textarea\n id={`reject-reason-${p.id}`}\n aria-label=\"Rejection reason\"\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n rows={2}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-2 text-sm text-text-primary focus:border-border-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n placeholder=\"Explain why this submission is being rejected…\"\n />\n <div className=\"mt-2 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setRejectingId(null);\n setRejectReason('');\n }}\n className=\"rounded-md border border-border-default bg-surface-default px-3 py-1 text-xs text-text-primary hover:bg-surface-hover\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void reject(p.id)}\n disabled={!rejectReason.trim() || actingId === p.id}\n className=\"rounded-md bg-surface-danger px-3 py-1 text-xs font-medium text-text-on-danger hover:bg-surface-danger-hover disabled:opacity-60\"\n >\n Submit rejection\n </button>\n </div>\n </div>\n )}\n </li>\n ))}\n </ul>\n )}\n </EmphasisPanel>\n\n {/* Recent Activity */}\n <section>\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Recent Activity</h2>\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n {/* Recently Approved */}\n <GlassCard className=\"overflow-hidden p-0\">\n <div className=\"flex items-center gap-2 border-b border-border-seam px-4 py-3\">\n <CheckCircle className=\"size-4 text-text-success\" />\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Recently Approved\n </h3>\n </div>\n {state.loading ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : state.recentPublished.length === 0 ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n No approved products yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam\">\n {state.recentPublished.map((p) => (\n <li key={p.id} className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-8 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-8 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n ?\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {p.reviewedBy ? `by ${p.reviewedBy} · ` : ''}\n {formatDate(p.publishedAt)}\n </p>\n </div>\n <span className=\"flex-shrink-0 rounded-full bg-surface-success-muted px-2 py-0.5 text-xs font-medium text-text-success\">\n Published\n </span>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n\n {/* Recently Rejected */}\n <GlassCard className=\"overflow-hidden p-0\">\n <div className=\"flex items-center gap-2 border-b border-border-seam px-4 py-3\">\n <XCircle className=\"size-4 text-text-danger\" />\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Recently Rejected\n </h3>\n </div>\n {state.loading ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : state.recentRejected.length === 0 ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n No rejected products yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam\">\n {state.recentRejected.map((p) => (\n <li key={p.id} className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-8 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-8 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n ?\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">\n {p.rejectedReason ? `\"${p.rejectedReason}\" · ` : ''}\n {formatDate(p.reviewedAt)}\n </p>\n </div>\n <span className=\"flex-shrink-0 rounded-full bg-surface-danger-muted px-2 py-0.5 text-xs font-medium text-text-danger\">\n Rejected\n </span>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </div>\n </section>\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminDashboardPage.js","names":[],"sources":["../../src/pages/AdminDashboardPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport {\n LayoutDashboard,\n PackageCheck,\n Store as StoreIcon,\n MessageSquareWarning,\n Users,\n Check,\n X,\n ExternalLink,\n CheckCircle,\n XCircle,\n RefreshCw,\n ChevronDown,\n ChevronUp,\n} from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\nimport { formatPriceForModel } from '../utils';\n\ntype RecentProduct = {\n id: string;\n slug: string;\n name: string;\n type: string;\n nature?: string | null;\n category?: string | null;\n icon?: string | null;\n price: number;\n currency: string;\n pricingModel: string;\n description?: string | null;\n submittedAt?: string | null;\n submittedBy?: string | null;\n publisher?: { name: string; email: string } | null;\n};\n\ntype ActivityProduct = {\n id: string;\n slug: string;\n name: string;\n icon?: string | null;\n status: string;\n publishedAt?: string | null;\n reviewedAt?: string | null;\n reviewedBy?: string | null;\n rejectedReason?: string | null;\n};\n\ntype DashboardState = {\n pendingCount: number;\n totalStores: number;\n recentPending: RecentProduct[];\n recentPublished: ActivityProduct[];\n recentRejected: ActivityProduct[];\n loading: boolean;\n error: string | null;\n};\n\nconst DASHBOARD_QUERY = /* GraphQL */ `\n query AdminDashboardData {\n recentPending: pendingReviewProducts(limit: 5) {\n totalCount\n products {\n id\n slug\n name\n type\n nature\n category\n icon\n price\n currency\n pricingModel\n description\n submittedAt\n submittedBy\n publisher {\n name\n email\n }\n }\n }\n stores {\n id\n }\n recentPublished: products(filter: { status: PUBLISHED }, limit: 5) {\n id\n slug\n name\n icon\n status\n publishedAt\n reviewedBy\n }\n recentRejected: products(filter: { status: REJECTED }, limit: 5) {\n id\n slug\n name\n icon\n status\n reviewedAt\n rejectedReason\n }\n }\n`;\n\nconst APPROVE_MUTATION = /* GraphQL */ `\n mutation ApproveProduct($id: ID!) {\n approveProduct(id: $id) {\n id\n status\n }\n }\n`;\n\nconst REJECT_MUTATION = /* GraphQL */ `\n mutation RejectProduct($id: ID!, $reason: String!) {\n rejectProduct(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\nexport const AdminDashboardPage: FC = () => {\n const navigate = useNavigate();\n const { authToken, basePath } = useStore();\n\n const [state, setState] = useState<DashboardState>({\n pendingCount: 0,\n totalStores: 0,\n recentPending: [],\n recentPublished: [],\n recentRejected: [],\n loading: true,\n error: null,\n });\n const [actingId, setActingId] = useState<string | null>(null);\n const [rejectingId, setRejectingId] = useState<string | null>(null);\n const [rejectReason, setRejectReason] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n const [viewingId, setViewingId] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n try {\n const result = await graphqlFetch<{\n recentPending: { totalCount: number; products: RecentProduct[] };\n stores: Array<{ id: string }>;\n recentPublished: ActivityProduct[];\n recentRejected: ActivityProduct[];\n }>({\n gateway: 'global',\n query: DASHBOARD_QUERY,\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to load dashboard');\n }\n setState({\n pendingCount: result.data?.recentPending.totalCount ?? 0,\n totalStores: result.data?.stores.length ?? 0,\n recentPending: result.data?.recentPending.products ?? [],\n recentPublished: result.data?.recentPublished ?? [],\n recentRejected: result.data?.recentRejected ?? [],\n loading: false,\n error: null,\n });\n } catch (err) {\n setState((prev) => ({\n ...prev,\n loading: false,\n error: err instanceof Error ? err.message : 'Failed to load dashboard',\n }));\n }\n }, [authToken]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const approve = async (id: string) => {\n setActingId(id);\n setActionError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: APPROVE_MUTATION,\n variables: { id },\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Approval failed');\n }\n await load();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Approval failed');\n } finally {\n setActingId(null);\n }\n };\n\n const reject = async (id: string) => {\n if (!rejectReason.trim()) return;\n setActingId(id);\n setActionError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: REJECT_MUTATION,\n variables: { id, reason: rejectReason.trim() },\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Rejection failed');\n }\n setRejectingId(null);\n setRejectReason('');\n await load();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Rejection failed');\n } finally {\n setActingId(null);\n }\n };\n\n const formatDate = (iso?: string | null) => {\n if (!iso) return '—';\n return new Date(iso).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const kpiTiles = [\n {\n label: 'Pending submissions',\n value: state.pendingCount,\n icon: PackageCheck,\n href: `${basePath}/submissions`,\n },\n {\n label: 'Stores in registry',\n value: state.totalStores,\n icon: StoreIcon,\n href: `${basePath}/stores`,\n },\n {\n label: 'Review queue',\n value: '—',\n icon: MessageSquareWarning,\n href: `${basePath}/reviews`,\n },\n {\n label: 'Publishers',\n value: '—',\n icon: Users,\n href: `${basePath}/dashboard`,\n },\n ];\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <LayoutDashboard className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Store admin dashboard</h1>\n </div>\n <button\n type=\"button\"\n onClick={() => void load()}\n disabled={state.loading}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover disabled:opacity-60\"\n >\n <RefreshCw className={`size-4 ${state.loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Manage store submissions, multi-store registry, and review moderation.\n </p>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl space-y-6 p-6\">\n {state.error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {state.error}\n </div>\n )}\n\n {/* KPI tiles */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {kpiTiles.map((tile) => {\n const Icon = tile.icon;\n return (\n <button\n key={tile.label}\n type=\"button\"\n onClick={() => navigate(tile.href)}\n className=\"rounded-lg border border-border-default bg-surface-raised p-4 text-left transition-colors hover:bg-surface-hover\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tile.label}\n </span>\n <Icon className=\"size-4 text-text-tertiary\" />\n </div>\n <div className=\"mt-2 text-3xl font-semibold text-text-primary\">\n {state.loading ? '…' : tile.value}\n </div>\n </button>\n );\n })}\n </div>\n\n {/* Recent Submissions */}\n <section>\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Recent Submissions</h2>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/submissions`)}\n className=\"inline-flex items-center gap-1 text-xs text-text-accent hover:underline\"\n >\n View all\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n\n {actionError && (\n <div\n role=\"alert\"\n className=\"mb-3 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-2 text-sm text-text-danger\"\n >\n {actionError}\n </div>\n )}\n\n {state.loading ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised py-10 text-center text-sm text-text-secondary\">\n Loading…\n </div>\n ) : state.recentPending.length === 0 ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised py-10 text-center text-sm text-text-secondary\">\n No pending submissions.\n </div>\n ) : (\n <ul className=\"space-y-2\">\n {state.recentPending.map((p) => (\n <li\n key={p.id}\n className=\"overflow-hidden rounded-lg border border-border-default bg-surface-raised\"\n >\n <div className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-10 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-10 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n {p.type.slice(0, 2)}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {p.publisher?.name ?? 'Unknown publisher'} ·{' '}\n {formatPriceForModel(p.price, p.currency, p.pricingModel)} ·{' '}\n {formatDate(p.submittedAt)}\n </p>\n </div>\n <div className=\"flex flex-shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setViewingId(viewingId === p.id ? null : p.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-3 py-1.5 text-xs text-text-secondary hover:bg-surface-hover\"\n >\n {viewingId === p.id ? (\n <ChevronUp className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n Details\n </button>\n <button\n type=\"button\"\n onClick={() => void approve(p.id)}\n disabled={actingId === p.id}\n className=\"inline-flex items-center gap-1 rounded-md bg-surface-success px-3 py-1.5 text-xs font-medium text-text-on-success hover:bg-surface-success-hover disabled:opacity-60\"\n >\n <Check className=\"size-3.5\" />\n Approve\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setRejectingId(p.id);\n setRejectReason('');\n setActionError(null);\n }}\n disabled={actingId === p.id}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-danger bg-surface-danger-muted px-3 py-1.5 text-xs font-medium text-text-danger hover:bg-surface-danger hover:text-text-on-danger disabled:opacity-60\"\n >\n <X className=\"size-3.5\" />\n Reject\n </button>\n </div>\n </div>\n\n {viewingId === p.id && (\n <div className=\"border-t border-border-default bg-surface-muted p-4\">\n <dl className=\"grid grid-cols-2 gap-x-6 gap-y-3 text-xs sm:grid-cols-3\">\n <div>\n <dt className=\"font-medium text-text-secondary\">Slug</dt>\n <dd className=\"mt-0.5 font-mono text-text-primary\">{p.slug}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-text-secondary\">Type</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.type}</dd>\n </div>\n {p.nature && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Nature</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.nature}</dd>\n </div>\n )}\n {p.category && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Category</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.category}</dd>\n </div>\n )}\n <div>\n <dt className=\"font-medium text-text-secondary\">Pricing</dt>\n <dd className=\"mt-0.5 text-text-primary\">\n {formatPriceForModel(p.price, p.currency, p.pricingModel)}{' '}\n <span className=\"text-text-tertiary\">({p.pricingModel})</span>\n </dd>\n </div>\n <div>\n <dt className=\"font-medium text-text-secondary\">Publisher</dt>\n <dd className=\"mt-0.5 text-text-primary\">\n {p.publisher?.name ?? '—'}\n {p.publisher?.email && (\n <span className=\"block text-text-tertiary\">{p.publisher.email}</span>\n )}\n </dd>\n </div>\n {p.submittedBy && (\n <div>\n <dt className=\"font-medium text-text-secondary\">Submitted by</dt>\n <dd className=\"mt-0.5 font-mono text-text-primary\">{p.submittedBy}</dd>\n </div>\n )}\n <div>\n <dt className=\"font-medium text-text-secondary\">Submitted at</dt>\n <dd className=\"mt-0.5 text-text-primary\">{formatDate(p.submittedAt)}</dd>\n </div>\n {p.description && (\n <div className=\"col-span-2 sm:col-span-3\">\n <dt className=\"font-medium text-text-secondary\">Description</dt>\n <dd className=\"mt-0.5 text-text-primary\">{p.description}</dd>\n </div>\n )}\n </dl>\n </div>\n )}\n\n {rejectingId === p.id && (\n <div className=\"border-t border-border-default bg-surface-muted px-4 py-3\">\n <label\n htmlFor={`reject-reason-${p.id}`}\n className=\"block text-xs font-medium text-text-secondary\"\n >\n Rejection reason (required)\n </label>\n <textarea\n id={`reject-reason-${p.id}`}\n aria-label=\"Rejection reason\"\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n rows={2}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-2 text-sm text-text-primary focus:border-border-accent focus:outline-none\"\n placeholder=\"Explain why this submission is being rejected…\"\n />\n <div className=\"mt-2 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setRejectingId(null);\n setRejectReason('');\n }}\n className=\"rounded-md border border-border-default bg-surface-default px-3 py-1 text-xs text-text-primary hover:bg-surface-hover\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void reject(p.id)}\n disabled={!rejectReason.trim() || actingId === p.id}\n className=\"rounded-md bg-surface-danger px-3 py-1 text-xs font-medium text-text-on-danger hover:bg-surface-danger-hover disabled:opacity-60\"\n >\n Submit rejection\n </button>\n </div>\n </div>\n )}\n </li>\n ))}\n </ul>\n )}\n </section>\n\n {/* Recent Activity */}\n <section>\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Recent Activity</h2>\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n {/* Recently Approved */}\n <div className=\"rounded-lg border border-border-default bg-surface-raised\">\n <div className=\"flex items-center gap-2 border-b border-border-default px-4 py-3\">\n <CheckCircle className=\"size-4 text-text-success\" />\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Recently Approved\n </h3>\n </div>\n {state.loading ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : state.recentPublished.length === 0 ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n No approved products yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-default\">\n {state.recentPublished.map((p) => (\n <li key={p.id} className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-8 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-8 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n ?\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {p.reviewedBy ? `by ${p.reviewedBy} · ` : ''}\n {formatDate(p.publishedAt)}\n </p>\n </div>\n <span className=\"flex-shrink-0 rounded-full bg-surface-success-muted px-2 py-0.5 text-xs font-medium text-text-success\">\n Published\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {/* Recently Rejected */}\n <div className=\"rounded-lg border border-border-default bg-surface-raised\">\n <div className=\"flex items-center gap-2 border-b border-border-default px-4 py-3\">\n <XCircle className=\"size-4 text-text-danger\" />\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Recently Rejected\n </h3>\n </div>\n {state.loading ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">Loading…</p>\n ) : state.recentRejected.length === 0 ? (\n <p className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n No rejected products yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-default\">\n {state.recentRejected.map((p) => (\n <li key={p.id} className=\"flex items-center gap-3 px-4 py-3\">\n {p.icon ? (\n <img\n src={p.icon}\n alt=\"\"\n className=\"size-8 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex size-8 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-xs text-text-secondary\">\n ?\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{p.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">\n {p.rejectedReason ? `\"${p.rejectedReason}\" · ` : ''}\n {formatDate(p.reviewedAt)}\n </p>\n </div>\n <span className=\"flex-shrink-0 rounded-full bg-surface-danger-muted px-2 py-0.5 text-xs font-medium text-text-danger\">\n Rejected\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n </section>\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -4,82 +4,81 @@ import { ArrowLeft as i, MessageSquareWarning as a, Search as o, X as s } from "
4
4
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
5
  import { useNavigate as u } from "react-router-dom";
6
6
  import { graphqlFetch as d } from "@burdenoff/fe-libs/shared/graphql";
7
- import { GlassCard as f } from "@burdenoff/fe-libs/ui";
8
7
  //#region src/pages/AdminReviewModerationPage.tsx
9
- var p = "query SearchProductsForModeration($query: String!) { searchProducts(query: $query, limit: 10) { id name slug } }", m = "query ProductReviewsForModeration($productId: String!) { productReviews(productId: $productId) { id userId rating title comment status helpful createdAt } }", h = "mutation RejectReview($id: ID!) { rejectReview(id: $id) { id status } }", g = () => {
10
- let g = u(), { authToken: _ } = e(), [v, y] = r(""), [b, x] = r([]), [S, C] = r(!1), [w, T] = r(!1), [E, D] = r(null), [O, k] = r([]), [A, j] = r(!1), [M, N] = r(null), [P, F] = r(null), I = n(null), L = n(null);
8
+ var f = "query SearchProductsForModeration($query: String!) { searchProducts(query: $query, limit: 10) { id name slug } }", p = "query ProductReviewsForModeration($productId: String!) { productReviews(productId: $productId) { id userId rating title comment status helpful createdAt } }", m = "mutation RejectReview($id: ID!) { rejectReview(id: $id) { id status } }", h = () => {
9
+ let h = u(), { authToken: g } = e(), [_, v] = r(""), [y, b] = r([]), [x, S] = r(!1), [C, w] = r(!1), [T, E] = r(null), [D, O] = r([]), [k, A] = r(!1), [j, M] = r(null), [N, P] = r(null), F = n(null), I = n(null);
11
10
  t(() => {
12
11
  let e = (e) => {
13
- L.current && !L.current.contains(e.target) && T(!1);
12
+ I.current && !I.current.contains(e.target) && w(!1);
14
13
  };
15
14
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
16
15
  }, []);
17
- let R = (e) => {
18
- if (y(e), D(null), k([]), N(null), I.current && clearTimeout(I.current), !e.trim()) {
19
- x([]), T(!1);
16
+ let L = (e) => {
17
+ if (v(e), E(null), O([]), M(null), F.current && clearTimeout(F.current), !e.trim()) {
18
+ b([]), w(!1);
20
19
  return;
21
20
  }
22
- I.current = setTimeout(async () => {
23
- C(!0);
21
+ F.current = setTimeout(async () => {
22
+ S(!0);
24
23
  try {
25
- x((await d({
24
+ b((await d({
26
25
  gateway: "global",
27
- query: p,
26
+ query: f,
28
27
  variables: { query: e },
29
- authToken: _ || void 0
30
- })).data?.searchProducts ?? []), T(!0);
28
+ authToken: g || void 0
29
+ })).data?.searchProducts ?? []), w(!0);
31
30
  } catch {
32
- x([]);
31
+ b([]);
33
32
  } finally {
34
- C(!1);
33
+ S(!1);
35
34
  }
36
35
  }, 300);
37
- }, z = (e) => {
38
- D(e), y(e.name), T(!1), B(e.id);
39
- }, B = async (e) => {
40
- j(!0), N(null);
36
+ }, R = (e) => {
37
+ E(e), v(e.name), w(!1), z(e.id);
38
+ }, z = async (e) => {
39
+ A(!0), M(null);
41
40
  try {
42
41
  let t = await d({
43
42
  gateway: "global",
44
- query: m,
43
+ query: p,
45
44
  variables: { productId: e },
46
- authToken: _ || void 0
45
+ authToken: g || void 0
47
46
  });
48
47
  if (t.errors?.length) throw Error(t.errors[0]?.message ?? "Failed to fetch reviews");
49
- k(t.data?.productReviews ?? []);
48
+ O(t.data?.productReviews ?? []);
50
49
  } catch (e) {
51
- N(e instanceof Error ? e.message : "Failed to fetch reviews");
50
+ M(e instanceof Error ? e.message : "Failed to fetch reviews");
52
51
  } finally {
53
- j(!1);
52
+ A(!1);
54
53
  }
55
- }, V = async (e) => {
56
- F(e), N(null);
54
+ }, B = async (e) => {
55
+ P(e), M(null);
57
56
  try {
58
57
  let t = await d({
59
58
  gateway: "global",
60
- query: h,
59
+ query: m,
61
60
  variables: { id: e },
62
- authToken: _ || void 0
61
+ authToken: g || void 0
63
62
  });
64
63
  if (t.errors?.length) throw Error(t.errors[0]?.message ?? "Failed to remove review");
65
- k((t) => t.filter((t) => t.id !== e));
64
+ O((t) => t.filter((t) => t.id !== e));
66
65
  } catch (e) {
67
- N(e instanceof Error ? e.message : "Failed to remove review");
66
+ M(e instanceof Error ? e.message : "Failed to remove review");
68
67
  } finally {
69
- F(null);
68
+ P(null);
70
69
  }
71
70
  };
72
71
  return /* @__PURE__ */ l("div", {
73
72
  className: "min-h-screen bg-surface-default",
74
73
  children: [/* @__PURE__ */ c("header", {
75
- className: "border-b border-border-seam bg-surface-raised",
74
+ className: "border-b border-border-default bg-surface-raised",
76
75
  children: /* @__PURE__ */ l("div", {
77
76
  className: "mx-auto max-w-7xl px-6 py-4",
78
77
  children: [/* @__PURE__ */ l("div", {
79
78
  className: "flex items-center gap-3",
80
79
  children: [/* @__PURE__ */ l("button", {
81
80
  type: "button",
82
- onClick: () => g(-1),
81
+ onClick: () => h(-1),
83
82
  "aria-label": "Go back",
84
83
  className: "inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary",
85
84
  children: [/* @__PURE__ */ c(i, { className: "size-4" }), "Back"]
@@ -100,11 +99,10 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
100
99
  children: /* @__PURE__ */ l("div", {
101
100
  className: "space-y-4",
102
101
  children: [
103
- /* @__PURE__ */ l(f, {
104
- treatment: "plain",
105
- className: "p-4",
102
+ /* @__PURE__ */ l("div", {
103
+ className: "rounded-lg border border-border-default bg-surface-raised p-4",
106
104
  children: [/* @__PURE__ */ l("div", {
107
- ref: L,
105
+ ref: I,
108
106
  className: "relative",
109
107
  children: [
110
108
  /* @__PURE__ */ c("label", {
@@ -119,24 +117,24 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
119
117
  /* @__PURE__ */ c("input", {
120
118
  id: "admin-review-product-search",
121
119
  "aria-label": "Search product by name",
122
- value: v,
123
- onChange: (e) => R(e.target.value),
124
- onFocus: () => b.length > 0 && T(!0),
120
+ value: _,
121
+ onChange: (e) => L(e.target.value),
122
+ onFocus: () => y.length > 0 && w(!0),
125
123
  placeholder: "Type a product name to search...",
126
124
  autoComplete: "off",
127
125
  className: "w-full rounded-md border border-border-default bg-surface-default py-2 pl-9 pr-3 text-sm text-text-primary outline-none focus:border-border-accent"
128
126
  }),
129
- S && /* @__PURE__ */ c("span", {
127
+ x && /* @__PURE__ */ c("span", {
130
128
  className: "absolute right-3 text-xs text-text-secondary",
131
129
  children: "Searching…"
132
130
  })
133
131
  ]
134
132
  }),
135
- w && b.length > 0 && /* @__PURE__ */ c("ul", {
133
+ C && y.length > 0 && /* @__PURE__ */ c("ul", {
136
134
  className: "absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised shadow-lg",
137
- children: b.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("button", {
135
+ children: y.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("button", {
138
136
  type: "button",
139
- onClick: () => z(e),
137
+ onClick: () => R(e),
140
138
  className: "w-full px-4 py-2.5 text-left text-sm hover:bg-surface-hover",
141
139
  children: [/* @__PURE__ */ c("span", {
142
140
  className: "font-medium text-text-primary",
@@ -147,48 +145,48 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
147
145
  })]
148
146
  }) }, e.id))
149
147
  }),
150
- w && !S && b.length === 0 && v.trim() && /* @__PURE__ */ l("div", {
148
+ C && !x && y.length === 0 && _.trim() && /* @__PURE__ */ l("div", {
151
149
  className: "absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised px-4 py-3 text-sm text-text-secondary shadow-lg",
152
150
  children: [
153
151
  "No products found for “",
154
- v,
152
+ _,
155
153
  "”"
156
154
  ]
157
155
  })
158
156
  ]
159
- }), E && /* @__PURE__ */ l("p", {
157
+ }), T && /* @__PURE__ */ l("p", {
160
158
  className: "mt-2 text-xs text-text-secondary",
161
159
  children: [
162
160
  "Moderating:",
163
161
  " ",
164
162
  /* @__PURE__ */ c("span", {
165
163
  className: "font-medium text-text-primary",
166
- children: E.name
164
+ children: T.name
167
165
  }),
168
166
  /* @__PURE__ */ l("span", {
169
167
  className: "ml-1 text-text-tertiary",
170
168
  children: [
171
169
  "(",
172
- E.id,
170
+ T.id,
173
171
  ")"
174
172
  ]
175
173
  })
176
174
  ]
177
175
  })]
178
176
  }),
179
- M && /* @__PURE__ */ c("div", {
177
+ j && /* @__PURE__ */ c("div", {
180
178
  role: "alert",
181
179
  className: "rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger",
182
- children: M
180
+ children: j
183
181
  }),
184
- A && /* @__PURE__ */ c("div", {
182
+ k && /* @__PURE__ */ c("div", {
185
183
  className: "rounded-lg border border-border-default bg-surface-raised p-10 text-center",
186
184
  children: /* @__PURE__ */ c("p", {
187
185
  className: "text-sm text-text-secondary",
188
186
  children: "Loading reviews…"
189
187
  })
190
188
  }),
191
- !A && E && O.length === 0 ? /* @__PURE__ */ l("div", {
189
+ !k && T && D.length === 0 ? /* @__PURE__ */ l("div", {
192
190
  className: "rounded-lg border border-border-default bg-surface-raised p-10 text-center",
193
191
  children: [/* @__PURE__ */ c(a, { className: "mx-auto mb-2 size-8 text-text-secondary" }), /* @__PURE__ */ c("p", {
194
192
  className: "text-sm text-text-secondary",
@@ -196,8 +194,8 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
196
194
  })]
197
195
  }) : /* @__PURE__ */ c("ul", {
198
196
  className: "space-y-3",
199
- children: O.map((e) => /* @__PURE__ */ c("li", {
200
- className: "rounded-lg border border-border-seam bg-surface-raised p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]",
197
+ children: D.map((e) => /* @__PURE__ */ c("li", {
198
+ className: "rounded-lg border border-border-default bg-surface-raised p-4",
201
199
  children: /* @__PURE__ */ l("div", {
202
200
  className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
203
201
  children: [/* @__PURE__ */ l("div", { children: [
@@ -230,8 +228,8 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
230
228
  className: "flex items-center gap-2",
231
229
  children: /* @__PURE__ */ l("button", {
232
230
  type: "button",
233
- onClick: () => V(e.id),
234
- disabled: P === e.id,
231
+ onClick: () => B(e.id),
232
+ disabled: N === e.id,
235
233
  className: "inline-flex items-center gap-1.5 rounded-md border border-border-danger px-3 py-1.5 text-sm font-medium text-text-danger hover:bg-surface-danger-muted disabled:cursor-not-allowed disabled:opacity-60",
236
234
  children: [/* @__PURE__ */ c(s, { className: "size-4" }), " Remove"]
237
235
  })
@@ -245,6 +243,6 @@ var p = "query SearchProductsForModeration($query: String!) { searchProducts(que
245
243
  });
246
244
  };
247
245
  //#endregion
248
- export { g as AdminReviewModerationPage };
246
+ export { h as AdminReviewModerationPage };
249
247
 
250
248
  //# sourceMappingURL=AdminReviewModerationPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminReviewModerationPage.js","names":[],"sources":["../../src/pages/AdminReviewModerationPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState, useRef, useEffect } from 'react';\nimport { ArrowLeft, Search, X, MessageSquareWarning } from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\n\ntype ModerationReview = {\n id: string;\n userId: string;\n rating: number;\n title?: string | null;\n comment?: string | null;\n status: string;\n helpful: number;\n createdAt: string;\n};\n\ntype ProductSearchResult = {\n id: string;\n name: string;\n slug: string;\n};\n\nconst SEARCH_PRODUCTS_QUERY = `query SearchProductsForModeration($query: String!) { searchProducts(query: $query, limit: 10) { id name slug } }`;\nconst PRODUCT_REVIEWS_QUERY = `query ProductReviewsForModeration($productId: String!) { productReviews(productId: $productId) { id userId rating title comment status helpful createdAt } }`;\nconst REJECT_REVIEW_MUTATION = `mutation RejectReview($id: ID!) { rejectReview(id: $id) { id status } }`;\n\nexport const AdminReviewModerationPage: FC = () => {\n const navigate = useNavigate();\n const { authToken } = useStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [searchResults, setSearchResults] = useState<ProductSearchResult[]>([]);\n const [searchLoading, setSearchLoading] = useState(false);\n const [showDropdown, setShowDropdown] = useState(false);\n const [selectedProduct, setSelectedProduct] = useState<ProductSearchResult | null>(null);\n const [reviews, setReviews] = useState<ModerationReview[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [actingId, setActingId] = useState<string | null>(null);\n const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setShowDropdown(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n setSelectedProduct(null);\n setReviews([]);\n setError(null);\n\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n if (!value.trim()) {\n setSearchResults([]);\n setShowDropdown(false);\n return;\n }\n\n searchDebounceRef.current = setTimeout(async () => {\n setSearchLoading(true);\n try {\n const result = await graphqlFetch<{ searchProducts: ProductSearchResult[] }>({\n gateway: 'global',\n query: SEARCH_PRODUCTS_QUERY,\n variables: { query: value },\n authToken: authToken || undefined,\n });\n setSearchResults(result.data?.searchProducts ?? []);\n setShowDropdown(true);\n } catch {\n setSearchResults([]);\n } finally {\n setSearchLoading(false);\n }\n }, 300);\n };\n\n const selectProduct = (product: ProductSearchResult) => {\n setSelectedProduct(product);\n setSearchQuery(product.name);\n setShowDropdown(false);\n void loadReviews(product.id);\n };\n\n const loadReviews = async (productId: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ productReviews: ModerationReview[] }>({\n gateway: 'global',\n query: PRODUCT_REVIEWS_QUERY,\n variables: { productId },\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to fetch reviews');\n }\n\n setReviews(result.data?.productReviews ?? []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to fetch reviews');\n } finally {\n setLoading(false);\n }\n };\n\n const removeReview = async (reviewId: string) => {\n setActingId(reviewId);\n setError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: REJECT_REVIEW_MUTATION,\n variables: { id: reviewId },\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to remove review');\n }\n\n setReviews((prev) => prev.filter((review) => review.id !== reviewId));\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to remove review');\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-seam bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n <div className=\"flex items-center gap-2\">\n <MessageSquareWarning className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Review Moderation</h1>\n </div>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Review published content by product and remove anything that violates guidelines\n </p>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl p-6\">\n <div className=\"space-y-4\">\n <GlassCard treatment=\"plain\" className=\"p-4\">\n <div ref={dropdownRef} className=\"relative\">\n <label\n htmlFor=\"admin-review-product-search\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n Search product by name\n </label>\n <div className=\"relative flex items-center\">\n <Search className=\"pointer-events-none absolute left-3 size-4 text-text-secondary\" />\n <input\n id=\"admin-review-product-search\"\n aria-label=\"Search product by name\"\n value={searchQuery}\n onChange={(e) => handleSearchChange(e.target.value)}\n onFocus={() => searchResults.length > 0 && setShowDropdown(true)}\n placeholder=\"Type a product name to search...\"\n autoComplete=\"off\"\n className=\"w-full rounded-md border border-border-default bg-surface-default py-2 pl-9 pr-3 text-sm text-text-primary outline-none focus:border-border-accent\"\n />\n {searchLoading && (\n <span className=\"absolute right-3 text-xs text-text-secondary\">Searching…</span>\n )}\n </div>\n\n {showDropdown && searchResults.length > 0 && (\n <ul className=\"absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised shadow-lg\">\n {searchResults.map((product) => (\n <li key={product.id}>\n <button\n type=\"button\"\n onClick={() => selectProduct(product)}\n className=\"w-full px-4 py-2.5 text-left text-sm hover:bg-surface-hover\"\n >\n <span className=\"font-medium text-text-primary\">{product.name}</span>\n <span className=\"ml-2 text-xs text-text-secondary\">{product.slug}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {showDropdown &&\n !searchLoading &&\n searchResults.length === 0 &&\n searchQuery.trim() && (\n <div className=\"absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised px-4 py-3 text-sm text-text-secondary shadow-lg\">\n No products found for &ldquo;{searchQuery}&rdquo;\n </div>\n )}\n </div>\n\n {selectedProduct && (\n <p className=\"mt-2 text-xs text-text-secondary\">\n Moderating:{' '}\n <span className=\"font-medium text-text-primary\">{selectedProduct.name}</span>\n <span className=\"ml-1 text-text-tertiary\">({selectedProduct.id})</span>\n </p>\n )}\n </GlassCard>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {loading && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-10 text-center\">\n <p className=\"text-sm text-text-secondary\">Loading reviews…</p>\n </div>\n )}\n\n {!loading && selectedProduct && reviews.length === 0 ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-10 text-center\">\n <MessageSquareWarning className=\"mx-auto mb-2 size-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">No reviews found for this product.</p>\n </div>\n ) : (\n <ul className=\"space-y-3\">\n {reviews.map((review) => (\n <li\n key={review.id}\n className=\"rounded-lg border border-border-seam bg-surface-raised p-4 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-text-primary\">\n {review.title || 'Untitled review'}\n </p>\n <span className=\"rounded-full bg-surface-muted px-2 py-0.5 text-xs text-text-secondary\">\n {review.status}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {review.comment || 'No comment provided.'}\n </p>\n <p className=\"mt-2 text-xs text-text-secondary\">\n User {review.userId} • Rating {review.rating}/5 • Helpful {review.helpful}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => removeReview(review.id)}\n disabled={actingId === review.id}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-danger px-3 py-1.5 text-sm font-medium text-text-danger hover:bg-surface-danger-muted disabled:cursor-not-allowed disabled:opacity-60\"\n >\n <X className=\"size-4\" /> Remove\n </button>\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminReviewModerationPage.js","names":[],"sources":["../../src/pages/AdminReviewModerationPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState, useRef, useEffect } from 'react';\nimport { ArrowLeft, Search, X, MessageSquareWarning } from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\n\ntype ModerationReview = {\n id: string;\n userId: string;\n rating: number;\n title?: string | null;\n comment?: string | null;\n status: string;\n helpful: number;\n createdAt: string;\n};\n\ntype ProductSearchResult = {\n id: string;\n name: string;\n slug: string;\n};\n\nconst SEARCH_PRODUCTS_QUERY = `query SearchProductsForModeration($query: String!) { searchProducts(query: $query, limit: 10) { id name slug } }`;\nconst PRODUCT_REVIEWS_QUERY = `query ProductReviewsForModeration($productId: String!) { productReviews(productId: $productId) { id userId rating title comment status helpful createdAt } }`;\nconst REJECT_REVIEW_MUTATION = `mutation RejectReview($id: ID!) { rejectReview(id: $id) { id status } }`;\n\nexport const AdminReviewModerationPage: FC = () => {\n const navigate = useNavigate();\n const { authToken } = useStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [searchResults, setSearchResults] = useState<ProductSearchResult[]>([]);\n const [searchLoading, setSearchLoading] = useState(false);\n const [showDropdown, setShowDropdown] = useState(false);\n const [selectedProduct, setSelectedProduct] = useState<ProductSearchResult | null>(null);\n const [reviews, setReviews] = useState<ModerationReview[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [actingId, setActingId] = useState<string | null>(null);\n const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setShowDropdown(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n setSelectedProduct(null);\n setReviews([]);\n setError(null);\n\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n if (!value.trim()) {\n setSearchResults([]);\n setShowDropdown(false);\n return;\n }\n\n searchDebounceRef.current = setTimeout(async () => {\n setSearchLoading(true);\n try {\n const result = await graphqlFetch<{ searchProducts: ProductSearchResult[] }>({\n gateway: 'global',\n query: SEARCH_PRODUCTS_QUERY,\n variables: { query: value },\n authToken: authToken || undefined,\n });\n setSearchResults(result.data?.searchProducts ?? []);\n setShowDropdown(true);\n } catch {\n setSearchResults([]);\n } finally {\n setSearchLoading(false);\n }\n }, 300);\n };\n\n const selectProduct = (product: ProductSearchResult) => {\n setSelectedProduct(product);\n setSearchQuery(product.name);\n setShowDropdown(false);\n void loadReviews(product.id);\n };\n\n const loadReviews = async (productId: string) => {\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ productReviews: ModerationReview[] }>({\n gateway: 'global',\n query: PRODUCT_REVIEWS_QUERY,\n variables: { productId },\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to fetch reviews');\n }\n\n setReviews(result.data?.productReviews ?? []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to fetch reviews');\n } finally {\n setLoading(false);\n }\n };\n\n const removeReview = async (reviewId: string) => {\n setActingId(reviewId);\n setError(null);\n try {\n const result = await graphqlFetch({\n gateway: 'global',\n query: REJECT_REVIEW_MUTATION,\n variables: { id: reviewId },\n authToken: authToken || undefined,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to remove review');\n }\n\n setReviews((prev) => prev.filter((review) => review.id !== reviewId));\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to remove review');\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n <div className=\"flex items-center gap-2\">\n <MessageSquareWarning className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Review Moderation</h1>\n </div>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Review published content by product and remove anything that violates guidelines\n </p>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl p-6\">\n <div className=\"space-y-4\">\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4\">\n <div ref={dropdownRef} className=\"relative\">\n <label\n htmlFor=\"admin-review-product-search\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n Search product by name\n </label>\n <div className=\"relative flex items-center\">\n <Search className=\"pointer-events-none absolute left-3 size-4 text-text-secondary\" />\n <input\n id=\"admin-review-product-search\"\n aria-label=\"Search product by name\"\n value={searchQuery}\n onChange={(e) => handleSearchChange(e.target.value)}\n onFocus={() => searchResults.length > 0 && setShowDropdown(true)}\n placeholder=\"Type a product name to search...\"\n autoComplete=\"off\"\n className=\"w-full rounded-md border border-border-default bg-surface-default py-2 pl-9 pr-3 text-sm text-text-primary outline-none focus:border-border-accent\"\n />\n {searchLoading && (\n <span className=\"absolute right-3 text-xs text-text-secondary\">Searching…</span>\n )}\n </div>\n\n {showDropdown && searchResults.length > 0 && (\n <ul className=\"absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised shadow-lg\">\n {searchResults.map((product) => (\n <li key={product.id}>\n <button\n type=\"button\"\n onClick={() => selectProduct(product)}\n className=\"w-full px-4 py-2.5 text-left text-sm hover:bg-surface-hover\"\n >\n <span className=\"font-medium text-text-primary\">{product.name}</span>\n <span className=\"ml-2 text-xs text-text-secondary\">{product.slug}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {showDropdown &&\n !searchLoading &&\n searchResults.length === 0 &&\n searchQuery.trim() && (\n <div className=\"absolute z-10 mt-1 w-full rounded-md border border-border-default bg-surface-raised px-4 py-3 text-sm text-text-secondary shadow-lg\">\n No products found for &ldquo;{searchQuery}&rdquo;\n </div>\n )}\n </div>\n\n {selectedProduct && (\n <p className=\"mt-2 text-xs text-text-secondary\">\n Moderating:{' '}\n <span className=\"font-medium text-text-primary\">{selectedProduct.name}</span>\n <span className=\"ml-1 text-text-tertiary\">({selectedProduct.id})</span>\n </p>\n )}\n </div>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {loading && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-10 text-center\">\n <p className=\"text-sm text-text-secondary\">Loading reviews…</p>\n </div>\n )}\n\n {!loading && selectedProduct && reviews.length === 0 ? (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-10 text-center\">\n <MessageSquareWarning className=\"mx-auto mb-2 size-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">No reviews found for this product.</p>\n </div>\n ) : (\n <ul className=\"space-y-3\">\n {reviews.map((review) => (\n <li\n key={review.id}\n className=\"rounded-lg border border-border-default bg-surface-raised p-4\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-text-primary\">\n {review.title || 'Untitled review'}\n </p>\n <span className=\"rounded-full bg-surface-muted px-2 py-0.5 text-xs text-text-secondary\">\n {review.status}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {review.comment || 'No comment provided.'}\n </p>\n <p className=\"mt-2 text-xs text-text-secondary\">\n User {review.userId} • Rating {review.rating}/5 • Helpful {review.helpful}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => removeReview(review.id)}\n disabled={actingId === review.id}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-danger px-3 py-1.5 text-sm font-medium text-text-danger hover:bg-surface-danger-muted disabled:cursor-not-allowed disabled:opacity-60\"\n >\n <X className=\"size-4\" /> Remove\n </button>\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;AAwBA,IAAM,IAAwB,oHACxB,IAAwB,gKACxB,IAAyB,2EAElB,UAAsC;CACjD,IAAM,IAAW,GAAa,EACxB,EAAE,iBAAc,GAAU,EAC1B,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAe,KAAoB,EAAgC,EAAE,CAAC,EACvE,CAAC,GAAe,KAAoB,EAAS,GAAM,EACnD,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAiB,KAAsB,EAAqC,KAAK,EAClF,CAAC,GAAS,KAAc,EAA6B,EAAE,CAAC,EACxD,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAU,KAAe,EAAwB,KAAK,EACvD,IAAoB,EAA6C,KAAK,EACtE,IAAc,EAAuB,KAAK;AAEhD,SAAgB;EACd,IAAM,KAAsB,MAAkB;AAC5C,GAAI,EAAY,WAAW,CAAC,EAAY,QAAQ,SAAS,EAAE,OAAe,IACxE,EAAgB,GAAM;;AAI1B,SADA,SAAS,iBAAiB,aAAa,EAAmB,QAC7C,SAAS,oBAAoB,aAAa,EAAmB;IACzE,EAAE,CAAC;CAEN,IAAM,KAAsB,MAAkB;AAO5C,MANA,EAAe,EAAM,EACrB,EAAmB,KAAK,EACxB,EAAW,EAAE,CAAC,EACd,EAAS,KAAK,EAEV,EAAkB,WAAS,aAAa,EAAkB,QAAQ,EAClE,CAAC,EAAM,MAAM,EAAE;AAEjB,GADA,EAAiB,EAAE,CAAC,EACpB,EAAgB,GAAM;AACtB;;AAGF,IAAkB,UAAU,WAAW,YAAY;AACjD,KAAiB,GAAK;AACtB,OAAI;AAQF,IADA,GANe,MAAM,EAAwD;KAC3E,SAAS;KACT,OAAO;KACP,WAAW,EAAE,OAAO,GAAO;KAC3B,WAAW,KAAa,KAAA;KACzB,CAAC,EACsB,MAAM,kBAAkB,EAAE,CAAC,EACnD,EAAgB,GAAK;WACf;AACN,MAAiB,EAAE,CAAC;aACZ;AACR,MAAiB,GAAM;;KAExB,IAAI;IAGH,KAAiB,MAAiC;AAIjD,EAHL,EAAmB,EAAQ,EAC3B,EAAe,EAAQ,KAAK,EAC5B,EAAgB,GAAM,EACjB,EAAY,EAAQ,GAAG;IAGxB,IAAc,OAAO,MAAsB;AAE/C,EADA,EAAW,GAAK,EAChB,EAAS,KAAK;AACd,MAAI;GACF,IAAM,IAAS,MAAM,EAAqD;IACxE,SAAS;IACT,OAAO;IACP,WAAW,EAAE,cAAW;IACxB,WAAW,KAAa,KAAA;IACzB,CAAC;AAEF,OAAI,EAAO,QAAQ,OACjB,OAAU,MAAM,EAAO,OAAO,IAAI,WAAW,0BAA0B;AAGzE,KAAW,EAAO,MAAM,kBAAkB,EAAE,CAAC;WACtC,GAAK;AACZ,KAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;YAChE;AACR,KAAW,GAAM;;IAIf,IAAe,OAAO,MAAqB;AAE/C,EADA,EAAY,EAAS,EACrB,EAAS,KAAK;AACd,MAAI;GACF,IAAM,IAAS,MAAM,EAAa;IAChC,SAAS;IACT,OAAO;IACP,WAAW,EAAE,IAAI,GAAU;IAC3B,WAAW,KAAa,KAAA;IACzB,CAAC;AAEF,OAAI,EAAO,QAAQ,OACjB,OAAU,MAAM,EAAO,OAAO,IAAI,WAAW,0BAA0B;AAGzE,MAAY,MAAS,EAAK,QAAQ,MAAW,EAAO,OAAO,EAAS,CAAC;WAC9D,GAAK;AACZ,KAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;YAChE;AACR,KAAY,KAAK;;;AAIrB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GAAQ,WAAU;aAChB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,GAAG;MAC3B,cAAW;MACX,WAAU;gBAJZ,CAME,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,EAAA,OAEzB;SACT,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAsB,WAAU,4BAA6B,CAAA,EAC7D,kBAAC,MAAD;OAAI,WAAU;iBAA0C;OAAsB,CAAA,CAC1E;QACF;QACN,kBAAC,KAAD;KAAG,WAAU;eAAmC;KAE5C,CAAA,CACA;;GACC,CAAA,EAET,kBAAC,QAAD;GAAM,WAAU;aACd,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,KAAK;OAAa,WAAU;iBAAjC;QACE,kBAAC,SAAD;SACE,SAAQ;SACR,WAAU;mBACX;SAEO,CAAA;QACR,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,GAAD,EAAQ,WAAU,kEAAmE,CAAA;UACrF,kBAAC,SAAD;WACE,IAAG;WACH,cAAW;WACX,OAAO;WACP,WAAW,MAAM,EAAmB,EAAE,OAAO,MAAM;WACnD,eAAe,EAAc,SAAS,KAAK,EAAgB,GAAK;WAChE,aAAY;WACZ,cAAa;WACb,WAAU;WACV,CAAA;UACD,KACC,kBAAC,QAAD;WAAM,WAAU;qBAA+C;WAAiB,CAAA;UAE9E;;QAEL,KAAgB,EAAc,SAAS,KACtC,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAc,KAAK,MAClB,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAc,EAAQ;UACrC,WAAU;oBAHZ,CAKE,kBAAC,QAAD;WAAM,WAAU;qBAAiC,EAAQ;WAAY,CAAA,EACrE,kBAAC,QAAD;WAAM,WAAU;qBAAoC,EAAQ;WAAY,CAAA,CACjE;aACN,EATI,EAAQ,GASZ,CACL;SACC,CAAA;QAGN,KACC,CAAC,KACD,EAAc,WAAW,KACzB,EAAY,MAAM,IAChB,kBAAC,OAAD;SAAK,WAAU;mBAAf;UAAqJ;UACrH;UAAY;UACtC;;QAEN;UAEL,KACC,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAAgD;QAClC;QACZ,kBAAC,QAAD;SAAM,WAAU;mBAAiC,EAAgB;SAAY,CAAA;QAC7E,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UAA0C;UAAE,EAAgB;UAAG;UAAQ;;QACrE;SAEF;;KAEL,KACC,kBAAC,OAAD;MACE,MAAK;MACL,WAAU;gBAET;MACG,CAAA;KAGP,KACC,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAoB,CAAA;MAC3D,CAAA;KAGP,CAAC,KAAW,KAAmB,EAAQ,WAAW,IACjD,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAsB,WAAU,2CAA4C,CAAA,EAC5E,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAsC,CAAA,CAC7E;UAEN,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAQ,KAAK,MACZ,kBAAC,MAAD;OAEE,WAAU;iBAEV,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAO,SAAS;WACf,CAAA,EACJ,kBAAC,QAAD;WAAM,WAAU;qBACb,EAAO;WACH,CAAA,CACH;;SACN,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAO,WAAW;UACjB,CAAA;SACJ,kBAAC,KAAD;UAAG,WAAU;oBAAb;WAAgD;WACxC,EAAO;WAAO;WAAW,EAAO;WAAO;WAAc,EAAO;WAChE;;SACA,EAAA,CAAA,EACN,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAa,EAAO,GAAG;UACtC,UAAU,MAAa,EAAO;UAC9B,WAAU;oBAJZ,CAME,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA,EAAA,UACjB;;SACL,CAAA,CACF;;OACH,EA/BE,EAAO,GA+BT,CACL;MACC,CAAA;KAEH;;GACD,CAAA,CACH"}