@burdenoff/microfe-export 2026.625.2 → 2026.626.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/export/pages/CreateExportPage.js +95 -90
- package/dist/export/pages/CreateExportPage.js.map +1 -1
- package/dist/export/pages/ExportDashboardPage.js +79 -46
- package/dist/export/pages/ExportDashboardPage.js.map +1 -1
- package/dist/export/pages/ExportDetailPage.js +157 -134
- package/dist/export/pages/ExportDetailPage.js.map +1 -1
- package/dist/export/pages/ExportHistoryPage.js +139 -135
- package/dist/export/pages/ExportHistoryPage.js.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.js +172 -168
- package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
- package/dist/export/pages/TemplateDetailPage.js +103 -97
- package/dist/export/pages/TemplateDetailPage.js.map +1 -1
- package/dist/node_modules/@apollo/client/version.js +1 -1
- package/dist/node_modules/@apollo/client/version.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,18 +5,18 @@ import { getFormatDisplayName as a } from "../constants/enums.js";
|
|
|
5
5
|
import { tWithFallback as ee } from "../utils/i18n.js";
|
|
6
6
|
import { PageLayout as te } from "../components/PageLayout.js";
|
|
7
7
|
import { isExportEntityDisabled as o } from "../utils/disabledModules.js";
|
|
8
|
-
import { useEffect as
|
|
8
|
+
import { useEffect as s, useRef as ne, useState as c } from "react";
|
|
9
9
|
import { ArrowLeft as l, ArrowRight as u, Building2 as d, CalendarRange as re, CheckCircle2 as f, Download as p, FileJson as m, FileSpreadsheet as h, Loader2 as g, Lock as ie, Package as ae, User as _, Users as v } from "lucide-react";
|
|
10
10
|
import { usePermission as y } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
11
11
|
import { useSearchParams as oe } from "react-router-dom";
|
|
12
12
|
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
13
|
-
import { useI18n as
|
|
14
|
-
import { EmphasisPanel as
|
|
13
|
+
import { useI18n as S } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
|
+
import { EmphasisPanel as se, IllustratedEmptyState as ce, PagePurpose as le, ShowMore as C } from "@burdenoff/fe-libs/ui";
|
|
15
15
|
//#region src/export/pages/CreateExportPage.tsx
|
|
16
|
-
var w = ["CSV", "JSON"],
|
|
16
|
+
var w = ["CSV", "JSON"], T = {
|
|
17
17
|
CSV: h,
|
|
18
18
|
JSON: m
|
|
19
|
-
},
|
|
19
|
+
}, E = [
|
|
20
20
|
{
|
|
21
21
|
value: "INDIVIDUAL",
|
|
22
22
|
label: "My Data Only",
|
|
@@ -36,50 +36,50 @@ var w = ["CSV", "JSON"], ce = {
|
|
|
36
36
|
Icon: d
|
|
37
37
|
}
|
|
38
38
|
];
|
|
39
|
-
function
|
|
40
|
-
let { basePath: d = "/", navigate: m, organizationId: h } = e(), { t: _ } =
|
|
41
|
-
|
|
42
|
-
let e =
|
|
43
|
-
if (!e || !
|
|
44
|
-
let t =
|
|
39
|
+
function D() {
|
|
40
|
+
let { basePath: d = "/", navigate: m, organizationId: h } = e(), { t: _ } = S(), v = (e, t, n) => ee(_, e, t, n), { createJob: D, isPending: O } = n(), { data: ue } = t(), { data: k } = r(), [A] = oe(), de = y("export:workspace:admin"), fe = y("export:org:admin"), [j, M] = c("entities"), [N, P] = c([]), [F, I] = c(""), [L, R] = c("CSV"), [z, B] = c("INDIVIDUAL"), [V, H] = c(A.get("templateId") ?? void 0), [U, pe] = c(""), [W, me] = c(""), [G, K] = c(null), q = ne(null);
|
|
41
|
+
s(() => {
|
|
42
|
+
let e = A.get("templateId");
|
|
43
|
+
if (!e || !k?.length || q.current === e) return;
|
|
44
|
+
let t = k.find((t) => t.id === e);
|
|
45
45
|
if (!t) return;
|
|
46
|
-
|
|
46
|
+
q.current = e, H(t.id), P((t.entityTypes ?? []).filter((e) => !o(e)));
|
|
47
47
|
let n = t.format?.toUpperCase();
|
|
48
|
-
n && w.includes(n) &&
|
|
49
|
-
}, [
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
},
|
|
53
|
-
if (
|
|
54
|
-
if (
|
|
55
|
-
|
|
48
|
+
n && w.includes(n) && R(n), t.name && I(t.name);
|
|
49
|
+
}, [A, k]);
|
|
50
|
+
let he = () => {
|
|
51
|
+
j === "options" ? M("entities") : j === "review" ? M("options") : m?.(d);
|
|
52
|
+
}, ge = () => {
|
|
53
|
+
if (j === "entities") {
|
|
54
|
+
if (N.length === 0) {
|
|
55
|
+
K(v("export.create.errors.selectEntity", "Please select at least one entity type to export"));
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
} else if (
|
|
60
|
-
if (!
|
|
61
|
-
|
|
58
|
+
K(null), M("options");
|
|
59
|
+
} else if (j === "options") {
|
|
60
|
+
if (!F.trim()) {
|
|
61
|
+
K(v("export.create.errors.exportNameRequired", "Please provide a name for this export"));
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
K(null), M("review");
|
|
65
65
|
}
|
|
66
|
-
},
|
|
66
|
+
}, _e = async () => {
|
|
67
67
|
try {
|
|
68
|
-
|
|
69
|
-
name:
|
|
70
|
-
entityTypes:
|
|
71
|
-
format:
|
|
72
|
-
exportScope:
|
|
73
|
-
organizationId:
|
|
74
|
-
templateId:
|
|
75
|
-
dateRangeStart:
|
|
76
|
-
dateRangeEnd:
|
|
68
|
+
K(null), await D({
|
|
69
|
+
name: F,
|
|
70
|
+
entityTypes: N,
|
|
71
|
+
format: L,
|
|
72
|
+
exportScope: z,
|
|
73
|
+
organizationId: z === "ORG_ADMIN" ? h : void 0,
|
|
74
|
+
templateId: V,
|
|
75
|
+
dateRangeStart: U ? new Date(U).toISOString() : null,
|
|
76
|
+
dateRangeEnd: W ? new Date(W).toISOString() : null
|
|
77
77
|
}), m?.(d);
|
|
78
78
|
} catch (e) {
|
|
79
|
-
|
|
79
|
+
K(e instanceof Error ? e.message : v("export.create.errors.createFailed", "Failed to create export"));
|
|
80
80
|
}
|
|
81
|
-
},
|
|
82
|
-
o(e) ||
|
|
81
|
+
}, ve = (e) => {
|
|
82
|
+
o(e) || P((t) => t.includes(e) ? t.filter((t) => t !== e) : [...t, e]);
|
|
83
83
|
}, J = (e) => {
|
|
84
84
|
switch (e) {
|
|
85
85
|
case "INDIVIDUAL": return v("export.create.scope.individual.label", "My Data Only");
|
|
@@ -87,7 +87,7 @@ function T() {
|
|
|
87
87
|
case "ORG_ADMIN": return v("export.create.scope.orgAdmin.label", "All Organization Data");
|
|
88
88
|
default: return e;
|
|
89
89
|
}
|
|
90
|
-
},
|
|
90
|
+
}, ye = (e) => {
|
|
91
91
|
switch (e) {
|
|
92
92
|
case "INDIVIDUAL": return v("export.create.scope.individual.description", "Export data you personally created across selected modules.");
|
|
93
93
|
case "WORKSPACE_ADMIN": return v("export.create.scope.workspaceAdmin.description", "Export all data in this workspace regardless of who created it. Requires workspace admin access.");
|
|
@@ -127,11 +127,11 @@ function T() {
|
|
|
127
127
|
label: v("export.create.entities.calendar.label", "Calendar Events"),
|
|
128
128
|
description: v("export.create.entities.calendar.description", "Events and bookings")
|
|
129
129
|
}
|
|
130
|
-
}, X =
|
|
131
|
-
let n = !t &&
|
|
130
|
+
}, X = ue.filter((e) => e.enabled !== !1), Z = X.filter((e) => !o(e.entityType)), Q = X.filter((e) => o(e.entityType)), $ = (e, t) => {
|
|
131
|
+
let n = !t && N.includes(e.entityType);
|
|
132
132
|
return /* @__PURE__ */ x("button", {
|
|
133
133
|
type: "button",
|
|
134
|
-
onClick: () =>
|
|
134
|
+
onClick: () => ve(e.entityType),
|
|
135
135
|
disabled: t,
|
|
136
136
|
"aria-disabled": t,
|
|
137
137
|
title: t ? v("export.create.select.unavailableHint", "Export for this product isn't available yet") : void 0,
|
|
@@ -189,6 +189,10 @@ function T() {
|
|
|
189
189
|
})]
|
|
190
190
|
})
|
|
191
191
|
}),
|
|
192
|
+
/* @__PURE__ */ b(le, {
|
|
193
|
+
icon: /* @__PURE__ */ b(p, { size: 16 }),
|
|
194
|
+
children: v("export.create.purpose", "Build a one-off export in three steps: pick which data to include, choose a format and scope, then review and start it. The export runs in the background and produces a downloadable ZIP you can grab from History when it finishes.")
|
|
195
|
+
}),
|
|
192
196
|
/* @__PURE__ */ b("div", {
|
|
193
197
|
className: "flex items-center gap-2 justify-center flex-wrap",
|
|
194
198
|
children: [
|
|
@@ -201,7 +205,7 @@ function T() {
|
|
|
201
205
|
size: 18,
|
|
202
206
|
className: "text-text-secondary"
|
|
203
207
|
}), /* @__PURE__ */ x("div", {
|
|
204
|
-
className: i("flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200",
|
|
208
|
+
className: i("flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200", j === e ? "bg-action-primary-bg text-action-primary-text border-primary shadow-[var(--shadow-pop)]" : "bg-bg-sunken/50 text-text-secondary border-border-seam"),
|
|
205
209
|
children: [/* @__PURE__ */ b("div", {
|
|
206
210
|
className: "flex items-center justify-center size-6 rounded-full bg-bg-surface/20 font-bold",
|
|
207
211
|
children: t + 1
|
|
@@ -212,11 +216,11 @@ function T() {
|
|
|
212
216
|
})]
|
|
213
217
|
}, e))
|
|
214
218
|
}),
|
|
215
|
-
|
|
219
|
+
G && /* @__PURE__ */ b("div", {
|
|
216
220
|
className: "border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-4 text-status-error-text text-sm",
|
|
217
|
-
children:
|
|
221
|
+
children: G
|
|
218
222
|
}),
|
|
219
|
-
|
|
223
|
+
j === "entities" && /* @__PURE__ */ x("div", {
|
|
220
224
|
className: "space-y-4",
|
|
221
225
|
children: [
|
|
222
226
|
/* @__PURE__ */ b("h2", {
|
|
@@ -227,9 +231,10 @@ function T() {
|
|
|
227
231
|
className: "text-sm text-text-secondary",
|
|
228
232
|
children: v("export.create.select.description", "Choose which entity types to include in your export.")
|
|
229
233
|
}),
|
|
230
|
-
X.length === 0 ? /* @__PURE__ */ b(
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
X.length === 0 ? /* @__PURE__ */ b(ce, {
|
|
235
|
+
illustration: "empty-data",
|
|
236
|
+
title: v("export.create.select.emptyTitle", "Nothing to export yet"),
|
|
237
|
+
description: v("export.create.select.empty", "No exportable entity types are configured for this workspace yet. Once your workspace has data in supported modules, they'll show up here to select.")
|
|
233
238
|
}) : /* @__PURE__ */ x("div", {
|
|
234
239
|
className: "space-y-6",
|
|
235
240
|
children: [Z.length > 0 && /* @__PURE__ */ b("div", {
|
|
@@ -255,7 +260,7 @@ function T() {
|
|
|
255
260
|
})
|
|
256
261
|
]
|
|
257
262
|
}),
|
|
258
|
-
|
|
263
|
+
j === "options" && /* @__PURE__ */ b("div", {
|
|
259
264
|
className: "space-y-6",
|
|
260
265
|
children: /* @__PURE__ */ x("div", {
|
|
261
266
|
className: "border border-border-seam rounded-xl p-6 space-y-5 bg-bg-surface",
|
|
@@ -269,13 +274,13 @@ function T() {
|
|
|
269
274
|
children: v("export.create.options.scope", "Export Scope")
|
|
270
275
|
}), /* @__PURE__ */ b("div", {
|
|
271
276
|
className: "grid grid-cols-1 sm:grid-cols-3 gap-3",
|
|
272
|
-
children:
|
|
273
|
-
let n = e === "WORKSPACE_ADMIN" && !
|
|
277
|
+
children: E.map(({ value: e, Icon: t }) => {
|
|
278
|
+
let n = e === "WORKSPACE_ADMIN" && !de || e === "ORG_ADMIN" && !fe;
|
|
274
279
|
return /* @__PURE__ */ x("button", {
|
|
275
280
|
type: "button",
|
|
276
|
-
onClick: () => !n &&
|
|
281
|
+
onClick: () => !n && B(e),
|
|
277
282
|
disabled: n,
|
|
278
|
-
className: i("text-left border-2 rounded-xl p-4 transition-all duration-200",
|
|
283
|
+
className: i("text-left border-2 rounded-xl p-4 transition-all duration-200", z === e ? "border-primary bg-action-primary-bg/5 shadow-md" : n ? "border-border-subtle/30 opacity-50 cursor-not-allowed" : "border-border-subtle/50 hover:border-primary/30 hover:shadow-sm"),
|
|
279
284
|
title: n ? e === "WORKSPACE_ADMIN" ? "Workspace admin access required" : "Organization admin access required" : void 0,
|
|
280
285
|
children: [
|
|
281
286
|
/* @__PURE__ */ x("div", {
|
|
@@ -283,9 +288,9 @@ function T() {
|
|
|
283
288
|
children: [
|
|
284
289
|
/* @__PURE__ */ b(t, {
|
|
285
290
|
size: 18,
|
|
286
|
-
className:
|
|
291
|
+
className: z === e ? "text-primary" : n ? "text-text-secondary/50" : "text-text-secondary"
|
|
287
292
|
}),
|
|
288
|
-
|
|
293
|
+
z === e && /* @__PURE__ */ b(f, {
|
|
289
294
|
size: 16,
|
|
290
295
|
className: "text-primary"
|
|
291
296
|
}),
|
|
@@ -301,7 +306,7 @@ function T() {
|
|
|
301
306
|
}),
|
|
302
307
|
/* @__PURE__ */ b("p", {
|
|
303
308
|
className: "text-xs text-text-secondary mt-1",
|
|
304
|
-
children:
|
|
309
|
+
children: ye(e)
|
|
305
310
|
})
|
|
306
311
|
]
|
|
307
312
|
}, e);
|
|
@@ -322,8 +327,8 @@ function T() {
|
|
|
322
327
|
type: "text",
|
|
323
328
|
id: "exportName",
|
|
324
329
|
"aria-label": v("export.create.options.name", "Export Name"),
|
|
325
|
-
value:
|
|
326
|
-
onChange: (e) =>
|
|
330
|
+
value: F,
|
|
331
|
+
onChange: (e) => I(e.target.value),
|
|
327
332
|
className: "w-full px-4 py-2.5 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all duration-200",
|
|
328
333
|
placeholder: v("export.create.options.namePlaceholder", "e.g., Monthly User Export")
|
|
329
334
|
})] }),
|
|
@@ -333,14 +338,14 @@ function T() {
|
|
|
333
338
|
}), /* @__PURE__ */ b("div", {
|
|
334
339
|
className: "grid grid-cols-2 gap-3",
|
|
335
340
|
children: w.map((e) => {
|
|
336
|
-
let t =
|
|
341
|
+
let t = T[e];
|
|
337
342
|
return /* @__PURE__ */ x("button", {
|
|
338
343
|
type: "button",
|
|
339
|
-
onClick: () =>
|
|
340
|
-
className: i("flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200",
|
|
344
|
+
onClick: () => R(e),
|
|
345
|
+
className: i("flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200", L === e ? "border-primary bg-action-primary-bg/5" : "border-border-subtle/50 hover:border-primary/30"),
|
|
341
346
|
children: [/* @__PURE__ */ b(t, {
|
|
342
347
|
size: 18,
|
|
343
|
-
className:
|
|
348
|
+
className: L === e ? "text-primary" : "text-text-secondary"
|
|
344
349
|
}), /* @__PURE__ */ b("span", {
|
|
345
350
|
className: "font-medium text-sm",
|
|
346
351
|
children: a(e)
|
|
@@ -402,8 +407,8 @@ function T() {
|
|
|
402
407
|
type: "date",
|
|
403
408
|
id: "dateFrom",
|
|
404
409
|
"aria-label": v("export.create.options.dateFrom", "From"),
|
|
405
|
-
value:
|
|
406
|
-
onChange: (e) =>
|
|
410
|
+
value: U,
|
|
411
|
+
onChange: (e) => pe(e.target.value),
|
|
407
412
|
className: "w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm"
|
|
408
413
|
})] }), /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("label", {
|
|
409
414
|
htmlFor: "dateTo",
|
|
@@ -413,9 +418,9 @@ function T() {
|
|
|
413
418
|
type: "date",
|
|
414
419
|
id: "dateTo",
|
|
415
420
|
"aria-label": v("export.create.options.dateTo", "To"),
|
|
416
|
-
value:
|
|
417
|
-
min:
|
|
418
|
-
onChange: (e) =>
|
|
421
|
+
value: W,
|
|
422
|
+
min: U,
|
|
423
|
+
onChange: (e) => me(e.target.value),
|
|
419
424
|
className: "w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm"
|
|
420
425
|
})] })]
|
|
421
426
|
}),
|
|
@@ -433,14 +438,14 @@ function T() {
|
|
|
433
438
|
children: v("export.create.shared.optional", "(optional)")
|
|
434
439
|
})
|
|
435
440
|
]
|
|
436
|
-
}),
|
|
437
|
-
value:
|
|
438
|
-
onChange: (e) =>
|
|
441
|
+
}), k.length > 0 ? /* @__PURE__ */ x("select", {
|
|
442
|
+
value: V ?? "",
|
|
443
|
+
onChange: (e) => H(e.target.value || void 0),
|
|
439
444
|
className: "w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary",
|
|
440
445
|
children: [/* @__PURE__ */ b("option", {
|
|
441
446
|
value: "",
|
|
442
447
|
children: v("export.create.options.noTemplate", "No template")
|
|
443
|
-
}),
|
|
448
|
+
}), k.map((e) => /* @__PURE__ */ b("option", {
|
|
444
449
|
value: e.id,
|
|
445
450
|
children: e.name
|
|
446
451
|
}, e.id))]
|
|
@@ -464,9 +469,9 @@ function T() {
|
|
|
464
469
|
]
|
|
465
470
|
})
|
|
466
471
|
}),
|
|
467
|
-
|
|
472
|
+
j === "review" && /* @__PURE__ */ b("div", {
|
|
468
473
|
className: "space-y-6",
|
|
469
|
-
children: /* @__PURE__ */ x(
|
|
474
|
+
children: /* @__PURE__ */ x(se, {
|
|
470
475
|
className: "p-6 space-y-4",
|
|
471
476
|
children: [/* @__PURE__ */ x("h2", {
|
|
472
477
|
className: "text-lg font-bold flex items-center gap-2",
|
|
@@ -479,31 +484,31 @@ function T() {
|
|
|
479
484
|
children: [
|
|
480
485
|
{
|
|
481
486
|
label: v("export.create.review.fields.name", "Name"),
|
|
482
|
-
value:
|
|
487
|
+
value: F
|
|
483
488
|
},
|
|
484
489
|
{
|
|
485
490
|
label: v("export.create.review.fields.scope", "Scope"),
|
|
486
|
-
value: J(
|
|
491
|
+
value: J(z)
|
|
487
492
|
},
|
|
488
493
|
{
|
|
489
494
|
label: v("export.create.review.fields.entityTypes", "Entity Types"),
|
|
490
|
-
value:
|
|
495
|
+
value: N.join(", ")
|
|
491
496
|
},
|
|
492
497
|
{
|
|
493
498
|
label: v("export.create.review.fields.format", "Format"),
|
|
494
|
-
value: a(
|
|
499
|
+
value: a(L)
|
|
495
500
|
},
|
|
496
501
|
{
|
|
497
502
|
label: v("export.create.review.fields.archive", "Archive"),
|
|
498
503
|
value: "ZIP"
|
|
499
504
|
},
|
|
500
|
-
...
|
|
505
|
+
...U || W ? [{
|
|
501
506
|
label: v("export.create.review.fields.dateRange", "Date Range"),
|
|
502
|
-
value: [
|
|
507
|
+
value: [U || "—", W || "—"].join(" → ")
|
|
503
508
|
}] : [],
|
|
504
|
-
...
|
|
509
|
+
...V ? [{
|
|
505
510
|
label: v("export.create.review.fields.template", "Template"),
|
|
506
|
-
value:
|
|
511
|
+
value: k.find((e) => e.id === V)?.name ?? V
|
|
507
512
|
}] : []
|
|
508
513
|
].map(({ label: e, value: t }) => /* @__PURE__ */ x("div", {
|
|
509
514
|
className: "flex flex-col sm:flex-row sm:justify-between gap-1",
|
|
@@ -522,21 +527,21 @@ function T() {
|
|
|
522
527
|
className: "flex flex-col sm:flex-row gap-3 pt-2",
|
|
523
528
|
children: [/* @__PURE__ */ b("button", {
|
|
524
529
|
type: "button",
|
|
525
|
-
onClick:
|
|
530
|
+
onClick: he,
|
|
526
531
|
className: "px-6 py-3 border-2 border-border-subtle/50 rounded-lg hover:bg-accent hover:border-primary/30 transition-all duration-200 font-medium",
|
|
527
|
-
children:
|
|
528
|
-
}),
|
|
532
|
+
children: j === "entities" ? v("export.create.actions.cancel", "Cancel") : v("export.create.actions.back", "Back")
|
|
533
|
+
}), j === "review" ? /* @__PURE__ */ x("button", {
|
|
529
534
|
type: "button",
|
|
530
|
-
onClick:
|
|
531
|
-
disabled:
|
|
535
|
+
onClick: _e,
|
|
536
|
+
disabled: O,
|
|
532
537
|
className: "flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg disabled:opacity-50 disabled:cursor-not-allowed",
|
|
533
|
-
children: [
|
|
538
|
+
children: [O ? /* @__PURE__ */ b(g, {
|
|
534
539
|
size: 18,
|
|
535
540
|
className: "animate-spin"
|
|
536
541
|
}) : /* @__PURE__ */ b(p, { size: 18 }), v("export.create.actions.startExport", "Start Export")]
|
|
537
542
|
}) : /* @__PURE__ */ x("button", {
|
|
538
543
|
type: "button",
|
|
539
|
-
onClick:
|
|
544
|
+
onClick: ge,
|
|
540
545
|
className: "flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg",
|
|
541
546
|
children: [v("export.create.actions.next", "Next"), /* @__PURE__ */ b(u, { size: 18 })]
|
|
542
547
|
})]
|
|
@@ -545,6 +550,6 @@ function T() {
|
|
|
545
550
|
});
|
|
546
551
|
}
|
|
547
552
|
//#endregion
|
|
548
|
-
export {
|
|
553
|
+
export { D as CreateExportPage };
|
|
549
554
|
|
|
550
555
|
//# sourceMappingURL=CreateExportPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateExportPage.js","names":[],"sources":["../../../src/export/pages/CreateExportPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n ArrowLeft,\n ArrowRight,\n Download,\n CheckCircle2,\n Loader2,\n FileSpreadsheet,\n FileJson,\n Package,\n CalendarRange,\n User,\n Users,\n Building2,\n Lock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { usePermission } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { EmphasisPanel, ShowMore } from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useCreateExportJob,\n useAvailableEntities,\n useExportTemplates,\n} from \"../hooks/useExportQueries\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { isExportEntityDisabled } from \"../utils/disabledModules\";\nimport type {\n ExportAvailableEntity,\n ExportFormat,\n ExportScope,\n} from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype WizardStep = \"entities\" | \"options\" | \"review\";\n\n// Backend only supports CSV and JSON\nconst SUPPORTED_FORMATS: ExportFormat[] = [\"CSV\", \"JSON\"];\n\nconst FORMAT_ICONS: Record<ExportFormat, typeof FileJson> = {\n CSV: FileSpreadsheet,\n JSON: FileJson,\n};\n\n/**\n * Create Export Page\n * Multi-step form: select entities, configure options, review & start\n */\nconst SCOPE_OPTIONS: Array<{\n value: ExportScope;\n label: string;\n description: string;\n Icon: typeof User;\n}> = [\n {\n value: \"INDIVIDUAL\",\n label: \"My Data Only\",\n description: \"Export data you personally created across selected modules.\",\n Icon: User,\n },\n {\n value: \"WORKSPACE_ADMIN\",\n label: \"All Workspace Data\",\n description:\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n Icon: Users,\n },\n {\n value: \"ORG_ADMIN\",\n label: \"All Organization Data\",\n description:\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n Icon: Building2,\n },\n];\n\nexport function CreateExportPage() {\n const { basePath = \"/\", navigate, organizationId } = useExport();\n const { t } = useI18n();\n const tr = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>,\n ) => tWithFallback(t, key, fallback, params);\n const { createJob, isPending } = useCreateExportJob();\n const { data: availableEntities } = useAvailableEntities();\n const { data: templates } = useExportTemplates();\n const [searchParams] = useSearchParams();\n\n // RBAC: Check permissions for admin scopes\n const canExportWorkspaceAdmin = usePermission(\"export:workspace:admin\");\n const canExportOrgAdmin = usePermission(\"export:org:admin\");\n\n const [step, setStep] = useState<WizardStep>(\"entities\");\n const [selectedEntities, setSelectedEntities] = useState<string[]>([]);\n const [exportName, setExportName] = useState(\"\");\n const [selectedFormat, setSelectedFormat] = useState<ExportFormat>(\"CSV\");\n const [selectedScope, setSelectedScope] = useState<ExportScope>(\"INDIVIDUAL\");\n const [selectedTemplateId, setSelectedTemplateId] = useState<\n string | undefined\n >(searchParams.get(\"templateId\") ?? undefined);\n const [dateRangeStart, setDateRangeStart] = useState(\"\");\n const [dateRangeEnd, setDateRangeEnd] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n // Pre-populate form when arriving from \"Use Template\" — apply only once per templateId\n const appliedTemplateRef = useRef<string | null>(null);\n useEffect(() => {\n const paramTemplateId = searchParams.get(\"templateId\");\n if (!paramTemplateId || !templates?.length) return;\n if (appliedTemplateRef.current === paramTemplateId) return;\n const tpl = templates.find((t) => t.id === paramTemplateId);\n if (!tpl) return;\n appliedTemplateRef.current = paramTemplateId;\n setSelectedTemplateId(tpl.id);\n // Skip entity types whose product export is currently disabled.\n setSelectedEntities(\n (tpl.entityTypes ?? []).filter((et) => !isExportEntityDisabled(et)),\n );\n const normalizedFormat = tpl.format?.toUpperCase() as\n | ExportFormat\n | undefined;\n if (normalizedFormat && SUPPORTED_FORMATS.includes(normalizedFormat)) {\n setSelectedFormat(normalizedFormat);\n }\n if (tpl.name) setExportName(tpl.name);\n }, [searchParams, templates]);\n\n const handleBack = () => {\n if (step === \"options\") setStep(\"entities\");\n else if (step === \"review\") setStep(\"options\");\n else navigate?.(basePath);\n };\n\n const handleNext = () => {\n if (step === \"entities\") {\n if (selectedEntities.length === 0) {\n setError(\n tr(\n \"export.create.errors.selectEntity\",\n \"Please select at least one entity type to export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"options\");\n } else if (step === \"options\") {\n if (!exportName.trim()) {\n setError(\n tr(\n \"export.create.errors.exportNameRequired\",\n \"Please provide a name for this export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"review\");\n }\n };\n\n const handleSubmit = async () => {\n try {\n setError(null);\n await createJob({\n name: exportName,\n entityTypes: selectedEntities,\n format: selectedFormat,\n exportScope: selectedScope,\n organizationId:\n selectedScope === \"ORG_ADMIN\" ? organizationId : undefined,\n templateId: selectedTemplateId,\n dateRangeStart: dateRangeStart\n ? new Date(dateRangeStart).toISOString()\n : null,\n dateRangeEnd: dateRangeEnd\n ? new Date(dateRangeEnd).toISOString()\n : null,\n });\n navigate?.(basePath);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"export.create.errors.createFailed\", \"Failed to create export\"),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n // Disabled-product entities can't be selected.\n if (isExportEntityDisabled(entityType)) return;\n setSelectedEntities((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n const getScopeLabel = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\"export.create.scope.individual.label\", \"My Data Only\");\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.label\",\n \"All Workspace Data\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.label\",\n \"All Organization Data\",\n );\n default:\n return scope;\n }\n };\n\n const getScopeDescription = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\n \"export.create.scope.individual.description\",\n \"Export data you personally created across selected modules.\",\n );\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.description\",\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.description\",\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n );\n default:\n return \"\";\n }\n };\n\n const fallbackEntityCopy: Record<\n string,\n { label: string; description: string }\n > = {\n users: {\n label: tr(\"export.create.entities.users.label\", \"Users\"),\n description: tr(\n \"export.create.entities.users.description\",\n \"Workspace members and profiles\",\n ),\n },\n projects: {\n label: tr(\"export.create.entities.projects.label\", \"Projects\"),\n description: tr(\n \"export.create.entities.projects.description\",\n \"Projects and their metadata\",\n ),\n },\n tasks: {\n label: tr(\"export.create.entities.tasks.label\", \"Tasks\"),\n description: tr(\n \"export.create.entities.tasks.description\",\n \"Task items and assignments\",\n ),\n },\n files: {\n label: tr(\"export.create.entities.files.label\", \"Files\"),\n description: tr(\n \"export.create.entities.files.description\",\n \"File metadata and references\",\n ),\n },\n conversations: {\n label: tr(\"export.create.entities.conversations.label\", \"Conversations\"),\n description: tr(\n \"export.create.entities.conversations.description\",\n \"Chat messages and threads\",\n ),\n },\n tags: {\n label: tr(\"export.create.entities.tags.label\", \"Tags\"),\n description: tr(\n \"export.create.entities.tags.description\",\n \"Tags and vocabularies\",\n ),\n },\n activity: {\n label: tr(\"export.create.entities.activity.label\", \"Activity Logs\"),\n description: tr(\n \"export.create.entities.activity.description\",\n \"Audit trail and activity history\",\n ),\n },\n calendar: {\n label: tr(\"export.create.entities.calendar.label\", \"Calendar Events\"),\n description: tr(\n \"export.create.entities.calendar.description\",\n \"Events and bookings\",\n ),\n },\n };\n\n // Entities the backend marks available, split so the ones a user can export\n // show first and disabled-product entities are listed (still visible) below.\n const visibleEntities = availableEntities.filter((e) => e.enabled !== false);\n const availableForExport = visibleEntities.filter(\n (e) => !isExportEntityDisabled(e.entityType),\n );\n const unavailableForExport = visibleEntities.filter((e) =>\n isExportEntityDisabled(e.entityType),\n );\n\n const renderEntityCard = (\n entity: ExportAvailableEntity,\n isDisabled: boolean,\n ) => {\n const isSelected =\n !isDisabled && selectedEntities.includes(entity.entityType);\n return (\n <button\n type=\"button\"\n key={entity.entityType}\n onClick={() => toggleEntity(entity.entityType)}\n disabled={isDisabled}\n aria-disabled={isDisabled}\n title={\n isDisabled\n ? tr(\n \"export.create.select.unavailableHint\",\n \"Export for this product isn't available yet\",\n )\n : undefined\n }\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : isSelected\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2 gap-2\">\n <h3 className=\"font-semibold\">\n {fallbackEntityCopy[entity.entityType]?.label ?? entity.displayName}\n </h3>\n {isDisabled ? (\n <span className=\"shrink-0 text-xs font-medium px-2 py-0.5 rounded-full bg-bg-sunken text-text-secondary\">\n {tr(\"export.create.select.unavailable\", \"Unavailable\")}\n </span>\n ) : (\n isSelected && <CheckCircle2 size={18} className=\"text-primary\" />\n )}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {fallbackEntityCopy[entity.entityType]?.description ??\n entity.description}\n </p>\n {entity.estimatedSize && (\n <p className=\"text-xs text-text-secondary mt-2\">\n ~{entity.estimatedSize}\n </p>\n )}\n </button>\n );\n };\n\n return (\n <PageLayout showHeader={false}>\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl bg-accent-wash border border-border-seam p-6 shadow-[var(--shadow-pop)]\">\n <div className=\"relative z-10 flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath)}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\"\n aria-label={tr(\n \"export.create.actions.backToDashboard\",\n \"Back to export dashboard\",\n )}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2.5 rounded-lg bg-action-primary-bg/10 backdrop-blur-sm\">\n <Download size={24} className=\"text-primary\" />\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tr(\"export.create.title\", \"New Export\")}\n </h1>\n </div>\n </div>\n </div>\n\n {/* Step Indicator */}\n <div className=\"flex items-center gap-2 justify-center flex-wrap\">\n {([\"entities\", \"options\", \"review\"] as WizardStep[]).map((s, i) => (\n <div key={s} className=\"flex items-center gap-2\">\n {i > 0 && (\n <ArrowRight size={18} className=\"text-text-secondary\" />\n )}\n <div\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200\",\n step === s\n ? \"bg-action-primary-bg text-action-primary-text border-primary shadow-[var(--shadow-pop)]\"\n : \"bg-bg-sunken/50 text-text-secondary border-border-seam\",\n )}\n >\n <div className=\"flex items-center justify-center size-6 rounded-full bg-bg-surface/20 font-bold\">\n {i + 1}\n </div>\n <span className=\"hidden sm:inline capitalize\">\n {s === \"entities\"\n ? tr(\"export.create.steps.entities\", \"Select Data\")\n : s === \"options\"\n ? tr(\"export.create.steps.options\", \"Options\")\n : tr(\"export.create.steps.review\", \"Review\")}\n </span>\n </div>\n </div>\n ))}\n </div>\n\n {/* Error */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-4 text-status-error-text text-sm\">\n {error}\n </div>\n )}\n\n {/* Step 1: Select Entities */}\n {step === \"entities\" && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.select.title\", \"Select data to export\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"export.create.select.description\",\n \"Choose which entity types to include in your export.\",\n )}\n </p>\n {visibleEntities.length === 0 ? (\n <div className=\"border-2 border-border-subtle rounded-xl bg-bg-sunken/30 p-6 text-sm text-text-secondary\">\n {tr(\n \"export.create.select.empty\",\n \"No exportable entity types are configured for this workspace yet.\",\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {availableForExport.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {availableForExport.map((entity) =>\n renderEntityCard(entity, false),\n )}\n </div>\n )}\n {unavailableForExport.length > 0 && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1 bg-border/60\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr(\n \"export.create.select.unavailableSection\",\n \"Not available yet\",\n )}\n </span>\n <div className=\"h-px flex-1 bg-border/60\" />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {unavailableForExport.map((entity) =>\n renderEntityCard(entity, true),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Step 2: Configure Options */}\n {step === \"options\" && (\n <div className=\"space-y-6\">\n <div className=\"border border-border-seam rounded-xl p-6 space-y-5 bg-bg-surface\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.options.title\", \"Export Options\")}\n </h2>\n\n {/* Scope selection */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.scope\", \"Export Scope\")}\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {SCOPE_OPTIONS.map(({ value, Icon }) => {\n // RBAC: Disable admin scopes if user lacks permission\n const isDisabled =\n (value === \"WORKSPACE_ADMIN\" && !canExportWorkspaceAdmin) ||\n (value === \"ORG_ADMIN\" && !canExportOrgAdmin);\n\n return (\n <button\n key={value}\n type=\"button\"\n onClick={() => !isDisabled && setSelectedScope(value)}\n disabled={isDisabled}\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n selectedScope === value\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n title={\n isDisabled\n ? value === \"WORKSPACE_ADMIN\"\n ? \"Workspace admin access required\"\n : \"Organization admin access required\"\n : undefined\n }\n >\n <div className=\"flex items-center justify-between mb-2\">\n <Icon\n size={18}\n className={\n selectedScope === value\n ? \"text-primary\"\n : isDisabled\n ? \"text-text-secondary/50\"\n : \"text-text-secondary\"\n }\n />\n {selectedScope === value && (\n <CheckCircle2 size={16} className=\"text-primary\" />\n )}\n {isDisabled && (\n <Lock\n size={14}\n className=\"text-text-secondary/50\"\n />\n )}\n </div>\n <p className=\"font-semibold text-sm\">\n {getScopeLabel(value)}\n </p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {getScopeDescription(value)}\n </p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name */}\n <div>\n <label\n htmlFor=\"exportName\"\n className=\"block text-sm font-semibold mb-2\"\n >\n {tr(\"export.create.options.name\", \"Export Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"exportName\"\n aria-label={tr(\"export.create.options.name\", \"Export Name\")}\n value={exportName}\n onChange={(e) => setExportName(e.target.value)}\n className=\"w-full px-4 py-2.5 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all duration-200\"\n placeholder={tr(\n \"export.create.options.namePlaceholder\",\n \"e.g., Monthly User Export\",\n )}\n />\n </div>\n\n {/* Format — only CSV and JSON are supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.outputFormat\", \"Output Format\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n {SUPPORTED_FORMATS.map((format) => {\n const Icon = FORMAT_ICONS[format];\n return (\n <button\n type=\"button\"\n key={format}\n onClick={() => setSelectedFormat(format)}\n className={cn(\n \"flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200\",\n selectedFormat === format\n ? \"border-primary bg-action-primary-bg/5\"\n : \"border-border-subtle/50 hover:border-primary/30\",\n )}\n >\n <Icon\n size={18}\n className={\n selectedFormat === format\n ? \"text-primary\"\n : \"text-text-secondary\"\n }\n />\n <span className=\"font-medium text-sm\">\n {getFormatDisplayName(format)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Archive format — only ZIP is supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.archiveFormat\", \"Archive Format\")}\n </label>\n <div className=\"flex gap-3\">\n <div\n className={cn(\n \"flex items-center gap-2 border-2 rounded-lg px-4 py-2 border-primary bg-action-primary-bg/5\",\n )}\n >\n <Package size={16} className=\"text-primary\" />\n <span className=\"font-medium text-sm\">ZIP</span>\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.archiveDescription\",\n \"Exports are packaged as ZIP archives.\",\n )}\n </p>\n </div>\n\n {/* Advanced / optional refinements — progressively disclosed */}\n <ShowMore\n collapsedHeight={0}\n label={tr(\n \"export.create.options.advancedToggle\",\n \"Date range & template\",\n )}\n >\n <div className=\"space-y-5 pt-1\">\n {/* Date range filter */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n <span className=\"inline-flex items-center gap-1.5\">\n <CalendarRange size={15} />\n {tr(\"export.create.options.dateRange\", \"Date Range\")}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </span>\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"dateFrom\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateFrom\", \"From\")}\n </label>\n <input\n type=\"date\"\n id=\"dateFrom\"\n aria-label={tr(\"export.create.options.dateFrom\", \"From\")}\n value={dateRangeStart}\n onChange={(e) => setDateRangeStart(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n <div>\n <label\n htmlFor=\"dateTo\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateTo\", \"To\")}\n </label>\n <input\n type=\"date\"\n id=\"dateTo\"\n aria-label={tr(\"export.create.options.dateTo\", \"To\")}\n value={dateRangeEnd}\n min={dateRangeStart}\n onChange={(e) => setDateRangeEnd(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.dateRangeDescription\",\n \"Leave blank to export all data regardless of date.\",\n )}\n </p>\n </div>\n\n {/* Optional: Use a template */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\n \"export.create.options.basedOnTemplate\",\n \"Based on Template\",\n )}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </label>\n {templates.length > 0 ? (\n <select\n value={selectedTemplateId ?? \"\"}\n onChange={(e) =>\n setSelectedTemplateId(e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n >\n <option value=\"\">\n {tr(\"export.create.options.noTemplate\", \"No template\")}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"export.create.options.noTemplates\", \"No templates yet.\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath + \"/templates\")}\n className=\"text-primary underline-offset-2 hover:underline\"\n >\n {tr(\n \"export.create.options.createTemplateLink\",\n \"Create one\",\n )}\n </button>{\" \"}\n {tr(\n \"export.create.options.reuseTemplateHint\",\n \"to reuse export configurations.\",\n )}\n </p>\n )}\n </div>\n </div>\n </ShowMore>\n </div>\n </div>\n )}\n\n {/* Step 3: Review */}\n {step === \"review\" && (\n <div className=\"space-y-6\">\n <EmphasisPanel className=\"p-6 space-y-4\">\n <h2 className=\"text-lg font-bold flex items-center gap-2\">\n <CheckCircle2 size={20} className=\"text-primary\" />\n {tr(\"export.create.review.title\", \"Review Export\")}\n </h2>\n <dl className=\"space-y-3 text-sm\">\n {[\n {\n label: tr(\"export.create.review.fields.name\", \"Name\"),\n value: exportName,\n },\n {\n label: tr(\"export.create.review.fields.scope\", \"Scope\"),\n value: getScopeLabel(selectedScope),\n },\n {\n label: tr(\n \"export.create.review.fields.entityTypes\",\n \"Entity Types\",\n ),\n value: selectedEntities.join(\", \"),\n },\n {\n label: tr(\"export.create.review.fields.format\", \"Format\"),\n value: getFormatDisplayName(selectedFormat),\n },\n {\n label: tr(\"export.create.review.fields.archive\", \"Archive\"),\n value: \"ZIP\",\n },\n ...(dateRangeStart || dateRangeEnd\n ? [\n {\n label: tr(\n \"export.create.review.fields.dateRange\",\n \"Date Range\",\n ),\n value: [\n dateRangeStart || \"—\",\n dateRangeEnd || \"—\",\n ].join(\" → \"),\n },\n ]\n : []),\n ...(selectedTemplateId\n ? [\n {\n label: tr(\n \"export.create.review.fields.template\",\n \"Template\",\n ),\n value:\n templates.find((t) => t.id === selectedTemplateId)\n ?.name ?? selectedTemplateId,\n },\n ]\n : []),\n ].map(({ label, value }) => (\n <div\n key={label}\n className=\"flex flex-col sm:flex-row sm:justify-between gap-1\"\n >\n <dt className=\"text-text-secondary\">{label}</dt>\n <dd className=\"font-semibold sm:text-right break-words\">\n {value}\n </dd>\n </div>\n ))}\n </dl>\n </EmphasisPanel>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-6 py-3 border-2 border-border-subtle/50 rounded-lg hover:bg-accent hover:border-primary/30 transition-all duration-200 font-medium\"\n >\n {step === \"entities\"\n ? tr(\"export.create.actions.cancel\", \"Cancel\")\n : tr(\"export.create.actions.back\", \"Back\")}\n </button>\n {step === \"review\" ? (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isPending}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isPending ? (\n <Loader2 size={18} className=\"animate-spin\" />\n ) : (\n <Download size={18} />\n )}\n {tr(\"export.create.actions.startExport\", \"Start Export\")}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleNext}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg\"\n >\n {tr(\"export.create.actions.next\", \"Next\")}\n <ArrowRight size={18} />\n </button>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateExportPage.js","names":[],"sources":["../../../src/export/pages/CreateExportPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n ArrowLeft,\n ArrowRight,\n Download,\n CheckCircle2,\n Loader2,\n FileSpreadsheet,\n FileJson,\n Package,\n CalendarRange,\n User,\n Users,\n Building2,\n Lock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { usePermission } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport {\n EmphasisPanel,\n ShowMore,\n PagePurpose,\n IllustratedEmptyState,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useCreateExportJob,\n useAvailableEntities,\n useExportTemplates,\n} from \"../hooks/useExportQueries\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { isExportEntityDisabled } from \"../utils/disabledModules\";\nimport type {\n ExportAvailableEntity,\n ExportFormat,\n ExportScope,\n} from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype WizardStep = \"entities\" | \"options\" | \"review\";\n\n// Backend only supports CSV and JSON\nconst SUPPORTED_FORMATS: ExportFormat[] = [\"CSV\", \"JSON\"];\n\nconst FORMAT_ICONS: Record<ExportFormat, typeof FileJson> = {\n CSV: FileSpreadsheet,\n JSON: FileJson,\n};\n\n/**\n * Create Export Page\n * Multi-step form: select entities, configure options, review & start\n */\nconst SCOPE_OPTIONS: Array<{\n value: ExportScope;\n label: string;\n description: string;\n Icon: typeof User;\n}> = [\n {\n value: \"INDIVIDUAL\",\n label: \"My Data Only\",\n description: \"Export data you personally created across selected modules.\",\n Icon: User,\n },\n {\n value: \"WORKSPACE_ADMIN\",\n label: \"All Workspace Data\",\n description:\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n Icon: Users,\n },\n {\n value: \"ORG_ADMIN\",\n label: \"All Organization Data\",\n description:\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n Icon: Building2,\n },\n];\n\nexport function CreateExportPage() {\n const { basePath = \"/\", navigate, organizationId } = useExport();\n const { t } = useI18n();\n const tr = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>,\n ) => tWithFallback(t, key, fallback, params);\n const { createJob, isPending } = useCreateExportJob();\n const { data: availableEntities } = useAvailableEntities();\n const { data: templates } = useExportTemplates();\n const [searchParams] = useSearchParams();\n\n // RBAC: Check permissions for admin scopes\n const canExportWorkspaceAdmin = usePermission(\"export:workspace:admin\");\n const canExportOrgAdmin = usePermission(\"export:org:admin\");\n\n const [step, setStep] = useState<WizardStep>(\"entities\");\n const [selectedEntities, setSelectedEntities] = useState<string[]>([]);\n const [exportName, setExportName] = useState(\"\");\n const [selectedFormat, setSelectedFormat] = useState<ExportFormat>(\"CSV\");\n const [selectedScope, setSelectedScope] = useState<ExportScope>(\"INDIVIDUAL\");\n const [selectedTemplateId, setSelectedTemplateId] = useState<\n string | undefined\n >(searchParams.get(\"templateId\") ?? undefined);\n const [dateRangeStart, setDateRangeStart] = useState(\"\");\n const [dateRangeEnd, setDateRangeEnd] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n // Pre-populate form when arriving from \"Use Template\" — apply only once per templateId\n const appliedTemplateRef = useRef<string | null>(null);\n useEffect(() => {\n const paramTemplateId = searchParams.get(\"templateId\");\n if (!paramTemplateId || !templates?.length) return;\n if (appliedTemplateRef.current === paramTemplateId) return;\n const tpl = templates.find((t) => t.id === paramTemplateId);\n if (!tpl) return;\n appliedTemplateRef.current = paramTemplateId;\n setSelectedTemplateId(tpl.id);\n // Skip entity types whose product export is currently disabled.\n setSelectedEntities(\n (tpl.entityTypes ?? []).filter((et) => !isExportEntityDisabled(et)),\n );\n const normalizedFormat = tpl.format?.toUpperCase() as\n | ExportFormat\n | undefined;\n if (normalizedFormat && SUPPORTED_FORMATS.includes(normalizedFormat)) {\n setSelectedFormat(normalizedFormat);\n }\n if (tpl.name) setExportName(tpl.name);\n }, [searchParams, templates]);\n\n const handleBack = () => {\n if (step === \"options\") setStep(\"entities\");\n else if (step === \"review\") setStep(\"options\");\n else navigate?.(basePath);\n };\n\n const handleNext = () => {\n if (step === \"entities\") {\n if (selectedEntities.length === 0) {\n setError(\n tr(\n \"export.create.errors.selectEntity\",\n \"Please select at least one entity type to export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"options\");\n } else if (step === \"options\") {\n if (!exportName.trim()) {\n setError(\n tr(\n \"export.create.errors.exportNameRequired\",\n \"Please provide a name for this export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"review\");\n }\n };\n\n const handleSubmit = async () => {\n try {\n setError(null);\n await createJob({\n name: exportName,\n entityTypes: selectedEntities,\n format: selectedFormat,\n exportScope: selectedScope,\n organizationId:\n selectedScope === \"ORG_ADMIN\" ? organizationId : undefined,\n templateId: selectedTemplateId,\n dateRangeStart: dateRangeStart\n ? new Date(dateRangeStart).toISOString()\n : null,\n dateRangeEnd: dateRangeEnd\n ? new Date(dateRangeEnd).toISOString()\n : null,\n });\n navigate?.(basePath);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"export.create.errors.createFailed\", \"Failed to create export\"),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n // Disabled-product entities can't be selected.\n if (isExportEntityDisabled(entityType)) return;\n setSelectedEntities((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n const getScopeLabel = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\"export.create.scope.individual.label\", \"My Data Only\");\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.label\",\n \"All Workspace Data\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.label\",\n \"All Organization Data\",\n );\n default:\n return scope;\n }\n };\n\n const getScopeDescription = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\n \"export.create.scope.individual.description\",\n \"Export data you personally created across selected modules.\",\n );\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.description\",\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.description\",\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n );\n default:\n return \"\";\n }\n };\n\n const fallbackEntityCopy: Record<\n string,\n { label: string; description: string }\n > = {\n users: {\n label: tr(\"export.create.entities.users.label\", \"Users\"),\n description: tr(\n \"export.create.entities.users.description\",\n \"Workspace members and profiles\",\n ),\n },\n projects: {\n label: tr(\"export.create.entities.projects.label\", \"Projects\"),\n description: tr(\n \"export.create.entities.projects.description\",\n \"Projects and their metadata\",\n ),\n },\n tasks: {\n label: tr(\"export.create.entities.tasks.label\", \"Tasks\"),\n description: tr(\n \"export.create.entities.tasks.description\",\n \"Task items and assignments\",\n ),\n },\n files: {\n label: tr(\"export.create.entities.files.label\", \"Files\"),\n description: tr(\n \"export.create.entities.files.description\",\n \"File metadata and references\",\n ),\n },\n conversations: {\n label: tr(\"export.create.entities.conversations.label\", \"Conversations\"),\n description: tr(\n \"export.create.entities.conversations.description\",\n \"Chat messages and threads\",\n ),\n },\n tags: {\n label: tr(\"export.create.entities.tags.label\", \"Tags\"),\n description: tr(\n \"export.create.entities.tags.description\",\n \"Tags and vocabularies\",\n ),\n },\n activity: {\n label: tr(\"export.create.entities.activity.label\", \"Activity Logs\"),\n description: tr(\n \"export.create.entities.activity.description\",\n \"Audit trail and activity history\",\n ),\n },\n calendar: {\n label: tr(\"export.create.entities.calendar.label\", \"Calendar Events\"),\n description: tr(\n \"export.create.entities.calendar.description\",\n \"Events and bookings\",\n ),\n },\n };\n\n // Entities the backend marks available, split so the ones a user can export\n // show first and disabled-product entities are listed (still visible) below.\n const visibleEntities = availableEntities.filter((e) => e.enabled !== false);\n const availableForExport = visibleEntities.filter(\n (e) => !isExportEntityDisabled(e.entityType),\n );\n const unavailableForExport = visibleEntities.filter((e) =>\n isExportEntityDisabled(e.entityType),\n );\n\n const renderEntityCard = (\n entity: ExportAvailableEntity,\n isDisabled: boolean,\n ) => {\n const isSelected =\n !isDisabled && selectedEntities.includes(entity.entityType);\n return (\n <button\n type=\"button\"\n key={entity.entityType}\n onClick={() => toggleEntity(entity.entityType)}\n disabled={isDisabled}\n aria-disabled={isDisabled}\n title={\n isDisabled\n ? tr(\n \"export.create.select.unavailableHint\",\n \"Export for this product isn't available yet\",\n )\n : undefined\n }\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : isSelected\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2 gap-2\">\n <h3 className=\"font-semibold\">\n {fallbackEntityCopy[entity.entityType]?.label ?? entity.displayName}\n </h3>\n {isDisabled ? (\n <span className=\"shrink-0 text-xs font-medium px-2 py-0.5 rounded-full bg-bg-sunken text-text-secondary\">\n {tr(\"export.create.select.unavailable\", \"Unavailable\")}\n </span>\n ) : (\n isSelected && <CheckCircle2 size={18} className=\"text-primary\" />\n )}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {fallbackEntityCopy[entity.entityType]?.description ??\n entity.description}\n </p>\n {entity.estimatedSize && (\n <p className=\"text-xs text-text-secondary mt-2\">\n ~{entity.estimatedSize}\n </p>\n )}\n </button>\n );\n };\n\n return (\n <PageLayout showHeader={false}>\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl bg-accent-wash border border-border-seam p-6 shadow-[var(--shadow-pop)]\">\n <div className=\"relative z-10 flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath)}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\"\n aria-label={tr(\n \"export.create.actions.backToDashboard\",\n \"Back to export dashboard\",\n )}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2.5 rounded-lg bg-action-primary-bg/10 backdrop-blur-sm\">\n <Download size={24} className=\"text-primary\" />\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tr(\"export.create.title\", \"New Export\")}\n </h1>\n </div>\n </div>\n </div>\n\n {/* Page purpose — explains the wizard's job in plain language */}\n <PagePurpose icon={<Download size={16} />}>\n {tr(\n \"export.create.purpose\",\n \"Build a one-off export in three steps: pick which data to include, choose a format and scope, then review and start it. The export runs in the background and produces a downloadable ZIP you can grab from History when it finishes.\",\n )}\n </PagePurpose>\n\n {/* Step Indicator */}\n <div className=\"flex items-center gap-2 justify-center flex-wrap\">\n {([\"entities\", \"options\", \"review\"] as WizardStep[]).map((s, i) => (\n <div key={s} className=\"flex items-center gap-2\">\n {i > 0 && (\n <ArrowRight size={18} className=\"text-text-secondary\" />\n )}\n <div\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200\",\n step === s\n ? \"bg-action-primary-bg text-action-primary-text border-primary shadow-[var(--shadow-pop)]\"\n : \"bg-bg-sunken/50 text-text-secondary border-border-seam\",\n )}\n >\n <div className=\"flex items-center justify-center size-6 rounded-full bg-bg-surface/20 font-bold\">\n {i + 1}\n </div>\n <span className=\"hidden sm:inline capitalize\">\n {s === \"entities\"\n ? tr(\"export.create.steps.entities\", \"Select Data\")\n : s === \"options\"\n ? tr(\"export.create.steps.options\", \"Options\")\n : tr(\"export.create.steps.review\", \"Review\")}\n </span>\n </div>\n </div>\n ))}\n </div>\n\n {/* Error */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-4 text-status-error-text text-sm\">\n {error}\n </div>\n )}\n\n {/* Step 1: Select Entities */}\n {step === \"entities\" && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.select.title\", \"Select data to export\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"export.create.select.description\",\n \"Choose which entity types to include in your export.\",\n )}\n </p>\n {visibleEntities.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr(\n \"export.create.select.emptyTitle\",\n \"Nothing to export yet\",\n )}\n description={tr(\n \"export.create.select.empty\",\n \"No exportable entity types are configured for this workspace yet. Once your workspace has data in supported modules, they'll show up here to select.\",\n )}\n />\n ) : (\n <div className=\"space-y-6\">\n {availableForExport.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {availableForExport.map((entity) =>\n renderEntityCard(entity, false),\n )}\n </div>\n )}\n {unavailableForExport.length > 0 && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1 bg-border/60\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr(\n \"export.create.select.unavailableSection\",\n \"Not available yet\",\n )}\n </span>\n <div className=\"h-px flex-1 bg-border/60\" />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {unavailableForExport.map((entity) =>\n renderEntityCard(entity, true),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Step 2: Configure Options */}\n {step === \"options\" && (\n <div className=\"space-y-6\">\n <div className=\"border border-border-seam rounded-xl p-6 space-y-5 bg-bg-surface\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.options.title\", \"Export Options\")}\n </h2>\n\n {/* Scope selection */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.scope\", \"Export Scope\")}\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {SCOPE_OPTIONS.map(({ value, Icon }) => {\n // RBAC: Disable admin scopes if user lacks permission\n const isDisabled =\n (value === \"WORKSPACE_ADMIN\" && !canExportWorkspaceAdmin) ||\n (value === \"ORG_ADMIN\" && !canExportOrgAdmin);\n\n return (\n <button\n key={value}\n type=\"button\"\n onClick={() => !isDisabled && setSelectedScope(value)}\n disabled={isDisabled}\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n selectedScope === value\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n title={\n isDisabled\n ? value === \"WORKSPACE_ADMIN\"\n ? \"Workspace admin access required\"\n : \"Organization admin access required\"\n : undefined\n }\n >\n <div className=\"flex items-center justify-between mb-2\">\n <Icon\n size={18}\n className={\n selectedScope === value\n ? \"text-primary\"\n : isDisabled\n ? \"text-text-secondary/50\"\n : \"text-text-secondary\"\n }\n />\n {selectedScope === value && (\n <CheckCircle2 size={16} className=\"text-primary\" />\n )}\n {isDisabled && (\n <Lock\n size={14}\n className=\"text-text-secondary/50\"\n />\n )}\n </div>\n <p className=\"font-semibold text-sm\">\n {getScopeLabel(value)}\n </p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {getScopeDescription(value)}\n </p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name */}\n <div>\n <label\n htmlFor=\"exportName\"\n className=\"block text-sm font-semibold mb-2\"\n >\n {tr(\"export.create.options.name\", \"Export Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"exportName\"\n aria-label={tr(\"export.create.options.name\", \"Export Name\")}\n value={exportName}\n onChange={(e) => setExportName(e.target.value)}\n className=\"w-full px-4 py-2.5 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all duration-200\"\n placeholder={tr(\n \"export.create.options.namePlaceholder\",\n \"e.g., Monthly User Export\",\n )}\n />\n </div>\n\n {/* Format — only CSV and JSON are supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.outputFormat\", \"Output Format\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n {SUPPORTED_FORMATS.map((format) => {\n const Icon = FORMAT_ICONS[format];\n return (\n <button\n type=\"button\"\n key={format}\n onClick={() => setSelectedFormat(format)}\n className={cn(\n \"flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200\",\n selectedFormat === format\n ? \"border-primary bg-action-primary-bg/5\"\n : \"border-border-subtle/50 hover:border-primary/30\",\n )}\n >\n <Icon\n size={18}\n className={\n selectedFormat === format\n ? \"text-primary\"\n : \"text-text-secondary\"\n }\n />\n <span className=\"font-medium text-sm\">\n {getFormatDisplayName(format)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Archive format — only ZIP is supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.archiveFormat\", \"Archive Format\")}\n </label>\n <div className=\"flex gap-3\">\n <div\n className={cn(\n \"flex items-center gap-2 border-2 rounded-lg px-4 py-2 border-primary bg-action-primary-bg/5\",\n )}\n >\n <Package size={16} className=\"text-primary\" />\n <span className=\"font-medium text-sm\">ZIP</span>\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.archiveDescription\",\n \"Exports are packaged as ZIP archives.\",\n )}\n </p>\n </div>\n\n {/* Advanced / optional refinements — progressively disclosed */}\n <ShowMore\n collapsedHeight={0}\n label={tr(\n \"export.create.options.advancedToggle\",\n \"Date range & template\",\n )}\n >\n <div className=\"space-y-5 pt-1\">\n {/* Date range filter */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n <span className=\"inline-flex items-center gap-1.5\">\n <CalendarRange size={15} />\n {tr(\"export.create.options.dateRange\", \"Date Range\")}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </span>\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"dateFrom\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateFrom\", \"From\")}\n </label>\n <input\n type=\"date\"\n id=\"dateFrom\"\n aria-label={tr(\"export.create.options.dateFrom\", \"From\")}\n value={dateRangeStart}\n onChange={(e) => setDateRangeStart(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n <div>\n <label\n htmlFor=\"dateTo\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateTo\", \"To\")}\n </label>\n <input\n type=\"date\"\n id=\"dateTo\"\n aria-label={tr(\"export.create.options.dateTo\", \"To\")}\n value={dateRangeEnd}\n min={dateRangeStart}\n onChange={(e) => setDateRangeEnd(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.dateRangeDescription\",\n \"Leave blank to export all data regardless of date.\",\n )}\n </p>\n </div>\n\n {/* Optional: Use a template */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\n \"export.create.options.basedOnTemplate\",\n \"Based on Template\",\n )}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </label>\n {templates.length > 0 ? (\n <select\n value={selectedTemplateId ?? \"\"}\n onChange={(e) =>\n setSelectedTemplateId(e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n >\n <option value=\"\">\n {tr(\"export.create.options.noTemplate\", \"No template\")}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"export.create.options.noTemplates\", \"No templates yet.\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath + \"/templates\")}\n className=\"text-primary underline-offset-2 hover:underline\"\n >\n {tr(\n \"export.create.options.createTemplateLink\",\n \"Create one\",\n )}\n </button>{\" \"}\n {tr(\n \"export.create.options.reuseTemplateHint\",\n \"to reuse export configurations.\",\n )}\n </p>\n )}\n </div>\n </div>\n </ShowMore>\n </div>\n </div>\n )}\n\n {/* Step 3: Review */}\n {step === \"review\" && (\n <div className=\"space-y-6\">\n <EmphasisPanel className=\"p-6 space-y-4\">\n <h2 className=\"text-lg font-bold flex items-center gap-2\">\n <CheckCircle2 size={20} className=\"text-primary\" />\n {tr(\"export.create.review.title\", \"Review Export\")}\n </h2>\n <dl className=\"space-y-3 text-sm\">\n {[\n {\n label: tr(\"export.create.review.fields.name\", \"Name\"),\n value: exportName,\n },\n {\n label: tr(\"export.create.review.fields.scope\", \"Scope\"),\n value: getScopeLabel(selectedScope),\n },\n {\n label: tr(\n \"export.create.review.fields.entityTypes\",\n \"Entity Types\",\n ),\n value: selectedEntities.join(\", \"),\n },\n {\n label: tr(\"export.create.review.fields.format\", \"Format\"),\n value: getFormatDisplayName(selectedFormat),\n },\n {\n label: tr(\"export.create.review.fields.archive\", \"Archive\"),\n value: \"ZIP\",\n },\n ...(dateRangeStart || dateRangeEnd\n ? [\n {\n label: tr(\n \"export.create.review.fields.dateRange\",\n \"Date Range\",\n ),\n value: [\n dateRangeStart || \"—\",\n dateRangeEnd || \"—\",\n ].join(\" → \"),\n },\n ]\n : []),\n ...(selectedTemplateId\n ? [\n {\n label: tr(\n \"export.create.review.fields.template\",\n \"Template\",\n ),\n value:\n templates.find((t) => t.id === selectedTemplateId)\n ?.name ?? selectedTemplateId,\n },\n ]\n : []),\n ].map(({ label, value }) => (\n <div\n key={label}\n className=\"flex flex-col sm:flex-row sm:justify-between gap-1\"\n >\n <dt className=\"text-text-secondary\">{label}</dt>\n <dd className=\"font-semibold sm:text-right break-words\">\n {value}\n </dd>\n </div>\n ))}\n </dl>\n </EmphasisPanel>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-6 py-3 border-2 border-border-subtle/50 rounded-lg hover:bg-accent hover:border-primary/30 transition-all duration-200 font-medium\"\n >\n {step === \"entities\"\n ? tr(\"export.create.actions.cancel\", \"Cancel\")\n : tr(\"export.create.actions.back\", \"Back\")}\n </button>\n {step === \"review\" ? (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isPending}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isPending ? (\n <Loader2 size={18} className=\"animate-spin\" />\n ) : (\n <Download size={18} />\n )}\n {tr(\"export.create.actions.startExport\", \"Start Export\")}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleNext}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg\"\n >\n {tr(\"export.create.actions.next\", \"Next\")}\n <ArrowRight size={18} />\n </button>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|