@open-mercato/core 0.6.4-develop.4363.1.2f376570ae → 0.6.4-develop.4368.1.2f7e9a7002

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.
Files changed (61) hide show
  1. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +66 -44
  2. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  3. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +124 -103
  4. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  5. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +26 -4
  6. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  7. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +24 -4
  8. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  9. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +35 -6
  10. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
  11. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +67 -47
  12. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  13. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +29 -6
  14. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  15. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +29 -6
  16. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  17. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +33 -4
  18. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  19. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +33 -4
  20. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  21. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +37 -8
  22. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +3 -3
  23. package/dist/modules/workflows/backend/definitions/[id]/page.js +24 -6
  24. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  25. package/package.json +7 -7
  26. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +39 -8
  27. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +38 -6
  28. package/src/modules/catalog/i18n/de.json +2 -0
  29. package/src/modules/catalog/i18n/en.json +2 -0
  30. package/src/modules/catalog/i18n/es.json +2 -0
  31. package/src/modules/catalog/i18n/pl.json +2 -0
  32. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +30 -4
  33. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +28 -6
  34. package/src/modules/directory/i18n/de.json +2 -0
  35. package/src/modules/directory/i18n/en.json +2 -0
  36. package/src/modules/directory/i18n/es.json +2 -0
  37. package/src/modules/directory/i18n/pl.json +2 -0
  38. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +44 -4
  39. package/src/modules/planner/i18n/de.json +1 -0
  40. package/src/modules/planner/i18n/en.json +1 -0
  41. package/src/modules/planner/i18n/es.json +1 -0
  42. package/src/modules/planner/i18n/pl.json +1 -0
  43. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +36 -7
  44. package/src/modules/sales/i18n/de.json +1 -0
  45. package/src/modules/sales/i18n/en.json +1 -0
  46. package/src/modules/sales/i18n/es.json +1 -0
  47. package/src/modules/sales/i18n/pl.json +1 -0
  48. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +33 -6
  49. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +33 -6
  50. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +44 -4
  51. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +44 -4
  52. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +44 -4
  53. package/src/modules/staff/i18n/de.json +5 -0
  54. package/src/modules/staff/i18n/en.json +5 -0
  55. package/src/modules/staff/i18n/es.json +5 -0
  56. package/src/modules/staff/i18n/pl.json +5 -0
  57. package/src/modules/workflows/backend/definitions/[id]/page.tsx +26 -3
  58. package/src/modules/workflows/i18n/de.json +1 -0
  59. package/src/modules/workflows/i18n/en.json +1 -0
  60. package/src/modules/workflows/i18n/es.json +1 -0
  61. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -7,6 +7,7 @@ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
7
7
  import { updateCrud, deleteCrud } from "@open-mercato/ui/backend/utils/crud";
8
8
  import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
9
9
  import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
