@burdenoff/microfe-devportal 2026.1101.1 → 2026.1107.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 (49) hide show
  1. package/dist/devportal/DevportalRoutes.d.ts.map +1 -1
  2. package/dist/devportal/DevportalRoutes.js +13 -9
  3. package/dist/devportal/DevportalRoutes.js.map +1 -1
  4. package/dist/devportal/components/OnboardingChecklist.d.ts +16 -0
  5. package/dist/devportal/components/OnboardingChecklist.d.ts.map +1 -0
  6. package/dist/devportal/components/OnboardingChecklist.js +151 -0
  7. package/dist/devportal/components/OnboardingChecklist.js.map +1 -0
  8. package/dist/devportal/constants/developerLinks.d.ts +47 -0
  9. package/dist/devportal/constants/developerLinks.d.ts.map +1 -0
  10. package/dist/devportal/constants/developerLinks.js +27 -0
  11. package/dist/devportal/constants/developerLinks.js.map +1 -0
  12. package/dist/devportal/hooks/useGraphQL.d.ts.map +1 -1
  13. package/dist/devportal/hooks/useGraphQL.js +2 -1
  14. package/dist/devportal/hooks/useGraphQL.js.map +1 -1
  15. package/dist/devportal/hooks/usePackageUpload.d.ts +3 -0
  16. package/dist/devportal/hooks/usePackageUpload.d.ts.map +1 -1
  17. package/dist/devportal/hooks/usePackageUpload.js +41 -32
  18. package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
  19. package/dist/devportal/pages/DashboardPage.d.ts.map +1 -1
  20. package/dist/devportal/pages/DashboardPage.js +107 -105
  21. package/dist/devportal/pages/DashboardPage.js.map +1 -1
  22. package/dist/devportal/pages/DocumentationPage.d.ts.map +1 -1
  23. package/dist/devportal/pages/DocumentationPage.js +114 -148
  24. package/dist/devportal/pages/DocumentationPage.js.map +1 -1
  25. package/dist/devportal/pages/PublisherProfilePage.d.ts.map +1 -1
  26. package/dist/devportal/pages/PublisherProfilePage.js +170 -160
  27. package/dist/devportal/pages/PublisherProfilePage.js.map +1 -1
  28. package/dist/devportal/pages/ResourcesPage.js +2 -2
  29. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  30. package/dist/devportal/pages/SetupPage.d.ts.map +1 -1
  31. package/dist/devportal/pages/SetupPage.js +363 -218
  32. package/dist/devportal/pages/SetupPage.js.map +1 -1
  33. package/dist/devportal/utils/developerOnboarding.d.ts +85 -0
  34. package/dist/devportal/utils/developerOnboarding.d.ts.map +1 -0
  35. package/dist/devportal/utils/developerOnboarding.js +104 -0
  36. package/dist/devportal/utils/developerOnboarding.js.map +1 -0
  37. package/dist/devportal/utils/uploadErrors.d.ts +46 -0
  38. package/dist/devportal/utils/uploadErrors.d.ts.map +1 -0
  39. package/dist/devportal/utils/uploadErrors.js +62 -0
  40. package/dist/devportal/utils/uploadErrors.js.map +1 -0
  41. package/dist/generated/global-operations.d.ts +53 -0
  42. package/dist/generated/global-operations.d.ts.map +1 -1
  43. package/dist/generated/global-operations.js +170 -134
  44. package/dist/generated/global-operations.js.map +1 -1
  45. package/dist/translations/en.d.ts +50 -0
  46. package/dist/translations/en.d.ts.map +1 -1
  47. package/dist/translations/en.js +51 -1
  48. package/dist/translations/en.js.map +1 -1
  49. package/package.json +1 -1
@@ -6,135 +6,137 @@ import { PageLayout as i } from "../components/PageLayout.js";
6
6
  import { AppCard as a } from "../components/AppCard.js";
7
7
  import { PermissionGuard as o } from "../components/PermissionGuard.js";
8
8
  import "../components/index.js";
9
+ import { OnboardingChecklist as s } from "../components/OnboardingChecklist.js";
9
10
  import "../hooks/index.js";
