@burdenoff/microfe-devportal 2026.1112.2 → 2026.1113.1

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 (31) hide show
  1. package/dist/devportal/components/AppCard.js +73 -70
  2. package/dist/devportal/components/AppCard.js.map +1 -1
  3. package/dist/devportal/components/ImageUploadField.js +82 -80
  4. package/dist/devportal/components/ImageUploadField.js.map +1 -1
  5. package/dist/devportal/components/StoreImage.d.ts +15 -0
  6. package/dist/devportal/components/StoreImage.js +30 -0
  7. package/dist/devportal/components/StoreImage.js.map +1 -0
  8. package/dist/devportal/components/index.d.ts +1 -0
  9. package/dist/devportal/components/index.js +17 -16
  10. package/dist/devportal/hooks/usePackageUpload.d.ts +46 -4
  11. package/dist/devportal/hooks/usePackageUpload.js +90 -36
  12. package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
  13. package/dist/devportal/pages/AdminReviewPage.js +205 -202
  14. package/dist/devportal/pages/AdminReviewPage.js.map +1 -1
  15. package/dist/devportal/pages/ApplicationDetailPage.js +2 -2
  16. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  17. package/dist/devportal/pages/ApplicationsPage.js +201 -199
  18. package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
  19. package/dist/devportal/pages/CreatePhysicalItemPage.js +2 -2
  20. package/dist/devportal/pages/CreatePhysicalItemPage.js.map +1 -1
  21. package/dist/devportal/pages/EditPhysicalItemPage.js +312 -307
  22. package/dist/devportal/pages/EditPhysicalItemPage.js.map +1 -1
  23. package/dist/devportal/pages/ListingPreviewPage.js +175 -171
  24. package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
  25. package/dist/devportal/pages/SellerDashboardPage.js +118 -116
  26. package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
  27. package/dist/devportal/pages/SellerItemsPage.js +202 -199
  28. package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
  29. package/dist/devportal/pages/StoreSubmissionPage.js +133 -131
  30. package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
  31. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SellerDashboardPage.js","names":["_Fragment","EmptyState","EmptyState$1","STATUS_BADGE_STYLES","formatPrice","curr","currency","price","BOOTSTRAP_QUERY","buildOrgCurrencyBatchQuery","orgIds","i","id","SELLER_PRODUCTS_QUERY","SellerDashboardPage","useDevportal","useI18n","tr","value","t","key","fallback","gqlUrl","resolveGlobalGraphqlEndpoint","apiGatewayUrl","bootstrapLoading","setBootstrapLoading","useState","productsLoading","setProductsLoading","orgs","setOrgs","publisherId","setPublisherId","products","setProducts","orgCurrencies","setOrgCurrencies","useEffect","cancelled","res","authToken","json","org","DIGITAL_TYPES","p","visibleOrgIds","next","o","isLoading","statsLoading","totalItems","pendingCount","publishedCount","handleNavigate","basePath","path","PermissionGuard","PageLayout","Fragment","GradientText","Plus","Loader2","StatPill","Package","Clock","CheckCircle2","Building2","DashSection","ArrowRight","ProductCard","product","OrgCard","icon","label","title","action","children","badge","GlassCard","onClick","initials","w","DollarSign","formatCurrency"],"sources":["../../../src/devportal/pages/SellerDashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Package,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n DollarSign,\n Clock,\n CheckCircle2,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { formatCurrency } from \"../utils/currency\";\nimport { resolveGlobalGraphqlEndpoint } from \"../utils/graphqlEndpoint\";\n\n// ---------------------------------------------------------------------------\n// Local types\n// ---------------------------------------------------------------------------\n\ntype ProductStatus =\n \"DRAFT\" | \"PENDING_REVIEW\" | \"PUBLISHED\" | \"REJECTED\" | \"INACTIVE\";\n\ninterface PhysicalProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n status: ProductStatus;\n price: number;\n currency: string;\n stockQuantity: number;\n icon?: string | null;\n}\n\ninterface OrgSummary {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string | null;\n isVerified: boolean;\n publishedApps?: number | null;\n totalInstalls?: number | null;\n totalRevenue?: number | null;\n kind: \"DIGITAL\" | \"PHYSICAL\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst STATUS_BADGE_STYLES: Record<\n ProductStatus,\n { label: string; className: string }\n> = {\n PUBLISHED: {\n label: \"Published\",\n className: \"text-status-success-text bg-status-success-bg-subtle\",\n },\n PENDING_REVIEW: {\n label: \"Pending Review\",\n className: \"text-status-warning-text bg-status-warning-bg-subtle\",\n },\n DRAFT: {\n label: \"Draft\",\n className: \"text-text-muted bg-bg-muted\",\n },\n REJECTED: {\n label: \"Rejected\",\n className: \"text-status-error-text bg-status-error-bg/10\",\n },\n INACTIVE: {\n label: \"Inactive\",\n className: \"text-text-muted bg-bg-muted\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(price: number, currency: string): string {\n const curr = currency || \"USD\";\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: curr,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(price);\n return `${formatted} ${curr}`;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL query strings\n// ---------------------------------------------------------------------------\n\nconst BOOTSTRAP_QUERY = `\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n`;\n\n/**\n * org.totalRevenue has no currency field of its own on the backend model —\n * one aliased developerOrgRevenueSummary lookup per visible org card (at\n * most 3 here) gets the org's real dominant currency to label it with,\n * batched into a single request the same way buildIssueFlagsBatchQuery does\n * in SellerOrdersPage.tsx.\n */\nfunction buildOrgCurrencyBatchQuery(orgIds: string[]): string {\n const fields = orgIds\n .map(\n (id, i) =>\n `o${i}: developerOrgRevenueSummary(organizationId: ${JSON.stringify(id)}, period: \"monthly\") { currency }`,\n )\n .join(\"\\n \");\n return `query SellerDashboardOrgCurrencies {\\n ${fields}\\n }`;\n}\n\nconst SELLER_PRODUCTS_QUERY = `\n query SellerDashboardProducts($publisherId: String!) {\n products(filter: { publisherId: $publisherId, nature: PHYSICAL }, limit: 3, offset: 0) {\n id\n name\n slug\n type\n status\n price\n currency\n stockQuantity\n icon\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Page component\n// ---------------------------------------------------------------------------\n\nexport const SellerDashboardPage: FC = () => {\n const { navigate, basePath, apiGatewayUrl, authToken } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const gqlUrl = resolveGlobalGraphqlEndpoint(apiGatewayUrl);\n\n const [bootstrapLoading, setBootstrapLoading] = useState(true);\n const [productsLoading, setProductsLoading] = useState(false);\n const [orgs, setOrgs] = useState<OrgSummary[]>([]);\n const [publisherId, setPublisherId] = useState<string | null>(null);\n const [products, setProducts] = useState<PhysicalProduct[]>([]);\n const [orgCurrencies, setOrgCurrencies] = useState<Record<string, string>>(\n {},\n );\n\n // Fetch orgs + publisher in one round-trip\n useEffect(() => {\n let cancelled = false;\n setBootstrapLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({ query: BOOTSTRAP_QUERY }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n myDeveloperOrganizations?: OrgSummary[];\n myPublisher?: { id: string } | null;\n };\n };\n if (cancelled) return;\n // Seller portal only ever shows PHYSICAL-kind orgs — a DIGITAL org\n // (regular app-publishing) has no business here. See DeveloperOrgKind\n // (BOFF-7285).\n setOrgs(\n (json.data?.myDeveloperOrganizations ?? []).filter(\n (org) => org.kind === \"PHYSICAL\",\n ),\n );\n setPublisherId(json.data?.myPublisher?.id ?? null);\n } finally {\n if (!cancelled) setBootstrapLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [gqlUrl, authToken]);\n\n // Fetch recent physical products once publisher is known\n useEffect(() => {\n if (!publisherId) return;\n let cancelled = false;\n setProductsLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: SELLER_PRODUCTS_QUERY,\n variables: { publisherId },\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n products?: Array<\n Omit<PhysicalProduct, \"status\"> & { status: string }\n >;\n };\n };\n if (cancelled) return;\n const DIGITAL_TYPES = new Set([\"APP\", \"NODE\", \"WORKFLOW\"]);\n setProducts(\n (json.data?.products ?? [])\n .filter((p) => !DIGITAL_TYPES.has(p.type))\n .map((p) => ({\n ...p,\n status: p.status as ProductStatus,\n })),\n );\n } finally {\n if (!cancelled) setProductsLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [publisherId, gqlUrl, authToken]);\n\n // Fetch each visible org card's real currency once orgs are known\n useEffect(() => {\n const visibleOrgIds = orgs.slice(0, 3).map((org) => org.id);\n if (visibleOrgIds.length === 0) return;\n let cancelled = false;\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: buildOrgCurrencyBatchQuery(visibleOrgIds),\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: Record<string, { currency: string } | null>;\n };\n if (cancelled || !json.data) return;\n const next: Record<string, string> = {};\n visibleOrgIds.forEach((id, i) => {\n const currency = json.data?.[`o${i}`]?.currency;\n if (currency) next[id] = currency;\n });\n setOrgCurrencies(next);\n } catch {\n // Non-critical — cards fall back to USD if this fails.\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- refetch keyed on org id membership, not array identity\n }, [orgs.map((o) => o.id).join(\",\"), gqlUrl, authToken]);\n\n const isLoading = bootstrapLoading;\n const statsLoading = bootstrapLoading || productsLoading;\n\n const totalItems = products.length;\n const pendingCount = products.filter(\n (p) => p.status === \"PENDING_REVIEW\",\n ).length;\n const publishedCount = products.filter(\n (p) => p.status === \"PUBLISHED\",\n ).length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.seller\", \"Seller\")}{\" \"}\n <GradientText>\n {tr(\"devportal.dashboard\", \"Dashboard\")}\n </GradientText>\n </>\n }\n actions={\n // Whether or not a PHYSICAL org exists yet, this always goes to the\n // same place — CreatePhysicalItemPage auto-provisions one via\n // createSellerOrganization on first listing (see\n // useSellerOrganization, BOFF-7285). Hidden only while loading.\n !isLoading ? (\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {statsLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<Package size={14} />}\n value={totalItems}\n label={tr(\"devportal.items\", \"Items\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Clock size={14} />}\n value={pendingCount}\n label={tr(\"devportal.pendingReview\", \"Pending Review\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<CheckCircle2 size={14} />}\n value={publishedCount}\n label={tr(\"devportal.published\", \"Published\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={orgs.length}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Listings */}\n <DashSection\n title={tr(\"devportal.recentListings\", \"Recent Listings\")}\n action={\n products.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/items\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading || productsLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : products.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {products.slice(0, 3).map((product) => (\n <ProductCard\n key={product.id}\n product={product}\n onClick={() => handleNavigate(\"/seller/items\")}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\n \"devportal.listYourFirstItem\",\n \"List your first item\",\n )}\n description={tr(\n \"devportal.addPhysicalProductsToYourStore\",\n \"Add physical products to your store and they will appear here. Your seller organization is set up automatically the first time you list an item.\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || orgs.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n orgs.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {orgs.slice(0, 3).map((org) => (\n <OrgCard\n key={org.id}\n org={org}\n currency={orgCurrencies[org.id] ?? \"USD\"}\n onClick={() =>\n handleNavigate(`/seller/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst ProductCard: FC<{\n product: PhysicalProduct;\n onClick: () => void;\n}> = ({ product, onClick }) => {\n const badge =\n STATUS_BADGE_STYLES[product.status] ?? STATUS_BADGE_STYLES.DRAFT;\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {product.icon ? (\n <img\n src={product.icon}\n alt={product.name}\n className=\"h-10 w-10 rounded-xl object-cover shrink-0\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary shrink-0\">\n <Package size={20} />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">\n {product.name}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {formatPrice(product.price, product.currency)}\n </p>\n </div>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${badge.className}`}\n >\n {badge.label}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <Package size={12} className=\"text-text-muted shrink-0\" />\n <span\n className={\n product.stockQuantity === 0\n ? \"text-status-error-text\"\n : \"text-text-secondary\"\n }\n >\n {product.stockQuantity === 0\n ? \"Out of stock\"\n : `${product.stockQuantity} in stock`}\n </span>\n </div>\n </GlassCard>\n );\n};\n\nconst OrgCard: FC<{\n org: OrgSummary;\n currency: string;\n onClick: () => void;\n}> = ({ org, currency, onClick }) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n {/* Every org on this page is PHYSICAL (seller-only dashboard) —\n \"Installs\" is an app-marketplace concept that doesn't apply, so\n Revenue gets the full-width cell instead of sharing a 2-col grid. */}\n <div className=\"grid grid-cols-1 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {formatCurrency(org.totalRevenue ?? 0, currency)}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"SellerDashboardPage.js","names":["_Fragment","EmptyState","EmptyState$1","STATUS_BADGE_STYLES","formatPrice","curr","currency","price","BOOTSTRAP_QUERY","buildOrgCurrencyBatchQuery","orgIds","i","id","SELLER_PRODUCTS_QUERY","SellerDashboardPage","useDevportal","useI18n","tr","value","t","key","fallback","gqlUrl","resolveGlobalGraphqlEndpoint","apiGatewayUrl","bootstrapLoading","setBootstrapLoading","useState","productsLoading","setProductsLoading","orgs","setOrgs","publisherId","setPublisherId","products","setProducts","orgCurrencies","setOrgCurrencies","useEffect","cancelled","res","authToken","json","org","DIGITAL_TYPES","p","visibleOrgIds","next","o","isLoading","statsLoading","totalItems","pendingCount","publishedCount","handleNavigate","basePath","path","PermissionGuard","PageLayout","Fragment","GradientText","Plus","Loader2","StatPill","Package","Clock","CheckCircle2","Building2","DashSection","ArrowRight","ProductCard","product","OrgCard","icon","label","title","action","children","badge","GlassCard","onClick","StoreImage","initials","w","DollarSign","formatCurrency"],"sources":["../../../src/devportal/pages/SellerDashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Package,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n DollarSign,\n Clock,\n CheckCircle2,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { formatCurrency } from \"../utils/currency\";\nimport { resolveGlobalGraphqlEndpoint } from \"../utils/graphqlEndpoint\";\nimport { StoreImage } from \"../components/StoreImage\";\n\n// ---------------------------------------------------------------------------\n// Local types\n// ---------------------------------------------------------------------------\n\ntype ProductStatus =\n \"DRAFT\" | \"PENDING_REVIEW\" | \"PUBLISHED\" | \"REJECTED\" | \"INACTIVE\";\n\ninterface PhysicalProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n status: ProductStatus;\n price: number;\n currency: string;\n stockQuantity: number;\n icon?: string | null;\n}\n\ninterface OrgSummary {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string | null;\n isVerified: boolean;\n publishedApps?: number | null;\n totalInstalls?: number | null;\n totalRevenue?: number | null;\n kind: \"DIGITAL\" | \"PHYSICAL\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst STATUS_BADGE_STYLES: Record<\n ProductStatus,\n { label: string; className: string }\n> = {\n PUBLISHED: {\n label: \"Published\",\n className: \"text-status-success-text bg-status-success-bg-subtle\",\n },\n PENDING_REVIEW: {\n label: \"Pending Review\",\n className: \"text-status-warning-text bg-status-warning-bg-subtle\",\n },\n DRAFT: {\n label: \"Draft\",\n className: \"text-text-muted bg-bg-muted\",\n },\n REJECTED: {\n label: \"Rejected\",\n className: \"text-status-error-text bg-status-error-bg/10\",\n },\n INACTIVE: {\n label: \"Inactive\",\n className: \"text-text-muted bg-bg-muted\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(price: number, currency: string): string {\n const curr = currency || \"USD\";\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: curr,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(price);\n return `${formatted} ${curr}`;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL query strings\n// ---------------------------------------------------------------------------\n\nconst BOOTSTRAP_QUERY = `\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n`;\n\n/**\n * org.totalRevenue has no currency field of its own on the backend model —\n * one aliased developerOrgRevenueSummary lookup per visible org card (at\n * most 3 here) gets the org's real dominant currency to label it with,\n * batched into a single request the same way buildIssueFlagsBatchQuery does\n * in SellerOrdersPage.tsx.\n */\nfunction buildOrgCurrencyBatchQuery(orgIds: string[]): string {\n const fields = orgIds\n .map(\n (id, i) =>\n `o${i}: developerOrgRevenueSummary(organizationId: ${JSON.stringify(id)}, period: \"monthly\") { currency }`,\n )\n .join(\"\\n \");\n return `query SellerDashboardOrgCurrencies {\\n ${fields}\\n }`;\n}\n\nconst SELLER_PRODUCTS_QUERY = `\n query SellerDashboardProducts($publisherId: String!) {\n products(filter: { publisherId: $publisherId, nature: PHYSICAL }, limit: 3, offset: 0) {\n id\n name\n slug\n type\n status\n price\n currency\n stockQuantity\n icon\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Page component\n// ---------------------------------------------------------------------------\n\nexport const SellerDashboardPage: FC = () => {\n const { navigate, basePath, apiGatewayUrl, authToken } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const gqlUrl = resolveGlobalGraphqlEndpoint(apiGatewayUrl);\n\n const [bootstrapLoading, setBootstrapLoading] = useState(true);\n const [productsLoading, setProductsLoading] = useState(false);\n const [orgs, setOrgs] = useState<OrgSummary[]>([]);\n const [publisherId, setPublisherId] = useState<string | null>(null);\n const [products, setProducts] = useState<PhysicalProduct[]>([]);\n const [orgCurrencies, setOrgCurrencies] = useState<Record<string, string>>(\n {},\n );\n\n // Fetch orgs + publisher in one round-trip\n useEffect(() => {\n let cancelled = false;\n setBootstrapLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({ query: BOOTSTRAP_QUERY }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n myDeveloperOrganizations?: OrgSummary[];\n myPublisher?: { id: string } | null;\n };\n };\n if (cancelled) return;\n // Seller portal only ever shows PHYSICAL-kind orgs — a DIGITAL org\n // (regular app-publishing) has no business here. See DeveloperOrgKind\n // (BOFF-7285).\n setOrgs(\n (json.data?.myDeveloperOrganizations ?? []).filter(\n (org) => org.kind === \"PHYSICAL\",\n ),\n );\n setPublisherId(json.data?.myPublisher?.id ?? null);\n } finally {\n if (!cancelled) setBootstrapLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [gqlUrl, authToken]);\n\n // Fetch recent physical products once publisher is known\n useEffect(() => {\n if (!publisherId) return;\n let cancelled = false;\n setProductsLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: SELLER_PRODUCTS_QUERY,\n variables: { publisherId },\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n products?: Array<\n Omit<PhysicalProduct, \"status\"> & { status: string }\n >;\n };\n };\n if (cancelled) return;\n const DIGITAL_TYPES = new Set([\"APP\", \"NODE\", \"WORKFLOW\"]);\n setProducts(\n (json.data?.products ?? [])\n .filter((p) => !DIGITAL_TYPES.has(p.type))\n .map((p) => ({\n ...p,\n status: p.status as ProductStatus,\n })),\n );\n } finally {\n if (!cancelled) setProductsLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [publisherId, gqlUrl, authToken]);\n\n // Fetch each visible org card's real currency once orgs are known\n useEffect(() => {\n const visibleOrgIds = orgs.slice(0, 3).map((org) => org.id);\n if (visibleOrgIds.length === 0) return;\n let cancelled = false;\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: buildOrgCurrencyBatchQuery(visibleOrgIds),\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: Record<string, { currency: string } | null>;\n };\n if (cancelled || !json.data) return;\n const next: Record<string, string> = {};\n visibleOrgIds.forEach((id, i) => {\n const currency = json.data?.[`o${i}`]?.currency;\n if (currency) next[id] = currency;\n });\n setOrgCurrencies(next);\n } catch {\n // Non-critical — cards fall back to USD if this fails.\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- refetch keyed on org id membership, not array identity\n }, [orgs.map((o) => o.id).join(\",\"), gqlUrl, authToken]);\n\n const isLoading = bootstrapLoading;\n const statsLoading = bootstrapLoading || productsLoading;\n\n const totalItems = products.length;\n const pendingCount = products.filter(\n (p) => p.status === \"PENDING_REVIEW\",\n ).length;\n const publishedCount = products.filter(\n (p) => p.status === \"PUBLISHED\",\n ).length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.seller\", \"Seller\")}{\" \"}\n <GradientText>\n {tr(\"devportal.dashboard\", \"Dashboard\")}\n </GradientText>\n </>\n }\n actions={\n // Whether or not a PHYSICAL org exists yet, this always goes to the\n // same place — CreatePhysicalItemPage auto-provisions one via\n // createSellerOrganization on first listing (see\n // useSellerOrganization, BOFF-7285). Hidden only while loading.\n !isLoading ? (\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {statsLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<Package size={14} />}\n value={totalItems}\n label={tr(\"devportal.items\", \"Items\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Clock size={14} />}\n value={pendingCount}\n label={tr(\"devportal.pendingReview\", \"Pending Review\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<CheckCircle2 size={14} />}\n value={publishedCount}\n label={tr(\"devportal.published\", \"Published\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={orgs.length}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Listings */}\n <DashSection\n title={tr(\"devportal.recentListings\", \"Recent Listings\")}\n action={\n products.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/items\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading || productsLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : products.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {products.slice(0, 3).map((product) => (\n <ProductCard\n key={product.id}\n product={product}\n onClick={() => handleNavigate(\"/seller/items\")}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\n \"devportal.listYourFirstItem\",\n \"List your first item\",\n )}\n description={tr(\n \"devportal.addPhysicalProductsToYourStore\",\n \"Add physical products to your store and they will appear here. Your seller organization is set up automatically the first time you list an item.\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || orgs.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n orgs.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {orgs.slice(0, 3).map((org) => (\n <OrgCard\n key={org.id}\n org={org}\n currency={orgCurrencies[org.id] ?? \"USD\"}\n onClick={() =>\n handleNavigate(`/seller/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst ProductCard: FC<{\n product: PhysicalProduct;\n onClick: () => void;\n}> = ({ product, onClick }) => {\n const badge =\n STATUS_BADGE_STYLES[product.status] ?? STATUS_BADGE_STYLES.DRAFT;\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n <StoreImage\n src={product.icon}\n alt={product.name}\n className=\"h-10 w-10 rounded-xl object-cover shrink-0\"\n fallback={\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary shrink-0\">\n <Package size={20} />\n </div>\n }\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">\n {product.name}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {formatPrice(product.price, product.currency)}\n </p>\n </div>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${badge.className}`}\n >\n {badge.label}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <Package size={12} className=\"text-text-muted shrink-0\" />\n <span\n className={\n product.stockQuantity === 0\n ? \"text-status-error-text\"\n : \"text-text-secondary\"\n }\n >\n {product.stockQuantity === 0\n ? \"Out of stock\"\n : `${product.stockQuantity} in stock`}\n </span>\n </div>\n </GlassCard>\n );\n};\n\nconst OrgCard: FC<{\n org: OrgSummary;\n currency: string;\n onClick: () => void;\n}> = ({ org, currency, onClick }) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n {/* Every org on this page is PHYSICAL (seller-only dashboard) —\n \"Installs\" is an app-marketplace concept that doesn't apply, so\n Revenue gets the full-width cell instead of sharing a 2-col grid. */}\n <div className=\"grid grid-cols-1 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {formatCurrency(org.totalRevenue ?? 0, currency)}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}