@open-mercato/core 0.6.6-develop.6201.1.8ceb502c4b → 0.6.6-develop.6204.1.30b1f58642
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/modules/catalog/backend/catalog/products/[id]/page.js +52 -45
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +9 -13
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesSection.js +17 -12
- package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityHistorySection.js +11 -7
- package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +75 -33
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +95 -43
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionarySelectControl.js +40 -19
- package/dist/modules/dictionaries/components/DictionarySelectControl.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +58 -48
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +14 -13
- package/src/modules/customers/components/detail/ActivitiesSection.tsx +22 -13
- package/src/modules/customers/components/detail/ActivityHistorySection.tsx +13 -7
- package/src/modules/dictionaries/components/DictionariesManager.tsx +82 -34
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +99 -42
- package/src/modules/dictionaries/components/DictionarySelectControl.tsx +43 -18
|
@@ -17,6 +17,7 @@ import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
|
17
17
|
import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
|
|
18
18
|
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
19
19
|
import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
|
|
20
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
20
21
|
import { useQueryClient } from "@tanstack/react-query";
|
|
21
22
|
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
22
23
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -54,6 +55,14 @@ function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = fals
|
|
|
54
55
|
const [errors, setErrors] = React.useState({});
|
|
55
56
|
const [translateEntry, setTranslateEntry] = React.useState(null);
|
|
56
57
|
const appearance = useAppearanceState(formState.icon, formState.color);
|
|
58
|
+
const mutationContextId = React.useMemo(
|
|
59
|
+
() => `dictionaries:dictionary_entry:${dictionaryId}`,
|
|
60
|
+
[dictionaryId]
|
|
61
|
+
);
|
|
62
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
63
|
+
contextId: mutationContextId,
|
|
64
|
+
blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
|
|
65
|
+
});
|
|
57
66
|
const resetForm = React.useCallback(() => {
|
|
58
67
|
setFormState({ value: "", label: "", color: null, icon: null });
|
|
59
68
|
appearance.setColor(null);
|
|
@@ -115,38 +124,63 @@ function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = fals
|
|
|
115
124
|
icon: appearance.icon
|
|
116
125
|
};
|
|
117
126
|
if (formState.id) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
const entryId = formState.id;
|
|
128
|
+
const expectedUpdatedAt = formState.updatedAt;
|
|
129
|
+
await runMutation({
|
|
130
|
+
operation: () => withScopedApiRequestHeaders(
|
|
131
|
+
buildOptimisticLockHeader(expectedUpdatedAt),
|
|
132
|
+
async () => {
|
|
133
|
+
const call = await apiCall(
|
|
134
|
+
`/api/dictionaries/${dictionaryId}/entries/${entryId}`,
|
|
135
|
+
{
|
|
136
|
+
method: "PATCH",
|
|
137
|
+
headers: { "content-type": "application/json" },
|
|
138
|
+
body: JSON.stringify(payload)
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
if (!call.ok) {
|
|
142
|
+
throw Object.assign(
|
|
143
|
+
new Error(typeof call.result?.error === "string" ? call.result.error : "Failed to save dictionary entry"),
|
|
144
|
+
{ status: call.status, ...call.result && typeof call.result === "object" ? call.result : {} }
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return call;
|
|
126
148
|
}
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
),
|
|
150
|
+
context: {
|
|
151
|
+
formId: mutationContextId,
|
|
152
|
+
resourceKind: "dictionaries.dictionary_entry",
|
|
153
|
+
resourceId: entryId,
|
|
154
|
+
retryLastMutation
|
|
155
|
+
},
|
|
156
|
+
mutationPayload: payload
|
|
157
|
+
});
|
|
135
158
|
flash(t("dictionaries.config.entries.success.update", "Dictionary entry updated."), "success");
|
|
136
159
|
} else {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
await runMutation({
|
|
161
|
+
operation: async () => {
|
|
162
|
+
const call = await apiCall(
|
|
163
|
+
`/api/dictionaries/${dictionaryId}/entries`,
|
|
164
|
+
{
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: { "content-type": "application/json" },
|
|
167
|
+
body: JSON.stringify(payload)
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
if (!call.ok) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
typeof call.result?.error === "string" ? call.result.error : "Failed to create dictionary entry"
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return call;
|
|
176
|
+
},
|
|
177
|
+
context: {
|
|
178
|
+
formId: mutationContextId,
|
|
179
|
+
resourceKind: "dictionaries.dictionary_entry",
|
|
180
|
+
retryLastMutation
|
|
181
|
+
},
|
|
182
|
+
mutationPayload: payload
|
|
183
|
+
});
|
|
150
184
|
flash(t("dictionaries.config.entries.success.create", "Dictionary entry created."), "success");
|
|
151
185
|
}
|
|
152
186
|
await invalidateDictionaryEntries(queryClient, dictionaryId);
|
|
@@ -164,7 +198,7 @@ function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = fals
|
|
|
164
198
|
} finally {
|
|
165
199
|
setIsSaving(false);
|
|
166
200
|
}
|
|
167
|
-
}, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, queryClient, readOnly, readOnlyMessage, t]);
|
|
201
|
+
}, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t]);
|
|
168
202
|
const handleDelete = React.useCallback(
|
|
169
203
|
async (entry) => {
|
|
170
204
|
if (readOnly) {
|
|
@@ -179,28 +213,46 @@ function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = fals
|
|
|
179
213
|
if (!confirmDelete) return;
|
|
180
214
|
setIsDeleting(true);
|
|
181
215
|
try {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
216
|
+
await runMutation({
|
|
217
|
+
operation: () => withScopedApiRequestHeaders(
|
|
218
|
+
buildOptimisticLockHeader(entry.updatedAt),
|
|
219
|
+
async () => {
|
|
220
|
+
const call = await apiCall(
|
|
221
|
+
`/api/dictionaries/${dictionaryId}/entries/${entry.id}`,
|
|
222
|
+
{ method: "DELETE" }
|
|
223
|
+
);
|
|
224
|
+
if (!call.ok) {
|
|
225
|
+
throw Object.assign(
|
|
226
|
+
new Error(
|
|
227
|
+
typeof call.result?.error === "string" ? call.result.error : "Failed to delete dictionary entry"
|
|
228
|
+
),
|
|
229
|
+
{ status: call.status, ...call.result && typeof call.result === "object" ? call.result : {} }
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
return call;
|
|
233
|
+
}
|
|
234
|
+
),
|
|
235
|
+
context: {
|
|
236
|
+
formId: mutationContextId,
|
|
237
|
+
resourceKind: "dictionaries.dictionary_entry",
|
|
238
|
+
resourceId: entry.id,
|
|
239
|
+
retryLastMutation
|
|
240
|
+
},
|
|
241
|
+
mutationPayload: { id: entry.id }
|
|
242
|
+
});
|
|
194
243
|
await invalidateDictionaryEntries(queryClient, dictionaryId);
|
|
195
244
|
flash(t("dictionaries.config.entries.success.delete", "Dictionary entry deleted."), "success");
|
|
196
245
|
} catch (err) {
|
|
246
|
+
if (surfaceRecordConflict(err, t)) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
197
249
|
console.error("Failed to delete dictionary entry", err);
|
|
198
250
|
flash(t("dictionaries.config.entries.error.delete", "Failed to delete dictionary entry."), "error");
|
|
199
251
|
} finally {
|
|
200
252
|
setIsDeleting(false);
|
|
201
253
|
}
|
|
202
254
|
},
|
|
203
|
-
[confirm, dictionaryId, queryClient, readOnly, readOnlyMessage, t]
|
|
255
|
+
[confirm, dictionaryId, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t]
|
|
204
256
|
);
|
|
205
257
|
const tableContent = React.useMemo(() => {
|
|
206
258
|
if (isInitialLoading) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/dictionaries/components/DictionaryEntriesEditor.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus, Pencil, Trash2, RefreshCw, Languages } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@open-mercato/ui/primitives/table'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { AppearanceSelector, useAppearanceState } from './AppearanceSelector'\nimport { DictionaryValue } from './dictionaryAppearance'\nimport {\n invalidateDictionaryEntries,\n useDictionaryEntries,\n} from './hooks/useDictionaryEntries'\nimport type { DictionaryEntryRecord } from './hooks/useDictionaryEntries'\nimport {\n DialogDescription,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Entry = DictionaryEntryRecord\n\ntype DictionaryEntriesEditorProps = {\n dictionaryId: string\n dictionaryName: string\n readOnly?: boolean\n}\n\ntype FormState = {\n id?: string | null\n value: string\n label: string\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\nexport function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = false }: DictionaryEntriesEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const readOnlyMessage = t('dictionaries.config.entries.readOnly', 'Inherited dictionaries are managed at the parent organization.')\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useDictionaryEntries(dictionaryId, scopeVersion)\n const entries = React.useMemo<Entry[]>(() => dictionaryQuery.data?.fullEntries ?? [], [dictionaryQuery.data?.fullEntries])\n const dictionaryMap = dictionaryQuery.data?.map ?? {}\n const isInitialLoading = dictionaryQuery.isLoading\n const loadError = dictionaryQuery.isError\n ? t('dictionaries.config.entries.error.load', 'Failed to load dictionary entries.')\n : null\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const [formState, setFormState] = React.useState<FormState>(() => ({\n value: '',\n label: '',\n color: null,\n icon: null,\n }))\n const [errors, setErrors] = React.useState<{ value?: string; label?: string }>({})\n const [translateEntry, setTranslateEntry] = React.useState<Entry | null>(null)\n const appearance = useAppearanceState(formState.icon, formState.color)\n\n const resetForm = React.useCallback(() => {\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n }, [appearance])\n\n const openDialog = React.useCallback(\n (entry?: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (entry) {\n setFormState({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n updatedAt: entry.updatedAt ?? null,\n })\n appearance.setColor(entry.color ?? null)\n appearance.setIcon(entry.icon ?? null)\n } else {\n resetForm()\n }\n setErrors({})\n setDialogOpen(true)\n },\n [appearance, readOnly, readOnlyMessage, resetForm],\n )\n\n const closeDialog = React.useCallback(() => {\n setDialogOpen(false)\n resetForm()\n setErrors({})\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n const trimmedValue = formState.value.trim()\n const trimmedLabel = formState.label.trim()\n const nextErrors: { value?: string } = {}\n if (!trimmedValue) {\n nextErrors.value = t('dictionaries.config.entries.error.required', 'Value is required.')\n }\n if (nextErrors.value) {\n setErrors(nextErrors)\n return\n }\n setErrors({})\n setIsSaving(true)\n try {\n const payload = {\n value: trimmedValue,\n label: trimmedLabel || trimmedValue,\n color: appearance.color,\n icon: appearance.icon,\n }\n if (formState.id) {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(formState.updatedAt),\n () =>\n apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${formState.id}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n ),\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to save dictionary entry'),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n flash(t('dictionaries.config.entries.success.update', 'Dictionary entry updated.'), 'success')\n } else {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary entry',\n )\n }\n flash(t('dictionaries.config.entries.success.create', 'Dictionary entry created.'), 'success')\n }\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n setDialogOpen(false)\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to save dictionary entry', err)\n flash(t('dictionaries.config.entries.error.save', 'Failed to save dictionary entry.'), 'error')\n } finally {\n setIsSaving(false)\n }\n }, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, queryClient, readOnly, readOnlyMessage, t])\n\n const handleDelete = React.useCallback(\n async (entry: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (!entry.id) return\n const confirmDelete = await confirm({\n title: t('dictionaries.config.entries.delete.confirm', 'Delete \"{{value}}\"?', { value: entry.label || entry.value }),\n variant: 'destructive',\n })\n if (!confirmDelete) return\n setIsDeleting(true)\n try {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () =>\n apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entry.id}`,\n { method: 'DELETE' },\n ),\n )\n if (!call.ok) {\n throw new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary entry',\n )\n }\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n flash(t('dictionaries.config.entries.success.delete', 'Dictionary entry deleted.'), 'success')\n } catch (err) {\n console.error('Failed to delete dictionary entry', err)\n flash(t('dictionaries.config.entries.error.delete', 'Failed to delete dictionary entry.'), 'error')\n } finally {\n setIsDeleting(false)\n }\n },\n [confirm, dictionaryId, queryClient, readOnly, readOnlyMessage, t],\n )\n\n const tableContent = React.useMemo(() => {\n if (isInitialLoading) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-8 text-center text-sm text-muted-foreground\">\n <Spinner className=\"mx-auto mb-2 h-5 w-5\" />\n {t('dictionaries.config.entries.loading', 'Loading entries\u2026')}\n </TableCell>\n </TableRow>\n )\n }\n if (loadError) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-destructive\">\n {loadError}\n </TableCell>\n </TableRow>\n )\n }\n if (!entries.length) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('dictionaries.config.entries.empty', 'No entries yet.')}\n </TableCell>\n </TableRow>\n )\n }\n return entries.map((entry) => (\n <TableRow key={entry.id}>\n <TableCell className=\"font-medium\">{entry.value}</TableCell>\n <TableCell>{entry.label}</TableCell>\n <TableCell>\n <DictionaryValue\n value={entry.value}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{t('dictionaries.config.entries.appearance.none', 'None')}</span>}\n />\n </TableCell>\n <TableCell className=\"flex items-center gap-2\">\n {readOnly ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('dictionaries.config.entries.readOnlyActions', 'Managed in parent organization')}\n </span>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openDialog(entry)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTranslateEntry(entry)}\n title={t('dictionaries.config.entries.actions.translate', 'Translate')}\n >\n <Languages className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(entry)}\n disabled={isDeleting}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </>\n )}\n </TableCell>\n </TableRow>\n ))\n }, [dictionaryMap, entries, handleDelete, isDeleting, isInitialLoading, loadError, openDialog, readOnly, t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">{dictionaryName}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {readOnly\n ? readOnlyMessage\n : t('dictionaries.config.entries.subtitle', 'Manage reusable values and appearance for this dictionary.')}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n dictionaryQuery.refetch().catch(() => {})\n }}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.refresh', 'Refresh')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => openDialog()}\n disabled={readOnly}\n title={readOnly ? readOnlyMessage : undefined}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.add', 'Add entry')}\n </Button>\n </div>\n </div>\n\n <div className=\"overflow-hidden rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.value', 'Value')}</TableHead>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.label', 'Label')}</TableHead>\n <TableHead>{t('dictionaries.config.entries.columns.appearance', 'Appearance')}</TableHead>\n <TableHead className=\"w-32 text-right\">{t('dictionaries.config.entries.columns.actions', 'Actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>{tableContent}</TableBody>\n </Table>\n </div>\n\n <Dialog open={dialogOpen} onOpenChange={(open) => (!open ? closeDialog() : undefined)}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {formState.id\n ? t('dictionaries.config.entries.dialog.editTitle', 'Edit dictionary entry')\n : t('dictionaries.config.entries.dialog.addTitle', 'Add dictionary entry')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.valueLabel', 'Value')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <Input\n type=\"text\"\n value={formState.value}\n onChange={(event) => {\n const nextValue = event.target.value\n setFormState((prev) => ({ ...prev, value: nextValue }))\n if (errors.value) {\n setErrors((prev) => ({ ...prev, value: undefined }))\n }\n }}\n aria-invalid={errors.value ? 'true' : 'false'}\n aria-describedby=\"dictionary-entry-value-error\"\n />\n {errors.value ? (\n <p id=\"dictionary-entry-value-error\" className=\"text-xs text-destructive\">\n {errors.value}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.labelLabel', 'Label')}\n </label>\n <Input\n type=\"text\"\n value={formState.label}\n onChange={(event) => setFormState((prev) => ({ ...prev, label: event.target.value }))}\n placeholder={t('dictionaries.config.entries.dialog.labelPlaceholder', 'Display name shown in UI')}\n />\n </div>\n <AppearanceSelector\n icon={appearance.icon}\n color={appearance.color}\n onIconChange={(next) => {\n appearance.setIcon(next)\n setFormState((prev) => ({ ...prev, icon: next }))\n }}\n onColorChange={(next) => {\n appearance.setColor(next)\n setFormState((prev) => ({ ...prev, color: next }))\n }}\n labels={{\n colorLabel: t('dictionaries.config.entries.dialog.colorLabel', 'Color'),\n colorHelp: t('dictionaries.config.entries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('dictionaries.config.entries.dialog.colorClear', 'Remove color'),\n iconLabel: t('dictionaries.config.entries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('dictionaries.config.entries.dialog.iconPlaceholder', 'Type an emoji or icon token.'),\n iconPickerTriggerLabel: t('dictionaries.config.entries.dialog.iconBrowse', 'Browse icons and emoji'),\n iconSearchPlaceholder: t('dictionaries.config.entries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('dictionaries.config.entries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('dictionaries.config.entries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('dictionaries.config.entries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('dictionaries.config.entries.dialog.previewEmpty', 'No appearance selected'),\n }}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={closeDialog}\n disabled={isSaving}\n >\n {t('dictionaries.config.entries.dialog.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.entries.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <Dialog open={!!translateEntry} onOpenChange={(open) => { if (!open) setTranslateEntry(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateEntry', 'Translate: {{label}}', { label: translateEntry?.label ?? '' })}</DialogTitle>\n <DialogDescription>\n {t('translations.manager.translateEntryDescription', 'Manage translations for this dictionary entry.')}\n </DialogDescription>\n </DialogHeader>\n {translateEntry?.id && (\n <TranslationManager\n mode=\"embedded\"\n entityType=\"dictionaries:dictionary_entry\"\n recordId={translateEntry.id}\n baseValues={{ label: translateEntry.label }}\n translatableFields={['label']}\n />\n )}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus, Pencil, Trash2, RefreshCw, Languages } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@open-mercato/ui/primitives/table'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { AppearanceSelector, useAppearanceState } from './AppearanceSelector'\nimport { DictionaryValue } from './dictionaryAppearance'\nimport {\n invalidateDictionaryEntries,\n useDictionaryEntries,\n} from './hooks/useDictionaryEntries'\nimport type { DictionaryEntryRecord } from './hooks/useDictionaryEntries'\nimport {\n DialogDescription,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Entry = DictionaryEntryRecord\n\ntype DictionaryEntriesEditorProps = {\n dictionaryId: string\n dictionaryName: string\n readOnly?: boolean\n}\n\ntype FormState = {\n id?: string | null\n value: string\n label: string\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\nexport function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = false }: DictionaryEntriesEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const readOnlyMessage = t('dictionaries.config.entries.readOnly', 'Inherited dictionaries are managed at the parent organization.')\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useDictionaryEntries(dictionaryId, scopeVersion)\n const entries = React.useMemo<Entry[]>(() => dictionaryQuery.data?.fullEntries ?? [], [dictionaryQuery.data?.fullEntries])\n const dictionaryMap = dictionaryQuery.data?.map ?? {}\n const isInitialLoading = dictionaryQuery.isLoading\n const loadError = dictionaryQuery.isError\n ? t('dictionaries.config.entries.error.load', 'Failed to load dictionary entries.')\n : null\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const [formState, setFormState] = React.useState<FormState>(() => ({\n value: '',\n label: '',\n color: null,\n icon: null,\n }))\n const [errors, setErrors] = React.useState<{ value?: string; label?: string }>({})\n const [translateEntry, setTranslateEntry] = React.useState<Entry | null>(null)\n const appearance = useAppearanceState(formState.icon, formState.color)\n const mutationContextId = React.useMemo(\n () => `dictionaries:dictionary_entry:${dictionaryId}`,\n [dictionaryId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId?: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const resetForm = React.useCallback(() => {\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n }, [appearance])\n\n const openDialog = React.useCallback(\n (entry?: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (entry) {\n setFormState({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n updatedAt: entry.updatedAt ?? null,\n })\n appearance.setColor(entry.color ?? null)\n appearance.setIcon(entry.icon ?? null)\n } else {\n resetForm()\n }\n setErrors({})\n setDialogOpen(true)\n },\n [appearance, readOnly, readOnlyMessage, resetForm],\n )\n\n const closeDialog = React.useCallback(() => {\n setDialogOpen(false)\n resetForm()\n setErrors({})\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n const trimmedValue = formState.value.trim()\n const trimmedLabel = formState.label.trim()\n const nextErrors: { value?: string } = {}\n if (!trimmedValue) {\n nextErrors.value = t('dictionaries.config.entries.error.required', 'Value is required.')\n }\n if (nextErrors.value) {\n setErrors(nextErrors)\n return\n }\n setErrors({})\n setIsSaving(true)\n try {\n const payload = {\n value: trimmedValue,\n label: trimmedLabel || trimmedValue,\n color: appearance.color,\n icon: appearance.icon,\n }\n if (formState.id) {\n const entryId = formState.id\n const expectedUpdatedAt = formState.updatedAt\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(expectedUpdatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entryId}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to save dictionary entry'),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entryId,\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.update', 'Dictionary entry updated.'), 'success')\n } else {\n await runMutation({\n operation: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary entry',\n )\n }\n return call\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.create', 'Dictionary entry created.'), 'success')\n }\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n setDialogOpen(false)\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to save dictionary entry', err)\n flash(t('dictionaries.config.entries.error.save', 'Failed to save dictionary entry.'), 'error')\n } finally {\n setIsSaving(false)\n }\n }, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t])\n\n const handleDelete = React.useCallback(\n async (entry: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (!entry.id) return\n const confirmDelete = await confirm({\n title: t('dictionaries.config.entries.delete.confirm', 'Delete \"{{value}}\"?', { value: entry.label || entry.value }),\n variant: 'destructive',\n })\n if (!confirmDelete) return\n setIsDeleting(true)\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entry.id}`,\n { method: 'DELETE' },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary entry',\n ),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entry.id,\n retryLastMutation,\n },\n mutationPayload: { id: entry.id },\n })\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n flash(t('dictionaries.config.entries.success.delete', 'Dictionary entry deleted.'), 'success')\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to delete dictionary entry', err)\n flash(t('dictionaries.config.entries.error.delete', 'Failed to delete dictionary entry.'), 'error')\n } finally {\n setIsDeleting(false)\n }\n },\n [confirm, dictionaryId, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t],\n )\n\n const tableContent = React.useMemo(() => {\n if (isInitialLoading) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-8 text-center text-sm text-muted-foreground\">\n <Spinner className=\"mx-auto mb-2 h-5 w-5\" />\n {t('dictionaries.config.entries.loading', 'Loading entries\u2026')}\n </TableCell>\n </TableRow>\n )\n }\n if (loadError) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-destructive\">\n {loadError}\n </TableCell>\n </TableRow>\n )\n }\n if (!entries.length) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('dictionaries.config.entries.empty', 'No entries yet.')}\n </TableCell>\n </TableRow>\n )\n }\n return entries.map((entry) => (\n <TableRow key={entry.id}>\n <TableCell className=\"font-medium\">{entry.value}</TableCell>\n <TableCell>{entry.label}</TableCell>\n <TableCell>\n <DictionaryValue\n value={entry.value}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{t('dictionaries.config.entries.appearance.none', 'None')}</span>}\n />\n </TableCell>\n <TableCell className=\"flex items-center gap-2\">\n {readOnly ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('dictionaries.config.entries.readOnlyActions', 'Managed in parent organization')}\n </span>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openDialog(entry)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTranslateEntry(entry)}\n title={t('dictionaries.config.entries.actions.translate', 'Translate')}\n >\n <Languages className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(entry)}\n disabled={isDeleting}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </>\n )}\n </TableCell>\n </TableRow>\n ))\n }, [dictionaryMap, entries, handleDelete, isDeleting, isInitialLoading, loadError, openDialog, readOnly, t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">{dictionaryName}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {readOnly\n ? readOnlyMessage\n : t('dictionaries.config.entries.subtitle', 'Manage reusable values and appearance for this dictionary.')}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n dictionaryQuery.refetch().catch(() => {})\n }}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.refresh', 'Refresh')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => openDialog()}\n disabled={readOnly}\n title={readOnly ? readOnlyMessage : undefined}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.add', 'Add entry')}\n </Button>\n </div>\n </div>\n\n <div className=\"overflow-hidden rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.value', 'Value')}</TableHead>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.label', 'Label')}</TableHead>\n <TableHead>{t('dictionaries.config.entries.columns.appearance', 'Appearance')}</TableHead>\n <TableHead className=\"w-32 text-right\">{t('dictionaries.config.entries.columns.actions', 'Actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>{tableContent}</TableBody>\n </Table>\n </div>\n\n <Dialog open={dialogOpen} onOpenChange={(open) => (!open ? closeDialog() : undefined)}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {formState.id\n ? t('dictionaries.config.entries.dialog.editTitle', 'Edit dictionary entry')\n : t('dictionaries.config.entries.dialog.addTitle', 'Add dictionary entry')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.valueLabel', 'Value')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <Input\n type=\"text\"\n value={formState.value}\n onChange={(event) => {\n const nextValue = event.target.value\n setFormState((prev) => ({ ...prev, value: nextValue }))\n if (errors.value) {\n setErrors((prev) => ({ ...prev, value: undefined }))\n }\n }}\n aria-invalid={errors.value ? 'true' : 'false'}\n aria-describedby=\"dictionary-entry-value-error\"\n />\n {errors.value ? (\n <p id=\"dictionary-entry-value-error\" className=\"text-xs text-destructive\">\n {errors.value}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.labelLabel', 'Label')}\n </label>\n <Input\n type=\"text\"\n value={formState.label}\n onChange={(event) => setFormState((prev) => ({ ...prev, label: event.target.value }))}\n placeholder={t('dictionaries.config.entries.dialog.labelPlaceholder', 'Display name shown in UI')}\n />\n </div>\n <AppearanceSelector\n icon={appearance.icon}\n color={appearance.color}\n onIconChange={(next) => {\n appearance.setIcon(next)\n setFormState((prev) => ({ ...prev, icon: next }))\n }}\n onColorChange={(next) => {\n appearance.setColor(next)\n setFormState((prev) => ({ ...prev, color: next }))\n }}\n labels={{\n colorLabel: t('dictionaries.config.entries.dialog.colorLabel', 'Color'),\n colorHelp: t('dictionaries.config.entries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('dictionaries.config.entries.dialog.colorClear', 'Remove color'),\n iconLabel: t('dictionaries.config.entries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('dictionaries.config.entries.dialog.iconPlaceholder', 'Type an emoji or icon token.'),\n iconPickerTriggerLabel: t('dictionaries.config.entries.dialog.iconBrowse', 'Browse icons and emoji'),\n iconSearchPlaceholder: t('dictionaries.config.entries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('dictionaries.config.entries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('dictionaries.config.entries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('dictionaries.config.entries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('dictionaries.config.entries.dialog.previewEmpty', 'No appearance selected'),\n }}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={closeDialog}\n disabled={isSaving}\n >\n {t('dictionaries.config.entries.dialog.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.entries.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <Dialog open={!!translateEntry} onOpenChange={(open) => { if (!open) setTranslateEntry(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateEntry', 'Translate: {{label}}', { label: translateEntry?.label ?? '' })}</DialogTitle>\n <DialogDescription>\n {t('translations.manager.translateEntryDescription', 'Manage translations for this dictionary entry.')}\n </DialogDescription>\n </DialogHeader>\n {translateEntry?.id && (\n <TranslationManager\n mode=\"embedded\"\n entityType=\"dictionaries:dictionary_entry\"\n recordId={translateEntry.id}\n baseValues={{ label: translateEntry.label }}\n translatableFields={['label']}\n />\n )}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
5
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
5
6
|
import { useQueryClient } from "@tanstack/react-query";
|
|
6
7
|
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
7
8
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -23,6 +24,14 @@ function DictionarySelectControl({
|
|
|
23
24
|
const t = useT();
|
|
24
25
|
const queryClient = useQueryClient();
|
|
25
26
|
const scopeVersion = useOrganizationScopeVersion();
|
|
27
|
+
const mutationContextId = React.useMemo(
|
|
28
|
+
() => `dictionaries:dictionary_entry:inline:${dictionaryId}`,
|
|
29
|
+
[dictionaryId]
|
|
30
|
+
);
|
|
31
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
32
|
+
contextId: mutationContextId,
|
|
33
|
+
blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
|
|
34
|
+
});
|
|
26
35
|
const [inlineCreateEnabled, setInlineCreateEnabled] = React.useState(allowInlineCreate);
|
|
27
36
|
React.useEffect(() => {
|
|
28
37
|
let cancelled = false;
|
|
@@ -94,24 +103,36 @@ function DictionarySelectControl({
|
|
|
94
103
|
}, [dictionaryId, normalizedPriority, queryClient, scopeVersion]);
|
|
95
104
|
const createOption = React.useCallback(
|
|
96
105
|
async (input) => {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
const payload = {
|
|
107
|
+
value: input.value,
|
|
108
|
+
label: input.label ?? input.value,
|
|
109
|
+
color: input.color,
|
|
110
|
+
icon: input.icon
|
|
111
|
+
};
|
|
112
|
+
const call = await runMutation({
|
|
113
|
+
operation: async () => {
|
|
114
|
+
const result = await apiCall(
|
|
115
|
+
`/api/dictionaries/${dictionaryId}/entries`,
|
|
116
|
+
{
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "content-type": "application/json" },
|
|
119
|
+
body: JSON.stringify(payload)
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
if (!result.ok) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
typeof result.result?.error === "string" ? result.result.error : "Failed to create dictionary entry"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
},
|
|
129
|
+
context: {
|
|
130
|
+
formId: mutationContextId,
|
|
131
|
+
resourceKind: "dictionaries.dictionary_entry",
|
|
132
|
+
retryLastMutation
|
|
133
|
+
},
|
|
134
|
+
mutationPayload: payload
|
|
135
|
+
});
|
|
115
136
|
await invalidateDictionaryEntries(queryClient, dictionaryId);
|
|
116
137
|
return {
|
|
117
138
|
value: String(call.result?.value ?? input.value),
|
|
@@ -120,7 +141,7 @@ function DictionarySelectControl({
|
|
|
120
141
|
icon: typeof call.result?.icon === "string" ? call.result.icon : null
|
|
121
142
|
};
|
|
122
143
|
},
|
|
123
|
-
[dictionaryId, queryClient]
|
|
144
|
+
[dictionaryId, mutationContextId, queryClient, runMutation, retryLastMutation]
|
|
124
145
|
);
|
|
125
146
|
const labels = React.useMemo(
|
|
126
147
|
() => ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/dictionaries/components/DictionarySelectControl.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DictionaryEntrySelect } from './DictionaryEntrySelect'\nimport {\n ensureDictionaryEntries,\n invalidateDictionaryEntries,\n} from './hooks/useDictionaryEntries'\n\ntype DictionarySelectControlProps = {\n dictionaryId: string\n value?: string | null\n onChange: (value: string | undefined) => void\n allowInlineCreate?: boolean\n selectClassName?: string\n disabled?: boolean\n priorityValues?: string[]\n seedOptions?: Array<{ value: string; label: string; color?: string | null; icon?: string | null }>\n}\n\nexport function DictionarySelectControl({\n dictionaryId,\n value,\n onChange,\n allowInlineCreate = true,\n selectClassName,\n disabled = false,\n priorityValues,\n seedOptions,\n}: DictionarySelectControlProps) {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const [inlineCreateEnabled, setInlineCreateEnabled] = React.useState<boolean>(allowInlineCreate)\n\n React.useEffect(() => {\n let cancelled = false\n async function evaluateInlineCreate() {\n if (!allowInlineCreate) {\n setInlineCreateEnabled(false)\n return\n }\n try {\n const call = await apiCall<{ isInherited?: boolean }>(`/api/dictionaries/${dictionaryId}`)\n if (cancelled) return\n if (call.ok && call.result && call.result.isInherited === true) {\n setInlineCreateEnabled(false)\n return\n }\n setInlineCreateEnabled(true)\n } catch (err) {\n console.warn('DictionarySelectControl.inlineCreate check failed', err)\n if (!cancelled) {\n setInlineCreateEnabled(allowInlineCreate)\n }\n }\n }\n evaluateInlineCreate().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [allowInlineCreate, dictionaryId, scopeVersion])\n\n const effectiveAllowInlineCreate = allowInlineCreate && inlineCreateEnabled\n\n const normalizedPriority = React.useMemo(() => {\n if (!Array.isArray(priorityValues) || !priorityValues.length) return []\n const seen = new Set<string>()\n const ordered: string[] = []\n priorityValues.forEach((code) => {\n if (typeof code !== 'string') return\n const normalized = code.trim().toLowerCase()\n if (!normalized.length || seen.has(normalized)) return\n seen.add(normalized)\n ordered.push(normalized)\n })\n return ordered\n }, [priorityValues])\n\n const fetchOptions = React.useCallback(async () => {\n const data = await ensureDictionaryEntries(queryClient, dictionaryId, scopeVersion)\n const options = data.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n if (!normalizedPriority.length) return options\n const byValue = new Map<string, (typeof options)[number]>()\n options.forEach((option) => {\n const key = option.value.trim().toLowerCase()\n if (!byValue.has(key)) byValue.set(key, option)\n })\n const prioritized: typeof options = []\n normalizedPriority.forEach((key) => {\n const match = byValue.get(key)\n if (match) {\n prioritized.push(match)\n byValue.delete(key)\n }\n })\n const remaining: typeof options = []\n byValue.forEach((option) => remaining.push(option))\n return [...prioritized, ...remaining]\n }, [dictionaryId, normalizedPriority, queryClient, scopeVersion])\n\n const createOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const call = await apiCall<Record<string, unknown>>(\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DictionaryEntrySelect } from './DictionaryEntrySelect'\nimport {\n ensureDictionaryEntries,\n invalidateDictionaryEntries,\n} from './hooks/useDictionaryEntries'\n\ntype DictionarySelectControlProps = {\n dictionaryId: string\n value?: string | null\n onChange: (value: string | undefined) => void\n allowInlineCreate?: boolean\n selectClassName?: string\n disabled?: boolean\n priorityValues?: string[]\n seedOptions?: Array<{ value: string; label: string; color?: string | null; icon?: string | null }>\n}\n\nexport function DictionarySelectControl({\n dictionaryId,\n value,\n onChange,\n allowInlineCreate = true,\n selectClassName,\n disabled = false,\n priorityValues,\n seedOptions,\n}: DictionarySelectControlProps) {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const mutationContextId = React.useMemo(\n () => `dictionaries:dictionary_entry:inline:${dictionaryId}`,\n [dictionaryId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const [inlineCreateEnabled, setInlineCreateEnabled] = React.useState<boolean>(allowInlineCreate)\n\n React.useEffect(() => {\n let cancelled = false\n async function evaluateInlineCreate() {\n if (!allowInlineCreate) {\n setInlineCreateEnabled(false)\n return\n }\n try {\n const call = await apiCall<{ isInherited?: boolean }>(`/api/dictionaries/${dictionaryId}`)\n if (cancelled) return\n if (call.ok && call.result && call.result.isInherited === true) {\n setInlineCreateEnabled(false)\n return\n }\n setInlineCreateEnabled(true)\n } catch (err) {\n console.warn('DictionarySelectControl.inlineCreate check failed', err)\n if (!cancelled) {\n setInlineCreateEnabled(allowInlineCreate)\n }\n }\n }\n evaluateInlineCreate().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [allowInlineCreate, dictionaryId, scopeVersion])\n\n const effectiveAllowInlineCreate = allowInlineCreate && inlineCreateEnabled\n\n const normalizedPriority = React.useMemo(() => {\n if (!Array.isArray(priorityValues) || !priorityValues.length) return []\n const seen = new Set<string>()\n const ordered: string[] = []\n priorityValues.forEach((code) => {\n if (typeof code !== 'string') return\n const normalized = code.trim().toLowerCase()\n if (!normalized.length || seen.has(normalized)) return\n seen.add(normalized)\n ordered.push(normalized)\n })\n return ordered\n }, [priorityValues])\n\n const fetchOptions = React.useCallback(async () => {\n const data = await ensureDictionaryEntries(queryClient, dictionaryId, scopeVersion)\n const options = data.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n if (!normalizedPriority.length) return options\n const byValue = new Map<string, (typeof options)[number]>()\n options.forEach((option) => {\n const key = option.value.trim().toLowerCase()\n if (!byValue.has(key)) byValue.set(key, option)\n })\n const prioritized: typeof options = []\n normalizedPriority.forEach((key) => {\n const match = byValue.get(key)\n if (match) {\n prioritized.push(match)\n byValue.delete(key)\n }\n })\n const remaining: typeof options = []\n byValue.forEach((option) => remaining.push(option))\n return [...prioritized, ...remaining]\n }, [dictionaryId, normalizedPriority, queryClient, scopeVersion])\n\n const createOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const payload = {\n value: input.value,\n label: input.label ?? input.value,\n color: input.color,\n icon: input.icon,\n }\n const call = await runMutation({\n operation: async () => {\n const result = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!result.ok) {\n throw new Error(\n typeof result.result?.error === 'string' ? result.result.error : 'Failed to create dictionary entry',\n )\n }\n return result\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n return {\n value: String(call.result?.value ?? input.value),\n label:\n typeof call.result?.label === 'string' && call.result.label.length\n ? call.result.label\n : String(call.result?.value ?? input.value),\n color: typeof call.result?.color === 'string' ? call.result.color : null,\n icon: typeof call.result?.icon === 'string' ? call.result.icon : null,\n }\n },\n [dictionaryId, mutationContextId, queryClient, runMutation, retryLastMutation],\n )\n\n const labels = React.useMemo(\n () => ({\n placeholder: t('dictionaries.customFields.selector.placeholder', 'Select an entry'),\n addLabel: t('dictionaries.customFields.selector.add', 'Add entry'),\n addPrompt: t('dictionaries.customFields.selector.dialogDescription', 'Create a new entry and reuse it across records.'),\n dialogTitle: t('dictionaries.config.entries.dialog.addTitle', 'Add dictionary entry'),\n valueLabel: t('dictionaries.config.entries.dialog.valueLabel', 'Value'),\n valuePlaceholder: t('dictionaries.config.entries.dialog.valueLabel', 'Value'),\n labelLabel: t('dictionaries.config.entries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('dictionaries.config.entries.dialog.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('dictionaries.config.entries.error.required', 'Value is required.'),\n cancelLabel: t('dictionaries.config.entries.dialog.cancel', 'Cancel'),\n saveLabel: t('dictionaries.config.entries.dialog.save', 'Save'),\n saveShortcutHint: t('dictionaries.config.entries.dialog.saveShortcut', '\u2318/Ctrl + Enter'),\n successCreateLabel: t('dictionaries.config.entries.success.create', 'Dictionary entry created.'),\n errorLoad: t('dictionaries.config.entries.error.load', 'Failed to load dictionary entries.'),\n errorSave: t('dictionaries.config.entries.error.save', 'Failed to save dictionary entry.'),\n loadingLabel: t('dictionaries.config.entries.loading', 'Loading entries\u2026'),\n manageTitle: t('dictionaries.customFields.manageLink', 'Manage dictionaries'),\n }),\n [t],\n )\n\n const appearanceLabels = React.useMemo(\n () => ({\n colorLabel: t('dictionaries.config.entries.dialog.colorLabel', 'Color'),\n colorHelp: t('dictionaries.config.entries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('dictionaries.config.entries.dialog.colorClear', 'Remove color'),\n iconLabel: t('dictionaries.config.entries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('dictionaries.config.entries.dialog.iconPlaceholder', 'Type an emoji or icon token.'),\n iconPickerTriggerLabel: t('dictionaries.config.entries.dialog.iconBrowse', 'Browse icons and emoji'),\n iconSearchPlaceholder: t('dictionaries.config.entries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('dictionaries.config.entries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('dictionaries.config.entries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('dictionaries.config.entries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('dictionaries.config.entries.dialog.previewEmpty', 'No appearance selected'),\n }),\n [t],\n )\n\n return (\n <DictionaryEntrySelect\n value={typeof value === 'string' ? value : undefined}\n onChange={onChange}\n fetchOptions={fetchOptions}\n createOption={effectiveAllowInlineCreate ? createOption : undefined}\n labels={labels}\n appearanceLabels={appearanceLabels}\n allowAppearance\n allowInlineCreate={effectiveAllowInlineCreate}\n selectClassName={selectClassName}\n seedOptions={seedOptions?.map((option) => ({\n value: option.value,\n label: option.label,\n color: option.color ?? null,\n icon: option.icon ?? null,\n }))}\n sortOptions=\"none\"\n disabled={disabled}\n manageHref=\"/backend/config/dictionaries\"\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.6-develop.
|
|
3
|
+
"version": "0.6.6-develop.6204.1.30b1f58642",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -246,16 +246,16 @@
|
|
|
246
246
|
"zod": "^4.4.3"
|
|
247
247
|
},
|
|
248
248
|
"peerDependencies": {
|
|
249
|
-
"@open-mercato/ai-assistant": "0.6.6-develop.
|
|
250
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
251
|
-
"@open-mercato/ui": "0.6.6-develop.
|
|
249
|
+
"@open-mercato/ai-assistant": "0.6.6-develop.6204.1.30b1f58642",
|
|
250
|
+
"@open-mercato/shared": "0.6.6-develop.6204.1.30b1f58642",
|
|
251
|
+
"@open-mercato/ui": "0.6.6-develop.6204.1.30b1f58642",
|
|
252
252
|
"react": "^19.0.0",
|
|
253
253
|
"react-dom": "^19.0.0"
|
|
254
254
|
},
|
|
255
255
|
"devDependencies": {
|
|
256
|
-
"@open-mercato/ai-assistant": "0.6.6-develop.
|
|
257
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
258
|
-
"@open-mercato/ui": "0.6.6-develop.
|
|
256
|
+
"@open-mercato/ai-assistant": "0.6.6-develop.6204.1.30b1f58642",
|
|
257
|
+
"@open-mercato/shared": "0.6.6-develop.6204.1.30b1f58642",
|
|
258
|
+
"@open-mercato/ui": "0.6.6-develop.6204.1.30b1f58642",
|
|
259
259
|
"@testing-library/dom": "^10.4.1",
|
|
260
260
|
"@testing-library/jest-dom": "^6.9.1",
|
|
261
261
|
"@testing-library/react": "^16.3.1",
|