10
- import { useEffect as s } from "react";
11
- import { AppWindow as c, ArrowRight as l, Building2 as u, DollarSign as d, Download as f, Loader2 as p, Plus as m } from "lucide-react";
12
- import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
13
- import { GlassCard as v, GradientText as y } from "@burdenoff/fe-libs/ui";
11
+ import { useEffect as c } from "react";
12
+ import { AppWindow as l, ArrowRight as u, Building2 as d, DollarSign as f, Download as p, Loader2 as m, Plus as h } from "lucide-react";
13
+ import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
14
+ import { GlassCard as y, GradientText as b } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/devportal/pages/DashboardPage.tsx
15
- var b = () => {
16
- let { navigate: d, basePath: f, activeOrgId: v, setActiveOrgId: b } = e(), w = t(), { data: T, loading: E } = r({
16
+ var x = () => {
17
+ let { navigate: f, basePath: p, activeOrgId: y, setActiveOrgId: x } = e(), T = t(), { data: E, loading: D } = r({
17
18
  variables: {},
18
19
  fetchPolicy: "network-only"
19
- }), D = (T?.myDeveloperOrganizations ?? []).filter((e) => e.kind !== "PHYSICAL"), O = (() => {
20
- if (D.length) return v && D.some((e) => e.id === v) ? v : D[0]?.id;
20
+ }), O = (E?.myDeveloperOrganizations ?? []).filter((e) => e.kind !== "PHYSICAL"), k = (() => {
21
+ if (O.length) return y && O.some((e) => e.id === y) ? y : O[0]?.id;
21
22
  })();
22
- s(() => {
23
- O && O !== v && b(O);
23
+ c(() => {
24
+ k && k !== y && x(k);
24
25
  }, [
25
- O,
26
- v,
27
- b
26
+ k,
27
+ y,
28
+ x
28
29
  ]);
29
- let { data: k, loading: A } = r({
30
- variables: { organizationId: O },
31
- skip: !O,
30
+ let { data: A, loading: j } = r({
31
+ variables: { organizationId: k },
32
+ skip: !k,
32
33
  fetchPolicy: "cache-and-network"
33
- }), j = E || A, M = k ?? T;
34
- s(() => {
35
- if (!(E || !T) && !(D.length > 0)) {
34
+ }), M = D || j, N = A ?? E;
35
+ c(() => {
36
+ if (!(D || !E) && !(O.length > 0)) {
36
37
  try {
37
38
  if (localStorage.getItem("devportal_setup_dismissed")) return;
38
39
  } catch {
39
40
  return;
40
41
  }
41
- d?.(`${f}/setup`);
42
+ f?.(`${p}/setup`);
42
43
  }
43
44
  }, [
45
+ D,
44
46
  E,
45
- T,
46
- D.length,
47
- d,
48
- f
47
+ O.length,
48
+ f,
49
+ p
49
50
  ]);
50
- let N = k?.applications?.edges?.map((e) => e.node) ?? [], P = M?.applications?.totalCount ?? 0, F = D.length, I = (e) => {
51
- d?.(`${f}${e}`);
52
- }, L = j, R = !E && D.length > 0;
53
- return /* @__PURE__ */ g(o, {
51
+ let P = A?.applications?.edges?.map((e) => e.node) ?? [], F = N?.applications?.totalCount ?? 0, I = O.length, L = (e) => {
52
+ f?.(`${p}${e}`);
53
+ }, R = M, z = !D && O.length > 0;
54
+ return /* @__PURE__ */ _(o, {
54
55
  authOnly: !0,
55
- children: /* @__PURE__ */ g(i, {
56
- title: /* @__PURE__ */ _(h, { children: [
57
- w("devportal.developer", "Developer"),
56
+ children: /* @__PURE__ */ _(i, {
57
+ title: /* @__PURE__ */ v(g, { children: [
58
+ T("devportal.developer", "Developer"),
58
59
  " ",
59
- /* @__PURE__ */ g(y, { children: w("devportal.portal", "Portal") })
60
+ /* @__PURE__ */ _(b, { children: T("devportal.portal", "Portal") })
60
61
  ] }),
61
- actions: R ? /* @__PURE__ */ _("button", {
62
+ actions: z ? /* @__PURE__ */ v("button", {
62
63
  "data-tour": "devportal-dashboard-create-app-button",
63
- onClick: () => I("/apps/new"),
64
+ onClick: () => L("/apps/new"),
64
65
  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",
65
- children: [/* @__PURE__ */ g(m, { size: 16 }), w("devportal.createApp", "Create App")]
66
- }) : L ? null : /* @__PURE__ */ _("button", {
66
+ children: [/* @__PURE__ */ _(h, { size: 16 }), T("devportal.createApp", "Create App")]
67
+ }) : R ? null : /* @__PURE__ */ v("button", {
67
68
  "data-tour": "devportal-dashboard-create-org-button",
68
- onClick: () => I("/organizations/new"),
69
+ onClick: () => L("/organizations/new"),
69
70
  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",
70
- children: [/* @__PURE__ */ g(m, { size: 16 }), w("devportal.createOrganization", "Create Organization")]
71
+ children: [/* @__PURE__ */ _(h, { size: 16 }), T("devportal.createOrganization", "Create Organization")]
71
72
  }),
72
- children: /* @__PURE__ */ _("div", {
73
+ children: /* @__PURE__ */ v("div", {
73
74
  className: "flex flex-col gap-8",
74
75
  children: [
75
- /* @__PURE__ */ g("div", {
76
+ /* @__PURE__ */ _(s, { onNavigate: L }),
77
+ /* @__PURE__ */ _("div", {
76
78
  className: "flex items-center gap-6 border-b border-border-seam pb-6",
77
- children: L ? /* @__PURE__ */ g(p, { className: "h-4 w-4 animate-spin text-text-secondary" }) : /* @__PURE__ */ _(h, { children: [
78
- /* @__PURE__ */ g(x, {
79
- icon: /* @__PURE__ */ g(c, { size: 14 }),
80
- value: P,
81
- label: w("devportal.apps", "Apps")
82
- }),
83
- /* @__PURE__ */ g("div", { className: "h-4 w-px bg-border-seam" }),
84
- /* @__PURE__ */ g(x, {
85
- icon: /* @__PURE__ */ g(u, { size: 14 }),
79
+ children: R ? /* @__PURE__ */ _(m, { className: "h-4 w-4 animate-spin text-text-secondary" }) : /* @__PURE__ */ v(g, { children: [
80
+ /* @__PURE__ */ _(S, {
81
+ icon: /* @__PURE__ */ _(l, { size: 14 }),
86
82
  value: F,
87
- label: w("devportal.organizations", "Organizations")
83
+ label: T("devportal.apps", "Apps")
84
+ }),
85
+ /* @__PURE__ */ _("div", { className: "h-4 w-px bg-border-seam" }),
86
+ /* @__PURE__ */ _(S, {
87
+ icon: /* @__PURE__ */ _(d, { size: 14 }),
88
+ value: I,
89
+ label: T("devportal.organizations", "Organizations")
88
90
  })
89
91
  ] })
90
92
  }),
91
- /* @__PURE__ */ g(S, {
92
- title: w("devportal.recentApplications", "Recent Applications"),
93
- action: N.length > 0 ? /* @__PURE__ */ _("button", {
94
- onClick: () => I("/apps"),
93
+ /* @__PURE__ */ _(C, {
94
+ title: T("devportal.recentApplications", "Recent Applications"),
95
+ action: P.length > 0 ? /* @__PURE__ */ v("button", {
96
+ onClick: () => L("/apps"),
95
97
  className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
96
- children: [w("devportal.viewAll", "View all"), /* @__PURE__ */ g(l, { size: 14 })]
98
+ children: [T("devportal.viewAll", "View all"), /* @__PURE__ */ _(u, { size: 14 })]
97
99
  }) : void 0,
98
- children: L ? /* @__PURE__ */ g("div", {
100
+ children: R ? /* @__PURE__ */ _("div", {
99
101
  className: "flex items-center justify-center py-12",
100
- children: /* @__PURE__ */ g(p, { className: "h-6 w-6 animate-spin text-text-secondary" })
101
- }) : N.length > 0 ? /* @__PURE__ */ g("div", {
102
+ children: /* @__PURE__ */ _(m, { className: "h-6 w-6 animate-spin text-text-secondary" })
103
+ }) : P.length > 0 ? /* @__PURE__ */ _("div", {
102
104
  className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
103
- children: N.slice(0, 3).map((e) => /* @__PURE__ */ g(a, {
105
+ children: P.slice(0, 3).map((e) => /* @__PURE__ */ _(a, {
104
106
  app: e,
105
- onClick: () => I(`/apps/${e.id}`),
107
+ onClick: () => L(`/apps/${e.id}`),
106
108
  showActions: !1
107
109
  }, e.id))
108
- }) : /* @__PURE__ */ g(n, {
110
+ }) : /* @__PURE__ */ _(n, {
109
111
  illustration: "empty-generic",
110
- title: w("devportal.noApplicationsYet", "No applications yet"),
111
- description: R ? w("devportal.createFirstApplicationToGetStarted", "Create your first application to get started") : w("devportal.createOrgFirstToPublishApps", "Create an organization first to start publishing apps"),
112
- action: R ? /* @__PURE__ */ _("button", {
113
- onClick: () => I("/apps/new"),
112
+ title: T("devportal.noApplicationsYet", "No applications yet"),
113
+ description: z ? T("devportal.createFirstApplicationToGetStarted", "Create your first application to get started") : T("devportal.createOrgFirstToPublishApps", "Create an organization first to start publishing apps"),
114
+ action: z ? /* @__PURE__ */ v("button", {
115
+ onClick: () => L("/apps/new"),
114
116
  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",
115
- children: [/* @__PURE__ */ g(m, { size: 16 }), w("devportal.createApp", "Create App")]
116
- }) : /* @__PURE__ */ _("button", {
117
- onClick: () => I("/organizations/new"),
117
+ children: [/* @__PURE__ */ _(h, { size: 16 }), T("devportal.createApp", "Create App")]
118
+ }) : /* @__PURE__ */ v("button", {
119
+ onClick: () => L("/organizations/new"),
118
120
  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",
119
- children: [/* @__PURE__ */ g(m, { size: 16 }), w("devportal.createOrganization", "Create Organization")]
121
+ children: [/* @__PURE__ */ _(h, { size: 16 }), T("devportal.createOrganization", "Create Organization")]
120
122
  })
121
123
  })
122
124
  }),
123
- (L || D.length > 0) && /* @__PURE__ */ g(S, {
124
- title: w("devportal.yourOrganizations", "Your Organizations"),
125
- action: D.length > 0 ? /* @__PURE__ */ _("button", {
126
- onClick: () => I("/organizations"),
125
+ (R || O.length > 0) && /* @__PURE__ */ _(C, {
126
+ title: T("devportal.yourOrganizations", "Your Organizations"),
127
+ action: O.length > 0 ? /* @__PURE__ */ v("button", {
128
+ onClick: () => L("/organizations"),
127
129
  className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
128
- children: [w("devportal.viewAll", "View all"), /* @__PURE__ */ g(l, { size: 14 })]
130
+ children: [T("devportal.viewAll", "View all"), /* @__PURE__ */ _(u, { size: 14 })]
129
131
  }) : void 0,
130
- children: L ? /* @__PURE__ */ g("div", {
132
+ children: R ? /* @__PURE__ */ _("div", {
131
133
  className: "flex items-center justify-center py-12",
132
- children: /* @__PURE__ */ g(p, { className: "h-6 w-6 animate-spin text-text-secondary" })
133
- }) : /* @__PURE__ */ g("div", {
134
+ children: /* @__PURE__ */ _(m, { className: "h-6 w-6 animate-spin text-text-secondary" })
135
+ }) : /* @__PURE__ */ _("div", {
134
136
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
135
- children: D.slice(0, 3).map((e) => /* @__PURE__ */ g(C, {
137
+ children: O.slice(0, 3).map((e) => /* @__PURE__ */ _(w, {
136
138
  org: e,
137
- onClick: () => I(`/organizations/${e.id}`)
139
+ onClick: () => L(`/organizations/${e.id}`)
138
140
  }, e.id))
139
141
  })
140
142
  })
@@ -142,34 +144,34 @@ var b = () => {
142
144
  })
143
145
  })
144
146
  });
145
- }, x = ({ icon: e, value: t, label: n }) => /* @__PURE__ */ _("div", {
147
+ }, S = ({ icon: e, value: t, label: n }) => /* @__PURE__ */ v("div", {
146
148
  className: "flex items-center gap-1.5",
147
149
  children: [
148
- /* @__PURE__ */ g("span", {
150
+ /* @__PURE__ */ _("span", {
149
151
  className: "text-text-muted",
150
152
  children: e
151
153
  }),
152
- /* @__PURE__ */ g("span", {
154
+ /* @__PURE__ */ _("span", {
153
155
  className: "text-sm font-semibold tabular-nums",
154
156
  children: t
155
157
  }),
156
- /* @__PURE__ */ g("span", {
158
+ /* @__PURE__ */ _("span", {
157
159
  className: "text-sm text-text-secondary",
158
160
  children: n
159
161
  })
160
162
  ]
161
- }), S = ({ title: e, action: t, children: n }) => /* @__PURE__ */ _("section", {
163
+ }), C = ({ title: e, action: t, children: n }) => /* @__PURE__ */ v("section", {
162
164
  className: "flex flex-col gap-4",
163
- children: [/* @__PURE__ */ _("div", {
165
+ children: [/* @__PURE__ */ v("div", {
164
166
  className: "flex items-center justify-between",
165
- children: [/* @__PURE__ */ g("h2", {
167
+ children: [/* @__PURE__ */ _("h2", {
166
168
  className: "text-sm font-semibold uppercase tracking-wider text-text-secondary",
167
169
  children: e
168
170
  }), t]
169
171
  }), n]
170
- }), C = ({ org: e, onClick: n }) => {
172
+ }), w = ({ org: e, onClick: n }) => {
171
173
  let r = t(), i = e.name.split(" ").map((e) => e[0]).join("").slice(0, 2).toUpperCase();
172
- return /* @__PURE__ */ _(v, {
174
+ return /* @__PURE__ */ v(y, {
173
175
  treatment: "insight",
174
176
  role: "button",
175
177
  tabIndex: 0,
@@ -178,23 +180,23 @@ var b = () => {
178
180
  onKeyDown: (e) => {
179
181
  (e.key === "Enter" || e.key === " ") && (e.preventDefault(), n());
180
182
  },
181
- children: [/* @__PURE__ */ _("div", {
183
+ children: [/* @__PURE__ */ v("div", {
182
184
  className: "flex items-center gap-3 mb-4",
183
185
  children: [
184
- e.logoUrl ? /* @__PURE__ */ g("img", {
186
+ e.logoUrl ? /* @__PURE__ */ _("img", {
185
187
  src: e.logoUrl,
186
188
  alt: e.name,
187
189
  className: "h-10 w-10 rounded-xl object-cover"
188
- }) : /* @__PURE__ */ g("div", {
190
+ }) : /* @__PURE__ */ _("div", {
189
191
  className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold",
190
192
  children: i
191
193
  }),
192
- /* @__PURE__ */ _("div", {
194
+ /* @__PURE__ */ v("div", {
193
195
  className: "min-w-0 flex-1",
194
- children: [/* @__PURE__ */ g("p", {
196
+ children: [/* @__PURE__ */ _("p", {
195
197
  className: "font-semibold truncate text-text-primary",
196
198
  children: e.name
197
- }), /* @__PURE__ */ _("p", {
199
+ }), /* @__PURE__ */ v("p", {
198
200
  className: "text-xs text-text-secondary mt-0.5",
199
201
  children: [
200
202
  e.publishedApps ?? 0,
@@ -203,34 +205,34 @@ var b = () => {
203
205
  ]
204
206
  })]
205
207
  }),
206
- /* @__PURE__ */ g(l, {
208
+ /* @__PURE__ */ _(u, {
207
209
  size: 15,
208
210
  className: "text-text-muted shrink-0"
209
211
  })
210
212
  ]
211
- }), /* @__PURE__ */ _("div", {
213
+ }), /* @__PURE__ */ v("div", {
212
214
  className: "grid grid-cols-2 gap-3",
213
- children: [/* @__PURE__ */ _("div", {
215
+ children: [/* @__PURE__ */ v("div", {
214
216
  className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
215
- children: [/* @__PURE__ */ g(f, {
217
+ children: [/* @__PURE__ */ _(p, {
216
218
  size: 12,
217
219
  className: "text-text-muted shrink-0"
218
- }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
220
+ }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
219
221
  className: "text-[11px] text-text-secondary leading-none mb-0.5",
220
222
  children: r("devportal.installs", "Installs")
221
- }), /* @__PURE__ */ g("p", {
223
+ }), /* @__PURE__ */ _("p", {
222
224
  className: "text-sm font-semibold tabular-nums",
223
225
  children: (e.totalInstalls || 0).toLocaleString()
224
226
  })] })]
225
- }), /* @__PURE__ */ _("div", {
227
+ }), /* @__PURE__ */ v("div", {
226
228
  className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
227
- children: [/* @__PURE__ */ g(d, {
229
+ children: [/* @__PURE__ */ _(f, {
228
230
  size: 12,
229
231
  className: "text-text-muted shrink-0"
230
- }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
232
+ }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
231
233
  className: "text-[11px] text-text-secondary leading-none mb-0.5",
232
234
  children: r("devportal.revenue", "Revenue")
233
- }), /* @__PURE__ */ _("p", {
235
+ }), /* @__PURE__ */ v("p", {
234
236
  className: "text-sm font-semibold tabular-nums",
235
237
  children: ["$", (e.totalRevenue || 0).toLocaleString()]
236
238
  })] })]
@@ -239,6 +241,6 @@ var b = () => {
239
241
  });
240
242
  };
241
243
  //#endregion
242
- export { b as DashboardPage };
244
+ export { x as DashboardPage };
243
245
 
244
246
  //# sourceMappingURL=DashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/devportal/pages/DashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect } from \"react\";\nimport {\n AppWindow,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n Download,\n DollarSign,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { useTr } from \"../utils/i18n\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\nexport const DashboardPage: FC = () => {\n const { navigate, basePath, activeOrgId, setActiveOrgId } = useDevportal();\n const tr = useTr();\n\n // network-only prevents a stale empty-orgs cache entry from\n // firing the /setup redirect before the real response arrives.\n const { data: orgsData, loading: orgsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: {},\n fetchPolicy: \"network-only\",\n });\n\n // This dashboard is only ever mounted at the plain (non-seller) devportal\n // route — exclude PHYSICAL orgs so a seller-portal org never shows up\n // here. See DeveloperOrgKind (BOFF-7285).\n const organizations: OrganizationFieldsFragment[] = (\n orgsData?.myDeveloperOrganizations ?? []\n ).filter((org: OrganizationFieldsFragment) => org.kind !== \"PHYSICAL\");\n\n const resolvedOrgId: string | undefined = (() => {\n if (!organizations.length) return undefined;\n if (activeOrgId && organizations.some((o) => o.id === activeOrgId))\n return activeOrgId;\n return organizations[0]?.id;\n })();\n\n useEffect(() => {\n if (resolvedOrgId && resolvedOrgId !== activeOrgId) {\n setActiveOrgId(resolvedOrgId);\n }\n }, [resolvedOrgId, activeOrgId, setActiveOrgId]);\n\n const { data: appsData, loading: appsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: { organizationId: resolvedOrgId },\n skip: !resolvedOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const loading = orgsLoading || appsLoading;\n const data = appsData ?? orgsData;\n\n useEffect(() => {\n if (orgsLoading || !orgsData) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [orgsLoading, orgsData, organizations.length, navigate, basePath]);\n\n const applications: ApplicationFieldsFragment[] =\n appsData?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n const totalApps = data?.applications?.totalCount ?? 0;\n const totalOrgs = organizations.length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n // hasOrgs depends only on the orgs query — not on appsLoading — so the\n // header action doesn't flash \"Create Organization\" while apps are loading.\n const hasOrgs = !orgsLoading && organizations.length > 0;\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n actions={\n hasOrgs ? (\n <button\n data-tour=\"devportal-dashboard-create-app-button\"\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : !isLoading ? (\n <button\n data-tour=\"devportal-dashboard-create-org-button\"\n onClick={() => handleNavigate(\"/organizations/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.createOrganization\", \"Create Organization\")}\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 {isLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<AppWindow size={14} />}\n value={totalApps}\n label={tr(\"devportal.apps\", \"Apps\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={totalOrgs}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Apps */}\n <DashSection\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n action={\n applications.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/apps\")}\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 ) : applications.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppCard\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n showActions={false}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={tr(\"devportal.noApplicationsYet\", \"No applications yet\")}\n description={\n hasOrgs\n ? tr(\n \"devportal.createFirstApplicationToGetStarted\",\n \"Create your first application to get started\",\n )\n : tr(\n \"devportal.createOrgFirstToPublishApps\",\n \"Create an organization first to start publishing apps\",\n )\n }\n action={\n hasOrgs ? (\n <button\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : (\n <button\n onClick={() => handleNavigate(\"/organizations/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(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n </button>\n )\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || organizations.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n organizations.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/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 {organizations\n .slice(0, 3)\n .map((org: OrganizationFieldsFragment) => (\n <OrgCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() =>\n handleNavigate(`/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\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 OrgCard: FC<{ org: DeveloperOrganization; onClick: () => void }> = ({\n org,\n onClick,\n}) => {\n const tr = useTr();\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 <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <Download 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.installs\", \"Installs\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n </div>\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 ${(org.totalRevenue || 0).toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAyBA,IAAa,UAA0B;CACrC,IAAM,EAAE,aAAU,aAAU,gBAAa,sBAAmB,GAAc,EACpE,IAAK,GAAO,EAIZ,EAAE,MAAM,GAAU,SAAS,MAC/B,EAAuC;EACrC,WAAW,EAAE;EACb,aAAa;EACd,CAAC,EAKE,KACJ,GAAU,4BAA4B,EAAE,EACxC,QAAQ,MAAoC,EAAI,SAAS,WAAW,EAEhE,WAA2C;AAC1C,QAAc,OAGnB,QAFI,KAAe,EAAc,MAAM,MAAM,EAAE,OAAO,EAAY,GACzD,IACF,EAAc,IAAI;KACvB;AAEJ,SAAgB;AACd,EAAI,KAAiB,MAAkB,KACrC,EAAe,EAAc;IAE9B;EAAC;EAAe;EAAa;EAAe,CAAC;CAEhD,IAAM,EAAE,MAAM,GAAU,SAAS,MAC/B,EAAuC;EACrC,WAAW,EAAE,gBAAgB,GAAe;EAC5C,MAAM,CAAC;EACP,aAAa;EACd,CAAC,EAEE,IAAU,KAAe,GACzB,IAAO,KAAY;AAEzB,SAAgB;AACV,aAAe,CAAC,MAChB,IAAc,SAAS,IAC3B;OAAI;AACF,QAAI,aAAa,QAAQ,4BAA4B,CAAE;WACjD;AACN;;AAEF,OAAW,GAAG,EAAS,QAAQ;;IAC9B;EAAC;EAAa;EAAU,EAAc;EAAQ;EAAU;EAAS,CAAC;CAErE,IAAM,IACJ,GAAU,cAAc,OAAO,KAC5B,MAA2C,EAAE,KAC/C,IAAI,EAAE,EAEH,IAAY,GAAM,cAAc,cAAc,GAC9C,IAAY,EAAc,QAE1B,KAAkB,MAAiB;AACvC,MAAW,GAAG,IAAW,IAAO;IAG5B,IAAY,GAGZ,IAAU,CAAC,KAAe,EAAc,SAAS;AAEvD,QACE,kBAAC,GAAD;EAAiB,UAAA;YACf,kBAAC,GAAD;GACE,OACE,kBAAA,GAAA,EAAA,UAAA;IACG,EAAG,uBAAuB,YAAY;IAAE;IACzC,kBAAC,GAAD,EAAA,UAAe,EAAG,oBAAoB,SAAS,EAAgB,CAAA;IAC9D,EAAA,CAAA;GAEL,SACE,IACE,kBAAC,UAAD;IACE,aAAU;IACV,eAAe,EAAe,YAAY;IAC1C,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,uBAAuB,aAAa,CACjC;QACN,IASD,OARF,kBAAC,UAAD;IACE,aAAU;IACV,eAAe,EAAe,qBAAqB;IACnD,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,gCAAgC,sBAAsB,CACnD;;aAIb,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEE,kBAAC,OAAD;MAAK,WAAU;gBACZ,IACC,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA,GAEhE,kBAAA,GAAA,EAAA,UAAA;OACE,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;QAC7B,OAAO;QACP,OAAO,EAAG,kBAAkB,OAAO;QACnC,CAAA;OACF,kBAAC,OAAD,EAAK,WAAU,2BAA4B,CAAA;OAC3C,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;QAC7B,OAAO;QACP,OAAO,EAAG,2BAA2B,gBAAgB;QACrD,CAAA;OACD,EAAA,CAAA;MAED,CAAA;KAGN,kBAAC,GAAD;MACE,OAAO,EAAG,gCAAgC,sBAAsB;MAChE,QACE,EAAa,SAAS,IACpB,kBAAC,UAAD;OACE,eAAe,EAAe,QAAQ;OACtC,WAAU;iBAFZ,CAIG,EAAG,qBAAqB,WAAW,EACpC,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA,CACjB;WACP,KAAA;gBAGL,IACC,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA;OAC5D,CAAA,GACJ,EAAa,SAAS,IACxB,kBAAC,OAAD;OAAK,WAAU;iBACZ,EACE,MAAM,GAAG,EAAE,CACX,KAAK,MACJ,kBAAC,GAAD;QAEO;QACL,eAAe,EAAe,SAAS,EAAI,KAAK;QAChD,aAAa;QACb,EAJK,EAAI,GAIT,CACF;OACA,CAAA,GAEN,kBAAC,GAAD;OACE,cAAa;OACb,OAAO,EAAG,+BAA+B,sBAAsB;OAC/D,aACE,IACI,EACE,gDACA,+CACD,GACD,EACE,yCACA,wDACD;OAEP,QACE,IACE,kBAAC,UAAD;QACE,eAAe,EAAe,YAAY;QAC1C,WAAU;kBAFZ,CAIE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,uBAAuB,aAAa,CACjC;YAET,kBAAC,UAAD;QACE,eAAe,EAAe,qBAAqB;QACnD,WAAU;kBAFZ,CAIE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EACC,gCACA,sBACD,CACM;;OAGb,CAAA;MAEQ,CAAA;MAGZ,KAAa,EAAc,SAAS,MACpC,kBAAC,GAAD;MACE,OAAO,EAAG,+BAA+B,qBAAqB;MAC9D,QACE,EAAc,SAAS,IACrB,kBAAC,UAAD;OACE,eAAe,EAAe,iBAAiB;OAC/C,WAAU;iBAFZ,CAIG,EAAG,qBAAqB,WAAW,EACpC,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA,CACjB;WACP,KAAA;gBAGL,IACC,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA;OAC5D,CAAA,GAEN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EACE,MAAM,GAAG,EAAE,CACX,KAAK,MACJ,kBAAC,GAAD;QAEO;QACL,eACE,EAAe,kBAAkB,EAAI,KAAK;QAE5C,EALK,EAAI,GAKT,CACF;OACA,CAAA;MAEI,CAAA;KAEZ;;GACK,CAAA;EACG,CAAA;GAIhB,KAAmE,EACvE,SACA,UACA,eAEA,kBAAC,OAAD;CAAK,WAAU;WAAf;EACE,kBAAC,QAAD;GAAM,WAAU;aAAmB;GAAY,CAAA;EAC/C,kBAAC,QAAD;GAAM,WAAU;aAAsC;GAAa,CAAA;EACnE,kBAAC,QAAD;GAAM,WAAU;aAA+B;GAAa,CAAA;EACxD;IAGF,KAIA,EAAE,UAAO,WAAQ,kBACrB,kBAAC,WAAD;CAAS,WAAU;WAAnB,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,MAAD;GAAI,WAAU;aACX;GACE,CAAA,EACJ,EACG;KACL,EACO;IAGN,KAAoE,EACxE,QACA,iBACI;CACJ,IAAM,IAAK,GAAO,EAEZ,IAAW,EAAI,KAClB,MAAM,IAAI,CACV,KAAK,MAAc,EAAE,GAAG,CACxB,KAAK,GAAG,CACR,MAAM,GAAG,EAAE,CACX,aAAa;AAEhB,QACE,kBAAC,GAAD;EACE,WAAU;EACV,MAAK;EACL,UAAU;EACV,WAAU;EACD;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,GAAS;;YATf,CAaE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACG,EAAI,UACH,kBAAC,OAAD;KACE,KAAK,EAAI;KACT,KAAK,EAAI;KACT,WAAU;KACV,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eACZ;KACG,CAAA;IAER,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAA4C,EAAI;MAAS,CAAA,EACtE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAI,iBAAiB;OAAG;OACxB,EAAG,2BAA2B,iBAAiB;OAC9C;QACA;;IACN,kBAAC,GAAD;KAAY,MAAM;KAAI,WAAU;KAA6B,CAAA;IACzD;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAU,MAAM;KAAI,WAAU;KAA6B,CAAA,EAC3D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,sBAAsB,WAAW;KACnC,CAAA,EACJ,kBAAC,KAAD;KAAG,WAAU;gBACT,EAAI,iBAAiB,GAAG,gBAAgB;KACxC,CAAA,CACA,EAAA,CAAA,CACF;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAY,MAAM;KAAI,WAAU;KAA6B,CAAA,EAC7D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,qBAAqB,UAAU;KACjC,CAAA,EACJ,kBAAC,KAAD;KAAG,WAAU;eAAb,CAAkD,MAC7C,EAAI,gBAAgB,GAAG,gBAAgB,CACxC;OACA,EAAA,CAAA,CACF;MACF;KACI"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/devportal/pages/DashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect } from \"react\";\nimport {\n AppWindow,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n Download,\n DollarSign,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { OnboardingChecklist } from \"../components/OnboardingChecklist\";\nimport { useTr } from \"../utils/i18n\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\nexport const DashboardPage: FC = () => {\n const { navigate, basePath, activeOrgId, setActiveOrgId } = useDevportal();\n const tr = useTr();\n\n // network-only prevents a stale empty-orgs cache entry from\n // firing the /setup redirect before the real response arrives.\n const { data: orgsData, loading: orgsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: {},\n fetchPolicy: \"network-only\",\n });\n\n // This dashboard is only ever mounted at the plain (non-seller) devportal\n // route — exclude PHYSICAL orgs so a seller-portal org never shows up\n // here. See DeveloperOrgKind (BOFF-7285).\n const organizations: OrganizationFieldsFragment[] = (\n orgsData?.myDeveloperOrganizations ?? []\n ).filter((org: OrganizationFieldsFragment) => org.kind !== \"PHYSICAL\");\n\n const resolvedOrgId: string | undefined = (() => {\n if (!organizations.length) return undefined;\n if (activeOrgId && organizations.some((o) => o.id === activeOrgId))\n return activeOrgId;\n return organizations[0]?.id;\n })();\n\n useEffect(() => {\n if (resolvedOrgId && resolvedOrgId !== activeOrgId) {\n setActiveOrgId(resolvedOrgId);\n }\n }, [resolvedOrgId, activeOrgId, setActiveOrgId]);\n\n const { data: appsData, loading: appsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: { organizationId: resolvedOrgId },\n skip: !resolvedOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const loading = orgsLoading || appsLoading;\n const data = appsData ?? orgsData;\n\n useEffect(() => {\n if (orgsLoading || !orgsData) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [orgsLoading, orgsData, organizations.length, navigate, basePath]);\n\n const applications: ApplicationFieldsFragment[] =\n appsData?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n const totalApps = data?.applications?.totalCount ?? 0;\n const totalOrgs = organizations.length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n // hasOrgs depends only on the orgs query — not on appsLoading — so the\n // header action doesn't flash \"Create Organization\" while apps are loading.\n const hasOrgs = !orgsLoading && organizations.length > 0;\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n actions={\n hasOrgs ? (\n <button\n data-tour=\"devportal-dashboard-create-app-button\"\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : !isLoading ? (\n <button\n data-tour=\"devportal-dashboard-create-org-button\"\n onClick={() => handleNavigate(\"/organizations/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.createOrganization\", \"Create Organization\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Developer onboarding checklist — hides itself once complete */}\n <OnboardingChecklist onNavigate={handleNavigate} />\n\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {isLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<AppWindow size={14} />}\n value={totalApps}\n label={tr(\"devportal.apps\", \"Apps\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={totalOrgs}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Apps */}\n <DashSection\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n action={\n applications.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/apps\")}\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 ) : applications.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppCard\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n showActions={false}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={tr(\"devportal.noApplicationsYet\", \"No applications yet\")}\n description={\n hasOrgs\n ? tr(\n \"devportal.createFirstApplicationToGetStarted\",\n \"Create your first application to get started\",\n )\n : tr(\n \"devportal.createOrgFirstToPublishApps\",\n \"Create an organization first to start publishing apps\",\n )\n }\n action={\n hasOrgs ? (\n <button\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : (\n <button\n onClick={() => handleNavigate(\"/organizations/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(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n </button>\n )\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || organizations.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n organizations.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/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 {organizations\n .slice(0, 3)\n .map((org: OrganizationFieldsFragment) => (\n <OrgCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() =>\n handleNavigate(`/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\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 OrgCard: FC<{ org: DeveloperOrganization; onClick: () => void }> = ({\n org,\n onClick,\n}) => {\n const tr = useTr();\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 <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <Download 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.installs\", \"Installs\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n </div>\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 ${(org.totalRevenue || 0).toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentationPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/DocumentationPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA0ThC,eAAO,MAAM,iBAAiB,EAAE,EAgL/B,CAAC"}
1
+ {"version":3,"file":"DocumentationPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/DocumentationPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAwRhC,eAAO,MAAM,iBAAiB,EAAE,EAgL/B,CAAC"}