@burdenoff/microfe-timecampus 2026.703.2 → 2026.703.3

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.
@@ -9,43 +9,51 @@ import { StatusBadge as oe } from "../../components/StatusBadge.js";
9
9
  import { ToastContainer as se, useToast as ce } from "../../components/Toast.js";
10
10
  import { useState as s } from "react";
11
11
  import { Building2 as c, Check as l, DollarSign as u, FolderOpen as d, Link2 as f, Pencil as p, Plus as le, Power as ue, RefreshCw as de, Trash2 as fe } from "lucide-react";
12
- import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
12
+ import { gql as m } from "@apollo/client";
13
+ import { useApolloClient as pe } from "@apollo/client/react";
14
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
15
+ import { uploadBlobToFiles as me } from "@burdenoff/fe-libs/storage";
13
16
  //#region src/timecampus/pages/client-portal/ClientPortalPage.tsx
14
- var _ = 25, v = "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary";
15
- function pe(e) {
17
+ var v = 25, y = "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary", he = "mt-1 block w-full text-sm text-text-secondary file:mr-3 file:rounded-md file:border-0 file:bg-action-primary-bg file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-action-primary-text hover:file:bg-action-primary-bg/90", ge = m`
18
+ query TimeCampus_GetFileDownloadUrl($id: ID!, $expiresIn: Int) {
19
+ getFileDownloadUrl(id: $id, expiresIn: $expiresIn)
20
+ }
21
+ `;
22
+ function _e(e) {
16
23
  return `${typeof window < "u" ? window.location.origin : ""}/portal/${e}`;
17
24
  }
18
- var y = {
25
+ var b = {
19
26
  clientName: "",
20
27
  contactEmail: "",
21
28
  contactPhone: "",
22
- description: ""
29
+ description: "",
30
+ logoUrl: ""
23
31
  };
24
- function b() {
25
- let { toasts: b, addToast: x, dismissToast: me } = ce(), [he, S] = s(null), { data: C, loading: w, error: T, refetch: E, fetchMore: D } = i({
32
+ function x() {
33
+ let { toasts: m, addToast: x, dismissToast: ve } = ce(), S = pe(), [C, w] = s(null), [T, E] = s(!1), { data: D, loading: O, error: k, refetch: A, fetchMore: j } = i({
26
34
  variables: {
27
- limit: _,
35
+ limit: v,
28
36
  offset: 0
29
37
  },
30
38
  notifyOnNetworkStatusChange: !0
31
- }), { data: O, refetch: k } = te(), [A, { loading: j }] = ne(), [M, { loading: N }] = r(), [P, { loading: F }] = ie(), [I, { loading: L }] = ee(), [R] = re(), z = C?.clientPortalConfigs?.items ?? [], ge = C?.clientPortalConfigs?.hasMore ?? !1, B = O?.clientPortalStats, [V, H] = s(!1), [_e, U] = s(!1), [W, G] = s(null), [K, q] = s(y), [J, Y] = s(null), [ve, X] = s(null), Z = async () => {
32
- await Promise.all([E(), k()]);
33
- }, ye = async (e) => {
39
+ }), { data: M, refetch: N } = te(), [P, { loading: F }] = ne(), [ye, { loading: I }] = r(), [be, { loading: L }] = ie(), [xe, { loading: R }] = ee(), [Se] = re(), z = D?.clientPortalConfigs?.items ?? [], Ce = D?.clientPortalConfigs?.hasMore ?? !1, B = M?.clientPortalStats, [V, H] = s(!1), [we, U] = s(!1), [W, G] = s(null), [K, q] = s(b), [J, Y] = s(null), [Te, X] = s(null), Z = async () => {
40
+ await Promise.all([A(), N()]);
41
+ }, Ee = async (e) => {
34
42
  if (e.shareToken) try {
35
- await navigator.clipboard.writeText(pe(e.shareToken)), S(e.id), window.setTimeout(() => S(null), 2e3);
43
+ await navigator.clipboard.writeText(_e(e.shareToken)), w(e.id), window.setTimeout(() => w(null), 2e3);
36
44
  } catch {
37
45
  x({
38
46
  title: "Clipboard unavailable",
39
47
  variant: "error"
40
48
  });
41
49
  }
42
- }, be = async (e) => {
50
+ }, De = async (e) => {
43
51
  X(e.id);
44
52
  try {
45
- await A({ variables: { id: e.id } }), x({
53
+ await P({ variables: { id: e.id } }), x({
46
54
  title: "Share link regenerated",
47
55
  variant: "success"
48
- }), await E();
56
+ }), await A();
49
57
  } catch {
50
58
  x({
51
59
  title: "Failed to regenerate link",
@@ -54,35 +62,68 @@ function b() {
54
62
  } finally {
55
63
  X(null);
56
64
  }
57
- }, xe = () => {
58
- G(null), q(y), U(!0);
59
- }, Se = (e) => {
65
+ }, Oe = () => {
66
+ G(null), q(b), U(!0);
67
+ }, ke = (e) => {
60
68
  G(e), q({
61
69
  clientName: e.clientName,
62
70
  contactEmail: e.contactEmail ?? "",
63
71
  contactPhone: e.contactPhone ?? "",
64
- description: e.description ?? ""
72
+ description: e.description ?? "",
73
+ logoUrl: e.logoUrl ?? ""
65
74
  }), U(!0);
75
+ }, Ae = async (e) => {
76
+ E(!0);
77
+ try {
78
+ let t = await me({
79
+ client: S,
80
+ blob: e,
81
+ filename: e.name,
82
+ mimeType: e.type || "application/octet-stream",
83
+ folderId: ""
84
+ }), { data: n } = await S.query({
85
+ query: ge,
86
+ variables: {
87
+ id: t.id,
88
+ expiresIn: 604800
89
+ },
90
+ fetchPolicy: "no-cache"
91
+ }), r = n?.getFileDownloadUrl;
92
+ if (!r) throw Error("No download URL returned");
93
+ q((e) => ({
94
+ ...e,
95
+ logoUrl: r
96
+ }));
97
+ } catch {
98
+ x({
99
+ title: "Failed to upload logo",
100
+ variant: "error"
101
+ });
102
+ } finally {
103
+ E(!1);
104
+ }
66
105
  }, Q = () => {
67
106
  U(!1), G(null);
68
- }, Ce = async () => {
107
+ }, je = async () => {
69
108
  if (K.clientName.trim()) try {
70
- W ? (await P({ variables: {
109
+ W ? (await be({ variables: {
71
110
  id: W.id,
72
111
  input: {
73
112
  clientName: K.clientName.trim(),
74
113
  contactEmail: K.contactEmail.trim() || void 0,
75
114
  contactPhone: K.contactPhone.trim() || void 0,
76
- description: K.description.trim() || void 0
115
+ description: K.description.trim() || void 0,
116
+ logoUrl: K.logoUrl || void 0
77
117
  }
78
118
  } }), x({
79
119
  title: "Client updated",
80
120
  variant: "success"
81
- })) : (await M({ variables: { input: {
121
+ })) : (await ye({ variables: { input: {
82
122
  clientName: K.clientName.trim(),
83
123
  contactEmail: K.contactEmail.trim() || void 0,
84
124
  contactPhone: K.contactPhone.trim() || void 0,
85
125
  description: K.description.trim() || void 0,
126
+ logoUrl: K.logoUrl || void 0,
86
127
  isActive: !0
87
128
  } } }), x({
88
129
  title: "Client added",
@@ -94,9 +135,9 @@ function b() {
94
135
  variant: "error"
95
136
  });
96
137
  }
97
- }, we = async () => {
138
+ }, Me = async () => {
98
139
  if (J) try {
99
- await I({ variables: { id: J.id } }), x({
140
+ await xe({ variables: { id: J.id } }), x({
100
141
  title: "Client deleted",
101
142
  variant: "success"
102
143
  }), Y(null), await Z();
@@ -106,10 +147,10 @@ function b() {
106
147
  variant: "error"
107
148
  });
108
149
  }
109
- }, Te = async (e) => {
150
+ }, Ne = async (e) => {
110
151
  X(e.id);
111
152
  try {
112
- await R({ variables: {
153
+ await Se({ variables: {
113
154
  id: e.id,
114
155
  isActive: !e.isActive
115
156
  } }), x({
@@ -124,12 +165,12 @@ function b() {
124
165
  } finally {
125
166
  X(null);
126
167
  }
127
- }, Ee = async () => {
168
+ }, Pe = async () => {
128
169
  H(!0);
129
170
  try {
130
- await D({
171
+ await j({
131
172
  variables: {
132
- limit: _,
173
+ limit: v,
133
174
  offset: z.length
134
175
  },
135
176
  updateQuery: (e, { fetchMoreResult: t }) => t ? {
@@ -144,53 +185,53 @@ function b() {
144
185
  H(!1);
145
186
  }
146
187
  };
147
- if (w && z.length === 0) return /* @__PURE__ */ h(a, {
188
+ if (O && z.length === 0) return /* @__PURE__ */ g(a, {
148
189
  title: "Client Portal",
149
190
  description: "Manage clients and their projects",
150
- children: /* @__PURE__ */ h(n, {
191
+ children: /* @__PURE__ */ g(n, {
151
192
  variant: "list",
152
193
  count: 4
153
194
  })
154
195
  });
155
- if (T) return /* @__PURE__ */ h(a, {
196
+ if (k) return /* @__PURE__ */ g(a, {
156
197
  title: "Client Portal",
157
198
  description: "Manage clients and their projects",
158
- children: /* @__PURE__ */ h("div", {
199
+ children: /* @__PURE__ */ g("div", {
159
200
  className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
160
201
  children: "Failed to load client portal data. Please try again later."
161
202
  })
162
203
  });
163
- let $ = /* @__PURE__ */ g("button", {
164
- onClick: xe,
204
+ let $ = /* @__PURE__ */ _("button", {
205
+ onClick: Oe,
165
206
  className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
166
- children: [/* @__PURE__ */ h(le, { className: "h-4 w-4" }), "Add Client"]
207
+ children: [/* @__PURE__ */ g(le, { className: "h-4 w-4" }), "Add Client"]
167
208
  });
168
- return /* @__PURE__ */ g(a, {
209
+ return /* @__PURE__ */ _(a, {
169
210
  title: "Client Portal",
170
211
  description: "Manage clients and their projects",
171
212
  purpose: "Give clients a transparent window into the work you do for them — the projects, hours and progress tied to each one — so billing conversations are backed by data and trust, not spreadsheets.",
172
213
  actions: $,
173
214
  children: [
174
- /* @__PURE__ */ g("div", {
215
+ /* @__PURE__ */ _("div", {
175
216
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
176
217
  children: [
177
- /* @__PURE__ */ h(t, {
218
+ /* @__PURE__ */ g(t, {
178
219
  featured: !0,
179
220
  title: "Active Clients",
180
221
  value: String(B?.activeClients ?? 0),
181
- icon: /* @__PURE__ */ h(c, { className: "h-5 w-5" })
222
+ icon: /* @__PURE__ */ g(c, { className: "h-5 w-5" })
182
223
  }),
183
- /* @__PURE__ */ h(t, {
224
+ /* @__PURE__ */ g(t, {
184
225
  title: "Total Projects",
185
226
  value: String(B?.totalProjectsShared ?? 0),
186
- icon: /* @__PURE__ */ h(d, { className: "h-5 w-5" })
227
+ icon: /* @__PURE__ */ g(d, { className: "h-5 w-5" })
187
228
  }),
188
- /* @__PURE__ */ h(t, {
229
+ /* @__PURE__ */ g(t, {
189
230
  title: "Total Clients",
190
231
  value: String(B?.totalClients ?? 0),
191
- icon: /* @__PURE__ */ h(u, { className: "h-5 w-5" })
232
+ icon: /* @__PURE__ */ g(u, { className: "h-5 w-5" })
192
233
  }),
193
- /* @__PURE__ */ h(t, {
234
+ /* @__PURE__ */ g(t, {
194
235
  title: "Active",
195
236
  value: String(B?.activeClients ?? 0),
196
237
  trend: {
@@ -200,28 +241,28 @@ function b() {
200
241
  })
201
242
  ]
202
243
  }),
203
- z.length === 0 ? /* @__PURE__ */ h(ae, {
244
+ z.length === 0 ? /* @__PURE__ */ g(ae, {
204
245
  illustration: "empty-people",
205
246
  title: "No clients configured yet",
206
247
  description: "Add your first client to share projects and tracked hours with them.",
207
248
  action: $
208
- }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", {
249
+ }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
209
250
  className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
210
- children: /* @__PURE__ */ h("div", {
251
+ children: /* @__PURE__ */ g("div", {
211
252
  className: "divide-y divide-border",
212
253
  children: z.map((t) => {
213
- let n = t.projects.reduce((e, t) => e + t.trackedHours, 0), r = ve === t.id;
214
- return /* @__PURE__ */ g("div", {
254
+ let n = t.projects.reduce((e, t) => e + t.trackedHours, 0), r = Te === t.id;
255
+ return /* @__PURE__ */ _("div", {
215
256
  className: "flex flex-col gap-3 p-4 hover:bg-bg-sunken/50 transition-colors sm:flex-row sm:items-center sm:justify-between",
216
- children: [/* @__PURE__ */ g("div", {
257
+ children: [/* @__PURE__ */ _("div", {
217
258
  className: "flex items-center gap-3",
218
- children: [/* @__PURE__ */ h("div", {
259
+ children: [/* @__PURE__ */ g("div", {
219
260
  className: "flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-sm font-medium text-primary",
220
261
  children: e(t.clientName)
221
- }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
262
+ }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
222
263
  className: "text-sm font-medium text-text-primary",
223
264
  children: t.clientName
224
- }), /* @__PURE__ */ g("p", {
265
+ }), /* @__PURE__ */ _("p", {
225
266
  className: "text-xs text-text-secondary",
226
267
  children: [
227
268
  t.projects.length,
@@ -229,88 +270,88 @@ function b() {
229
270
  " ",
230
271
  n,
231
272
  "h tracked",
232
- t.contactEmail && /* @__PURE__ */ g(m, { children: [" · ", t.contactEmail] })
273
+ t.contactEmail && /* @__PURE__ */ _(h, { children: [" · ", t.contactEmail] })
233
274
  ]
234
275
  })] })]
235
- }), /* @__PURE__ */ g("div", {
276
+ }), /* @__PURE__ */ _("div", {
236
277
  className: "flex flex-wrap items-center gap-2",
237
278
  children: [
238
- t.isActive && t.shareToken && /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("button", {
279
+ t.isActive && t.shareToken && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
239
280
  type: "button",
240
- onClick: () => void ye(t),
281
+ onClick: () => void Ee(t),
241
282
  title: "Copy the client's private share link",
242
283
  className: "inline-flex items-center gap-1 rounded-md border border-border-seam bg-bg-surface px-2 py-1 text-xs text-text-secondary hover:bg-bg-sunken/50",
243
- children: he === t.id ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(l, { className: "h-3.5 w-3.5" }), " Copied"] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(f, { className: "h-3.5 w-3.5" }), " Share link"] })
244
- }), /* @__PURE__ */ h("button", {
284
+ children: C === t.id ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(l, { className: "h-3.5 w-3.5" }), " Copied"] }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(f, { className: "h-3.5 w-3.5" }), " Share link"] })
285
+ }), /* @__PURE__ */ g("button", {
245
286
  type: "button",
246
- disabled: r && j,
247
- onClick: () => void be(t),
287
+ disabled: r && F,
288
+ onClick: () => void De(t),
248
289
  title: "Regenerate the link (invalidates the old one)",
249
290
  className: "inline-flex items-center rounded-md border border-border-seam bg-bg-surface p-1.5 text-text-secondary hover:bg-bg-sunken/50 disabled:opacity-50",
250
- children: /* @__PURE__ */ h(de, { className: `h-3.5 w-3.5 ${r && j ? "animate-spin" : ""}` })
291
+ children: /* @__PURE__ */ g(de, { className: `h-3.5 w-3.5 ${r && F ? "animate-spin" : ""}` })
251
292
  })] }),
252
- /* @__PURE__ */ g("button", {
293
+ /* @__PURE__ */ _("button", {
253
294
  type: "button",
254
295
  disabled: r,
255
- onClick: () => void Te(t),
296
+ onClick: () => void Ne(t),
256
297
  title: t.isActive ? "Deactivate client portal" : "Activate client portal",
257
298
  className: "inline-flex items-center gap-1 rounded-md border border-border-seam bg-bg-surface px-2 py-1 text-xs text-text-secondary hover:bg-bg-sunken/50 disabled:opacity-50",
258
- children: [/* @__PURE__ */ h(ue, { className: "h-3.5 w-3.5" }), t.isActive ? "Deactivate" : "Activate"]
299
+ children: [/* @__PURE__ */ g(ue, { className: "h-3.5 w-3.5" }), t.isActive ? "Deactivate" : "Activate"]
259
300
  }),
260
- /* @__PURE__ */ h(oe, {
301
+ /* @__PURE__ */ g(oe, {
261
302
  label: t.isActive ? "active" : "inactive",
262
303
  status: t.isActive ? "active" : "inactive"
263
304
  }),
264
- /* @__PURE__ */ h("button", {
305
+ /* @__PURE__ */ g("button", {
265
306
  type: "button",
266
- onClick: () => Se(t),
307
+ onClick: () => ke(t),
267
308
  title: "Edit client",
268
309
  className: "inline-flex items-center rounded-md border border-border-seam bg-bg-surface p-1.5 text-text-secondary hover:bg-bg-sunken/50",
269
- children: /* @__PURE__ */ h(p, { className: "h-3.5 w-3.5" })
310
+ children: /* @__PURE__ */ g(p, { className: "h-3.5 w-3.5" })
270
311
  }),
271
- /* @__PURE__ */ h("button", {
312
+ /* @__PURE__ */ g("button", {
272
313
  type: "button",
273
314
  onClick: () => Y(t),
274
315
  title: "Delete client",
275
316
  className: "inline-flex items-center rounded-md border border-border-seam bg-bg-surface p-1.5 text-status-error-text hover:bg-status-error-bg",
276
- children: /* @__PURE__ */ h(fe, { className: "h-3.5 w-3.5" })
317
+ children: /* @__PURE__ */ g(fe, { className: "h-3.5 w-3.5" })
277
318
  })
278
319
  ]
279
320
  })]
280
321
  }, t.id);
281
322
  })
282
323
  })
283
- }), ge && /* @__PURE__ */ h("div", {
324
+ }), Ce && /* @__PURE__ */ g("div", {
284
325
  className: "mt-4 flex justify-center",
285
- children: /* @__PURE__ */ h("button", {
286
- onClick: Ee,
326
+ children: /* @__PURE__ */ g("button", {
327
+ onClick: Pe,
287
328
  disabled: V,
288
329
  className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50 disabled:opacity-50",
289
330
  children: V ? "Loading..." : "Load more"
290
331
  })
291
332
  })] }),
292
- /* @__PURE__ */ h(o, {
293
- open: _e,
333
+ /* @__PURE__ */ g(o, {
334
+ open: we,
294
335
  onClose: Q,
295
336
  title: W ? "Edit Client" : "Add Client",
296
337
  description: W ? "Update this client's portal details." : "Set up a client so you can share projects and tracked hours with them.",
297
- footer: /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("button", {
338
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
298
339
  onClick: Q,
299
340
  className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
300
341
  children: "Cancel"
301
- }), /* @__PURE__ */ h("button", {
302
- onClick: Ce,
303
- disabled: N || F || !K.clientName.trim(),
342
+ }), /* @__PURE__ */ g("button", {
343
+ onClick: je,
344
+ disabled: I || L || !K.clientName.trim(),
304
345
  className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
305
- children: N || F ? "Saving..." : W ? "Save Changes" : "Add Client"
346
+ children: I || L ? "Saving..." : W ? "Save Changes" : "Add Client"
306
347
  })] }),
307
- children: /* @__PURE__ */ g("div", {
348
+ children: /* @__PURE__ */ _("div", {
308
349
  className: "space-y-4",
309
350
  children: [
310
- /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
351
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
311
352
  className: "block text-sm font-medium text-text-primary",
312
353
  children: "Client Name"
313
- }), /* @__PURE__ */ h("input", {
354
+ }), /* @__PURE__ */ g("input", {
314
355
  type: "text",
315
356
  placeholder: "e.g. Acme Corp",
316
357
  value: K.clientName,
@@ -318,14 +359,14 @@ function b() {
318
359
  ...K,
319
360
  clientName: e.target.value
320
361
  }),
321
- className: v
362
+ className: y
322
363
  })] }),
323
- /* @__PURE__ */ g("div", {
364
+ /* @__PURE__ */ _("div", {
324
365
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
325
- children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
366
+ children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
326
367
  className: "block text-sm font-medium text-text-primary",
327
368
  children: "Contact Email"
328
- }), /* @__PURE__ */ h("input", {
369
+ }), /* @__PURE__ */ g("input", {
329
370
  type: "email",
330
371
  placeholder: "contact@client.com",
331
372
  value: K.contactEmail,
@@ -333,11 +374,11 @@ function b() {
333
374
  ...K,
334
375
  contactEmail: e.target.value
335
376
  }),
336
- className: v
337
- })] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
377
+ className: y
378
+ })] }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
338
379
  className: "block text-sm font-medium text-text-primary",
339
380
  children: "Contact Phone"
340
- }), /* @__PURE__ */ h("input", {
381
+ }), /* @__PURE__ */ g("input", {
341
382
  type: "tel",
342
383
  placeholder: "Optional",
343
384
  value: K.contactPhone,
@@ -345,13 +386,13 @@ function b() {
345
386
  ...K,
346
387
  contactPhone: e.target.value
347
388
  }),
348
- className: v
389
+ className: y
349
390
  })] })]
350
391
  }),
351
- /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
392
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
352
393
  className: "block text-sm font-medium text-text-primary",
353
394
  children: "Description"
354
- }), /* @__PURE__ */ h("textarea", {
395
+ }), /* @__PURE__ */ g("textarea", {
355
396
  rows: 3,
356
397
  placeholder: "Notes about this client (optional)",
357
398
  value: K.description,
@@ -359,40 +400,65 @@ function b() {
359
400
  ...K,
360
401
  description: e.target.value
361
402
  }),
362
- className: v
363
- })] })
403
+ className: y
404
+ })] }),
405
+ /* @__PURE__ */ _("div", { children: [
406
+ /* @__PURE__ */ g("label", {
407
+ className: "block text-sm font-medium text-text-primary",
408
+ children: "Logo"
409
+ }),
410
+ /* @__PURE__ */ g("input", {
411
+ type: "file",
412
+ accept: "image/*",
413
+ disabled: T,
414
+ onChange: (e) => {
415
+ let t = e.target.files?.[0];
416
+ t && Ae(t), e.target.value = "";
417
+ },
418
+ className: he
419
+ }),
420
+ T && /* @__PURE__ */ g("p", {
421
+ className: "mt-1 text-xs text-text-secondary",
422
+ children: "Uploading…"
423
+ }),
424
+ K.logoUrl && /* @__PURE__ */ g("img", {
425
+ src: K.logoUrl,
426
+ alt: "Client logo preview",
427
+ className: "mt-2 h-16 w-16 rounded-md border border-border-seam object-cover"
428
+ })
429
+ ] })
364
430
  ]
365
431
  })
366
432
  }),
367
- /* @__PURE__ */ h(o, {
433
+ /* @__PURE__ */ g(o, {
368
434
  open: J !== null,
369
435
  onClose: () => Y(null),
370
436
  title: "Delete client?",
371
437
  description: J ? `"${J.clientName}" and its share link will be removed.` : void 0,
372
438
  size: "sm",
373
- footer: /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("button", {
439
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
374
440
  onClick: () => Y(null),
375
441
  className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
376
442
  children: "Cancel"
377
- }), /* @__PURE__ */ h("button", {
378
- onClick: we,
379
- disabled: L,
443
+ }), /* @__PURE__ */ g("button", {
444
+ onClick: Me,
445
+ disabled: R,
380
446
  className: "rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50",
381
- children: L ? "Deleting..." : "Delete"
447
+ children: R ? "Deleting..." : "Delete"
382
448
  })] }),
383
- children: /* @__PURE__ */ h("p", {
449
+ children: /* @__PURE__ */ g("p", {
384
450
  className: "text-sm text-text-secondary",
385
451
  children: "The client will lose access to their shared portal immediately. This cannot be undone."
386
452
  })
387
453
  }),
388
- /* @__PURE__ */ h(se, {
389
- toasts: b,
390
- onDismiss: me
454
+ /* @__PURE__ */ g(se, {
455
+ toasts: m,
456
+ onDismiss: ve
391
457
  })
392
458
  ]
393
459
  });
394
460
  }
395
461
  //#endregion
396
- export { b as ClientPortalPage };
462
+ export { x as ClientPortalPage };
397
463
 
398
464
  //# sourceMappingURL=ClientPortalPage.js.map