10
+ import { ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
10
11
  import { useT } from "@open-mercato/shared/lib/i18n/context";
11
12
  import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
12
13
  import { E } from "../../../../../../../generated/entities.ids.generated.js";
@@ -46,19 +47,30 @@ function EditCatalogCategoryPage({ params }) {
46
47
  const [pathLabel, setPathLabel] = React.useState("");
47
48
  const [loading, setLoading] = React.useState(true);
48
49
  const [error, setError] = React.useState(null);
50
+ const [isNotFound, setIsNotFound] = React.useState(false);
49
51
  React.useEffect(() => {
50
52
  if (!categoryId) return;
51
53
  let cancelled = false;
52
54
  async function load() {
53
55
  setLoading(true);
54
56
  setError(null);
57
+ setIsNotFound(false);
55
58
  try {
56
- const { ok, result } = await apiCall(
59
+ const { ok, status, result } = await apiCall(
57
60
  `/api/catalog/categories?view=manage&ids=${encodeURIComponent(categoryId)}&status=all&page=1&pageSize=1`
58
61
  );
59
- if (!ok) throw new Error(t("catalog.categories.form.errors.load", "Failed to load category"));
62
+ if (!ok) {
63
+ if (status === 404) {
64
+ if (!cancelled) setIsNotFound(true);
65
+ return;
66
+ }
67
+ throw new Error(t("catalog.categories.form.errors.load", "Failed to load category"));
68
+ }
60
69
  const record = Array.isArray(result?.items) ? result.items?.[0] : null;
61
- if (!record) throw new Error(t("catalog.categories.form.errors.notFound", "Category not found"));
70
+ if (!record) {
71
+ if (!cancelled) setIsNotFound(true);
72
+ return;
73
+ }
62
74
  if (cancelled) return;
63
75
  const customValues = extractCustomFieldEntries(record);
64
76
  setInitialValues({
@@ -144,50 +156,60 @@ function EditCatalogCategoryPage({ params }) {
144
156
  if (!categoryId) {
145
157
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: t("catalog.categories.form.errors.idRequired", "Category identifier is required.") }) }) });
146
158
  }
147
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs(PageBody, { children: [
148
- error ? /* @__PURE__ */ jsx("div", { className: "mb-4 rounded border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error }) : null,
149
- /* @__PURE__ */ jsx(
150
- CrudForm,
159
+ if (isNotFound) {
160
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
161
+ RecordNotFoundState,
151
162
  {
152
- title: t("catalog.categories.form.editTitle", "Edit category"),
163
+ label: t("catalog.categories.form.errors.notFound", "Category not found"),
153
164
  backHref: "/backend/catalog/categories",
154
- versionHistory: { resourceKind: "catalog.category", resourceId: categoryId ? String(categoryId) : "" },
155
- fields,
156
- groups,
157
- entityId: E.catalog.catalog_product_category,
158
- initialValues: initialValues ?? { id: categoryId, name: "", slug: "", description: "", parentId: "", isActive: true },
159
- isLoading: loading,
160
- loadingMessage: t("catalog.categories.form.loading", "Loading category..."),
161
- submitLabel: t("catalog.categories.form.action.save", "Save"),
162
- cancelHref: "/backend/catalog/categories",
163
- successRedirect: `/backend/catalog/categories?flash=${encodeURIComponent(t("catalog.categories.flash.updated", "Category updated"))}&type=success`,
164
- extraActions: /* @__PURE__ */ jsxs(Fragment, { children: [
165
- /* @__PURE__ */ jsx(
166
- SendObjectMessageDialog,
167
- {
168
- object: {
169
- entityModule: "catalog",
170
- entityType: "category",
171
- entityId: categoryId,
172
- previewData: { title: initialValues?.name ?? categoryId }
173
- },
174
- viewHref: `/backend/catalog/categories/${categoryId}/edit`
175
- }
176
- ),
177
- pathLabel ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("catalog.categories.form.pathLabel", { path: pathLabel }) }) : null
178
- ] }),
179
- onSubmit: async (values) => {
180
- await submitCategoryUpdate(categoryId, values, t);
181
- },
182
- onDelete: async () => {
183
- await deleteCrud("catalog/categories", categoryId, {
184
- errorMessage: t("catalog.categories.form.errors.delete", "Failed to delete category")
185
- });
186
- },
187
- deleteRedirect: `/backend/catalog/categories?flash=${encodeURIComponent(t("catalog.categories.flash.deleted", "Category archived"))}&type=success`
165
+ backLabel: t("catalog.categories.form.actions.backToList", "Back to categories")
188
166
  }
189
- )
190
- ] }) });
167
+ ) }) });
168
+ }
169
+ if (error && !loading) {
170
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error }) }) });
171
+ }
172
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
173
+ CrudForm,
174
+ {
175
+ title: t("catalog.categories.form.editTitle", "Edit category"),
176
+ backHref: "/backend/catalog/categories",
177
+ versionHistory: { resourceKind: "catalog.category", resourceId: categoryId ? String(categoryId) : "" },
178
+ fields,
179
+ groups,
180
+ entityId: E.catalog.catalog_product_category,
181
+ initialValues: initialValues ?? { id: categoryId, name: "", slug: "", description: "", parentId: "", isActive: true },
182
+ isLoading: loading,
183
+ loadingMessage: t("catalog.categories.form.loading", "Loading category..."),
184
+ submitLabel: t("catalog.categories.form.action.save", "Save"),
185
+ cancelHref: "/backend/catalog/categories",
186
+ successRedirect: `/backend/catalog/categories?flash=${encodeURIComponent(t("catalog.categories.flash.updated", "Category updated"))}&type=success`,
187
+ extraActions: /* @__PURE__ */ jsxs(Fragment, { children: [
188
+ /* @__PURE__ */ jsx(
189
+ SendObjectMessageDialog,
190
+ {
191
+ object: {
192
+ entityModule: "catalog",
193
+ entityType: "category",
194
+ entityId: categoryId,
195
+ previewData: { title: initialValues?.name ?? categoryId }
196
+ },
197
+ viewHref: `/backend/catalog/categories/${categoryId}/edit`
198
+ }
199
+ ),
200
+ pathLabel ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("catalog.categories.form.pathLabel", { path: pathLabel }) }) : null
201
+ ] }),
202
+ onSubmit: async (values) => {
203
+ await submitCategoryUpdate(categoryId, values, t);
204
+ },
205
+ onDelete: async () => {
206
+ await deleteCrud("catalog/categories", categoryId, {
207
+ errorMessage: t("catalog.categories.form.errors.delete", "Failed to delete category")
208
+ });
209
+ },
210
+ deleteRedirect: `/backend/catalog/categories?flash=${encodeURIComponent(t("catalog.categories.flash.deleted", "Category archived"))}&type=success`
211
+ }
212
+ ) }) });
191
213
  }
