@fonderie/react-courier-admin-screens 0.6.0 → 0.8.0
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/index.cjs +354 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -4
- package/dist/index.d.ts +45 -4
- package/dist/index.js +362 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
// src/screens/TemplateEditorScreen.tsx
|
|
2
|
+
import {
|
|
3
|
+
createAdminT,
|
|
4
|
+
formatAdminDate
|
|
5
|
+
} from "@fonderie/client";
|
|
2
6
|
import {
|
|
3
7
|
useTemplate,
|
|
4
8
|
useTemplatePreview,
|
|
5
9
|
useTemplateRevisions,
|
|
6
10
|
useTemplates
|
|
7
11
|
} from "@fonderie/react-courier-admin";
|
|
8
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
12
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
9
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
14
|
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
11
15
|
var PREVIEW_DEBOUNCE_MS = 500;
|
|
@@ -13,10 +17,16 @@ function TemplateEditorScreen({
|
|
|
13
17
|
client,
|
|
14
18
|
type,
|
|
15
19
|
locale,
|
|
16
|
-
onSaved
|
|
20
|
+
onSaved,
|
|
21
|
+
system = false,
|
|
22
|
+
onDeleted,
|
|
23
|
+
onAddLocale,
|
|
24
|
+
uiLocale
|
|
17
25
|
}) {
|
|
26
|
+
const t = useMemo(() => createAdminT(uiLocale), [uiLocale]);
|
|
18
27
|
const { template, isLoading, error, refresh } = useTemplate(client, type, locale);
|
|
19
|
-
const { saveTemplate } = useTemplates(client);
|
|
28
|
+
const { saveTemplate, removeTemplate } = useTemplates(client);
|
|
29
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
20
30
|
const { revisions, rollback } = useTemplateRevisions(client, type, locale);
|
|
21
31
|
const [isSaving, setIsSaving] = useState(false);
|
|
22
32
|
const [saveError, setSaveError] = useState(null);
|
|
@@ -39,13 +49,13 @@ function TemplateEditorScreen({
|
|
|
39
49
|
try {
|
|
40
50
|
const parsed = JSON.parse(sampleJson || "{}");
|
|
41
51
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
42
|
-
setSampleError("
|
|
52
|
+
setSampleError(t("templates.editor.sampleNotObject"));
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
45
55
|
data = parsed;
|
|
46
56
|
setSampleError(null);
|
|
47
57
|
} catch {
|
|
48
|
-
setSampleError("
|
|
58
|
+
setSampleError(t("templates.editor.sampleInvalid"));
|
|
49
59
|
return;
|
|
50
60
|
}
|
|
51
61
|
const result = await renderPreview(
|
|
@@ -58,7 +68,7 @@ function TemplateEditorScreen({
|
|
|
58
68
|
const seeded = { ...data, ...Object.fromEntries(missing.map((v) => [v, v])) };
|
|
59
69
|
setSampleJson(JSON.stringify(seeded, null, 2));
|
|
60
70
|
}
|
|
61
|
-
}, [renderPreview, type, text, subject, html, locale, sampleJson]);
|
|
71
|
+
}, [renderPreview, type, text, subject, html, locale, sampleJson, t]);
|
|
62
72
|
const runRef = useRef(run);
|
|
63
73
|
runRef.current = run;
|
|
64
74
|
const loadedType = template ? `${type}:${locale ?? ""}` : null;
|
|
@@ -86,20 +96,46 @@ function TemplateEditorScreen({
|
|
|
86
96
|
setIsSaving(false);
|
|
87
97
|
}
|
|
88
98
|
};
|
|
89
|
-
|
|
99
|
+
const handleDelete = async () => {
|
|
100
|
+
const message = locale ? t("templates.editor.confirmDeleteLocale", { type, locale }) : t("templates.editor.confirmDelete", { type });
|
|
101
|
+
if (!window.confirm(message)) return;
|
|
102
|
+
setIsDeleting(true);
|
|
103
|
+
setSaveError(null);
|
|
104
|
+
try {
|
|
105
|
+
await removeTemplate(type, locale);
|
|
106
|
+
onDeleted?.();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
setSaveError(err);
|
|
109
|
+
} finally {
|
|
110
|
+
setIsDeleting(false);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
if (isLoading) return /* @__PURE__ */ jsx("p", { style: styles.status, children: t("templates.editor.loading") });
|
|
90
114
|
if (error)
|
|
91
115
|
return /* @__PURE__ */ jsx("p", { style: styles.error, role: "alert", children: error.explanation });
|
|
92
116
|
return /* @__PURE__ */ jsxs("div", { style: styles.container, children: [
|
|
93
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
|
|
118
|
+
/* @__PURE__ */ jsx("h1", { style: styles.title, children: type }),
|
|
119
|
+
onAddLocale && !locale ? /* @__PURE__ */ jsx(
|
|
120
|
+
"button",
|
|
121
|
+
{
|
|
122
|
+
type: "button",
|
|
123
|
+
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
124
|
+
onClick: () => onAddLocale(type),
|
|
125
|
+
children: t("templates.editor.addLocale")
|
|
126
|
+
}
|
|
127
|
+
) : null
|
|
128
|
+
] }),
|
|
94
129
|
/* @__PURE__ */ jsxs("p", { style: styles.meta, children: [
|
|
95
|
-
locale ?? "
|
|
130
|
+
/* @__PURE__ */ jsx("strong", { children: locale ?? t("templates.defaultLocale") }),
|
|
96
131
|
" \xB7 v",
|
|
97
|
-
template?.version ?? 1
|
|
132
|
+
template?.version ?? 1,
|
|
133
|
+
system ? ` \xB7 ${t("templates.editor.builtInNote")}` : ""
|
|
98
134
|
] }),
|
|
99
135
|
/* @__PURE__ */ jsxs("div", { style: styles.split, children: [
|
|
100
136
|
/* @__PURE__ */ jsxs("div", { style: styles.column, children: [
|
|
101
137
|
/* @__PURE__ */ jsxs("form", { style: styles.form, onSubmit: handleSubmit, children: [
|
|
102
|
-
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-subject", children: "
|
|
138
|
+
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-subject", children: t("templates.subject") }),
|
|
103
139
|
/* @__PURE__ */ jsx(
|
|
104
140
|
"input",
|
|
105
141
|
{
|
|
@@ -109,7 +145,7 @@ function TemplateEditorScreen({
|
|
|
109
145
|
onChange: (event) => setSubject(event.target.value)
|
|
110
146
|
}
|
|
111
147
|
),
|
|
112
|
-
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-html", children: "
|
|
148
|
+
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-html", children: t("templates.htmlBody") }),
|
|
113
149
|
/* @__PURE__ */ jsx(
|
|
114
150
|
"textarea",
|
|
115
151
|
{
|
|
@@ -120,7 +156,7 @@ function TemplateEditorScreen({
|
|
|
120
156
|
rows: 8
|
|
121
157
|
}
|
|
122
158
|
),
|
|
123
|
-
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-text", children: "
|
|
159
|
+
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-text", children: t("templates.textBody") }),
|
|
124
160
|
/* @__PURE__ */ jsx(
|
|
125
161
|
"textarea",
|
|
126
162
|
{
|
|
@@ -141,9 +177,24 @@ function TemplateEditorScreen({
|
|
|
141
177
|
onChange: (event) => setActive(event.target.checked)
|
|
142
178
|
}
|
|
143
179
|
),
|
|
144
|
-
"
|
|
180
|
+
t("templates.editor.active")
|
|
145
181
|
] }),
|
|
146
|
-
saveError
|
|
182
|
+
saveError?.reason === "VERSION_CONFLICT" ? /* @__PURE__ */ jsxs("p", { style: styles.error, role: "alert", children: [
|
|
183
|
+
t("templates.editor.conflict"),
|
|
184
|
+
" ",
|
|
185
|
+
/* @__PURE__ */ jsx(
|
|
186
|
+
"button",
|
|
187
|
+
{
|
|
188
|
+
type: "button",
|
|
189
|
+
style: styles.rollbackButton,
|
|
190
|
+
onClick: () => {
|
|
191
|
+
setSaveError(null);
|
|
192
|
+
void refresh();
|
|
193
|
+
},
|
|
194
|
+
children: t("common.reload")
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] }) : saveError ? /* @__PURE__ */ jsx("p", { style: styles.error, role: "alert", children: saveError.explanation }) : null,
|
|
147
198
|
/* @__PURE__ */ jsxs("div", { style: styles.saveRow, children: [
|
|
148
199
|
/* @__PURE__ */ jsx(
|
|
149
200
|
"button",
|
|
@@ -151,13 +202,29 @@ function TemplateEditorScreen({
|
|
|
151
202
|
type: "submit",
|
|
152
203
|
disabled: isSaving || !dirty,
|
|
153
204
|
style: dirty ? styles.button : styles.buttonDisabled,
|
|
154
|
-
children: isSaving ? "
|
|
205
|
+
children: isSaving ? t("common.saving") : t("common.save")
|
|
155
206
|
}
|
|
156
207
|
),
|
|
157
|
-
!dirty && !isSaving && /* @__PURE__ */ jsx("span", { style: styles.meta, children: "
|
|
208
|
+
!dirty && !isSaving && /* @__PURE__ */ jsx("span", { style: styles.meta, children: t("templates.editor.noChanges") }),
|
|
209
|
+
!system ? /* @__PURE__ */ jsx(
|
|
210
|
+
"button",
|
|
211
|
+
{
|
|
212
|
+
type: "button",
|
|
213
|
+
disabled: isDeleting,
|
|
214
|
+
onClick: () => void handleDelete(),
|
|
215
|
+
style: {
|
|
216
|
+
...styles.rollbackButton,
|
|
217
|
+
height: 36,
|
|
218
|
+
marginLeft: "auto",
|
|
219
|
+
color: "var(--fonderie-danger,#e00)",
|
|
220
|
+
borderColor: "color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)"
|
|
221
|
+
},
|
|
222
|
+
children: isDeleting ? t("common.deleting") : t("common.delete")
|
|
223
|
+
}
|
|
224
|
+
) : null
|
|
158
225
|
] })
|
|
159
226
|
] }),
|
|
160
|
-
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-sample", children: "
|
|
227
|
+
/* @__PURE__ */ jsx("label", { style: styles.label, htmlFor: "template-sample", children: t("templates.editor.sampleData") }),
|
|
161
228
|
/* @__PURE__ */ jsx(
|
|
162
229
|
"textarea",
|
|
163
230
|
{
|
|
@@ -173,8 +240,8 @@ function TemplateEditorScreen({
|
|
|
173
240
|
] }),
|
|
174
241
|
/* @__PURE__ */ jsxs("div", { style: styles.previewColumn, children: [
|
|
175
242
|
/* @__PURE__ */ jsxs("div", { style: styles.previewHeader, children: [
|
|
176
|
-
/* @__PURE__ */ jsx("span", { style: styles.label, children: "
|
|
177
|
-
/* @__PURE__ */ jsx("span", { style: styles.meta, children: isPreviewing ? "
|
|
243
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: t("templates.editor.preview") }),
|
|
244
|
+
/* @__PURE__ */ jsx("span", { style: styles.meta, children: isPreviewing ? t("templates.editor.rendering") : t("templates.editor.live") })
|
|
178
245
|
] }),
|
|
179
246
|
previewError && /* @__PURE__ */ jsx("p", { style: styles.error, role: "alert", children: previewError.explanation }),
|
|
180
247
|
preview?.subject && /* @__PURE__ */ jsx("p", { style: styles.previewSubject, children: preview.subject }),
|
|
@@ -185,26 +252,26 @@ function TemplateEditorScreen({
|
|
|
185
252
|
/* @__PURE__ */ jsx(
|
|
186
253
|
"iframe",
|
|
187
254
|
{
|
|
188
|
-
title: "
|
|
255
|
+
title: t("templates.editor.previewTitle"),
|
|
189
256
|
style: styles.previewFrame,
|
|
190
257
|
sandbox: "",
|
|
191
258
|
srcDoc: preview.html
|
|
192
259
|
}
|
|
193
260
|
)
|
|
194
|
-
) : preview ? /* @__PURE__ */ jsx("pre", { style: styles.previewText, children: preview.text }) : /* @__PURE__ */ jsx("p", { style: styles.meta, children: "
|
|
261
|
+
) : preview ? /* @__PURE__ */ jsx("pre", { style: styles.previewText, children: preview.text }) : /* @__PURE__ */ jsx("p", { style: styles.meta, children: t("templates.editor.nothingRendered") })
|
|
195
262
|
] })
|
|
196
263
|
] }),
|
|
197
264
|
revisions.length > 0 && /* @__PURE__ */ jsxs("div", { style: styles.revisions, children: [
|
|
198
|
-
/* @__PURE__ */ jsx("h2", { style: styles.subtitle, children: "
|
|
265
|
+
/* @__PURE__ */ jsx("h2", { style: styles.subtitle, children: t("templates.editor.history") }),
|
|
199
266
|
/* @__PURE__ */ jsx("ul", { style: styles.list, children: revisions.map((rev) => /* @__PURE__ */ jsxs("li", { style: styles.row, children: [
|
|
200
267
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
201
268
|
"v",
|
|
202
269
|
rev.version,
|
|
203
270
|
" \u2014 ",
|
|
204
|
-
rev.actor ?? "
|
|
271
|
+
rev.actor ?? t("templates.editor.unknownActor"),
|
|
205
272
|
" \u2014",
|
|
206
273
|
" ",
|
|
207
|
-
|
|
274
|
+
formatAdminDate(rev.createdAt, uiLocale)
|
|
208
275
|
] }),
|
|
209
276
|
/* @__PURE__ */ jsx(
|
|
210
277
|
"button",
|
|
@@ -212,7 +279,7 @@ function TemplateEditorScreen({
|
|
|
212
279
|
type: "button",
|
|
213
280
|
onClick: () => rollback(rev.version),
|
|
214
281
|
style: styles.rollbackButton,
|
|
215
|
-
children: "
|
|
282
|
+
children: t("templates.editor.rollBack")
|
|
216
283
|
}
|
|
217
284
|
)
|
|
218
285
|
] }, rev.version)) })
|
|
@@ -388,14 +455,44 @@ var styles = {
|
|
|
388
455
|
};
|
|
389
456
|
|
|
390
457
|
// src/screens/TemplateListScreen.tsx
|
|
458
|
+
import {
|
|
459
|
+
createAdminT as createAdminT2
|
|
460
|
+
} from "@fonderie/client";
|
|
391
461
|
import { useTemplates as useTemplates2 } from "@fonderie/react-courier-admin";
|
|
392
462
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
393
|
-
function TemplateListScreen({
|
|
463
|
+
function TemplateListScreen({
|
|
464
|
+
client,
|
|
465
|
+
onSelectTemplate,
|
|
466
|
+
onCreateTemplate,
|
|
467
|
+
locale
|
|
468
|
+
}) {
|
|
469
|
+
const t = createAdminT2(locale);
|
|
394
470
|
const { templates, isLoading, error } = useTemplates2(client);
|
|
395
471
|
return /* @__PURE__ */ jsxs2("div", { style: styles2.container, children: [
|
|
396
|
-
/* @__PURE__ */
|
|
397
|
-
|
|
398
|
-
|
|
472
|
+
/* @__PURE__ */ jsxs2(
|
|
473
|
+
"div",
|
|
474
|
+
{
|
|
475
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 },
|
|
476
|
+
children: [
|
|
477
|
+
/* @__PURE__ */ jsx2("h1", { style: styles2.title, children: t("templates.list.title") }),
|
|
478
|
+
onCreateTemplate ? /* @__PURE__ */ jsx2(
|
|
479
|
+
"button",
|
|
480
|
+
{
|
|
481
|
+
type: "button",
|
|
482
|
+
onClick: () => onCreateTemplate({
|
|
483
|
+
locales: [
|
|
484
|
+
...new Set(templates.map((row) => row.locale).filter((l) => !!l))
|
|
485
|
+
]
|
|
486
|
+
}),
|
|
487
|
+
style: styles2.newButton,
|
|
488
|
+
children: t("templates.list.newTemplate")
|
|
489
|
+
}
|
|
490
|
+
) : null
|
|
491
|
+
]
|
|
492
|
+
}
|
|
493
|
+
),
|
|
494
|
+
/* @__PURE__ */ jsx2("p", { style: styles2.hint, children: t("templates.list.hint") }),
|
|
495
|
+
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles2.status, children: t("templates.list.loading") }) : error ? /* @__PURE__ */ jsx2("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsx2("ul", { style: styles2.list, children: templates.map((template) => /* @__PURE__ */ jsx2("li", { style: styles2.row, children: /* @__PURE__ */ jsxs2(
|
|
399
496
|
"button",
|
|
400
497
|
{
|
|
401
498
|
type: "button",
|
|
@@ -403,10 +500,11 @@ function TemplateListScreen({ client, onSelectTemplate }) {
|
|
|
403
500
|
style: styles2.rowButton,
|
|
404
501
|
children: [
|
|
405
502
|
/* @__PURE__ */ jsx2("span", { style: styles2.type, children: template.type }),
|
|
406
|
-
/* @__PURE__ */ jsx2("span", { style: styles2.locale, children: template.locale ?? "
|
|
503
|
+
/* @__PURE__ */ jsx2("span", { style: styles2.locale, children: template.locale ?? t("templates.defaultLocale") }),
|
|
504
|
+
template.system ? /* @__PURE__ */ jsx2("span", { style: styles2.builtIn, children: t("templates.builtInBadge") }) : null,
|
|
407
505
|
/* @__PURE__ */ jsxs2("span", { style: template.active ? styles2.active : styles2.inactive, children: [
|
|
408
506
|
/* @__PURE__ */ jsx2("span", { style: styles2.dot }),
|
|
409
|
-
template.active ? "active" : "inactive"
|
|
507
|
+
template.active ? t("common.status.active") : t("common.status.inactive")
|
|
410
508
|
] })
|
|
411
509
|
]
|
|
412
510
|
}
|
|
@@ -469,6 +567,29 @@ var styles2 = {
|
|
|
469
567
|
},
|
|
470
568
|
locale: { fontSize: 12.5, color: "var(--fonderie-text-muted,#5c5c5c)" },
|
|
471
569
|
dot: { width: 6, height: 6, borderRadius: 999, background: "currentColor" },
|
|
570
|
+
builtIn: {
|
|
571
|
+
fontSize: 11,
|
|
572
|
+
fontWeight: 500,
|
|
573
|
+
padding: "1px 7px",
|
|
574
|
+
borderRadius: 999,
|
|
575
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
576
|
+
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
577
|
+
},
|
|
578
|
+
newButton: {
|
|
579
|
+
display: "inline-flex",
|
|
580
|
+
alignItems: "center",
|
|
581
|
+
height: 32,
|
|
582
|
+
boxSizing: "border-box",
|
|
583
|
+
borderRadius: 6,
|
|
584
|
+
padding: "0 12px",
|
|
585
|
+
fontSize: 13,
|
|
586
|
+
fontWeight: 500,
|
|
587
|
+
fontFamily: "inherit",
|
|
588
|
+
cursor: "pointer",
|
|
589
|
+
backgroundColor: "var(--fonderie-text,#171717)",
|
|
590
|
+
color: "var(--fonderie-surface,#fff)",
|
|
591
|
+
border: "1px solid var(--fonderie-text,#171717)"
|
|
592
|
+
},
|
|
472
593
|
active: {
|
|
473
594
|
...pill,
|
|
474
595
|
color: "var(--fonderie-accent-strong,#009767)",
|
|
@@ -480,7 +601,216 @@ var styles2 = {
|
|
|
480
601
|
background: "color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)"
|
|
481
602
|
}
|
|
482
603
|
};
|
|
604
|
+
|
|
605
|
+
// src/screens/TemplateCreateScreen.tsx
|
|
606
|
+
import {
|
|
607
|
+
FonderieApiError,
|
|
608
|
+
createAdminT as createAdminT3
|
|
609
|
+
} from "@fonderie/client";
|
|
610
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
611
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
612
|
+
var TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
613
|
+
var LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
614
|
+
function TemplateCreateScreen({
|
|
615
|
+
client,
|
|
616
|
+
type,
|
|
617
|
+
locales = [],
|
|
618
|
+
onCreated,
|
|
619
|
+
locale
|
|
620
|
+
}) {
|
|
621
|
+
const tr = createAdminT3(locale);
|
|
622
|
+
const addingLocale = type !== void 0;
|
|
623
|
+
const [newType, setNewType] = useState2("");
|
|
624
|
+
const [targetLocale, setTargetLocale] = useState2("");
|
|
625
|
+
const [subject, setSubject] = useState2("");
|
|
626
|
+
const [html, setHtml] = useState2("");
|
|
627
|
+
const [text, setText] = useState2("");
|
|
628
|
+
const [error, setError] = useState2(null);
|
|
629
|
+
const [busy, setBusy] = useState2(false);
|
|
630
|
+
useEffect2(() => {
|
|
631
|
+
if (!type) return;
|
|
632
|
+
client.getTemplate(type, null).then(({ result }) => {
|
|
633
|
+
setSubject(result.subject ?? "");
|
|
634
|
+
setHtml(result.html ?? "");
|
|
635
|
+
setText(result.text);
|
|
636
|
+
}).catch(() => void 0);
|
|
637
|
+
}, [client, type]);
|
|
638
|
+
const submit = async (e) => {
|
|
639
|
+
e.preventDefault();
|
|
640
|
+
setError(null);
|
|
641
|
+
const t = addingLocale ? type : newType.trim();
|
|
642
|
+
const l = targetLocale.trim() || null;
|
|
643
|
+
if (!TYPE_RE.test(t)) return setError(tr("templates.create.errorType"));
|
|
644
|
+
if (addingLocale && !l) return setError(tr("templates.create.errorLocaleRequired"));
|
|
645
|
+
if (l && !LOCALE_RE.test(l)) return setError(tr("templates.create.errorLocale"));
|
|
646
|
+
if (!text.trim()) return setError(tr("templates.create.errorText"));
|
|
647
|
+
setBusy(true);
|
|
648
|
+
try {
|
|
649
|
+
const exists = await client.getTemplate(t, l).then(
|
|
650
|
+
() => true,
|
|
651
|
+
(err) => !(err instanceof FonderieApiError && err.status === 404)
|
|
652
|
+
);
|
|
653
|
+
if (exists) {
|
|
654
|
+
setError(
|
|
655
|
+
l ? tr("templates.create.existsLocale", { type: t, locale: l }) : tr("templates.create.exists", { type: t })
|
|
656
|
+
);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const input = { text, active: true };
|
|
660
|
+
if (subject) input.subject = subject;
|
|
661
|
+
if (html) input.html = html;
|
|
662
|
+
await client.setTemplate(t, input, l);
|
|
663
|
+
onCreated?.({ type: t, locale: l });
|
|
664
|
+
} catch (err) {
|
|
665
|
+
setError(err instanceof FonderieApiError ? err.explanation : String(err));
|
|
666
|
+
} finally {
|
|
667
|
+
setBusy(false);
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
return /* @__PURE__ */ jsxs3("div", { style: styles3.container, children: [
|
|
671
|
+
/* @__PURE__ */ jsx3("h1", { style: styles3.title, children: addingLocale ? tr("templates.create.titleLocale", { type }) : tr("templates.create.titleNew") }),
|
|
672
|
+
/* @__PURE__ */ jsx3("p", { style: styles3.meta, children: addingLocale ? tr("templates.create.hintLocale") : tr("templates.create.hintNew") }),
|
|
673
|
+
/* @__PURE__ */ jsxs3("form", { style: styles3.form, onSubmit: (e) => void submit(e), children: [
|
|
674
|
+
!addingLocale ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
675
|
+
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-type", children: tr("templates.create.type") }),
|
|
676
|
+
/* @__PURE__ */ jsx3(
|
|
677
|
+
"input",
|
|
678
|
+
{
|
|
679
|
+
id: "new-template-type",
|
|
680
|
+
style: styles3.input,
|
|
681
|
+
value: newType,
|
|
682
|
+
placeholder: "weekly-digest",
|
|
683
|
+
autoComplete: "off",
|
|
684
|
+
spellCheck: false,
|
|
685
|
+
onChange: (e) => setNewType(e.target.value)
|
|
686
|
+
}
|
|
687
|
+
)
|
|
688
|
+
] }) : null,
|
|
689
|
+
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-locale", children: addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional") }),
|
|
690
|
+
/* @__PURE__ */ jsx3(
|
|
691
|
+
"input",
|
|
692
|
+
{
|
|
693
|
+
id: "new-template-locale",
|
|
694
|
+
style: styles3.input,
|
|
695
|
+
value: targetLocale,
|
|
696
|
+
placeholder: "fr",
|
|
697
|
+
list: "new-template-locales",
|
|
698
|
+
autoComplete: "off",
|
|
699
|
+
spellCheck: false,
|
|
700
|
+
onChange: (e) => setTargetLocale(e.target.value)
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
/* @__PURE__ */ jsx3("datalist", { id: "new-template-locales", children: [...new Set(locales)].map((l) => /* @__PURE__ */ jsx3("option", { value: l }, l)) }),
|
|
704
|
+
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-subject", children: tr("templates.subject") }),
|
|
705
|
+
/* @__PURE__ */ jsx3(
|
|
706
|
+
"input",
|
|
707
|
+
{
|
|
708
|
+
id: "new-template-subject",
|
|
709
|
+
style: styles3.input,
|
|
710
|
+
value: subject,
|
|
711
|
+
onChange: (e) => setSubject(e.target.value)
|
|
712
|
+
}
|
|
713
|
+
),
|
|
714
|
+
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-html", children: tr("templates.htmlBody") }),
|
|
715
|
+
/* @__PURE__ */ jsx3(
|
|
716
|
+
"textarea",
|
|
717
|
+
{
|
|
718
|
+
id: "new-template-html",
|
|
719
|
+
style: { ...styles3.textarea, minHeight: 160 },
|
|
720
|
+
value: html,
|
|
721
|
+
onChange: (e) => setHtml(e.target.value)
|
|
722
|
+
}
|
|
723
|
+
),
|
|
724
|
+
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-text", children: tr("templates.textBody") }),
|
|
725
|
+
/* @__PURE__ */ jsx3(
|
|
726
|
+
"textarea",
|
|
727
|
+
{
|
|
728
|
+
id: "new-template-text",
|
|
729
|
+
style: { ...styles3.textarea, minHeight: 100 },
|
|
730
|
+
value: text,
|
|
731
|
+
onChange: (e) => setText(e.target.value)
|
|
732
|
+
}
|
|
733
|
+
),
|
|
734
|
+
error ? /* @__PURE__ */ jsx3("p", { style: styles3.error, role: "alert", children: error }) : null,
|
|
735
|
+
/* @__PURE__ */ jsx3("button", { type: "submit", disabled: busy, style: styles3.button, children: busy ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew") })
|
|
736
|
+
] })
|
|
737
|
+
] });
|
|
738
|
+
}
|
|
739
|
+
var MONO = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
740
|
+
var styles3 = {
|
|
741
|
+
container: { padding: "8px 40px 64px", maxWidth: 760, boxSizing: "border-box" },
|
|
742
|
+
title: {
|
|
743
|
+
fontSize: 22,
|
|
744
|
+
fontWeight: 600,
|
|
745
|
+
margin: "8px 0 4px",
|
|
746
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)",
|
|
747
|
+
lineHeight: 1.25
|
|
748
|
+
},
|
|
749
|
+
meta: {
|
|
750
|
+
fontSize: 13,
|
|
751
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
752
|
+
marginBottom: 20,
|
|
753
|
+
lineHeight: 1.5
|
|
754
|
+
},
|
|
755
|
+
form: {
|
|
756
|
+
display: "flex",
|
|
757
|
+
flexDirection: "column",
|
|
758
|
+
gap: 4,
|
|
759
|
+
background: "var(--fonderie-surface,#fff)",
|
|
760
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
761
|
+
borderRadius: "var(--fonderie-radius-lg,8px)",
|
|
762
|
+
padding: "6px 20px 20px"
|
|
763
|
+
},
|
|
764
|
+
label: { fontSize: 13, fontWeight: 500, marginTop: 14, marginBottom: 2 },
|
|
765
|
+
input: {
|
|
766
|
+
height: 36,
|
|
767
|
+
boxSizing: "border-box",
|
|
768
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
769
|
+
borderRadius: 6,
|
|
770
|
+
padding: "0 10px",
|
|
771
|
+
fontSize: 13.5,
|
|
772
|
+
fontFamily: "inherit",
|
|
773
|
+
background: "var(--fonderie-surface,#fff)",
|
|
774
|
+
color: "var(--fonderie-text,#171717)"
|
|
775
|
+
},
|
|
776
|
+
textarea: {
|
|
777
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
778
|
+
borderRadius: 6,
|
|
779
|
+
padding: 10,
|
|
780
|
+
fontSize: 13,
|
|
781
|
+
lineHeight: 1.55,
|
|
782
|
+
background: "var(--fonderie-surface,#fff)",
|
|
783
|
+
color: "var(--fonderie-text,#171717)",
|
|
784
|
+
fontFamily: MONO
|
|
785
|
+
},
|
|
786
|
+
error: {
|
|
787
|
+
color: "var(--fonderie-danger,#e00)",
|
|
788
|
+
background: "color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)",
|
|
789
|
+
borderRadius: 6,
|
|
790
|
+
padding: "8px 12px",
|
|
791
|
+
margin: "8px 0",
|
|
792
|
+
fontSize: 13.5
|
|
793
|
+
},
|
|
794
|
+
button: {
|
|
795
|
+
display: "inline-flex",
|
|
796
|
+
alignItems: "center",
|
|
797
|
+
height: 36,
|
|
798
|
+
boxSizing: "border-box",
|
|
799
|
+
backgroundColor: "var(--fonderie-text,#171717)",
|
|
800
|
+
color: "var(--fonderie-surface,#fff)",
|
|
801
|
+
padding: "0 16px",
|
|
802
|
+
borderRadius: 6,
|
|
803
|
+
border: "1px solid var(--fonderie-text,#171717)",
|
|
804
|
+
fontSize: 13.5,
|
|
805
|
+
fontWeight: 600,
|
|
806
|
+
fontFamily: "inherit",
|
|
807
|
+
cursor: "pointer",
|
|
808
|
+
alignSelf: "flex-start",
|
|
809
|
+
marginTop: 16
|
|
810
|
+
}
|
|
811
|
+
};
|
|
483
812
|
export {
|
|
813
|
+
TemplateCreateScreen,
|
|
484
814
|
TemplateEditorScreen,
|
|
485
815
|
TemplateListScreen
|
|
486
816
|
};
|