@burdenoff/microfe-devportal 2026.626.7 → 2026.629.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.
@@ -15,12 +15,15 @@ import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
15
15
  import { EmphasisPanel as D, GradientText as O, NextSteps as k } from "@burdenoff/fe-libs/ui";
16
16
  //#region src/devportal/pages/DashboardPage.tsx
17
17
  var A = () => {
18
- let { navigate: A, basePath: N } = e(), { t: P } = d(), F = (e, t) => {
19
- let n = P(e);
18
+ let { navigate: A, basePath: N, activeOrgId: P } = e(), { t: F } = d(), I = (e, t) => {
19
+ let n = F(e);
20
20
  return n === e ? t : n;
21
- }, { data: I, loading: L } = n({ fetchPolicy: "cache-and-network" }), R = I?.myDeveloperOrganizations ?? [];
21
+ }, { data: L, loading: R } = n({
22
+ variables: { organizationId: P ?? void 0 },
23
+ fetchPolicy: "cache-and-network"
24
+ }), z = L?.myDeveloperOrganizations ?? [];
22
25
  u(() => {
23
- if (!(L || !I) && !(R.length > 0)) {
26
+ if (!(R || !L) && !(z.length > 0)) {
24
27
  try {
25
28
  if (localStorage.getItem("devportal_setup_dismissed")) return;
26
29
  } catch {
@@ -29,45 +32,45 @@ var A = () => {
29
32
  A?.(`${N}/setup`);
30
33
  }
31
34
  }, [
35
+ R,
32
36
  L,
33
- I,
34
- R.length,
37
+ z.length,
35
38
  A,
36
39
  N
37
40
  ]);
38
- let z = I?.applications?.edges?.map((e) => e.node) ?? [], B = {
39
- totalApps: I?.applications?.totalCount ?? 0,
40
- totalOrgs: R.length,
41
+ let B = L?.applications?.edges?.map((e) => e.node) ?? [], V = {
42
+ totalApps: L?.applications?.totalCount ?? 0,
43
+ totalOrgs: z.length,
41
44
  totalApiKeys: 0,
42
45
  totalWebhooks: 0,
43
- totalApiCalls: R.reduce((e, t) => e + parseInt(t.totalApiCalls || "0"), 0),
44
- activeInstalls: R.reduce((e, t) => e + (t.activeInstalls || 0), 0),
45
- monthlyRevenue: R.reduce((e, t) => e + (t.totalRevenue || 0), 0),
46
+ totalApiCalls: z.reduce((e, t) => e + parseInt(t.totalApiCalls || "0"), 0),
47
+ activeInstalls: z.reduce((e, t) => e + (t.activeInstalls || 0), 0),
48
+ monthlyRevenue: z.reduce((e, t) => e + (t.totalRevenue || 0), 0),
46
49
  errorRate: 0
47
- }, V = (e) => {
50
+ }, H = (e) => {
48
51
  A?.(`${N}${e}`);
49
- }, H = L, U = !H && R.length > 0;
52
+ }, U = R, W = !U && z.length > 0;
50
53
  return /* @__PURE__ */ T(c, {
51
54
  permission: l.APP_READ,
52
55
  children: /* @__PURE__ */ E(r, {
53
56
  heroBackdrop: !0,
54
57
  title: /* @__PURE__ */ E(w, { children: [
55
- F("devportal.developer", "Developer"),
58
+ I("devportal.developer", "Developer"),
56
59
  " ",
57
- /* @__PURE__ */ T(O, { children: F("devportal.portal", "Portal") })
60
+ /* @__PURE__ */ T(O, { children: I("devportal.portal", "Portal") })
58
61
  ] }),
59
- description: F("devportal.buildManageMonitor", "Build, manage, and monitor your applications"),
60
- purpose: F("devportal.dashboardPurpose", "This is your developer home base — a single view of the apps you ship, the organizations behind them, and how they are performing (installs, API usage, revenue). Start an organization, then create and publish apps from here."),
61
- actions: U ? /* @__PURE__ */ E("button", {
62
+ description: I("devportal.buildManageMonitor", "Build, manage, and monitor your applications"),
63
+ purpose: I("devportal.dashboardPurpose", "This is your developer home base — a single view of the apps you ship, the organizations behind them, and how they are performing (installs, API usage, revenue). Start an organization, then create and publish apps from here."),
64
+ actions: W ? /* @__PURE__ */ E("button", {
62
65
  "data-tour": "devportal-dashboard-create-app-button",
63
- onClick: () => V("/apps/new"),
66
+ onClick: () => H("/apps/new"),
64
67
  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__ */ T(y, { size: 16 }), F("devportal.createApp", "Create App")]
66
- }) : H ? null : /* @__PURE__ */ E("button", {
68
+ children: [/* @__PURE__ */ T(y, { size: 16 }), I("devportal.createApp", "Create App")]
69
+ }) : U ? null : /* @__PURE__ */ E("button", {
67
70
  "data-tour": "devportal-dashboard-create-org-button",
68
- onClick: () => V("/organizations/new"),
71
+ onClick: () => H("/organizations/new"),
69
72
  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__ */ T(y, { size: 16 }), F("devportal.createOrganization", "Create Organization")]
73
+ children: [/* @__PURE__ */ T(y, { size: 16 }), I("devportal.createOrganization", "Create Organization")]
71
74
  }),
72
75
  children: [
73
76
  /* @__PURE__ */ T(D, {
@@ -77,93 +80,93 @@ var A = () => {
77
80
  children: [
78
81
  /* @__PURE__ */ T(a, {
79
82
  featured: !0,
80
- title: F("devportal.totalApps", "Total Apps"),
81
- value: H ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : B.totalApps,
83
+ title: I("devportal.totalApps", "Total Apps"),
84
+ value: U ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : V.totalApps,
82
85
  icon: /* @__PURE__ */ T(p, { size: 20 }),
83
86
  trend: void 0
84
87
  }),
85
88
  /* @__PURE__ */ T(a, {
86
- title: F("devportal.organizations", "Organizations"),
87
- value: H ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : B.totalOrgs,
89
+ title: I("devportal.organizations", "Organizations"),
90
+ value: U ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : V.totalOrgs,
88
91
  icon: /* @__PURE__ */ T(h, { size: 20 })
89
92
  }),
90
93
  /* @__PURE__ */ T(a, {
91
- title: F("devportal.apiKeys", "API Keys"),
92
- value: B.totalApiKeys,
94
+ title: I("devportal.apiKeys", "API Keys"),
95
+ value: V.totalApiKeys,
93
96
  icon: /* @__PURE__ */ T(_, { size: 20 }),
94
- description: F("devportal.activeKeys", "Active keys")
97
+ description: I("devportal.activeKeys", "Active keys")
95
98
  }),
96
99
  /* @__PURE__ */ T(a, {
97
- title: F("devportal.webhooks", "Webhooks"),
98
- value: B.totalWebhooks,
100
+ title: I("devportal.webhooks", "Webhooks"),
101
+ value: V.totalWebhooks,
99
102
  icon: /* @__PURE__ */ T(C, { size: 20 }),
100
- description: F("devportal.configured", "Configured")
103
+ description: I("devportal.configured", "Configured")
101
104
  })
102
105
  ]
103
106
  })
104
107
  }),
105
- !H && /* @__PURE__ */ T(k, {
108
+ !U && /* @__PURE__ */ T(k, {
106
109
  storageKey: "devportal-dashboard",
107
110
  steps: [
108
111
  {
109
112
  id: "create-org",
110
- label: F("devportal.createOrganization", "Create Organization"),
111
- description: F("devportal.setUpATeamToCollaborate", "Set up a team to collaborate"),
113
+ label: I("devportal.createOrganization", "Create Organization"),
114
+ description: I("devportal.setUpATeamToCollaborate", "Set up a team to collaborate"),
112
115
  icon: /* @__PURE__ */ T(h, { size: 16 }),
113
- onClick: () => V("/organizations/new"),
114
- done: U
116
+ onClick: () => H("/organizations/new"),
117
+ done: W
115
118
  },
116
119
  {
117
120
  id: "create-app",
118
- label: F("devportal.createApp", "Create App"),
119
- description: F("devportal.startBuildingANewApplication", "Start building a new application"),
121
+ label: I("devportal.createApp", "Create App"),
122
+ description: I("devportal.startBuildingANewApplication", "Start building a new application"),
120
123
  icon: /* @__PURE__ */ T(p, { size: 16 }),
121
- onClick: () => V("/apps/new"),
122
- done: B.totalApps > 0
124
+ onClick: () => H("/apps/new"),
125
+ done: V.totalApps > 0
123
126
  },
124
127
  {
125
128
  id: "api-key",
126
- label: F("devportal.generateApiKey", "Generate API Key"),
127
- description: F("devportal.createCredentialsForYourApps", "Create credentials for your apps"),
129
+ label: I("devportal.generateApiKey", "Generate API Key"),
130
+ description: I("devportal.createCredentialsForYourApps", "Create credentials for your apps"),
128
131
  icon: /* @__PURE__ */ T(_, { size: 16 }),
129
- onClick: () => V("/api-keys")
132
+ onClick: () => H("/api-keys")
130
133
  },
131
134
  {
132
135
  id: "webhooks",
133
- label: F("devportal.configureWebhooks", "Configure Webhooks"),
134
- description: F("devportal.setUpEventNotifications", "Set up event notifications"),
136
+ label: I("devportal.configureWebhooks", "Configure Webhooks"),
137
+ description: I("devportal.setUpEventNotifications", "Set up event notifications"),
135
138
  icon: /* @__PURE__ */ T(C, { size: 16 }),
136
- onClick: () => V("/webhooks")
139
+ onClick: () => H("/webhooks")
137
140
  }
138
141
  ]
139
142
  }),
140
143
  /* @__PURE__ */ T(i, {
141
- title: F("devportal.usageOverview", "Usage Overview"),
144
+ title: I("devportal.usageOverview", "Usage Overview"),
142
145
  "data-tour": "devportal-dashboard-usage-overview",
143
146
  children: /* @__PURE__ */ E(o, {
144
147
  columns: 4,
145
148
  children: [
146
149
  /* @__PURE__ */ T(a, {
147
- title: F("devportal.apiCalls", "API Calls"),
148
- value: H ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : B.totalApiCalls > 1e6 ? `${(B.totalApiCalls / 1e6).toFixed(1)}M` : B.totalApiCalls > 1e3 ? `${(B.totalApiCalls / 1e3).toFixed(1)}K` : B.totalApiCalls.toString(),
150
+ title: I("devportal.apiCalls", "API Calls"),
151
+ value: U ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : V.totalApiCalls > 1e6 ? `${(V.totalApiCalls / 1e6).toFixed(1)}M` : V.totalApiCalls > 1e3 ? `${(V.totalApiCalls / 1e3).toFixed(1)}K` : V.totalApiCalls.toString(),
149
152
  icon: /* @__PURE__ */ T(f, { size: 20 }),
150
153
  trend: void 0
151
154
  }),
152
155
  /* @__PURE__ */ T(a, {
153
- title: F("devportal.activeInstalls", "Active Installs"),
154
- value: H ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : B.activeInstalls > 1e3 ? `${(B.activeInstalls / 1e3).toFixed(1)}K` : B.activeInstalls.toString(),
156
+ title: I("devportal.activeInstalls", "Active Installs"),
157
+ value: U ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : V.activeInstalls > 1e3 ? `${(V.activeInstalls / 1e3).toFixed(1)}K` : V.activeInstalls.toString(),
155
158
  icon: /* @__PURE__ */ T(S, { size: 20 }),
156
159
  trend: void 0
157
160
  }),
158
161
  /* @__PURE__ */ T(a, {
159
- title: F("devportal.monthlyRevenue", "Monthly Revenue"),
160
- value: H ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : `$${B.monthlyRevenue.toLocaleString()}`,
162
+ title: I("devportal.monthlyRevenue", "Monthly Revenue"),
163
+ value: U ? /* @__PURE__ */ T(v, { className: "h-5 w-5 animate-spin" }) : `$${V.monthlyRevenue.toLocaleString()}`,
161
164
  icon: /* @__PURE__ */ T(g, { size: 20 }),
162
165
  trend: void 0
163
166
  }),
164
167
  /* @__PURE__ */ T(a, {
165
- title: F("devportal.errorRate", "Error Rate"),
166
- value: `${B.errorRate}%`,
168
+ title: I("devportal.errorRate", "Error Rate"),
169
+ value: `${V.errorRate}%`,
167
170
  icon: /* @__PURE__ */ T(x, { size: 20 }),
168
171
  trend: void 0
169
172
  })
@@ -174,102 +177,102 @@ var A = () => {
174
177
  className: "grid gap-6 lg:grid-cols-2",
175
178
  children: [/* @__PURE__ */ T(i, {
176
179
  "data-tour": "devportal-dashboard-recent-apps",
177
- title: F("devportal.recentApplications", "Recent Applications"),
180
+ title: I("devportal.recentApplications", "Recent Applications"),
178
181
  actions: /* @__PURE__ */ E("button", {
179
- onClick: () => V("/apps"),
182
+ onClick: () => H("/apps"),
180
183
  className: "text-sm text-primary hover:underline flex items-center gap-1",
181
184
  children: [
182
- F("devportal.viewAll", "View all"),
185
+ I("devportal.viewAll", "View all"),
183
186
  " ",
184
187
  /* @__PURE__ */ T(m, { size: 14 })
185
188
  ]
186
189
  }),
187
- children: H ? /* @__PURE__ */ T("div", {
190
+ children: U ? /* @__PURE__ */ T("div", {
188
191
  className: "flex items-center justify-center py-8",
189
192
  children: /* @__PURE__ */ T(v, { className: "h-6 w-6 animate-spin text-text-secondary" })
190
- }) : z.length > 0 ? /* @__PURE__ */ T("div", {
193
+ }) : B.length > 0 ? /* @__PURE__ */ T("div", {
191
194
  className: "space-y-2",
192
- children: z.slice(0, 3).map((e) => /* @__PURE__ */ T(s, {
195
+ children: B.slice(0, 3).map((e) => /* @__PURE__ */ T(s, {
193
196
  app: e,
194
- onClick: () => V(`/apps/${e.id}`)
197
+ onClick: () => H(`/apps/${e.id}`)
195
198
  }, e.id))
196
199
  }) : /* @__PURE__ */ T(t, {
197
200
  illustration: "empty-generic",
198
- title: F("devportal.noApplicationsYet", "No applications yet"),
199
- description: U ? F("devportal.createFirstApplicationToGetStarted", "Create your first application to get started") : F("devportal.createOrgFirstToPublishApps", "Create an organization first to start publishing apps"),
200
- action: U ? /* @__PURE__ */ E("button", {
201
- onClick: () => V("/apps/new"),
201
+ title: I("devportal.noApplicationsYet", "No applications yet"),
202
+ description: W ? I("devportal.createFirstApplicationToGetStarted", "Create your first application to get started") : I("devportal.createOrgFirstToPublishApps", "Create an organization first to start publishing apps"),
203
+ action: W ? /* @__PURE__ */ E("button", {
204
+ onClick: () => H("/apps/new"),
202
205
  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",
203
- children: [/* @__PURE__ */ T(y, { size: 16 }), F("devportal.createApp", "Create App")]
206
+ children: [/* @__PURE__ */ T(y, { size: 16 }), I("devportal.createApp", "Create App")]
204
207
  }) : /* @__PURE__ */ E("button", {
205
- onClick: () => V("/organizations/new"),
208
+ onClick: () => H("/organizations/new"),
206
209
  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",
207
- children: [/* @__PURE__ */ T(y, { size: 16 }), F("devportal.createOrganization", "Create Organization")]
210
+ children: [/* @__PURE__ */ T(y, { size: 16 }), I("devportal.createOrganization", "Create Organization")]
208
211
  })
209
212
  })
210
213
  }), /* @__PURE__ */ T(i, {
211
- title: F("devportal.quickActions", "Quick Actions"),
214
+ title: I("devportal.quickActions", "Quick Actions"),
212
215
  "data-tour": "devportal-dashboard-quick-actions",
213
216
  children: /* @__PURE__ */ E("div", {
214
217
  className: "grid gap-3",
215
218
  children: [
216
- U ? /* @__PURE__ */ T(j, {
217
- title: F("devportal.createNewApp", "Create New App"),
218
- description: F("devportal.startBuildingANewApplication", "Start building a new application"),
219
+ W ? /* @__PURE__ */ T(j, {
220
+ title: I("devportal.createNewApp", "Create New App"),
221
+ description: I("devportal.startBuildingANewApplication", "Start building a new application"),
219
222
  icon: /* @__PURE__ */ T(p, { size: 20 }),
220
- onClick: () => V("/apps/new")
223
+ onClick: () => H("/apps/new")
221
224
  }) : /* @__PURE__ */ T(j, {
222
- title: F("devportal.createOrganization", "Create Organization"),
223
- description: F("devportal.setUpATeamToCollaborate", "Set up a team to collaborate"),
225
+ title: I("devportal.createOrganization", "Create Organization"),
226
+ description: I("devportal.setUpATeamToCollaborate", "Set up a team to collaborate"),
224
227
  icon: /* @__PURE__ */ T(h, { size: 20 }),
225
- onClick: () => V("/organizations/new"),
228
+ onClick: () => H("/organizations/new"),
226
229
  primary: !0
227
230
  }),
228
- U && /* @__PURE__ */ T(j, {
229
- title: F("devportal.publisherProfile", "Publisher Profile"),
230
- description: F("devportal.manageYourStorePresence", "Manage your store publisher presence"),
231
+ W && /* @__PURE__ */ T(j, {
232
+ title: I("devportal.publisherProfile", "Publisher Profile"),
233
+ description: I("devportal.manageYourStorePresence", "Manage your store publisher presence"),
231
234
  icon: /* @__PURE__ */ T(b, { size: 20 }),
232
- onClick: () => V("/publisher/profile")
235
+ onClick: () => H("/publisher/profile")
233
236
  }),
234
237
  /* @__PURE__ */ T(j, {
235
- title: F("devportal.generateApiKey", "Generate API Key"),
236
- description: F("devportal.createCredentialsForYourApps", "Create credentials for your apps"),
238
+ title: I("devportal.generateApiKey", "Generate API Key"),
239
+ description: I("devportal.createCredentialsForYourApps", "Create credentials for your apps"),
237
240
  icon: /* @__PURE__ */ T(_, { size: 20 }),
238
- onClick: () => V("/api-keys")
241
+ onClick: () => H("/api-keys")
239
242
  }),
240
243
  /* @__PURE__ */ T(j, {
241
- title: F("devportal.configureWebhooks", "Configure Webhooks"),
242
- description: F("devportal.setUpEventNotifications", "Set up event notifications"),
244
+ title: I("devportal.configureWebhooks", "Configure Webhooks"),
245
+ description: I("devportal.setUpEventNotifications", "Set up event notifications"),
243
246
  icon: /* @__PURE__ */ T(C, { size: 20 }),
244
- onClick: () => V("/webhooks")
247
+ onClick: () => H("/webhooks")
245
248
  })
246
249
  ]
247
250
  })
248
251
  })]
249
252
  }),
250
- H ? /* @__PURE__ */ T(i, {
253
+ U ? /* @__PURE__ */ T(i, {
251
254
  "data-tour": "devportal-dashboard-organizations",
252
- title: F("devportal.yourOrganizations", "Your Organizations"),
255
+ title: I("devportal.yourOrganizations", "Your Organizations"),
253
256
  children: /* @__PURE__ */ T("div", {
254
257
  className: "flex items-center justify-center py-8",
255
258
  children: /* @__PURE__ */ T(v, { className: "h-6 w-6 animate-spin text-text-secondary" })
256
259
  })
257
- }) : R.length > 0 ? /* @__PURE__ */ T(i, {
258
- title: F("devportal.yourOrganizations", "Your Organizations"),
260
+ }) : z.length > 0 ? /* @__PURE__ */ T(i, {
261
+ title: I("devportal.yourOrganizations", "Your Organizations"),
259
262
  actions: /* @__PURE__ */ E("button", {
260
- onClick: () => V("/organizations"),
263
+ onClick: () => H("/organizations"),
261
264
  className: "text-sm text-primary hover:underline flex items-center gap-1",
262
265
  children: [
263
- F("devportal.viewAll", "View all"),
266
+ I("devportal.viewAll", "View all"),
264
267
  " ",
265
268
  /* @__PURE__ */ T(m, { size: 14 })
266
269
  ]
267
270
  }),
268
271
  children: /* @__PURE__ */ T("div", {
269
272
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
270
- children: R.slice(0, 3).map((e) => /* @__PURE__ */ T(M, {
273
+ children: z.slice(0, 3).map((e) => /* @__PURE__ */ T(M, {
271
274
  org: e,
272
- onClick: () => V(`/organizations/${e.id}`)
275
+ onClick: () => H(`/organizations/${e.id}`)
273
276
  }, e.id))
274
277
  })
275
278
  }) : null
@@ -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 { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AppWindow,\n Building2,\n Key,\n Webhook,\n TrendingUp,\n Users,\n DollarSign,\n Activity,\n Plus,\n ArrowRight,\n Loader2,\n Store,\n} from \"lucide-react\";\nimport { EmphasisPanel, GradientText, NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Developer Portal Dashboard Page\n *\n * Shows an overview of the developer's applications, organizations,\n * and key metrics using real data from the GraphQL API.\n */\nexport const DashboardPage: FC = () => {\n const { navigate, basePath } = 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 // Fetch dashboard bootstrap in a single global query\n const { data, loading } = useGetDevportalDashboardBootstrapQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations: OrganizationFieldsFragment[] =\n data?.myDeveloperOrganizations ?? [];\n\n // First-time users: redirect to setup wizard when no org exists and they\n // haven't already dismissed the wizard in this browser.\n useEffect(() => {\n if (loading || !data) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n // localStorage unavailable — don't redirect\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [loading, data, organizations.length, navigate, basePath]);\n const applications: ApplicationFieldsFragment[] =\n data?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n // Calculate aggregate stats\n const stats = {\n totalApps: data?.applications?.totalCount ?? 0,\n totalOrgs: organizations.length,\n totalApiKeys: 0,\n totalWebhooks: 0,\n totalApiCalls: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + parseInt(org.totalApiCalls || \"0\"),\n 0,\n ),\n activeInstalls: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls || 0),\n 0,\n ),\n monthlyRevenue: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalRevenue || 0),\n 0,\n ),\n errorRate: 0,\n };\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n\n const hasOrgs = !isLoading && organizations.length > 0;\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n heroBackdrop\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n description={tr(\n \"devportal.buildManageMonitor\",\n \"Build, manage, and monitor your applications\",\n )}\n purpose={tr(\n \"devportal.dashboardPurpose\",\n \"This is your developer home base — a single view of the apps you ship, the organizations behind them, and how they are performing (installs, API usage, revenue). Start an organization, then create and publish apps from here.\",\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 {/* Stats Overview — primary emphasis zone */}\n <EmphasisPanel data-tour=\"devportal-dashboard-stats-overview\">\n <StatCardGrid columns={4}>\n <StatCard\n featured\n title={tr(\"devportal.totalApps\", \"Total Apps\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n stats.totalApps\n )\n }\n icon={<AppWindow size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.organizations\", \"Organizations\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n stats.totalOrgs\n )\n }\n icon={<Building2 size={20} />}\n />\n <StatCard\n title={tr(\"devportal.apiKeys\", \"API Keys\")}\n value={stats.totalApiKeys}\n icon={<Key size={20} />}\n description={tr(\"devportal.activeKeys\", \"Active keys\")}\n />\n <StatCard\n title={tr(\"devportal.webhooks\", \"Webhooks\")}\n value={stats.totalWebhooks}\n icon={<Webhook size={20} />}\n description={tr(\"devportal.configured\", \"Configured\")}\n />\n </StatCardGrid>\n </EmphasisPanel>\n\n {/* Guided next steps for new developers (dismissable) */}\n {!isLoading && (\n <NextSteps\n storageKey=\"devportal-dashboard\"\n steps={[\n {\n id: \"create-org\",\n label: tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n ),\n description: tr(\n \"devportal.setUpATeamToCollaborate\",\n \"Set up a team to collaborate\",\n ),\n icon: <Building2 size={16} />,\n onClick: () => handleNavigate(\"/organizations/new\"),\n done: hasOrgs,\n },\n {\n id: \"create-app\",\n label: tr(\"devportal.createApp\", \"Create App\"),\n description: tr(\n \"devportal.startBuildingANewApplication\",\n \"Start building a new application\",\n ),\n icon: <AppWindow size={16} />,\n onClick: () => handleNavigate(\"/apps/new\"),\n done: stats.totalApps > 0,\n },\n {\n id: \"api-key\",\n label: tr(\"devportal.generateApiKey\", \"Generate API Key\"),\n description: tr(\n \"devportal.createCredentialsForYourApps\",\n \"Create credentials for your apps\",\n ),\n icon: <Key size={16} />,\n onClick: () => handleNavigate(\"/api-keys\"),\n },\n {\n id: \"webhooks\",\n label: tr(\"devportal.configureWebhooks\", \"Configure Webhooks\"),\n description: tr(\n \"devportal.setUpEventNotifications\",\n \"Set up event notifications\",\n ),\n icon: <Webhook size={16} />,\n onClick: () => handleNavigate(\"/webhooks\"),\n },\n ]}\n />\n )}\n\n {/* Usage Stats */}\n <PageSection\n title={tr(\"devportal.usageOverview\", \"Usage Overview\")}\n data-tour=\"devportal-dashboard-usage-overview\"\n >\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.apiCalls\", \"API Calls\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : stats.totalApiCalls > 1000000 ? (\n `${(stats.totalApiCalls / 1000000).toFixed(1)}M`\n ) : stats.totalApiCalls > 1000 ? (\n `${(stats.totalApiCalls / 1000).toFixed(1)}K`\n ) : (\n stats.totalApiCalls.toString()\n )\n }\n icon={<Activity size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : stats.activeInstalls > 1000 ? (\n `${(stats.activeInstalls / 1000).toFixed(1)}K`\n ) : (\n stats.activeInstalls.toString()\n )\n }\n icon={<Users size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.monthlyRevenue\", \"Monthly Revenue\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n `$${stats.monthlyRevenue.toLocaleString()}`\n )\n }\n icon={<DollarSign size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.errorRate\", \"Error Rate\")}\n value={`${stats.errorRate}%`}\n icon={<TrendingUp size={20} />}\n trend={undefined}\n />\n </StatCardGrid>\n </PageSection>\n\n {/* Quick Actions & Recent Items */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {/* Recent Apps */}\n <PageSection\n data-tour=\"devportal-dashboard-recent-apps\"\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps\")}\n className=\"text-sm text-primary hover:underline flex items-center gap-1\"\n >\n {tr(\"devportal.viewAll\", \"View all\")} <ArrowRight size={14} />\n </button>\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : applications.length > 0 ? (\n <div className=\"space-y-2\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppListItem\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\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 </PageSection>\n\n {/* Quick Actions */}\n <PageSection\n title={tr(\"devportal.quickActions\", \"Quick Actions\")}\n data-tour=\"devportal-dashboard-quick-actions\"\n >\n <div className=\"grid gap-3\">\n {!hasOrgs ? (\n <QuickActionCard\n title={tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n description={tr(\n \"devportal.setUpATeamToCollaborate\",\n \"Set up a team to collaborate\",\n )}\n icon={<Building2 size={20} />}\n onClick={() => handleNavigate(\"/organizations/new\")}\n primary\n />\n ) : (\n <QuickActionCard\n title={tr(\"devportal.createNewApp\", \"Create New App\")}\n description={tr(\n \"devportal.startBuildingANewApplication\",\n \"Start building a new application\",\n )}\n icon={<AppWindow size={20} />}\n onClick={() => handleNavigate(\"/apps/new\")}\n />\n )}\n {hasOrgs && (\n <QuickActionCard\n title={tr(\"devportal.publisherProfile\", \"Publisher Profile\")}\n description={tr(\n \"devportal.manageYourStorePresence\",\n \"Manage your store publisher presence\",\n )}\n icon={<Store size={20} />}\n onClick={() => handleNavigate(\"/publisher/profile\")}\n />\n )}\n <QuickActionCard\n title={tr(\"devportal.generateApiKey\", \"Generate API Key\")}\n description={tr(\n \"devportal.createCredentialsForYourApps\",\n \"Create credentials for your apps\",\n )}\n icon={<Key size={20} />}\n onClick={() => handleNavigate(\"/api-keys\")}\n />\n <QuickActionCard\n title={tr(\"devportal.configureWebhooks\", \"Configure Webhooks\")}\n description={tr(\n \"devportal.setUpEventNotifications\",\n \"Set up event notifications\",\n )}\n icon={<Webhook size={20} />}\n onClick={() => handleNavigate(\"/webhooks\")}\n />\n </div>\n </PageSection>\n </div>\n\n {/* Organizations */}\n {isLoading ? (\n <PageSection\n data-tour=\"devportal-dashboard-organizations\"\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n >\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n </PageSection>\n ) : organizations.length > 0 ? (\n <PageSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n actions={\n <button\n onClick={() => handleNavigate(\"/organizations\")}\n className=\"text-sm text-primary hover:underline flex items-center gap-1\"\n >\n {tr(\"devportal.viewAll\", \"View all\")} <ArrowRight size={14} />\n </button>\n }\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={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n </PageSection>\n ) : null}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Quick action card component\nconst QuickActionCard: FC<{\n title: string;\n description: string;\n icon: React.ReactNode;\n onClick: () => void;\n primary?: boolean;\n}> = ({ title, description, icon, onClick, primary }) => (\n <button\n onClick={onClick}\n className={[\n \"flex w-full items-center gap-4 rounded-card border p-4 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n primary\n ? \"border-primary bg-action-primary-bg/5 hover:bg-action-primary-bg/10\"\n : \"border-border-seam bg-bg-surface shadow-[var(--shadow-pop)] hover:bg-accent\",\n ].join(\" \")}\n >\n <div\n className={[\n \"rounded-lg p-2\",\n primary\n ? \"bg-action-primary-bg/20 text-primary\"\n : \"bg-action-primary-bg/10 text-primary\",\n ].join(\" \")}\n >\n {icon}\n </div>\n <div>\n <p className=\"font-medium\">{title}</p>\n <p className=\"text-sm text-text-secondary\">{description}</p>\n </div>\n </button>\n);\n\n// Organization card component\nconst OrgCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, 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 return (\n <button\n onClick={onClick}\n className=\"w-full rounded-card border border-border-seam bg-bg-surface p-4 text-left shadow-[var(--shadow-pop)] transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex items-center gap-3\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={20} />\n </div>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{org.name}</p>\n <p className=\"text-sm text-text-secondary\">\n {org.publishedApps}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n </div>\n <div className=\"mt-3 flex gap-4 text-sm text-text-secondary\">\n <span>\n {(org.totalInstalls || 0).toLocaleString()}{\" \"}\n {tr(\"devportal.installs\", \"installs\")}\n </span>\n <span>\n ${(org.totalRevenue || 0).toLocaleString()}{\" \"}\n {tr(\"devportal.revenue\", \"revenue\")}\n </span>\n </div>\n </button>\n );\n};\n"],"mappings":"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"}
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 { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AppWindow,\n Building2,\n Key,\n Webhook,\n TrendingUp,\n Users,\n DollarSign,\n Activity,\n Plus,\n ArrowRight,\n Loader2,\n Store,\n} from \"lucide-react\";\nimport { EmphasisPanel, GradientText, NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Developer Portal Dashboard Page\n *\n * Shows an overview of the developer's applications, organizations,\n * and key metrics using real data from the GraphQL API.\n */\nexport const DashboardPage: FC = () => {\n const { navigate, basePath, activeOrgId } = 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 // Fetch dashboard bootstrap in a single global query — scope apps to the active org\n const { data, loading } = useGetDevportalDashboardBootstrapQuery({\n variables: { organizationId: activeOrgId ?? undefined },\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations: OrganizationFieldsFragment[] =\n data?.myDeveloperOrganizations ?? [];\n\n // First-time users: redirect to setup wizard when no org exists and they\n // haven't already dismissed the wizard in this browser.\n useEffect(() => {\n if (loading || !data) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n // localStorage unavailable — don't redirect\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [loading, data, organizations.length, navigate, basePath]);\n const applications: ApplicationFieldsFragment[] =\n data?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n // Calculate aggregate stats\n const stats = {\n totalApps: data?.applications?.totalCount ?? 0,\n totalOrgs: organizations.length,\n totalApiKeys: 0,\n totalWebhooks: 0,\n totalApiCalls: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + parseInt(org.totalApiCalls || \"0\"),\n 0,\n ),\n activeInstalls: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls || 0),\n 0,\n ),\n monthlyRevenue: organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalRevenue || 0),\n 0,\n ),\n errorRate: 0,\n };\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n\n const hasOrgs = !isLoading && organizations.length > 0;\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n heroBackdrop\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n description={tr(\n \"devportal.buildManageMonitor\",\n \"Build, manage, and monitor your applications\",\n )}\n purpose={tr(\n \"devportal.dashboardPurpose\",\n \"This is your developer home base — a single view of the apps you ship, the organizations behind them, and how they are performing (installs, API usage, revenue). Start an organization, then create and publish apps from here.\",\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 {/* Stats Overview — primary emphasis zone */}\n <EmphasisPanel data-tour=\"devportal-dashboard-stats-overview\">\n <StatCardGrid columns={4}>\n <StatCard\n featured\n title={tr(\"devportal.totalApps\", \"Total Apps\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n stats.totalApps\n )\n }\n icon={<AppWindow size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.organizations\", \"Organizations\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n stats.totalOrgs\n )\n }\n icon={<Building2 size={20} />}\n />\n <StatCard\n title={tr(\"devportal.apiKeys\", \"API Keys\")}\n value={stats.totalApiKeys}\n icon={<Key size={20} />}\n description={tr(\"devportal.activeKeys\", \"Active keys\")}\n />\n <StatCard\n title={tr(\"devportal.webhooks\", \"Webhooks\")}\n value={stats.totalWebhooks}\n icon={<Webhook size={20} />}\n description={tr(\"devportal.configured\", \"Configured\")}\n />\n </StatCardGrid>\n </EmphasisPanel>\n\n {/* Guided next steps for new developers (dismissable) */}\n {!isLoading && (\n <NextSteps\n storageKey=\"devportal-dashboard\"\n steps={[\n {\n id: \"create-org\",\n label: tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n ),\n description: tr(\n \"devportal.setUpATeamToCollaborate\",\n \"Set up a team to collaborate\",\n ),\n icon: <Building2 size={16} />,\n onClick: () => handleNavigate(\"/organizations/new\"),\n done: hasOrgs,\n },\n {\n id: \"create-app\",\n label: tr(\"devportal.createApp\", \"Create App\"),\n description: tr(\n \"devportal.startBuildingANewApplication\",\n \"Start building a new application\",\n ),\n icon: <AppWindow size={16} />,\n onClick: () => handleNavigate(\"/apps/new\"),\n done: stats.totalApps > 0,\n },\n {\n id: \"api-key\",\n label: tr(\"devportal.generateApiKey\", \"Generate API Key\"),\n description: tr(\n \"devportal.createCredentialsForYourApps\",\n \"Create credentials for your apps\",\n ),\n icon: <Key size={16} />,\n onClick: () => handleNavigate(\"/api-keys\"),\n },\n {\n id: \"webhooks\",\n label: tr(\"devportal.configureWebhooks\", \"Configure Webhooks\"),\n description: tr(\n \"devportal.setUpEventNotifications\",\n \"Set up event notifications\",\n ),\n icon: <Webhook size={16} />,\n onClick: () => handleNavigate(\"/webhooks\"),\n },\n ]}\n />\n )}\n\n {/* Usage Stats */}\n <PageSection\n title={tr(\"devportal.usageOverview\", \"Usage Overview\")}\n data-tour=\"devportal-dashboard-usage-overview\"\n >\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.apiCalls\", \"API Calls\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : stats.totalApiCalls > 1000000 ? (\n `${(stats.totalApiCalls / 1000000).toFixed(1)}M`\n ) : stats.totalApiCalls > 1000 ? (\n `${(stats.totalApiCalls / 1000).toFixed(1)}K`\n ) : (\n stats.totalApiCalls.toString()\n )\n }\n icon={<Activity size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : stats.activeInstalls > 1000 ? (\n `${(stats.activeInstalls / 1000).toFixed(1)}K`\n ) : (\n stats.activeInstalls.toString()\n )\n }\n icon={<Users size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.monthlyRevenue\", \"Monthly Revenue\")}\n value={\n isLoading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n `$${stats.monthlyRevenue.toLocaleString()}`\n )\n }\n icon={<DollarSign size={20} />}\n trend={undefined}\n />\n <StatCard\n title={tr(\"devportal.errorRate\", \"Error Rate\")}\n value={`${stats.errorRate}%`}\n icon={<TrendingUp size={20} />}\n trend={undefined}\n />\n </StatCardGrid>\n </PageSection>\n\n {/* Quick Actions & Recent Items */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {/* Recent Apps */}\n <PageSection\n data-tour=\"devportal-dashboard-recent-apps\"\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps\")}\n className=\"text-sm text-primary hover:underline flex items-center gap-1\"\n >\n {tr(\"devportal.viewAll\", \"View all\")} <ArrowRight size={14} />\n </button>\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : applications.length > 0 ? (\n <div className=\"space-y-2\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppListItem\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\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 </PageSection>\n\n {/* Quick Actions */}\n <PageSection\n title={tr(\"devportal.quickActions\", \"Quick Actions\")}\n data-tour=\"devportal-dashboard-quick-actions\"\n >\n <div className=\"grid gap-3\">\n {!hasOrgs ? (\n <QuickActionCard\n title={tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n description={tr(\n \"devportal.setUpATeamToCollaborate\",\n \"Set up a team to collaborate\",\n )}\n icon={<Building2 size={20} />}\n onClick={() => handleNavigate(\"/organizations/new\")}\n primary\n />\n ) : (\n <QuickActionCard\n title={tr(\"devportal.createNewApp\", \"Create New App\")}\n description={tr(\n \"devportal.startBuildingANewApplication\",\n \"Start building a new application\",\n )}\n icon={<AppWindow size={20} />}\n onClick={() => handleNavigate(\"/apps/new\")}\n />\n )}\n {hasOrgs && (\n <QuickActionCard\n title={tr(\"devportal.publisherProfile\", \"Publisher Profile\")}\n description={tr(\n \"devportal.manageYourStorePresence\",\n \"Manage your store publisher presence\",\n )}\n icon={<Store size={20} />}\n onClick={() => handleNavigate(\"/publisher/profile\")}\n />\n )}\n <QuickActionCard\n title={tr(\"devportal.generateApiKey\", \"Generate API Key\")}\n description={tr(\n \"devportal.createCredentialsForYourApps\",\n \"Create credentials for your apps\",\n )}\n icon={<Key size={20} />}\n onClick={() => handleNavigate(\"/api-keys\")}\n />\n <QuickActionCard\n title={tr(\"devportal.configureWebhooks\", \"Configure Webhooks\")}\n description={tr(\n \"devportal.setUpEventNotifications\",\n \"Set up event notifications\",\n )}\n icon={<Webhook size={20} />}\n onClick={() => handleNavigate(\"/webhooks\")}\n />\n </div>\n </PageSection>\n </div>\n\n {/* Organizations */}\n {isLoading ? (\n <PageSection\n data-tour=\"devportal-dashboard-organizations\"\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n >\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n </PageSection>\n ) : organizations.length > 0 ? (\n <PageSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n actions={\n <button\n onClick={() => handleNavigate(\"/organizations\")}\n className=\"text-sm text-primary hover:underline flex items-center gap-1\"\n >\n {tr(\"devportal.viewAll\", \"View all\")} <ArrowRight size={14} />\n </button>\n }\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={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n </PageSection>\n ) : null}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Quick action card component\nconst QuickActionCard: FC<{\n title: string;\n description: string;\n icon: React.ReactNode;\n onClick: () => void;\n primary?: boolean;\n}> = ({ title, description, icon, onClick, primary }) => (\n <button\n onClick={onClick}\n className={[\n \"flex w-full items-center gap-4 rounded-card border p-4 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n primary\n ? \"border-primary bg-action-primary-bg/5 hover:bg-action-primary-bg/10\"\n : \"border-border-seam bg-bg-surface shadow-[var(--shadow-pop)] hover:bg-accent\",\n ].join(\" \")}\n >\n <div\n className={[\n \"rounded-lg p-2\",\n primary\n ? \"bg-action-primary-bg/20 text-primary\"\n : \"bg-action-primary-bg/10 text-primary\",\n ].join(\" \")}\n >\n {icon}\n </div>\n <div>\n <p className=\"font-medium\">{title}</p>\n <p className=\"text-sm text-text-secondary\">{description}</p>\n </div>\n </button>\n);\n\n// Organization card component\nconst OrgCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, 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 return (\n <button\n onClick={onClick}\n className=\"w-full rounded-card border border-border-seam bg-bg-surface p-4 text-left shadow-[var(--shadow-pop)] transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex items-center gap-3\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={20} />\n </div>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{org.name}</p>\n <p className=\"text-sm text-text-secondary\">\n {org.publishedApps}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n </div>\n <div className=\"mt-3 flex gap-4 text-sm text-text-secondary\">\n <span>\n {(org.totalInstalls || 0).toLocaleString()}{\" \"}\n {tr(\"devportal.installs\", \"installs\")}\n </span>\n <span>\n ${(org.totalRevenue || 0).toLocaleString()}{\" \"}\n {tr(\"devportal.revenue\", \"revenue\")}\n </span>\n </div>\n </button>\n );\n};\n"],"mappings":"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"}
@@ -108,7 +108,11 @@ var H = () => {
108
108
  variables: { id: s },
109
109
  skip: !s
110
110
  }), k = x ?? S, { data: j } = r({
111
- variables: { limit: 50 },
111
+ variables: {
112
+ limit: 50,
113
+ organizationId: s
114
+ },
115
+ skip: !s,
112
116
  fetchPolicy: "cache-and-network"
113
117
  }), M = (e) => {
114
118
  n?.(`${a}${e}`);
@@ -151,7 +155,7 @@ var H = () => {
151
155
  ]
152
156
  })
153
157
  });
154
- let F = B(k.developerOrganization), R = (k.developerOrganization.members ?? []).map(V), H = j?.applications?.edges?.map((e) => e.node) ?? [], q = s ? H.filter((e) => e.developerOrganizationId === s) : H, J = parseInt(F.apiCallsUsed) / F.apiCallsLimit * 100, Y = parseInt(F.storageUsed) / parseInt(F.storageLimit) * 100;
158
+ let F = B(k.developerOrganization), R = (k.developerOrganization.members ?? []).map(V), H = j?.applications?.edges?.map((e) => e.node) ?? [], q = parseInt(F.apiCallsUsed) / F.apiCallsLimit * 100, J = parseInt(F.storageUsed) / parseInt(F.storageLimit) * 100;
155
159
  return /* @__PURE__ */ L(o, {
156
160
  title: F.name,
157
161
  description: F.description,
@@ -230,15 +234,15 @@ var H = () => {
230
234
  children: [
231
235
  d === "overview" && /* @__PURE__ */ I(U, {
232
236
  org: F,
233
- apps: q,
237
+ apps: H,
234
238
  members: R,
235
- apiCallsPercent: J,
236
- storagePercent: Y,
239
+ apiCallsPercent: q,
240
+ storagePercent: J,
237
241
  onNavigate: M,
238
242
  onShowApps: () => f("apps")
239
243
  }),
240
244
  d === "apps" && /* @__PURE__ */ I(W, {
241
- apps: q,
245
+ apps: H,
242
246
  onNavigate: M
243
247
  }),
244
248
  d === "members" && /* @__PURE__ */ I(G, {