192
214
  export {
193
215
  EditCatalogCategoryPage as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/catalog/backend/catalog/categories/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { CategorySelect } from '../../../../../components/categories/CategorySelect'\nimport { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n isActive: boolean\n pathLabel?: string\n}\n\ntype CategoryResponse = {\n items?: CategoryRow[]\n}\n\ntype CategoryFormValues = {\n id?: string\n name: string\n slug?: string\n description?: string\n parentId?: string | null\n isActive?: boolean\n}\n\nasync function submitCategoryUpdate(\n categoryId: string,\n values: CategoryFormValues,\n t: (key: string, fallback?: string) => string,\n) {\n const resolvedId = typeof values.id === 'string' && values.id.length ? values.id : categoryId\n if (!resolvedId) {\n const message = t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')\n throw createCrudFormError(message, { id: message })\n }\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (!name) {\n const message = t('catalog.categories.form.errors.name', 'Provide the category name.')\n throw createCrudFormError(message, { name: message })\n }\n const slug = typeof values.slug === 'string' && values.slug.trim().length ? values.slug.trim() : undefined\n const description =\n typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : undefined\n const parentId =\n typeof values.parentId === 'string' && values.parentId.trim().length\n ? values.parentId.trim()\n : null\n const customFields = collectCustomFieldValues(values as Record<string, unknown>)\n const payload: Record<string, unknown> = {\n id: resolvedId,\n name,\n slug,\n description,\n parentId,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n await updateCrud('catalog/categories', payload)\n}\n\nexport default function EditCatalogCategoryPage({ params }: { params?: { id?: string } }) {\n const categoryId = params?.id ?? ''\n const t = useT()\n const [initialValues, setInitialValues] = React.useState<CategoryFormValues | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [loading, setLoading] = React.useState<boolean>(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n if (!categoryId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const { ok, result } = await apiCall<CategoryResponse>(\n `/api/catalog/categories?view=manage&ids=${encodeURIComponent(categoryId)}&status=all&page=1&pageSize=1`,\n )\n if (!ok) throw new Error(t('catalog.categories.form.errors.load', 'Failed to load category'))\n const record = Array.isArray(result?.items) ? result.items?.[0] : null\n if (!record) throw new Error(t('catalog.categories.form.errors.notFound', 'Category not found'))\n if (cancelled) return\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n description: record.description ?? '',\n parentId: record.parentId ?? '',\n isActive: record.isActive,\n ...customValues,\n })\n setPathLabel(record.pathLabel ?? '')\n } catch (err) {\n if (!cancelled) {\n const fallback = t('catalog.categories.form.errors.load', 'Failed to load category')\n const message = err instanceof Error ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [categoryId, t])\n\n const fields = React.useMemo<CrudField[]>(() => [\n {\n id: 'name',\n label: t('catalog.categories.form.field.name', 'Name'),\n type: 'text',\n required: true,\n placeholder: t('catalog.categories.form.field.namePlaceholder', 'e.g., Footwear'),\n },\n {\n id: 'slug',\n label: t('catalog.categories.form.field.slug', 'Slug'),\n type: 'text',\n description: t('catalog.categories.form.field.slugHelp', 'Lowercase identifier for URLs or imports.'),\n },\n {\n id: 'description',\n label: t('catalog.categories.form.field.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'parentId',\n label: t('catalog.categories.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <CategorySelect\n id={id}\n value={typeof value === 'string' ? value : null}\n onChange={(next) => setValue(next ?? '')}\n includeEmptyOption\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'isActive',\n label: t('catalog.categories.form.field.isActive', 'Active'),\n type: 'checkbox',\n },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n {\n id: 'details',\n title: t('catalog.categories.form.group.details', 'Details'),\n column: 1,\n fields: ['name', 'slug', 'description', 'parentId', 'isActive'],\n component: (ctx) => <CategorySlugFieldSync {...ctx} />,\n },\n {\n id: 'custom',\n title: t('catalog.categories.form.group.custom', 'Custom data'),\n column: 2,\n kind: 'customFields',\n },\n ], [t])\n\n if (!categoryId) {\n return (\n <Page>\n <PageBody>\n <p className=\"text-sm text-destructive\">\n {t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')}\n </p>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n {error ? (\n <div className=\"mb-4 rounded border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n ) : null}\n <CrudForm<CategoryFormValues>\n title={t('catalog.categories.form.editTitle', 'Edit category')}\n backHref=\"/backend/catalog/categories\"\n versionHistory={{ resourceKind: 'catalog.category', resourceId: categoryId ? String(categoryId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.catalog.catalog_product_category}\n initialValues={initialValues ?? { id: categoryId, name: '', slug: '', description: '', parentId: '', isActive: true }}\n isLoading={loading}\n loadingMessage={t('catalog.categories.form.loading', 'Loading category...')}\n submitLabel={t('catalog.categories.form.action.save', 'Save')}\n cancelHref=\"/backend/catalog/categories\"\n successRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.updated', 'Category updated'))}&type=success`}\n extraActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'category',\n entityId: categoryId,\n previewData: { title: initialValues?.name ?? categoryId },\n }}\n viewHref={`/backend/catalog/categories/${categoryId}/edit`}\n />\n {pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('catalog.categories.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n </>\n )}\n onSubmit={async (values) => {\n await submitCategoryUpdate(categoryId, values, t)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/categories', categoryId, {\n errorMessage: t('catalog.categories.form.errors.delete', 'Failed to delete category'),\n })\n }}\n deleteRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.deleted', 'Category archived'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { CategorySelect } from '../../../../../components/categories/CategorySelect'\nimport { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n isActive: boolean\n pathLabel?: string\n}\n\ntype CategoryResponse = {\n items?: CategoryRow[]\n}\n\ntype CategoryFormValues = {\n id?: string\n name: string\n slug?: string\n description?: string\n parentId?: string | null\n isActive?: boolean\n}\n\nasync function submitCategoryUpdate(\n categoryId: string,\n values: CategoryFormValues,\n t: (key: string, fallback?: string) => string,\n) {\n const resolvedId = typeof values.id === 'string' && values.id.length ? values.id : categoryId\n if (!resolvedId) {\n const message = t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')\n throw createCrudFormError(message, { id: message })\n }\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (!name) {\n const message = t('catalog.categories.form.errors.name', 'Provide the category name.')\n throw createCrudFormError(message, { name: message })\n }\n const slug = typeof values.slug === 'string' && values.slug.trim().length ? values.slug.trim() : undefined\n const description =\n typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : undefined\n const parentId =\n typeof values.parentId === 'string' && values.parentId.trim().length\n ? values.parentId.trim()\n : null\n const customFields = collectCustomFieldValues(values as Record<string, unknown>)\n const payload: Record<string, unknown> = {\n id: resolvedId,\n name,\n slug,\n description,\n parentId,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n await updateCrud('catalog/categories', payload)\n}\n\nexport default function EditCatalogCategoryPage({ params }: { params?: { id?: string } }) {\n const categoryId = params?.id ?? ''\n const t = useT()\n const [initialValues, setInitialValues] = React.useState<CategoryFormValues | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [loading, setLoading] = React.useState<boolean>(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState<boolean>(false)\n\n React.useEffect(() => {\n if (!categoryId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const { ok, status, result } = await apiCall<CategoryResponse>(\n `/api/catalog/categories?view=manage&ids=${encodeURIComponent(categoryId)}&status=all&page=1&pageSize=1`,\n )\n if (!ok) {\n if (status === 404) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n throw new Error(t('catalog.categories.form.errors.load', 'Failed to load category'))\n }\n const record = Array.isArray(result?.items) ? result.items?.[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n if (cancelled) return\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n description: record.description ?? '',\n parentId: record.parentId ?? '',\n isActive: record.isActive,\n ...customValues,\n })\n setPathLabel(record.pathLabel ?? '')\n } catch (err) {\n if (!cancelled) {\n const fallback = t('catalog.categories.form.errors.load', 'Failed to load category')\n const message = err instanceof Error ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [categoryId, t])\n\n const fields = React.useMemo<CrudField[]>(() => [\n {\n id: 'name',\n label: t('catalog.categories.form.field.name', 'Name'),\n type: 'text',\n required: true,\n placeholder: t('catalog.categories.form.field.namePlaceholder', 'e.g., Footwear'),\n },\n {\n id: 'slug',\n label: t('catalog.categories.form.field.slug', 'Slug'),\n type: 'text',\n description: t('catalog.categories.form.field.slugHelp', 'Lowercase identifier for URLs or imports.'),\n },\n {\n id: 'description',\n label: t('catalog.categories.form.field.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'parentId',\n label: t('catalog.categories.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <CategorySelect\n id={id}\n value={typeof value === 'string' ? value : null}\n onChange={(next) => setValue(next ?? '')}\n includeEmptyOption\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'isActive',\n label: t('catalog.categories.form.field.isActive', 'Active'),\n type: 'checkbox',\n },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n {\n id: 'details',\n title: t('catalog.categories.form.group.details', 'Details'),\n column: 1,\n fields: ['name', 'slug', 'description', 'parentId', 'isActive'],\n component: (ctx) => <CategorySlugFieldSync {...ctx} />,\n },\n {\n id: 'custom',\n title: t('catalog.categories.form.group.custom', 'Custom data'),\n column: 2,\n kind: 'customFields',\n },\n ], [t])\n\n if (!categoryId) {\n return (\n <Page>\n <PageBody>\n <p className=\"text-sm text-destructive\">\n {t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')}\n </p>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('catalog.categories.form.errors.notFound', 'Category not found')}\n backHref=\"/backend/catalog/categories\"\n backLabel={t('catalog.categories.form.actions.backToList', 'Back to categories')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<CategoryFormValues>\n title={t('catalog.categories.form.editTitle', 'Edit category')}\n backHref=\"/backend/catalog/categories\"\n versionHistory={{ resourceKind: 'catalog.category', resourceId: categoryId ? String(categoryId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.catalog.catalog_product_category}\n initialValues={initialValues ?? { id: categoryId, name: '', slug: '', description: '', parentId: '', isActive: true }}\n isLoading={loading}\n loadingMessage={t('catalog.categories.form.loading', 'Loading category...')}\n submitLabel={t('catalog.categories.form.action.save', 'Save')}\n cancelHref=\"/backend/catalog/categories\"\n successRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.updated', 'Category updated'))}&type=success`}\n extraActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'category',\n entityId: categoryId,\n previewData: { title: initialValues?.name ?? categoryId },\n }}\n viewHref={`/backend/catalog/categories/${categoryId}/edit`}\n />\n {pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('catalog.categories.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n </>\n )}\n onSubmit={async (values) => {\n await submitCategoryUpdate(categoryId, values, t)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/categories', categoryId, {\n errorMessage: t('catalog.categories.form.errors.delete', 'Failed to delete category'),\n })\n }}\n deleteRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.deleted', 'Category archived'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": ";AAiKQ,SAqFI,UArFJ,KAqFI,YArFJ;AA/JR,YAAY,WAAW;AACvB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gBAAoD;AAC7D,SAAS,eAAe;AACxB,SAAS,YAAY,kBAAkB;AACvC,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AACzC,SAAS,cAAc,2BAA2B;AAClD,SAAS,YAAY;AACrB,SAAS,iCAAiC;AAC1C,SAAS,SAAS;AAClB,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AAyBxC,eAAe,qBACb,YACA,QACA,GACA;AACA,QAAM,aAAa,OAAO,OAAO,OAAO,YAAY,OAAO,GAAG,SAAS,OAAO,KAAK;AACnF,MAAI,CAAC,YAAY;AACf,UAAM,UAAU,EAAE,6CAA6C,kCAAkC;AACjG,UAAM,oBAAoB,SAAS,EAAE,IAAI,QAAQ,CAAC;AAAA,EACpD;AACA,QAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,IAAI;AACpE,MAAI,CAAC,MAAM;AACT,UAAM,UAAU,EAAE,uCAAuC,4BAA4B;AACrF,UAAM,oBAAoB,SAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,EACtD;AACA,QAAM,OAAO,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,KAAK,EAAE,SAAS,OAAO,KAAK,KAAK,IAAI;AACjG,QAAM,cACJ,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,KAAK,EAAE,SAChE,OAAO,YAAY,KAAK,IACxB;AACN,QAAM,WACJ,OAAO,OAAO,aAAa,YAAY,OAAO,SAAS,KAAK,EAAE,SAC1D,OAAO,SAAS,KAAK,IACrB;AACN,QAAM,eAAe,yBAAyB,MAAiC;AAC/E,QAAM,UAAmC;AAAA,IACvC,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,OAAO,aAAa;AAAA,EAChC;AACA,MAAI,OAAO,KAAK,YAAY,EAAE,SAAS,EAAG,SAAQ,eAAe;AACjE,QAAM,WAAW,sBAAsB,OAAO;AAChD;AAEe,SAAR,wBAAyC,EAAE,OAAO,GAAiC;AACxF,QAAM,aAAa,QAAQ,MAAM;AACjC,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAoC,IAAI;AACxF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAiB,EAAE;AAC3D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAkB,IAAI;AAC1D,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAkB,KAAK;AAEjE,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,WAAY;AACjB,QAAI,YAAY;AAChB,mBAAe,OAAO;AACpB,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,oBAAc,KAAK;AACnB,UAAI;AACF,cAAM,EAAE,IAAI,QAAQ,OAAO,IAAI,MAAM;AAAA,UACnC,2CAA2C,mBAAmB,UAAU,CAAC;AAAA,QAC3E;AACA,YAAI,CAAC,IAAI;AACP,cAAI,WAAW,KAAK;AAClB,gBAAI,CAAC,UAAW,eAAc,IAAI;AAClC;AAAA,UACF;AACA,gBAAM,IAAI,MAAM,EAAE,uCAAuC,yBAAyB,CAAC;AAAA,QACrF;AACA,cAAM,SAAS,MAAM,QAAQ,QAAQ,KAAK,IAAI,OAAO,QAAQ,CAAC,IAAI;AAClE,YAAI,CAAC,QAAQ;AACX,cAAI,CAAC,UAAW,eAAc,IAAI;AAClC;AAAA,QACF;AACA,YAAI,UAAW;AACf,cAAM,eAAe,0BAA0B,MAAiC;AAChF,yBAAiB;AAAA,UACf,IAAI,OAAO;AAAA,UACX,MAAM,OAAO;AAAA,UACb,MAAM,OAAO,QAAQ;AAAA,UACrB,aAAa,OAAO,eAAe;AAAA,UACnC,UAAU,OAAO,YAAY;AAAA,UAC7B,UAAU,OAAO;AAAA,UACjB,GAAG;AAAA,QACL,CAAC;AACD,qBAAa,OAAO,aAAa,EAAE;AAAA,MACrC,SAAS,KAAK;AACZ,YAAI,CAAC,WAAW;AACd,gBAAM,WAAW,EAAE,uCAAuC,yBAAyB;AACnF,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,mBAAS,OAAO;AAAA,QAClB;AAAA,MACF,UAAE;AACA,YAAI,CAAC,UAAW,YAAW,KAAK;AAAA,MAClC;AAAA,IACF;AACA,SAAK;AACL,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,YAAY,CAAC,CAAC;AAElB,QAAM,SAAS,MAAM,QAAqB,MAAM;AAAA,IAC9C;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,sCAAsC,MAAM;AAAA,MACrD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa,EAAE,iDAAiD,gBAAgB;AAAA,IAClF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,sCAAsC,MAAM;AAAA,MACrD,MAAM;AAAA,MACN,aAAa,EAAE,0CAA0C,2CAA2C;AAAA,IACtG;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,6CAA6C,aAAa;AAAA,MACnE,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,wCAAwC,QAAQ;AAAA,MACzD,MAAM;AAAA,MACN,WAAW,CAAC,EAAE,IAAI,OAAO,SAAS,MAChC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC3C,UAAU,CAAC,SAAS,SAAS,QAAQ,EAAE;AAAA,UACvC,oBAAkB;AAAA,UAClB,WAAU;AAAA;AAAA,MACZ;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,0CAA0C,QAAQ;AAAA,MAC3D,MAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,SAAS,MAAM,QAAyB,MAAM;AAAA,IAClD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,yCAAyC,SAAS;AAAA,MAC3D,QAAQ;AAAA,MACR,QAAQ,CAAC,QAAQ,QAAQ,eAAe,YAAY,UAAU;AAAA,MAC9D,WAAW,CAAC,QAAQ,oBAAC,yBAAuB,GAAG,KAAK;AAAA,IACtD;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,wCAAwC,aAAa;AAAA,MAC9D,QAAQ;AAAA,MACR,MAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,MAAI,CAAC,YAAY;AACf,WACE,oBAAC,QACC,8BAAC,YACC,8BAAC,OAAE,WAAU,4BACV,YAAE,6CAA6C,kCAAkC,GACpF,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,YAAY;AACd,WACE,oBAAC,QACC,8BAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,2CAA2C,oBAAoB;AAAA,QACxE,UAAS;AAAA,QACT,WAAW,EAAE,8CAA8C,oBAAoB;AAAA;AAAA,IACjF,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,SAAS,CAAC,SAAS;AACrB,WACE,oBAAC,QACC,8BAAC,YACC,8BAAC,gBAAa,OAAO,OAAO,GAC9B,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,QACC,8BAAC,YACC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,qCAAqC,eAAe;AAAA,MAC7D,UAAS;AAAA,MACT,gBAAgB,EAAE,cAAc,oBAAoB,YAAY,aAAa,OAAO,UAAU,IAAI,GAAG;AAAA,MACrG;AAAA,MACA;AAAA,MACA,UAAU,EAAE,QAAQ;AAAA,MACpB,eAAe,iBAAiB,EAAE,IAAI,YAAY,MAAM,IAAI,MAAM,IAAI,aAAa,IAAI,UAAU,IAAI,UAAU,KAAK;AAAA,MACpH,WAAW;AAAA,MACX,gBAAgB,EAAE,mCAAmC,qBAAqB;AAAA,MAC1E,aAAa,EAAE,uCAAuC,MAAM;AAAA,MAC5D,YAAW;AAAA,MACX,iBAAiB,qCAAqC,mBAAmB,EAAE,oCAAoC,kBAAkB,CAAC,CAAC;AAAA,MACnI,cACE,iCACE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,cACN,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,aAAa,EAAE,OAAO,eAAe,QAAQ,WAAW;AAAA,YAC1D;AAAA,YACA,UAAU,+BAA+B,UAAU;AAAA;AAAA,QACrD;AAAA,QACC,YACC,oBAAC,UAAK,WAAU,iCACb,YAAE,qCAAqC,EAAE,MAAM,UAAU,CAAC,GAC7D,IACE;AAAA,SACN;AAAA,MAEF,UAAU,OAAO,WAAW;AAC1B,cAAM,qBAAqB,YAAY,QAAQ,CAAC;AAAA,MAClD;AAAA,MACA,UAAU,YAAY;AACpB,cAAM,WAAW,sBAAsB,YAAY;AAAA,UACjD,cAAc,EAAE,yCAAyC,2BAA2B;AAAA,QACtF,CAAC;AAAA,MACH;AAAA,MACA,gBAAgB,qCAAqC,mBAAmB,EAAE,oCAAoC,mBAAmB,CAAC,CAAC;AAAA;AAAA,EACrI,GACF,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
@@ -9,7 +9,7 @@ import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors
9
9
  import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
10
10
  import { apiCall, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
11
11
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
12
- import { ErrorMessage } from "@open-mercato/ui/backend/detail";
12
+ import { ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
13
13
  import { useT } from "@open-mercato/shared/lib/i18n/context";
14
14
  import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
15
15
  import { E } from "../../../../../../../../generated/entities.ids.generated.js";
@@ -59,6 +59,7 @@ function EditVariantPage({ params }) {
59
59
  const [existingPriceIds, setExistingPriceIds] = React.useState({});
60
60
  const [loading, setLoading] = React.useState(true);
61
61
  const [error, setError] = React.useState(null);
62
+ const [isNotFound, setIsNotFound] = React.useState(false);
62
63
  const [currentProductId, setCurrentProductId] = React.useState(productId);
63
64
  const [productTitle, setProductTitle] = React.useState("");
64
65
  const [productTaxRateId, setProductTaxRateId] = React.useState(null);
@@ -118,13 +119,23 @@ function EditVariantPage({ params }) {
118
119
  async function load() {
119
120
  setLoading(true);
120
121
  setError(null);
122
+ setIsNotFound(false);
121
123
  try {
122
124
  const variantRes = await apiCall(
123
125
  `/api/catalog/variants?id=${encodeURIComponent(variantId)}&page=1&pageSize=1`
124
126
  );
125
- if (!variantRes.ok) throw new Error(t("catalog.variants.form.errors.load", "Failed to load variant."));
127
+ if (!variantRes.ok) {
128
+ if (variantRes.status === 404) {
129
+ if (!cancelled) setIsNotFound(true);
130
+ return;
131
+ }
132
+ throw new Error(t("catalog.variants.form.errors.load", "Failed to load variant."));
133
+ }
126
134
  const record = Array.isArray(variantRes.result?.items) ? variantRes.result?.items?.[0] : void 0;
127
- if (!record) throw new Error(t("catalog.variants.form.errors.notFound", "Variant not found."));
135
+ if (!record) {
136
+ if (!cancelled) setIsNotFound(true);
137
+ return;
138
+ }
128
139
  const resolvedProductId = typeof record.product_id === "string" ? record.product_id : typeof record.productId === "string" ? record.productId : currentProductId;
129
140
  if (resolvedProductId) setCurrentProductId(resolvedProductId);
130
141
  const metadata = typeof record.metadata === "object" && record.metadata ? { ...record.metadata } : {};
@@ -291,108 +302,118 @@ function EditVariantPage({ params }) {
291
302
  }
292
303
  const formTitle = productTitle ? t("catalog.variants.form.editTitleFor", "Edit variant \u2022 {{title}}").replace("{{title}}", productTitle) : t("catalog.variants.form.editTitle", "Edit variant");
293
304
  const productVariantsHref = `/backend/catalog/products/${currentProductId}#variants`;
294
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs(PageBody, { children: [
295
- error ? /* @__PURE__ */ jsx(ErrorMessage, { label: error, className: "mb-4" }) : null,
296
- /* @__PURE__ */ jsx(
297
- CrudForm,
305
+ if (isNotFound) {
306
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
307
+ RecordNotFoundState,
298
308
  {
299
- title: formTitle,
309
+ label: t("catalog.variants.form.errors.notFound", "Variant not found."),
300
310
  backHref: productVariantsHref,
301
- versionHistory: { resourceKind: "catalog.variant", resourceId: variantId ? String(variantId) : "" },
302
- extraActions: /* @__PURE__ */ jsx(
303
- SendObjectMessageDialog,
304
- {
305
- object: {
306
- entityModule: "catalog",
307
- entityType: "variant",
308
- entityId: variantId,
309
- previewData: {
310
- title: typeof initialValues?.name === "string" && initialValues.name.trim().length ? initialValues.name : variantId,
311
- metadata: {
312
- [t("catalog.variants.form.skuLabel")]: typeof initialValues?.sku === "string" && initialValues.sku.trim().length ? initialValues.sku : "-",
313
- [t("catalog.variants.form.pricesLabel")]: resolveVariantPriceLabel(initialValues?.prices) ?? "-"
314
- }
315
- }
316
- },
317
- viewHref: `/backend/catalog/products/${currentProductId}/variants/${variantId}`
318
- }
319
- ),
320
- fields: [],
321
- groups,
322
- entityId: E.catalog.catalog_product_variant,
323
- customFieldsetBindings: { [E.catalog.catalog_product_variant]: { valueKey: "customFieldsetCode" } },
324
- initialValues: initialValues ?? void 0,
325
- isLoading: loading,
326
- loadingMessage: t("catalog.variants.form.loading", "Loading variant..."),
327
- submitLabel: t("catalog.variants.form.save", "Save changes"),
328
- cancelHref: productVariantsHref,
329
- onSubmit: async (values) => {
330
- const name = values.name?.trim();
331
- if (!name) {
332
- const message = t("catalog.variants.form.errors.nameRequired", "Provide the variant name.");
333
- throw createCrudFormError(message, { name: message });
334
- }
335
- const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices);
336
- if (invalidPriceKinds.length) {
337
- const message = t("catalog.variants.form.errors.invalidPrice", "Provide a valid non-negative price.");
338
- throw createCrudFormError(message, { prices: message });
339
- }
340
- const resolveTaxRateValue = (taxRateId) => {
341
- if (!taxRateId) return null;
342
- const match = taxRates.find((rate) => rate.id === taxRateId);
343
- return typeof match?.rate === "number" && Number.isFinite(match.rate) ? match.rate : null;
344
- };
345
- const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null;
346
- const resolvedTaxRateValue = values.taxRateId && resolvedTaxRateId ? resolveTaxRateValue(resolvedTaxRateId) : productTaxRateId ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate : productTaxRate ?? null;
347
- const metadata = typeof values.metadata === "object" && values.metadata ? { ...values.metadata } : {};
348
- const defaultMediaEntry = values.defaultMediaId ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId) : null;
349
- const defaultMediaUrl = defaultMediaEntry ? buildAttachmentImageUrl(defaultMediaEntry.id, {
350
- slug: slugifyAttachmentFileName(defaultMediaEntry.fileName)
351
- }) : null;
352
- const payload = {
353
- id: variantId,
354
- productId: currentProductId,
355
- name,
356
- sku: values.sku?.trim() || void 0,
357
- barcode: values.barcode?.trim() || void 0,
358
- isDefault: Boolean(values.isDefault),
359
- isActive: values.isActive !== false,
360
- optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : void 0,
361
- metadata,
362
- defaultMediaId: values.defaultMediaId ?? void 0,
363
- defaultMediaUrl: defaultMediaUrl ?? void 0,
364
- customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : void 0,
365
- taxRateId: resolvedTaxRateId,
366
- taxRate: resolvedTaxRateValue
367
- };
368
- const customFields = collectCustomFieldValues(values);
369
- if (Object.keys(customFields).length) payload.customFields = customFields;
370
- await updateCrud("catalog/variants", payload);
371
- await syncVariantPricesUpdate({
372
- priceKinds,
373
- priceDrafts: values.prices ?? {},
374
- existingPriceIds,
375
- productId: currentProductId,
376
- variantId,
377
- taxRates,
378
- taxRateId: values.taxRateId,
379
- productTaxRateId,
380
- productTaxRate
381
- });
382
- flash(t("catalog.variants.form.updated", "Variant updated."), "success");
383
- router.push(productVariantsHref);
384
- },
385
- onDelete: async () => {
386
- await deleteCrud("catalog/variants", variantId, {
387
- errorMessage: t("catalog.variants.form.deleteError", "Failed to delete variant.")
388
- });
389
- flash(t("catalog.variants.form.deleted", "Variant deleted."), "success");
390
- router.push(productVariantsHref);
391
- },
392
- deleteRedirect: productVariantsHref
311
+ backLabel: t("catalog.variants.form.actions.backToProduct", "Back to product variants")
393
312
  }
394
- )
395
- ] }) });
313
+ ) }) });
314
+ }
315
+ if (error && !loading) {
316
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error }) }) });
317
+ }
318
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
319
+ CrudForm,
320
+ {
321
+ title: formTitle,
322
+ backHref: productVariantsHref,
323
+ versionHistory: { resourceKind: "catalog.variant", resourceId: variantId ? String(variantId) : "" },
324
+ extraActions: /* @__PURE__ */ jsx(
325
+ SendObjectMessageDialog,
326
+ {
327
+ object: {
328
+ entityModule: "catalog",
329
+ entityType: "variant",
330
+ entityId: variantId,
331
+ previewData: {
332
+ title: typeof initialValues?.name === "string" && initialValues.name.trim().length ? initialValues.name : variantId,
333
+ metadata: {
334
+ [t("catalog.variants.form.skuLabel")]: typeof initialValues?.sku === "string" && initialValues.sku.trim().length ? initialValues.sku : "-",
335
+ [t("catalog.variants.form.pricesLabel")]: resolveVariantPriceLabel(initialValues?.prices) ?? "-"
336
+ }
337
+ }
338
+ },
339
+ viewHref: `/backend/catalog/products/${currentProductId}/variants/${variantId}`
340
+ }
341
+ ),
342
+ fields: [],
343
+ groups,
344
+ entityId: E.catalog.catalog_product_variant,
345
+ customFieldsetBindings: { [E.catalog.catalog_product_variant]: { valueKey: "customFieldsetCode" } },
346
+ initialValues: initialValues ?? void 0,
347
+ isLoading: loading,
348
+ loadingMessage: t("catalog.variants.form.loading", "Loading variant..."),
349
+ submitLabel: t("catalog.variants.form.save", "Save changes"),
350
+ cancelHref: productVariantsHref,
351
+ onSubmit: async (values) => {
352
+ const name = values.name?.trim();
353
+ if (!name) {
354
+ const message = t("catalog.variants.form.errors.nameRequired", "Provide the variant name.");
355
+ throw createCrudFormError(message, { name: message });
356
+ }
357
+ const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices);
358
+ if (invalidPriceKinds.length) {
359
+ const message = t("catalog.variants.form.errors.invalidPrice", "Provide a valid non-negative price.");
360
+ throw createCrudFormError(message, { prices: message });
361
+ }
362
+ const resolveTaxRateValue = (taxRateId) => {
363
+ if (!taxRateId) return null;
364
+ const match = taxRates.find((rate) => rate.id === taxRateId);
365
+ return typeof match?.rate === "number" && Number.isFinite(match.rate) ? match.rate : null;
366
+ };
367
+ const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null;
368
+ const resolvedTaxRateValue = values.taxRateId && resolvedTaxRateId ? resolveTaxRateValue(resolvedTaxRateId) : productTaxRateId ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate : productTaxRate ?? null;
369
+ const metadata = typeof values.metadata === "object" && values.metadata ? { ...values.metadata } : {};
370
+ const defaultMediaEntry = values.defaultMediaId ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId) : null;
371
+ const defaultMediaUrl = defaultMediaEntry ? buildAttachmentImageUrl(defaultMediaEntry.id, {
372
+ slug: slugifyAttachmentFileName(defaultMediaEntry.fileName)
373
+ }) : null;
374
+ const payload = {
375
+ id: variantId,
376
+ productId: currentProductId,
377
+ name,
378
+ sku: values.sku?.trim() || void 0,
379
+ barcode: values.barcode?.trim() || void 0,
380
+ isDefault: Boolean(values.isDefault),
381
+ isActive: values.isActive !== false,
382
+ optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : void 0,
383
+ metadata,
384
+ defaultMediaId: values.defaultMediaId ?? void 0,
385
+ defaultMediaUrl: defaultMediaUrl ?? void 0,
386
+ customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : void 0,
387
+ taxRateId: resolvedTaxRateId,
388
+ taxRate: resolvedTaxRateValue
389
+ };
390
+ const customFields = collectCustomFieldValues(values);
391
+ if (Object.keys(customFields).length) payload.customFields = customFields;
392
+ await updateCrud("catalog/variants", payload);
393
+ await syncVariantPricesUpdate({
394
+ priceKinds,
395
+ priceDrafts: values.prices ?? {},
396
+ existingPriceIds,
397
+ productId: currentProductId,
398
+ variantId,
399
+ taxRates,
400
+ taxRateId: values.taxRateId,
401
+ productTaxRateId,
402
+ productTaxRate
403
+ });
404
+ flash(t("catalog.variants.form.updated", "Variant updated."), "success");
405
+ router.push(productVariantsHref);
406
+ },
407
+ onDelete: async () => {
408
+ await deleteCrud("catalog/variants", variantId, {
409
+ errorMessage: t("catalog.variants.form.deleteError", "Failed to delete variant.")
410
+ });
411
+ flash(t("catalog.variants.form.deleted", "Variant deleted."), "success");
412
+ router.push(productVariantsHref);
413
+ },
414
+ deleteRedirect: productVariantsHref
415
+ }
416
+ ) }) });
396
417
  }
397
418
  function reconcileOptionValues(optionValues, optionDefinitions) {
398
419
  if (!optionValues || !optionDefinitions.length) {