@burdenoff/microfe-export 2026.830.1 → 2026.830.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/ExportRoot.d.ts.map +1 -1
- package/dist/export/ExportRoot.js +41 -36
- package/dist/export/ExportRoot.js.map +1 -1
- package/dist/export/ExportRoutes.d.ts.map +1 -1
- package/dist/export/ExportRoutes.js +75 -66
- package/dist/export/ExportRoutes.js.map +1 -1
- package/dist/export/components/ExportProgressBar.d.ts.map +1 -1
- package/dist/export/components/ExportProgressBar.js +19 -18
- package/dist/export/components/ExportProgressBar.js.map +1 -1
- package/dist/export/components/ExportStatusBadge.d.ts.map +1 -1
- package/dist/export/components/ExportStatusBadge.js +19 -20
- package/dist/export/components/ExportStatusBadge.js.map +1 -1
- package/dist/export/hooks/useTr.d.ts +19 -0
- package/dist/export/hooks/useTr.d.ts.map +1 -0
- package/dist/export/hooks/useTr.js +15 -0
- package/dist/export/hooks/useTr.js.map +1 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/export/index.d.ts.map +1 -1
- package/dist/export/index.js +1 -0
- package/dist/export/pages/CreateExportPage.d.ts +4 -0
- package/dist/export/pages/CreateExportPage.d.ts.map +1 -1
- package/dist/export/pages/CreateExportPage.js +271 -283
- package/dist/export/pages/CreateExportPage.js.map +1 -1
- package/dist/export/pages/ExportDashboardPage.d.ts.map +1 -1
- package/dist/export/pages/ExportDashboardPage.js +71 -72
- package/dist/export/pages/ExportDashboardPage.js.map +1 -1
- package/dist/export/pages/ExportDetailPage.d.ts.map +1 -1
- package/dist/export/pages/ExportDetailPage.js +171 -173
- package/dist/export/pages/ExportDetailPage.js.map +1 -1
- package/dist/export/pages/ExportHistoryPage.d.ts.map +1 -1
- package/dist/export/pages/ExportHistoryPage.js +110 -111
- package/dist/export/pages/ExportHistoryPage.js.map +1 -1
- package/dist/export/pages/ExportLandingPage.d.ts.map +1 -1
- package/dist/export/pages/ExportLandingPage.js +28 -27
- package/dist/export/pages/ExportLandingPage.js.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.d.ts.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.js +115 -116
- package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
- package/dist/export/pages/TemplateDetailPage.d.ts.map +1 -1
- package/dist/export/pages/TemplateDetailPage.js +122 -118
- package/dist/export/pages/TemplateDetailPage.js.map +1 -1
- package/dist/export/utils/i18n.d.ts +18 -2
- package/dist/export/utils/i18n.d.ts.map +1 -1
- package/dist/export/utils/i18n.js +2 -9
- package/dist/export/utils/i18n.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/translations/en.d.ts +454 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/dist/translations/en.js +417 -0
- package/dist/translations/en.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,228 +1,232 @@
|
|
|
1
1
|
import { useExport as e } from "../providers/ExportProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import { useTr as t } from "../hooks/useTr.js";
|
|
3
|
+
import { useDeleteExportTemplate as n, useExportTemplate as r } from "../hooks/useExportQueries.js";
|
|
4
|
+
import { getArchiveFormatDisplayName as i, getFormatDisplayName as a } from "../constants/enums.js";
|
|
5
|
+
import { PageLayout as o, PageSection as s } from "../components/PageLayout.js";
|
|
6
|
+
import { nativeImpact as c, nativeNotify as l } from "../../utils/nativeBridge.js";
|
|
7
|
+
import { useState as u } from "react";
|
|
8
|
+
import { ArrowLeft as d, Clock as f, Download as p, FileBox as m, FileText as h, HardDrive as g, Loader2 as _, Play as v, Trash2 as y } from "lucide-react";
|
|
9
|
+
import { useParams as b } from "react-router";
|
|
10
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
11
|
+
import { CTAOverflowMenu as C, GlassCard as w, IllustratedEmptyState as T, NextSteps as E, ShowMore as D } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/export/pages/TemplateDetailPage.tsx
|
|
12
|
-
var
|
|
13
|
-
function
|
|
14
|
-
let { templateId:
|
|
15
|
-
if (
|
|
13
|
+
var O = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
14
|
+
function k() {
|
|
15
|
+
let { templateId: k } = b(), { basePath: A = "/", navigate: j } = e(), M = t(), [N, P] = u(!1), { data: F, isLoading: I } = r(k), { deleteTemplate: L, isPending: R } = n();
|
|
16
|
+
if (I) return /* @__PURE__ */ S("div", {
|
|
16
17
|
className: "flex flex-col items-center justify-center py-20",
|
|
17
|
-
children: [/* @__PURE__ */
|
|
18
|
+
children: [/* @__PURE__ */ x(_, {
|
|
18
19
|
size: 48,
|
|
19
20
|
className: "animate-spin text-primary"
|
|
20
|
-
}), /* @__PURE__ */
|
|
21
|
+
}), /* @__PURE__ */ x("span", {
|
|
21
22
|
className: "mt-6 text-sm font-medium text-text-secondary",
|
|
22
|
-
children: "Loading template details…"
|
|
23
|
+
children: M("export.templateDetail.loading", "Loading template details…")
|
|
23
24
|
})]
|
|
24
25
|
});
|
|
25
|
-
if (!
|
|
26
|
+
if (!F) return /* @__PURE__ */ S(o, {
|
|
26
27
|
showHeader: !1,
|
|
27
|
-
children: [/* @__PURE__ */
|
|
28
|
+
children: [/* @__PURE__ */ S("div", {
|
|
28
29
|
className: "flex items-center gap-3 mb-6",
|
|
29
|
-
children: [/* @__PURE__ */
|
|
30
|
+
children: [/* @__PURE__ */ x("button", {
|
|
30
31
|
type: "button",
|
|
31
|
-
onClick: () =>
|
|
32
|
-
"aria-label": "Back to templates",
|
|
32
|
+
onClick: () => j?.(O(A, "templates")),
|
|
33
|
+
"aria-label": M("export.templateDetail.actions.backToTemplates", "Back to templates"),
|
|
33
34
|
className: "p-2.5 hover:bg-accent rounded-lg transition-all duration-200",
|
|
34
|
-
children: /* @__PURE__ */
|
|
35
|
-
}), /* @__PURE__ */
|
|
35
|
+
children: /* @__PURE__ */ x(d, { size: 20 })
|
|
36
|
+
}), /* @__PURE__ */ x("h1", {
|
|
36
37
|
className: "text-xl font-bold",
|
|
37
|
-
children: "Template Not Found"
|
|
38
|
+
children: M("export.templateDetail.notFound.title", "Template Not Found")
|
|
38
39
|
})]
|
|
39
|
-
}), /* @__PURE__ */
|
|
40
|
+
}), /* @__PURE__ */ x(T, {
|
|
40
41
|
illustration: "empty-data",
|
|
41
|
-
title: "Template not found",
|
|
42
|
-
description: "The template you are looking for does not exist.",
|
|
43
|
-
action: /* @__PURE__ */
|
|
42
|
+
title: M("export.templateDetail.notFound.heading", "Template not found"),
|
|
43
|
+
description: M("export.templateDetail.notFound.description", "The template you are looking for does not exist."),
|
|
44
|
+
action: /* @__PURE__ */ S("button", {
|
|
44
45
|
type: "button",
|
|
45
|
-
onClick: () =>
|
|
46
|
+
onClick: () => j?.(O(A, "templates")),
|
|
46
47
|
className: "inline-flex items-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
48
|
+
children: [/* @__PURE__ */ x(d, { size: 18 }), M("export.templateDetail.actions.backToTemplates", "Back to Templates")]
|
|
48
49
|
})
|
|
49
50
|
})]
|
|
50
51
|
});
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
if (
|
|
55
|
-
|
|
52
|
+
let z = () => {
|
|
53
|
+
j?.(O(A, `new?templateId=${k}`));
|
|
54
|
+
}, B = async () => {
|
|
55
|
+
if (k) {
|
|
56
|
+
c("medium");
|
|
56
57
|
try {
|
|
57
|
-
await
|
|
58
|
+
await L(k), l("success"), j?.(O(A, "templates"));
|
|
58
59
|
} catch {
|
|
59
|
-
|
|
60
|
+
l("error");
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
|
-
},
|
|
63
|
-
label: "Delete Template",
|
|
64
|
-
icon: /* @__PURE__ */
|
|
63
|
+
}, V = F.isDefault ? [] : [{
|
|
64
|
+
label: M("export.templateDetail.actions.delete", "Delete Template"),
|
|
65
|
+
icon: /* @__PURE__ */ x(y, { size: 16 }),
|
|
65
66
|
intent: "destructive",
|
|
66
|
-
disabled:
|
|
67
|
-
onSelect: () =>
|
|
68
|
-
}],
|
|
67
|
+
disabled: R,
|
|
68
|
+
onSelect: () => P(!0)
|
|
69
|
+
}], H = [{
|
|
69
70
|
id: "use",
|
|
70
|
-
label: "Start an export from this template",
|
|
71
|
-
description: "Pre-fills a new export with this template's entity types and format.",
|
|
72
|
-
icon: /* @__PURE__ */
|
|
73
|
-
onClick:
|
|
71
|
+
label: M("export.templateDetail.nextSteps.use.label", "Start an export from this template"),
|
|
72
|
+
description: M("export.templateDetail.nextSteps.use.description", "Pre-fills a new export with this template's entity types and format."),
|
|
73
|
+
icon: /* @__PURE__ */ x(v, { size: 16 }),
|
|
74
|
+
onClick: z
|
|
74
75
|
}, {
|
|
75
76
|
id: "browse",
|
|
76
|
-
label: "Browse all templates",
|
|
77
|
-
description: "Manage your other saved export configurations.",
|
|
78
|
-
icon: /* @__PURE__ */
|
|
79
|
-
onClick: () =>
|
|
77
|
+
label: M("export.templateDetail.nextSteps.browse.label", "Browse all templates"),
|
|
78
|
+
description: M("export.templateDetail.nextSteps.browse.description", "Manage your other saved export configurations."),
|
|
79
|
+
icon: /* @__PURE__ */ x(m, { size: 16 }),
|
|
80
|
+
onClick: () => j?.(O(A, "templates"))
|
|
80
81
|
}];
|
|
81
|
-
return /* @__PURE__ */
|
|
82
|
+
return /* @__PURE__ */ S(o, {
|
|
82
83
|
showHeader: !1,
|
|
83
84
|
children: [
|
|
84
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ x("div", {
|
|
85
86
|
className: "relative overflow-hidden rounded-xl bg-accent-wash border border-border-seam p-6 shadow-[var(--shadow-pop)]",
|
|
86
|
-
children: /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ S("div", {
|
|
87
88
|
className: "relative z-10 flex flex-col sm:flex-row sm:items-center gap-4",
|
|
88
89
|
children: [
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ x("button", {
|
|
90
91
|
type: "button",
|
|
91
|
-
onClick: () =>
|
|
92
|
-
"aria-label": "Back to templates",
|
|
92
|
+
onClick: () => j?.(O(A, "templates")),
|
|
93
|
+
"aria-label": M("export.templateDetail.actions.backToTemplates", "Back to templates"),
|
|
93
94
|
className: "p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 self-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
|
|
94
|
-
children: /* @__PURE__ */
|
|
95
|
+
children: /* @__PURE__ */ x(d, { size: 20 })
|
|
95
96
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ S("div", {
|
|
97
98
|
className: "flex items-center gap-3 flex-1 min-w-0",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ x("div", {
|
|
99
100
|
className: "p-2.5 rounded-lg bg-action-primary-bg/10",
|
|
100
|
-
children: /* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ x(m, {
|
|
101
102
|
size: 24,
|
|
102
103
|
className: "text-primary"
|
|
103
104
|
})
|
|
104
|
-
}), /* @__PURE__ */
|
|
105
|
+
}), /* @__PURE__ */ S("div", {
|
|
105
106
|
className: "flex-1 min-w-0",
|
|
106
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ x("h1", {
|
|
107
108
|
className: "text-xl sm:text-2xl font-bold truncate",
|
|
108
|
-
children:
|
|
109
|
-
}), /* @__PURE__ */
|
|
109
|
+
children: F.name
|
|
110
|
+
}), /* @__PURE__ */ x("p", {
|
|
110
111
|
className: "text-sm text-text-secondary mt-1",
|
|
111
|
-
children:
|
|
112
|
+
children: F.isDefault ? M("export.templateDetail.badge.default", "Default template") : M("export.templateDetail.badge.custom", "Custom template")
|
|
112
113
|
})]
|
|
113
114
|
})]
|
|
114
115
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ x("div", {
|
|
116
117
|
className: "flex-shrink-0",
|
|
117
|
-
children: /* @__PURE__ */
|
|
118
|
+
children: /* @__PURE__ */ x(C, {
|
|
118
119
|
primary: {
|
|
119
|
-
label: "Use Template",
|
|
120
|
-
icon: /* @__PURE__ */
|
|
121
|
-
onSelect:
|
|
120
|
+
label: M("export.templateDetail.actions.use", "Use Template"),
|
|
121
|
+
icon: /* @__PURE__ */ x(v, { size: 16 }),
|
|
122
|
+
onSelect: z
|
|
122
123
|
},
|
|
123
|
-
actions:
|
|
124
|
+
actions: V
|
|
124
125
|
})
|
|
125
126
|
})
|
|
126
127
|
]
|
|
127
128
|
})
|
|
128
129
|
}),
|
|
129
|
-
|
|
130
|
+
F.description && /* @__PURE__ */ x("div", {
|
|
130
131
|
className: "border border-border-seam rounded-xl p-5 bg-bg-surface",
|
|
131
|
-
children: /* @__PURE__ */
|
|
132
|
+
children: /* @__PURE__ */ x("p", {
|
|
132
133
|
className: "text-sm text-text-secondary",
|
|
133
|
-
children:
|
|
134
|
+
children: F.description
|
|
134
135
|
})
|
|
135
136
|
}),
|
|
136
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ x("div", {
|
|
137
138
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
138
139
|
children: [
|
|
139
140
|
{
|
|
140
|
-
icon: /* @__PURE__ */
|
|
141
|
-
label: "Format",
|
|
142
|
-
value:
|
|
141
|
+
icon: /* @__PURE__ */ x(h, { size: 18 }),
|
|
142
|
+
label: M("export.templateDetail.info.format", "Format"),
|
|
143
|
+
value: a(F.format)
|
|
143
144
|
},
|
|
144
145
|
{
|
|
145
|
-
icon: /* @__PURE__ */
|
|
146
|
-
label: "Archive",
|
|
147
|
-
value:
|
|
146
|
+
icon: /* @__PURE__ */ x(g, { size: 18 }),
|
|
147
|
+
label: M("export.templateDetail.info.archive", "Archive"),
|
|
148
|
+
value: i("ZIP")
|
|
148
149
|
},
|
|
149
150
|
{
|
|
150
|
-
icon: /* @__PURE__ */
|
|
151
|
-
label: "Entity Types",
|
|
152
|
-
value:
|
|
151
|
+
icon: /* @__PURE__ */ x(p, { size: 18 }),
|
|
152
|
+
label: M("export.templateDetail.info.entityTypes", "Entity Types"),
|
|
153
|
+
value: M("export.templateDetail.info.entityTypesCount", "{{count}} type{{suffix}}", {
|
|
154
|
+
count: F.entityTypes.length,
|
|
155
|
+
suffix: F.entityTypes.length === 1 ? "" : "s"
|
|
156
|
+
})
|
|
153
157
|
},
|
|
154
158
|
{
|
|
155
|
-
icon: /* @__PURE__ */
|
|
156
|
-
label: "Last Updated",
|
|
157
|
-
value: new Date(
|
|
159
|
+
icon: /* @__PURE__ */ x(f, { size: 18 }),
|
|
160
|
+
label: M("export.templateDetail.info.lastUpdated", "Last Updated"),
|
|
161
|
+
value: new Date(F.updatedAt).toLocaleDateString()
|
|
158
162
|
}
|
|
159
|
-
].map((e) => /* @__PURE__ */
|
|
163
|
+
].map((e) => /* @__PURE__ */ S(w, {
|
|
160
164
|
treatment: "metric",
|
|
161
165
|
className: "p-4 border-border-seam",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ S("div", {
|
|
163
167
|
className: "flex items-center gap-2 text-text-secondary mb-1",
|
|
164
|
-
children: [e.icon, /* @__PURE__ */
|
|
168
|
+
children: [e.icon, /* @__PURE__ */ x("span", {
|
|
165
169
|
className: "text-xs font-medium",
|
|
166
170
|
children: e.label
|
|
167
171
|
})]
|
|
168
|
-
}), /* @__PURE__ */
|
|
172
|
+
}), /* @__PURE__ */ x("p", {
|
|
169
173
|
className: "font-bold text-lg tabular-nums",
|
|
170
174
|
children: e.value
|
|
171
175
|
})]
|
|
172
176
|
}, e.label))
|
|
173
177
|
}),
|
|
174
|
-
/* @__PURE__ */
|
|
175
|
-
storageKey: `export-template-${
|
|
176
|
-
title: "What's next",
|
|
177
|
-
steps:
|
|
178
|
+
/* @__PURE__ */ x(E, {
|
|
179
|
+
storageKey: `export-template-${F.id}`,
|
|
180
|
+
title: M("export.templateDetail.nextSteps.title", "What's next"),
|
|
181
|
+
steps: H
|
|
178
182
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
180
|
-
title: "Included Entity Types",
|
|
181
|
-
description: "Data types that will be exported",
|
|
182
|
-
children: /* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ x(s, {
|
|
184
|
+
title: M("export.templateDetail.entityTypes.title", "Included Entity Types"),
|
|
185
|
+
description: M("export.templateDetail.entityTypes.description", "Data types that will be exported"),
|
|
186
|
+
children: /* @__PURE__ */ x(D, {
|
|
183
187
|
collapsedHeight: 96,
|
|
184
|
-
children: /* @__PURE__ */
|
|
188
|
+
children: /* @__PURE__ */ x("div", {
|
|
185
189
|
className: "flex flex-wrap gap-2",
|
|
186
|
-
children:
|
|
190
|
+
children: F.entityTypes.map((e) => /* @__PURE__ */ x("span", {
|
|
187
191
|
className: "inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium border border-border-seam bg-bg-sunken/30",
|
|
188
192
|
children: e
|
|
189
193
|
}, e))
|
|
190
194
|
})
|
|
191
195
|
})
|
|
192
196
|
}),
|
|
193
|
-
|
|
197
|
+
N && /* @__PURE__ */ x("div", {
|
|
194
198
|
role: "dialog",
|
|
195
199
|
"aria-modal": "true",
|
|
196
200
|
"aria-labelledby": "template-delete-title",
|
|
197
201
|
className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4",
|
|
198
|
-
children: /* @__PURE__ */
|
|
202
|
+
children: /* @__PURE__ */ S("div", {
|
|
199
203
|
className: "w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl",
|
|
200
204
|
children: [
|
|
201
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ x("h2", {
|
|
202
206
|
id: "template-delete-title",
|
|
203
207
|
className: "text-lg font-bold",
|
|
204
|
-
children: "Delete template?"
|
|
208
|
+
children: M("export.templateDetail.delete.title", "Delete template?")
|
|
205
209
|
}),
|
|
206
|
-
/* @__PURE__ */
|
|
210
|
+
/* @__PURE__ */ x("p", {
|
|
207
211
|
className: "mt-2 text-sm text-text-secondary",
|
|
208
|
-
children: "This removes the saved export configuration. Existing export jobs are not deleted."
|
|
212
|
+
children: M("export.templateDetail.delete.description", "This removes the saved export configuration. Existing export jobs are not deleted.")
|
|
209
213
|
}),
|
|
210
|
-
/* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ S("div", {
|
|
211
215
|
className: "mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3",
|
|
212
|
-
children: [/* @__PURE__ */
|
|
216
|
+
children: [/* @__PURE__ */ x("button", {
|
|
213
217
|
type: "button",
|
|
214
|
-
onClick: () =>
|
|
218
|
+
onClick: () => P(!1),
|
|
215
219
|
className: "px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium",
|
|
216
|
-
children: "Keep Template"
|
|
217
|
-
}), /* @__PURE__ */
|
|
220
|
+
children: M("export.templateDetail.delete.keep", "Keep Template")
|
|
221
|
+
}), /* @__PURE__ */ S("button", {
|
|
218
222
|
type: "button",
|
|
219
|
-
onClick:
|
|
220
|
-
disabled:
|
|
223
|
+
onClick: B,
|
|
224
|
+
disabled: R,
|
|
221
225
|
className: "inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium disabled:opacity-50",
|
|
222
|
-
children: [
|
|
226
|
+
children: [R ? /* @__PURE__ */ x(_, {
|
|
223
227
|
size: 16,
|
|
224
228
|
className: "animate-spin"
|
|
225
|
-
}) : null, "Delete Template"]
|
|
229
|
+
}) : null, M("export.templateDetail.delete.confirmAction", "Delete Template")]
|
|
226
230
|
})]
|
|
227
231
|
})
|
|
228
232
|
]
|
|
@@ -232,6 +236,6 @@ function O() {
|
|
|
232
236
|
});
|
|
233
237
|
}
|
|
234
238
|
//#endregion
|
|
235
|
-
export {
|
|
239
|
+
export { k as TemplateDetailPage };
|
|
236
240
|
|
|
237
241
|
//# sourceMappingURL=TemplateDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateDetailPage.js","names":[],"sources":["../../../src/export/pages/TemplateDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router\";\nimport { useState } from \"react\";\nimport {\n ArrowLeft,\n FileBox,\n Download,\n Play,\n Trash2,\n Clock,\n FileText,\n HardDrive,\n Loader2,\n} from \"lucide-react\";\nimport {\n GlassCard,\n CTAOverflowMenu,\n ShowMore,\n IllustratedEmptyState,\n NextSteps,\n type NextStep,\n} from \"@burdenoff/fe-libs/ui\";\nimport type { CTAAction } from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useExportTemplate,\n useDeleteExportTemplate,\n} from \"../hooks/useExportQueries\";\nimport {\n getFormatDisplayName,\n getArchiveFormatDisplayName,\n} from \"../constants/enums\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n/**\n * Helper to join paths correctly\n */\nconst joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n};\n\n/**\n * Template Detail Page\n * View template details and use it to create a new export.\n * Fetches template from the backend via useExportTemplate hook.\n */\nexport function TemplateDetailPage() {\n const { templateId } = useParams<{ templateId: string }>();\n const { basePath = \"/\", navigate } = useExport();\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n\n const { data: template, isLoading } = useExportTemplate(templateId);\n const { deleteTemplate, isPending: deleting } = useDeleteExportTemplate();\n\n // Loading\n if (isLoading) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 size={48} className=\"animate-spin text-primary\" />\n <span className=\"mt-6 text-sm font-medium text-text-secondary\">\n Loading template details…\n </span>\n </div>\n );\n }\n\n if (!template) {\n return (\n <PageLayout showHeader={false}>\n <div className=\"flex items-center gap-3 mb-6\">\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n aria-label=\"Back to templates\"\n className=\"p-2.5 hover:bg-accent rounded-lg transition-all duration-200\"\n >\n <ArrowLeft size={20} />\n </button>\n <h1 className=\"text-xl font-bold\">Template Not Found</h1>\n </div>\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"Template not found\"\n description=\"The template you are looking for does not exist.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n className=\"inline-flex items-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium\"\n >\n <ArrowLeft size={18} />\n Back to Templates\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const handleUseTemplate = () => {\n // Navigate to new export page pre-selected with this template\n navigate?.(joinPath(basePath, `new?templateId=${templateId}`));\n };\n\n const handleDelete = async () => {\n if (!templateId) return;\n nativeImpact(\"medium\");\n try {\n await deleteTemplate(templateId);\n nativeNotify(\"success\");\n navigate?.(joinPath(basePath, \"templates\"));\n } catch {\n nativeNotify(\"error\");\n }\n };\n\n const overflowActions: CTAAction[] = template.isDefault\n ? []\n : [\n {\n label: \"Delete Template\",\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n disabled: deleting,\n onSelect: () => setShowDeleteConfirm(true),\n },\n ];\n\n // Next-step guidance — what a new user would do with a saved template.\n const nextSteps: NextStep[] = [\n {\n id: \"use\",\n label: \"Start an export from this template\",\n description:\n \"Pre-fills a new export with this template's entity types and format.\",\n icon: <Play size={16} />,\n onClick: handleUseTemplate,\n },\n {\n id: \"browse\",\n label: \"Browse all templates\",\n description: \"Manage your other saved export configurations.\",\n icon: <FileBox size={16} />,\n onClick: () => navigate?.(joinPath(basePath, \"templates\")),\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 flex-col sm:flex-row sm:items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n aria-label=\"Back to templates\"\n className=\"p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 self-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\"\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3 flex-1 min-w-0\">\n <div className=\"p-2.5 rounded-lg bg-action-primary-bg/10\">\n <FileBox size={24} className=\"text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold truncate\">\n {template.name}\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {template.isDefault ? \"Default template\" : \"Custom template\"}\n </p>\n </div>\n </div>\n <div className=\"flex-shrink-0\">\n <CTAOverflowMenu\n primary={{\n label: \"Use Template\",\n icon: <Play size={16} />,\n onSelect: handleUseTemplate,\n }}\n actions={overflowActions}\n />\n </div>\n </div>\n </div>\n\n {/* Description */}\n {template.description && (\n <div className=\"border border-border-seam rounded-xl p-5 bg-bg-surface\">\n <p className=\"text-sm text-text-secondary\">{template.description}</p>\n </div>\n )}\n\n {/* Info Grid */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n {[\n {\n icon: <FileText size={18} />,\n label: \"Format\",\n value: getFormatDisplayName(template.format),\n },\n {\n icon: <HardDrive size={18} />,\n label: \"Archive\",\n // Backend template doesn't carry archiveFormat, default to ZIP\n value: getArchiveFormatDisplayName(\"ZIP\"),\n },\n {\n icon: <Download size={18} />,\n label: \"Entity Types\",\n value: `${template.entityTypes.length} type${template.entityTypes.length !== 1 ? \"s\" : \"\"}`,\n },\n {\n icon: <Clock size={18} />,\n label: \"Last Updated\",\n value: new Date(template.updatedAt).toLocaleDateString(),\n },\n ].map((item) => (\n <GlassCard\n key={item.label}\n treatment=\"metric\"\n className=\"p-4 border-border-seam\"\n >\n <div className=\"flex items-center gap-2 text-text-secondary mb-1\">\n {item.icon}\n <span className=\"text-xs font-medium\">{item.label}</span>\n </div>\n <p className=\"font-bold text-lg tabular-nums\">{item.value}</p>\n </GlassCard>\n ))}\n </div>\n\n {/* Next-step guidance (dismissable, per-template) */}\n <NextSteps\n storageKey={`export-template-${template.id}`}\n title=\"What's next\"\n steps={nextSteps}\n />\n\n {/* Entity Types */}\n <PageSection\n title=\"Included Entity Types\"\n description=\"Data types that will be exported\"\n >\n <ShowMore collapsedHeight={96}>\n <div className=\"flex flex-wrap gap-2\">\n {template.entityTypes.map((entity) => (\n <span\n key={entity}\n className=\"inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium border border-border-seam bg-bg-sunken/30\"\n >\n {entity}\n </span>\n ))}\n </div>\n </ShowMore>\n </PageSection>\n\n {showDeleteConfirm && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"template-delete-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4\"\n >\n <div className=\"w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl\">\n <h2 id=\"template-delete-title\" className=\"text-lg font-bold\">\n Delete template?\n </h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n This removes the saved export configuration. Existing export jobs\n are not deleted.\n </p>\n <div className=\"mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowDeleteConfirm(false)}\n className=\"px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium\"\n >\n Keep Template\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={deleting}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium disabled:opacity-50\"\n >\n {deleting ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : null}\n Delete Template\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateDetailPage.js","names":[],"sources":["../../../src/export/pages/TemplateDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router\";\nimport { useState } from \"react\";\nimport {\n ArrowLeft,\n FileBox,\n Download,\n Play,\n Trash2,\n Clock,\n FileText,\n HardDrive,\n Loader2,\n} from \"lucide-react\";\nimport {\n GlassCard,\n CTAOverflowMenu,\n ShowMore,\n IllustratedEmptyState,\n NextSteps,\n type NextStep,\n} from \"@burdenoff/fe-libs/ui\";\nimport type { CTAAction } from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useExportTemplate,\n useDeleteExportTemplate,\n} from \"../hooks/useExportQueries\";\nimport {\n getFormatDisplayName,\n getArchiveFormatDisplayName,\n} from \"../constants/enums\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { useTr } from \"../hooks/useTr\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n/**\n * Helper to join paths correctly\n */\nconst joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n};\n\n/**\n * Template Detail Page\n * View template details and use it to create a new export.\n * Fetches template from the backend via useExportTemplate hook.\n */\nexport function TemplateDetailPage() {\n const { templateId } = useParams<{ templateId: string }>();\n const { basePath = \"/\", navigate } = useExport();\n const tr = useTr();\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n\n const { data: template, isLoading } = useExportTemplate(templateId);\n const { deleteTemplate, isPending: deleting } = useDeleteExportTemplate();\n\n // Loading\n if (isLoading) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 size={48} className=\"animate-spin text-primary\" />\n <span className=\"mt-6 text-sm font-medium text-text-secondary\">\n {tr(\"export.templateDetail.loading\", \"Loading template details…\")}\n </span>\n </div>\n );\n }\n\n if (!template) {\n return (\n <PageLayout showHeader={false}>\n <div className=\"flex items-center gap-3 mb-6\">\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n aria-label={tr(\n \"export.templateDetail.actions.backToTemplates\",\n \"Back to templates\",\n )}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-all duration-200\"\n >\n <ArrowLeft size={20} />\n </button>\n <h1 className=\"text-xl font-bold\">\n {tr(\"export.templateDetail.notFound.title\", \"Template Not Found\")}\n </h1>\n </div>\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr(\n \"export.templateDetail.notFound.heading\",\n \"Template not found\",\n )}\n description={tr(\n \"export.templateDetail.notFound.description\",\n \"The template you are looking for does not exist.\",\n )}\n action={\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n className=\"inline-flex items-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium\"\n >\n <ArrowLeft size={18} />\n {tr(\n \"export.templateDetail.actions.backToTemplates\",\n \"Back to Templates\",\n )}\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const handleUseTemplate = () => {\n // Navigate to new export page pre-selected with this template\n navigate?.(joinPath(basePath, `new?templateId=${templateId}`));\n };\n\n const handleDelete = async () => {\n if (!templateId) return;\n nativeImpact(\"medium\");\n try {\n await deleteTemplate(templateId);\n nativeNotify(\"success\");\n navigate?.(joinPath(basePath, \"templates\"));\n } catch {\n nativeNotify(\"error\");\n }\n };\n\n const overflowActions: CTAAction[] = template.isDefault\n ? []\n : [\n {\n label: tr(\"export.templateDetail.actions.delete\", \"Delete Template\"),\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n disabled: deleting,\n onSelect: () => setShowDeleteConfirm(true),\n },\n ];\n\n // Next-step guidance — what a new user would do with a saved template.\n const nextSteps: NextStep[] = [\n {\n id: \"use\",\n label: tr(\n \"export.templateDetail.nextSteps.use.label\",\n \"Start an export from this template\",\n ),\n description: tr(\n \"export.templateDetail.nextSteps.use.description\",\n \"Pre-fills a new export with this template's entity types and format.\",\n ),\n icon: <Play size={16} />,\n onClick: handleUseTemplate,\n },\n {\n id: \"browse\",\n label: tr(\n \"export.templateDetail.nextSteps.browse.label\",\n \"Browse all templates\",\n ),\n description: tr(\n \"export.templateDetail.nextSteps.browse.description\",\n \"Manage your other saved export configurations.\",\n ),\n icon: <FileBox size={16} />,\n onClick: () => navigate?.(joinPath(basePath, \"templates\")),\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 flex-col sm:flex-row sm:items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"templates\"))}\n aria-label={tr(\n \"export.templateDetail.actions.backToTemplates\",\n \"Back to templates\",\n )}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 self-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\"\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3 flex-1 min-w-0\">\n <div className=\"p-2.5 rounded-lg bg-action-primary-bg/10\">\n <FileBox size={24} className=\"text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold truncate\">\n {template.name}\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {template.isDefault\n ? tr(\n \"export.templateDetail.badge.default\",\n \"Default template\",\n )\n : tr(\"export.templateDetail.badge.custom\", \"Custom template\")}\n </p>\n </div>\n </div>\n <div className=\"flex-shrink-0\">\n <CTAOverflowMenu\n primary={{\n label: tr(\"export.templateDetail.actions.use\", \"Use Template\"),\n icon: <Play size={16} />,\n onSelect: handleUseTemplate,\n }}\n actions={overflowActions}\n />\n </div>\n </div>\n </div>\n\n {/* Description */}\n {template.description && (\n <div className=\"border border-border-seam rounded-xl p-5 bg-bg-surface\">\n <p className=\"text-sm text-text-secondary\">{template.description}</p>\n </div>\n )}\n\n {/* Info Grid */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n {[\n {\n icon: <FileText size={18} />,\n label: tr(\"export.templateDetail.info.format\", \"Format\"),\n value: getFormatDisplayName(template.format),\n },\n {\n icon: <HardDrive size={18} />,\n label: tr(\"export.templateDetail.info.archive\", \"Archive\"),\n // Backend template doesn't carry archiveFormat, default to ZIP\n value: getArchiveFormatDisplayName(\"ZIP\"),\n },\n {\n icon: <Download size={18} />,\n label: tr(\"export.templateDetail.info.entityTypes\", \"Entity Types\"),\n value: tr(\n \"export.templateDetail.info.entityTypesCount\",\n \"{{count}} type{{suffix}}\",\n {\n count: template.entityTypes.length,\n suffix: template.entityTypes.length !== 1 ? \"s\" : \"\",\n },\n ),\n },\n {\n icon: <Clock size={18} />,\n label: tr(\"export.templateDetail.info.lastUpdated\", \"Last Updated\"),\n value: new Date(template.updatedAt).toLocaleDateString(),\n },\n ].map((item) => (\n <GlassCard\n key={item.label}\n treatment=\"metric\"\n className=\"p-4 border-border-seam\"\n >\n <div className=\"flex items-center gap-2 text-text-secondary mb-1\">\n {item.icon}\n <span className=\"text-xs font-medium\">{item.label}</span>\n </div>\n <p className=\"font-bold text-lg tabular-nums\">{item.value}</p>\n </GlassCard>\n ))}\n </div>\n\n {/* Next-step guidance (dismissable, per-template) */}\n <NextSteps\n storageKey={`export-template-${template.id}`}\n title={tr(\"export.templateDetail.nextSteps.title\", \"What's next\")}\n steps={nextSteps}\n />\n\n {/* Entity Types */}\n <PageSection\n title={tr(\n \"export.templateDetail.entityTypes.title\",\n \"Included Entity Types\",\n )}\n description={tr(\n \"export.templateDetail.entityTypes.description\",\n \"Data types that will be exported\",\n )}\n >\n <ShowMore collapsedHeight={96}>\n <div className=\"flex flex-wrap gap-2\">\n {template.entityTypes.map((entity) => (\n <span\n key={entity}\n className=\"inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium border border-border-seam bg-bg-sunken/30\"\n >\n {entity}\n </span>\n ))}\n </div>\n </ShowMore>\n </PageSection>\n\n {showDeleteConfirm && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"template-delete-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4\"\n >\n <div className=\"w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl\">\n <h2 id=\"template-delete-title\" className=\"text-lg font-bold\">\n {tr(\"export.templateDetail.delete.title\", \"Delete template?\")}\n </h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {tr(\n \"export.templateDetail.delete.description\",\n \"This removes the saved export configuration. Existing export jobs are not deleted.\",\n )}\n </p>\n <div className=\"mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowDeleteConfirm(false)}\n className=\"px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium\"\n >\n {tr(\"export.templateDetail.delete.keep\", \"Keep Template\")}\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={deleting}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium disabled:opacity-50\"\n >\n {deleting ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : null}\n {tr(\n \"export.templateDetail.delete.confirmAction\",\n \"Delete Template\",\n )}\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { I18nContextValue } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
|
|
2
2
|
|
|
3
|
-
type TranslationParams = Record<string, string | number>;
|
|
3
|
+
export type TranslationParams = Record<string, string | number>;
|
|
4
|
+
/**
|
|
5
|
+
* Interpolate `{{key}}` placeholders in a fallback string.
|
|
6
|
+
*
|
|
7
|
+
* Matches the VibeControls `useTr` interpolation convention so call sites
|
|
8
|
+
* across the platform stay consistent.
|
|
9
|
+
*/
|
|
10
|
+
export declare function interpolateFallback(fallback: string, params?: TranslationParams): string;
|
|
11
|
+
/**
|
|
12
|
+
* Translate a key using the provided `t` function, falling back to the
|
|
13
|
+
* caller's English string when the key is missing.
|
|
14
|
+
*
|
|
15
|
+
* Supports optional interpolation with `{{key}}` placeholders.
|
|
16
|
+
*
|
|
17
|
+
* Prefer the `useTr()` hook in components; this helper is useful when a
|
|
18
|
+
* translation is needed outside a hook context (e.g. inside a callback that
|
|
19
|
+
* already has access to `t`).
|
|
20
|
+
*/
|
|
4
21
|
export declare function tWithFallback(t: I18nContextValue["t"], key: string, fallback: string, params?: TranslationParams): string;
|
|
5
|
-
export {};
|
|
6
22
|
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/export/utils/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wDAAwD,CAAC;AAE/F,
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/export/utils/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wDAAwD,CAAC;AAE/F,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,iBAAiB,GACzB,MAAM,CAUR;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,EACxB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,iBAAiB,GACzB,MAAM,CAIR"}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
//#region src/export/utils/i18n.ts
|
|
2
2
|
function e(e, t) {
|
|
3
|
-
return t ? e.replace(
|
|
4
|
-
let r = t[n];
|
|
5
|
-
return r == null ? e : String(r);
|
|
6
|
-
}) : e;
|
|
7
|
-
}
|
|
8
|
-
function t(t, n, r, i) {
|
|
9
|
-
let a = t(n, i);
|
|
10
|
-
return a === n ? e(r, i) : a;
|
|
3
|
+
return t ? Object.entries(t).reduce((e, [t, n]) => e.replace(RegExp(`\\{\\{${t}\\}\\}`, "g"), String(n)), e) : e;
|
|
11
4
|
}
|
|
12
5
|
//#endregion
|
|
13
|
-
export {
|
|
6
|
+
export { e as interpolateFallback };
|
|
14
7
|
|
|
15
8
|
//# sourceMappingURL=i18n.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","names":[],"sources":["../../../src/export/utils/i18n.ts"],"sourcesContent":["import type { I18nContextValue } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\n\
|
|
1
|
+
{"version":3,"file":"i18n.js","names":[],"sources":["../../../src/export/utils/i18n.ts"],"sourcesContent":["import type { I18nContextValue } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\n\nexport type TranslationParams = Record<string, string | number>;\n\n/**\n * Interpolate `{{key}}` placeholders in a fallback string.\n *\n * Matches the VibeControls `useTr` interpolation convention so call sites\n * across the platform stay consistent.\n */\nexport function interpolateFallback(\n fallback: string,\n params?: TranslationParams,\n): string {\n if (!params) {\n return fallback;\n }\n\n return Object.entries(params).reduce(\n (str, [key, value]) =>\n str.replace(new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, \"g\"), String(value)),\n fallback,\n );\n}\n\n/**\n * Translate a key using the provided `t` function, falling back to the\n * caller's English string when the key is missing.\n *\n * Supports optional interpolation with `{{key}}` placeholders.\n *\n * Prefer the `useTr()` hook in components; this helper is useful when a\n * translation is needed outside a hook context (e.g. inside a callback that\n * already has access to `t`).\n */\nexport function tWithFallback(\n t: I18nContextValue[\"t\"],\n key: string,\n fallback: string,\n params?: TranslationParams,\n): string {\n const translated = t(key);\n const raw = translated === key ? fallback : translated;\n return interpolateFallback(raw, params);\n}\n"],"mappings":";AAUA,SAAgB,EACd,GACA,GACQ;AAKR,QAJK,IAIE,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAK,OACV,EAAI,QAAY,OAAO,SAAS,EAAI,SAAS,IAAI,EAAE,OAAO,EAAM,CAAC,EACnE,EACD,GAPQ"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useExport as e } from "./export/providers/ExportProvider.js";
|
|
2
2
|
import { useExportStore as t } from "./export/store/exportStore.js";
|
|
3
3
|
import { ExportRoot as n } from "./export/ExportRoot.js";
|
|
4
|
+
import { enTranslations as r } from "./translations/en.js";
|
|
4
5
|
import "./export/index.js";
|
|
5
|
-
export { n as ExportRoot, e as useExport, t as useExportStore };
|
|
6
|
+
export { n as ExportRoot, r as enTranslations, e as useExport, t as useExportStore };
|