@burdenoff/microfe-devportal 2026.915.12 → 2026.916.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/devportal/DevportalRoutes.d.ts.map +1 -1
- package/dist/devportal/DevportalRoutes.js +131 -126
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.d.ts.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +516 -527
- package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.d.ts.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +79 -93
- package/dist/devportal/pages/OrganizationsPage.js.map +1 -1
- package/dist/devportal/pages/RevenueDashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/RevenueDashboardPage.js +196 -203
- package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.js +120 -96
- package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SellerOrdersPage.d.ts.map +1 -1
- package/dist/devportal/pages/SellerOrdersPage.js +100 -106
- package/dist/devportal/pages/SellerOrdersPage.js.map +1 -1
- package/dist/devportal/utils/currency.d.ts +2 -0
- package/dist/devportal/utils/currency.d.ts.map +1 -0
- package/dist/devportal/utils/currency.js +12 -0
- package/dist/devportal/utils/currency.js.map +1 -0
- package/dist/generated/global-operations.js +51 -44
- package/dist/generated/global-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,27 +9,27 @@ import { StatusBadge as c, VerifiedBadge as l } from "../components/StatusBadge.
|
|
|
9
9
|
import { PermissionGuard as u } from "../components/PermissionGuard.js";
|
|
10
10
|
import "../components/index.js";
|
|
11
11
|
import "../hooks/index.js";
|
|
12
|
-
import { AlertCircle as d, AppWindow as f, Building2 as p, CheckCircle as m,
|
|
13
|
-
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
12
|
+
import { AlertCircle as d, AppWindow as f, Building2 as p, CheckCircle as m, Loader2 as h, Plus as g, Users as _ } from "lucide-react";
|
|
13
|
+
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
14
14
|
import { EmphasisPanel as x, GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
15
15
|
//#region src/devportal/pages/OrganizationsPage.tsx
|
|
16
16
|
var C = () => {
|
|
17
|
-
let { navigate: c, basePath: l } = e(), f = t(), p = i(), { data: m, loading:
|
|
17
|
+
let { navigate: c, basePath: l } = e(), f = t(), p = i(), { data: m, loading: _, error: C, refetch: T } = a({ fetchPolicy: "cache-and-network" }), E = (m?.myDeveloperOrganizations ?? []).filter((e) => p ? e.kind === "PHYSICAL" : e.kind !== "PHYSICAL"), D = (e) => {
|
|
18
18
|
c?.(`${l}${e}`);
|
|
19
|
-
},
|
|
20
|
-
return
|
|
21
|
-
title:
|
|
22
|
-
description:
|
|
19
|
+
}, O = r(p, "new"), k = (e) => r(p, e), A = p ? f("devportal.sellerOrganizations", "Seller Organizations") : f("devportal.developerOrganizations", "Developer Organizations"), j = p ? f("devportal.manageYourSellerOrgs", "Manage the organizations you sell physical goods under") : f("devportal.manageYourDevTeams", "Manage your development teams");
|
|
20
|
+
return _ && !m ? /* @__PURE__ */ y(s, {
|
|
21
|
+
title: A,
|
|
22
|
+
description: j,
|
|
23
23
|
children: /* @__PURE__ */ b("div", {
|
|
24
24
|
className: "flex items-center justify-center py-12",
|
|
25
|
-
children: [/* @__PURE__ */ y(
|
|
25
|
+
children: [/* @__PURE__ */ y(h, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ y("span", {
|
|
26
26
|
className: "ml-2 text-text-secondary",
|
|
27
27
|
children: f("devportal.loadingOrganizations", "Loading organizations...")
|
|
28
28
|
})]
|
|
29
29
|
})
|
|
30
|
-
}) :
|
|
31
|
-
title:
|
|
32
|
-
description:
|
|
30
|
+
}) : C ? /* @__PURE__ */ y(s, {
|
|
31
|
+
title: A,
|
|
32
|
+
description: j,
|
|
33
33
|
children: /* @__PURE__ */ b("div", {
|
|
34
34
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
35
35
|
children: [
|
|
@@ -40,10 +40,10 @@ var C = () => {
|
|
|
40
40
|
}),
|
|
41
41
|
/* @__PURE__ */ y("p", {
|
|
42
42
|
className: "mt-1 text-sm text-text-secondary",
|
|
43
|
-
children: o(
|
|
43
|
+
children: o(C)
|
|
44
44
|
}),
|
|
45
45
|
/* @__PURE__ */ y("button", {
|
|
46
|
-
onClick: () =>
|
|
46
|
+
onClick: () => T(),
|
|
47
47
|
className: "mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
48
48
|
children: f("devportal.tryAgain", "Try Again")
|
|
49
49
|
})
|
|
@@ -52,68 +52,64 @@ var C = () => {
|
|
|
52
52
|
}) : /* @__PURE__ */ y(u, {
|
|
53
53
|
authOnly: !0,
|
|
54
54
|
children: /* @__PURE__ */ b(s, {
|
|
55
|
-
title:
|
|
56
|
-
description:
|
|
55
|
+
title: A,
|
|
56
|
+
description: j,
|
|
57
57
|
purpose: p ? f("devportal.sellerOrganizationsPurpose", "A seller organization owns your physical listings, orders, and revenue. It's created automatically the first time you list an item, or you can create one here.") : f("devportal.organizationsPurpose", "An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation."),
|
|
58
58
|
actions: /* @__PURE__ */ b("button", {
|
|
59
|
-
onClick: () =>
|
|
59
|
+
onClick: () => D(O),
|
|
60
60
|
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",
|
|
61
|
-
children: [/* @__PURE__ */ y(
|
|
61
|
+
children: [/* @__PURE__ */ y(g, { size: 16 }), f("devportal.createOrganization", "Create Organization")]
|
|
62
62
|
}),
|
|
63
|
-
children: [
|
|
63
|
+
children: [E.length > 0 && /* @__PURE__ */ y(x, {
|
|
64
64
|
className: "mb-6",
|
|
65
65
|
children: /* @__PURE__ */ b("div", {
|
|
66
|
-
className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
67
|
-
children: [
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
className: "
|
|
82
|
-
children:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
children: T.reduce((e, t) => e + (t.activeInstalls ?? 0), 0).toLocaleString()
|
|
99
|
-
})]
|
|
100
|
-
})
|
|
101
|
-
]
|
|
66
|
+
className: p ? "grid grid-cols-1 gap-4 sm:max-w-xs" : "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
67
|
+
children: [/* @__PURE__ */ b(S, {
|
|
68
|
+
treatment: "metric",
|
|
69
|
+
className: "p-4",
|
|
70
|
+
children: [/* @__PURE__ */ y("p", {
|
|
71
|
+
className: "text-sm text-text-secondary",
|
|
72
|
+
children: f("devportal.organizations", "Organizations")
|
|
73
|
+
}), /* @__PURE__ */ y("p", {
|
|
74
|
+
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
75
|
+
children: E.length
|
|
76
|
+
})]
|
|
77
|
+
}), !p && /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ b(S, {
|
|
78
|
+
treatment: "metric",
|
|
79
|
+
className: "p-4",
|
|
80
|
+
children: [/* @__PURE__ */ y("p", {
|
|
81
|
+
className: "text-sm text-text-secondary",
|
|
82
|
+
children: f("devportal.totalApps", "Total Apps")
|
|
83
|
+
}), /* @__PURE__ */ y("p", {
|
|
84
|
+
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
85
|
+
children: E.reduce((e, t) => e + (t.totalApps ?? 0), 0)
|
|
86
|
+
})]
|
|
87
|
+
}), /* @__PURE__ */ b(S, {
|
|
88
|
+
treatment: "metric",
|
|
89
|
+
className: "p-4",
|
|
90
|
+
children: [/* @__PURE__ */ y("p", {
|
|
91
|
+
className: "text-sm text-text-secondary",
|
|
92
|
+
children: f("devportal.activeInstalls", "Active Installs")
|
|
93
|
+
}), /* @__PURE__ */ y("p", {
|
|
94
|
+
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
95
|
+
children: E.reduce((e, t) => e + (t.activeInstalls ?? 0), 0).toLocaleString()
|
|
96
|
+
})]
|
|
97
|
+
})] })]
|
|
102
98
|
})
|
|
103
|
-
}),
|
|
99
|
+
}), E.length > 0 ? /* @__PURE__ */ y("div", {
|
|
104
100
|
className: "grid gap-6",
|
|
105
|
-
children:
|
|
101
|
+
children: E.map((e) => /* @__PURE__ */ y(w, {
|
|
106
102
|
org: e,
|
|
107
|
-
onClick: () =>
|
|
103
|
+
onClick: () => D(k(e.id))
|
|
108
104
|
}, e.id))
|
|
109
105
|
}) : /* @__PURE__ */ y(n, {
|
|
110
106
|
illustration: "empty-people",
|
|
111
107
|
title: p ? f("devportal.noSellerOrganizationsYet", "No seller organizations yet") : f("devportal.noOrganizationsYet", "No organizations yet"),
|
|
112
108
|
description: p ? f("devportal.createSellerOrgToSell", "Create a seller organization to start selling physical products, or list your first item and one will be set up for you") : f("devportal.createOrgToCollaborate", "Create an organization to collaborate with your team and manage apps together"),
|
|
113
109
|
action: /* @__PURE__ */ b("button", {
|
|
114
|
-
onClick: () =>
|
|
110
|
+
onClick: () => D(O),
|
|
115
111
|
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",
|
|
116
|
-
children: [/* @__PURE__ */ y(
|
|
112
|
+
children: [/* @__PURE__ */ y(g, { size: 16 }), f("devportal.createOrganization", "Create Organization")]
|
|
117
113
|
})
|
|
118
114
|
})]
|
|
119
115
|
})
|
|
@@ -175,41 +171,31 @@ var C = () => {
|
|
|
175
171
|
] })]
|
|
176
172
|
}), /* @__PURE__ */ b("div", {
|
|
177
173
|
className: "flex flex-wrap gap-6 text-sm",
|
|
178
|
-
children: [
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
/* @__PURE__ */
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
] })]
|
|
202
|
-
}),
|
|
203
|
-
/* @__PURE__ */ b("div", {
|
|
204
|
-
className: "flex items-center gap-2",
|
|
205
|
-
children: [/* @__PURE__ */ y(h, {
|
|
206
|
-
size: 16,
|
|
207
|
-
className: "text-text-secondary"
|
|
208
|
-
}), /* @__PURE__ */ b("span", { children: ["$", (e.totalRevenue || 0).toLocaleString()] })]
|
|
209
|
-
})
|
|
210
|
-
]
|
|
174
|
+
children: [/* @__PURE__ */ b("div", {
|
|
175
|
+
className: "flex items-center gap-2",
|
|
176
|
+
children: [/* @__PURE__ */ y(_, {
|
|
177
|
+
size: 16,
|
|
178
|
+
className: "text-text-secondary"
|
|
179
|
+
}), /* @__PURE__ */ b("span", { children: [
|
|
180
|
+
e.members?.length || 0,
|
|
181
|
+
" ",
|
|
182
|
+
r("devportal.membersLower", "members")
|
|
183
|
+
] })]
|
|
184
|
+
}), e.kind !== "PHYSICAL" && /* @__PURE__ */ b("div", {
|
|
185
|
+
className: "flex items-center gap-2",
|
|
186
|
+
children: [/* @__PURE__ */ y(f, {
|
|
187
|
+
size: 16,
|
|
188
|
+
className: "text-text-secondary"
|
|
189
|
+
}), /* @__PURE__ */ b("span", { children: [
|
|
190
|
+
e.publishedApps,
|
|
191
|
+
" / ",
|
|
192
|
+
e.totalApps,
|
|
193
|
+
" ",
|
|
194
|
+
r("devportal.appsLower", "apps")
|
|
195
|
+
] })]
|
|
196
|
+
})]
|
|
211
197
|
})]
|
|
212
|
-
}), /* @__PURE__ */ b("div", {
|
|
198
|
+
}), e.kind !== "PHYSICAL" && /* @__PURE__ */ b("div", {
|
|
213
199
|
className: "mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4",
|
|
214
200
|
children: [
|
|
215
201
|
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n DollarSign,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useIsSellerSection,\n orgSectionPath,\n} from \"../hooks/useIsSellerSection\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const tr = useTr();\n const isSeller = useIsSellerSection();\n\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n // Shared page for both DIGITAL orgs (regular devportal) and PHYSICAL orgs\n // (seller portal) — filtered by which section it's reached from. See\n // DeveloperOrgKind (BOFF-7285).\n const organizations = (data?.myDeveloperOrganizations ?? []).filter(\n (org: OrganizationFieldsFragment) =>\n isSeller ? org.kind === \"PHYSICAL\" : org.kind !== \"PHYSICAL\",\n );\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const createPath = orgSectionPath(isSeller, \"new\");\n const detailPath = (orgId: string) => orgSectionPath(isSeller, orgId);\n\n const pageTitle = isSeller\n ? tr(\"devportal.sellerOrganizations\", \"Seller Organizations\")\n : tr(\"devportal.developerOrganizations\", \"Developer Organizations\");\n const pageDescription = isSeller\n ? tr(\n \"devportal.manageYourSellerOrgs\",\n \"Manage the organizations you sell physical goods under\",\n )\n : tr(\"devportal.manageYourDevTeams\", \"Manage your development teams\");\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout title={pageTitle} description={pageDescription}>\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout title={pageTitle} description={pageDescription}>\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 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 {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={pageTitle}\n description={pageDescription}\n purpose={\n isSeller\n ? tr(\n \"devportal.sellerOrganizationsPurpose\",\n \"A seller organization owns your physical listings, orders, and revenue. It's created automatically the first time you list an item, or you can create one here.\",\n )\n : tr(\n \"devportal.organizationsPurpose\",\n \"An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation.\",\n )\n }\n actions={\n <button\n onClick={() => handleNavigate(createPath)}\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.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 && (\n <EmphasisPanel className=\"mb-6\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.organizations\", \"Organizations\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalApps ?? 0),\n 0,\n )}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations\n .reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls ?? 0),\n 0,\n )\n .toLocaleString()}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n )}\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(detailPath(org.id))}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={\n isSeller\n ? tr(\n \"devportal.noSellerOrganizationsYet\",\n \"No seller organizations yet\",\n )\n : tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")\n }\n description={\n isSeller\n ? tr(\n \"devportal.createSellerOrgToSell\",\n \"Create a seller organization to start selling physical products, or list your first item and one will be set up for you\",\n )\n : tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )\n }\n action={\n <button\n onClick={() => handleNavigate(createPath)}\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.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n const tr = useTr();\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} />{\" \"}\n {tr(\"devportal.certified\", \"Certified\")}\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>\n {org.members?.length || 0}{\" \"}\n {tr(\"devportal.membersLower\", \"members\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps}{\" \"}\n {tr(\"devportal.appsLower\", \"apps\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <DollarSign size={16} className=\"text-text-secondary\" />\n <span>${(org.totalRevenue || 0).toLocaleString()}</span>\n </div>\n </div>\n </div>\n\n {/* Stats bar */}\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.totalInstalls\", \"Total Installs\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.apiCalls\", \"API Calls\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.avgRating\", \"Avg Rating\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating\n ? `${org.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")}\n </p>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useIsSellerSection,\n orgSectionPath,\n} from \"../hooks/useIsSellerSection\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const tr = useTr();\n const isSeller = useIsSellerSection();\n\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n // Shared page for both DIGITAL orgs (regular devportal) and PHYSICAL orgs\n // (seller portal) — filtered by which section it's reached from. See\n // DeveloperOrgKind (BOFF-7285).\n const organizations = (data?.myDeveloperOrganizations ?? []).filter(\n (org: OrganizationFieldsFragment) =>\n isSeller ? org.kind === \"PHYSICAL\" : org.kind !== \"PHYSICAL\",\n );\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const createPath = orgSectionPath(isSeller, \"new\");\n const detailPath = (orgId: string) => orgSectionPath(isSeller, orgId);\n\n const pageTitle = isSeller\n ? tr(\"devportal.sellerOrganizations\", \"Seller Organizations\")\n : tr(\"devportal.developerOrganizations\", \"Developer Organizations\");\n const pageDescription = isSeller\n ? tr(\n \"devportal.manageYourSellerOrgs\",\n \"Manage the organizations you sell physical goods under\",\n )\n : tr(\"devportal.manageYourDevTeams\", \"Manage your development teams\");\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout title={pageTitle} description={pageDescription}>\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout title={pageTitle} description={pageDescription}>\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 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 {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={pageTitle}\n description={pageDescription}\n purpose={\n isSeller\n ? tr(\n \"devportal.sellerOrganizationsPurpose\",\n \"A seller organization owns your physical listings, orders, and revenue. It's created automatically the first time you list an item, or you can create one here.\",\n )\n : tr(\n \"devportal.organizationsPurpose\",\n \"An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation.\",\n )\n }\n actions={\n <button\n onClick={() => handleNavigate(createPath)}\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.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 && (\n <EmphasisPanel className=\"mb-6\">\n <div\n className={\n isSeller\n ? \"grid grid-cols-1 gap-4 sm:max-w-xs\"\n : \"grid grid-cols-2 gap-4 sm:grid-cols-3\"\n }\n >\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.organizations\", \"Organizations\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.length}\n </p>\n </GlassCard>\n {/* Total Apps / Active Installs are app-marketplace concepts —\n meaningless for PHYSICAL (seller) orgs, which sell items,\n not apps. */}\n {!isSeller && (\n <>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalApps ?? 0),\n 0,\n )}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations\n .reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls ?? 0),\n 0,\n )\n .toLocaleString()}\n </p>\n </GlassCard>\n </>\n )}\n </div>\n </EmphasisPanel>\n )}\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(detailPath(org.id))}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={\n isSeller\n ? tr(\n \"devportal.noSellerOrganizationsYet\",\n \"No seller organizations yet\",\n )\n : tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")\n }\n description={\n isSeller\n ? tr(\n \"devportal.createSellerOrgToSell\",\n \"Create a seller organization to start selling physical products, or list your first item and one will be set up for you\",\n )\n : tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )\n }\n action={\n <button\n onClick={() => handleNavigate(createPath)}\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.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n const tr = useTr();\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} />{\" \"}\n {tr(\"devportal.certified\", \"Certified\")}\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats. Installs/API calls/avg rating/apps count are\n app-marketplace concepts that don't apply to a PHYSICAL (seller)\n org, so it only gets a member count here — everything real for a\n seller org (revenue, items) is one click away on its detail\n page. */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>\n {org.members?.length || 0}{\" \"}\n {tr(\"devportal.membersLower\", \"members\")}\n </span>\n </div>\n {org.kind !== \"PHYSICAL\" && (\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps}{\" \"}\n {tr(\"devportal.appsLower\", \"apps\")}\n </span>\n </div>\n )}\n </div>\n </div>\n\n {org.kind !== \"PHYSICAL\" && (\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.totalInstalls\", \"Total Installs\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.apiCalls\", \"API Calls\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.avgRating\", \"Avg Rating\")}\n </p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating\n ? `${org.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")}\n </p>\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevenueDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/RevenueDashboardPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"RevenueDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/RevenueDashboardPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA8EhC,eAAO,MAAM,oBAAoB,EAAE,EA8qClC,CAAC"}
|