@open-mercato/core 0.6.3-develop.3881.1.0b590ac4eb → 0.6.3-develop.3894.1.352abf4240

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 (34) hide show
  1. package/dist/modules/auth/backend/auth/profile/page.js +1 -1
  2. package/dist/modules/auth/backend/auth/profile/page.js.map +2 -2
  3. package/dist/modules/auth/backend/profile/change-password/page.js +1 -1
  4. package/dist/modules/auth/backend/profile/change-password/page.js.map +2 -2
  5. package/dist/modules/auth/backend/users/[id]/edit/page.js +1 -1
  6. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  7. package/dist/modules/auth/backend/users/create/page.js +6 -1
  8. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  9. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +8 -1
  10. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  11. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +3 -2
  12. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  13. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +3 -2
  14. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
  15. package/dist/modules/configs/cli.js +27 -14
  16. package/dist/modules/configs/cli.js.map +2 -2
  17. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -1
  18. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  19. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +1 -1
  20. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  21. package/dist/modules/sales/components/channels/ChannelOfferForm.js +1 -1
  22. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  23. package/package.json +7 -7
  24. package/src/modules/auth/backend/auth/profile/page.tsx +1 -1
  25. package/src/modules/auth/backend/profile/change-password/page.tsx +1 -1
  26. package/src/modules/auth/backend/users/[id]/edit/page.tsx +1 -1
  27. package/src/modules/auth/backend/users/create/page.tsx +6 -1
  28. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +8 -1
  29. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +3 -2
  30. package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +3 -2
  31. package/src/modules/configs/cli.ts +34 -13
  32. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +1 -1
  33. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +1 -1
  34. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +1 -1
@@ -9,6 +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
13
  import { useT } from "@open-mercato/shared/lib/i18n/context";
13
14
  import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
14
15
  import { E } from "../../../../../../../../generated/entities.ids.generated.js";
@@ -121,7 +122,7 @@ function EditVariantPage({ params }) {
121
122
  const variantRes = await apiCall(
122
123
  `/api/catalog/variants?id=${encodeURIComponent(variantId)}&page=1&pageSize=1`
123
124
  );
124
- if (!variantRes.ok) throw new Error("load_variant_failed");
125
+ if (!variantRes.ok) throw new Error(t("catalog.variants.form.errors.load", "Failed to load variant."));
125
126
  const record = Array.isArray(variantRes.result?.items) ? variantRes.result?.items?.[0] : void 0;
126
127
  if (!record) throw new Error(t("catalog.variants.form.errors.notFound", "Variant not found."));
127
128
  const resolvedProductId = typeof record.product_id === "string" ? record.product_id : typeof record.productId === "string" ? record.productId : currentProductId;
@@ -291,7 +292,7 @@ function EditVariantPage({ params }) {
291
292
  const formTitle = productTitle ? t("catalog.variants.form.editTitleFor", "Edit variant \u2022 {{title}}").replace("{{title}}", productTitle) : t("catalog.variants.form.editTitle", "Edit variant");
292
293
  const productVariantsHref = `/backend/catalog/products/${currentProductId}#variants`;
293
294
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs(PageBody, { children: [
294
- error ? /* @__PURE__ */ jsx("div", { className: "mb-4 rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive", children: error }) : null,
295
+ error ? /* @__PURE__ */ jsx(ErrorMessage, { label: error, className: "mb-4" }) : null,
295
296
  /* @__PURE__ */ jsx(
296
297
  CrudForm,
297
298
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../../src/modules/catalog/backend/catalog/products/%5BproductId%5D/variants/%5BvariantId%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud, 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 { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\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 { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport {\n type VariantFormValues,\n type VariantPriceDraft,\n type OptionDefinition,\n createVariantInitialValues,\n normalizeOptionSchema,\n mapPriceItemToDraft,\n findInvalidVariantPriceKinds,\n} from '@open-mercato/core/modules/catalog/components/products/variantForm'\nimport {\n type PriceKindSummary,\n type PriceKindApiPayload,\n type TaxRateSummary,\n normalizePriceKindSummary,\n} from '@open-mercato/core/modules/catalog/components/products/productForm'\nimport { parseNumericInput } from '@open-mercato/core/modules/catalog/components/products/productFormUtils'\nimport {\n VariantBasicsSection,\n VariantOptionValuesSection,\n VariantDimensionsSection,\n VariantMetadataSection,\n VariantPricesSection,\n VariantMediaSection,\n} from '@open-mercato/core/modules/catalog/components/products/VariantBuilder'\nimport type { ProductMediaItem } from '@open-mercato/core/modules/catalog/components/products/ProductMediaManager'\nimport { buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { fetchOptionSchemaTemplate } from '../../../optionSchemaClient'\nimport CreateVariantPage from '../create/page'\n\ntype VariantResponse = {\n items?: Array<Record<string, unknown>>\n}\n\ntype ProductResponse = {\n items?: Array<{\n id?: string\n title?: string | null\n metadata?: Record<string, unknown> | null\n tax_rate_id?: string | null\n taxRateId?: string | null\n tax_rate?: number | string | null\n taxRate?: number | string | null\n }>\n}\n\ntype PriceListResponse = {\n items?: Array<Record<string, unknown>>\n}\n\ntype AttachmentListResponse = {\n items?: ProductMediaItem[]\n}\n\nfunction resolveVariantPriceLabel(prices: Record<string, VariantPriceDraft> | undefined): string | null {\n if (!prices || typeof prices !== 'object') return null\n const entries = Object.values(prices)\n for (const entry of entries) {\n const amount = typeof entry?.amount === 'string' ? entry.amount.trim() : ''\n if (!amount) continue\n const currencyCode =\n typeof entry.currencyCode === 'string' && entry.currencyCode.trim().length\n ? entry.currencyCode.trim().toUpperCase()\n : null\n return currencyCode ? `${currencyCode} ${amount}` : amount\n }\n return null\n}\n\nexport default function EditVariantPage({ params }: { params?: { productId?: string; variantId?: string } }) {\n const router = useRouter()\n const t = useT()\n const productId = params?.productId ? String(params.productId) : null\n const variantId = params?.variantId ? String(params.variantId) : null\n const isCreateSentinel = variantId === 'create'\n const [priceKinds, setPriceKinds] = React.useState<PriceKindSummary[]>([])\n const [taxRates, setTaxRates] = React.useState<TaxRateSummary[]>([])\n const [optionDefinitions, setOptionDefinitions] = React.useState<OptionDefinition[]>([])\n const [initialValues, setInitialValues] = React.useState<VariantFormValues | null>(null)\n const [existingPriceIds, setExistingPriceIds] = React.useState<Record<string, string>>({})\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [currentProductId, setCurrentProductId] = React.useState<string | null>(productId)\n const [productTitle, setProductTitle] = React.useState<string>('')\n const [productTaxRateId, setProductTaxRateId] = React.useState<string | null>(null)\n const [productTaxRate, setProductTaxRate] = React.useState<number | null>(null)\n\n React.useEffect(() => {\n const loadPriceKinds = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n '/api/catalog/price-kinds?pageSize=100',\n undefined,\n { errorMessage: t('catalog.priceKinds.errors.load', 'Failed to load price kinds.') },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setPriceKinds(items.map((item) => normalizePriceKindSummary(item)).filter((item): item is PriceKindSummary => !!item))\n } catch (err) {\n console.error('catalog.price-kinds.fetch failed', err)\n setPriceKinds([])\n }\n }\n loadPriceKinds().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n const loadTaxRates = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(\n '/api/sales/tax-rates?pageSize=200',\n undefined,\n { errorMessage: t('catalog.products.create.taxRates.error', 'Failed to load tax rates.'), fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setTaxRates(\n items.map((item) => {\n const rawRate = typeof item.rate === 'number' ? item.rate : Number(item.rate ?? Number.NaN)\n return {\n id: String(item.id),\n name:\n typeof item.name === 'string' && item.name.trim().length\n ? item.name\n : t('catalog.products.create.taxRates.unnamed', 'Untitled tax rate'),\n code: typeof item.code === 'string' && item.code.trim().length ? item.code : null,\n rate: Number.isFinite(rawRate) ? rawRate : null,\n isDefault: Boolean(\n typeof item.isDefault === 'boolean'\n ? item.isDefault\n : typeof item.is_default === 'boolean'\n ? item.is_default\n : false,\n ),\n }\n }),\n )\n } catch (err) {\n console.error('sales.tax-rates.fetch failed', err)\n setTaxRates([])\n }\n }\n loadTaxRates().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n if (!variantId || isCreateSentinel || priceKinds.length === 0) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const variantRes = await apiCall<VariantResponse>(\n `/api/catalog/variants?id=${encodeURIComponent(variantId!)}&page=1&pageSize=1`,\n )\n if (!variantRes.ok) throw new Error('load_variant_failed')\n const record = Array.isArray(variantRes.result?.items) ? variantRes.result?.items?.[0] : undefined\n if (!record) throw new Error(t('catalog.variants.form.errors.notFound', 'Variant not found.'))\n const resolvedProductId =\n typeof record.product_id === 'string'\n ? record.product_id\n : typeof record.productId === 'string'\n ? record.productId\n : currentProductId\n if (resolvedProductId) setCurrentProductId(resolvedProductId)\n const metadata = typeof record.metadata === 'object' && record.metadata ? { ...(record.metadata as Record<string, unknown>) } : {}\n const attachments = await fetchVariantAttachments(variantId!)\n const priceDrafts = await loadVariantPrices(variantId!, priceKinds)\n const priceIdMap: Record<string, string> = {}\n Object.entries(priceDrafts).forEach(([kindId, draft]) => {\n if (draft.priceId) priceIdMap[kindId] = draft.priceId\n })\n setExistingPriceIds(priceIdMap)\n const customDefaults = extractCustomFieldEntries(record)\n let loadedOptionDefinitions: OptionDefinition[] = []\n if (resolvedProductId) {\n const productRes = await apiCall<ProductResponse>(\n `/api/catalog/products?id=${encodeURIComponent(resolvedProductId)}&page=1&pageSize=1`,\n )\n if (productRes.ok) {\n const product = Array.isArray(productRes.result?.items) ? productRes.result?.items?.[0] : undefined\n if (product) {\n setProductTitle(typeof product.title === 'string' ? product.title : '')\n const taxRateId =\n typeof (product as any).tax_rate_id === 'string'\n ? (product as any).tax_rate_id\n : typeof (product as any).taxRateId === 'string'\n ? (product as any).taxRateId\n : null\n const taxRateValueRaw =\n typeof (product as any).tax_rate === 'number'\n ? (product as any).tax_rate\n : typeof (product as any).tax_rate === 'string'\n ? Number((product as any).tax_rate)\n : typeof (product as any).taxRate === 'number'\n ? (product as any).taxRate\n : typeof (product as any).taxRate === 'string'\n ? Number((product as any).taxRate)\n : null\n const taxRateValue = Number.isFinite(taxRateValueRaw) ? Number(taxRateValueRaw) : null\n setProductTaxRateId(taxRateId)\n setProductTaxRate(taxRateValue)\n const productMetadata = (product.metadata ?? {}) as Record<string, unknown>\n const optionSchemaId =\n typeof (product as any).option_schema_id === 'string'\n ? (product as any).option_schema_id\n : typeof (product as any).optionSchemaId === 'string'\n ? (product as any).optionSchemaId\n : null\n let schemaSource: unknown =\n productMetadata.optionSchema ?? (productMetadata.option_schema as unknown)\n if (optionSchemaId) {\n const template = await fetchOptionSchemaTemplate(optionSchemaId)\n if (template?.schema?.options) {\n schemaSource = template.schema.options.map((option) => ({\n code: option.code,\n label: option.label,\n values: Array.isArray(option.choices)\n ? option.choices.map((choice) => ({\n id: choice.code ?? undefined,\n label: choice.label ?? choice.code ?? '',\n }))\n : [],\n }))\n }\n }\n loadedOptionDefinitions = normalizeOptionSchema(schemaSource)\n setOptionDefinitions(loadedOptionDefinitions)\n }\n }\n }\n if (!cancelled) {\n const optionValues =\n typeof record.option_values === 'object' && record.option_values\n ? { ...(record.option_values as Record<string, string>) }\n : typeof record.optionValues === 'object' && record.optionValues\n ? { ...(record.optionValues as Record<string, string>) }\n : {}\n const normalizedOptionValues = reconcileOptionValues(optionValues, loadedOptionDefinitions)\n const defaultMediaId =\n typeof record.default_media_id === 'string'\n ? record.default_media_id\n : typeof record.defaultMediaId === 'string'\n ? record.defaultMediaId\n : attachments[0]?.id ?? null\n const defaultMediaUrl =\n typeof record.default_media_url === 'string'\n ? record.default_media_url\n : typeof record.defaultMediaUrl === 'string'\n ? record.defaultMediaUrl\n : ''\n const base = createVariantInitialValues()\n setInitialValues({\n ...base,\n mediaDraftId: variantId!,\n name: typeof record.name === 'string' ? record.name : '',\n sku: typeof record.sku === 'string' ? record.sku : '',\n barcode: typeof record.barcode === 'string' ? record.barcode : '',\n isDefault: record.is_default === true || record.isDefault === true,\n isActive: record.is_active !== false && record.isActive !== false,\n optionValues: normalizedOptionValues,\n metadata,\n mediaItems: attachments,\n defaultMediaId,\n defaultMediaUrl,\n prices: priceDrafts,\n taxRateId:\n typeof (record as any).tax_rate_id === 'string'\n ? (record as any).tax_rate_id\n : typeof (record as any).taxRateId === 'string'\n ? (record as any).taxRateId\n : null,\n customFieldsetCode:\n typeof record.custom_fieldset_code === 'string'\n ? record.custom_fieldset_code\n : typeof record.customFieldsetCode === 'string'\n ? record.customFieldsetCode\n : null,\n ...customDefaults,\n })\n }\n } catch (err) {\n console.error('catalog.variants.load.failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message ? err.message : t('catalog.variants.form.errors.load', 'Failed to load variant.')\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [variantId, t, currentProductId, priceKinds])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const list: CrudFormGroup[] = [\n {\n id: 'general',\n column: 1,\n title: t('catalog.variants.form.general', 'General'),\n component: ({ values, setValue, errors }) => (\n <VariantBasicsSection values={values as VariantFormValues} setValue={setValue} errors={errors} />\n ),\n },\n {\n id: 'metadata',\n column: 1,\n title: t('catalog.products.edit.metadata.title', 'Metadata'),\n description: t('catalog.products.edit.metadata.hint', 'Attach structured key/value pairs for integrations.'),\n component: ({ values, setValue }) => (\n <VariantMetadataSection values={values as VariantFormValues} setValue={setValue} showIntro={false} embedded />\n ),\n },\n {\n id: 'prices',\n column: 1,\n title: t('catalog.variants.form.pricesLabel', 'Prices'),\n description: t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.'),\n component: ({ values, setValue }) => (\n <VariantPricesSection\n values={values as VariantFormValues}\n setValue={setValue}\n priceKinds={priceKinds}\n taxRates={taxRates}\n showHeader={false}\n embedded\n />\n ),\n },\n {\n id: 'media',\n column: 1,\n title: t('catalog.variants.form.media', 'Media'),\n component: ({ values, setValue }) => (\n <VariantMediaSection values={values as VariantFormValues} setValue={setValue} showLabel={false} />\n ),\n },\n ]\n\n if (optionDefinitions.length) {\n list.push({\n id: 'options',\n column: 2,\n title: t('catalog.variants.form.options', 'Option values'),\n component: ({ values, setValue }) => (\n <VariantOptionValuesSection\n values={values as VariantFormValues}\n setValue={setValue}\n optionDefinitions={optionDefinitions}\n showHeading={false}\n />\n ),\n })\n }\n\n list.push({\n id: 'dimensions',\n column: 2,\n title: t('catalog.variants.form.dimensions', 'Dimensions & weight'),\n component: ({ values, setValue }) => (\n <VariantDimensionsSection values={values as VariantFormValues} setValue={setValue} showHeading={false} />\n ),\n })\n\n list.push({\n id: 'custom',\n column: 2,\n title: t('catalog.variants.form.customFields', 'Custom attributes'),\n kind: 'customFields',\n })\n\n return list\n }, [optionDefinitions, priceKinds, t, taxRates])\n\n if (isCreateSentinel) {\n if (!productId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.productMissing', 'Product identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n return <CreateVariantPage params={{ productId }} />\n }\n\n if (!variantId || !currentProductId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.variantMissing', 'Variant identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const formTitle = productTitle\n ? t('catalog.variants.form.editTitleFor', 'Edit variant \u2022 {{title}}').replace('{{title}}', productTitle)\n : t('catalog.variants.form.editTitle', 'Edit variant')\n const productVariantsHref = `/backend/catalog/products/${currentProductId}#variants`\n\n return (\n <Page>\n <PageBody>\n {error ? (\n <div className=\"mb-4 rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">{error}</div>\n ) : null}\n <CrudForm<VariantFormValues>\n title={formTitle}\n backHref={productVariantsHref}\n versionHistory={{ resourceKind: 'catalog.variant', resourceId: variantId ? String(variantId) : '' }}\n extraActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'variant',\n entityId: variantId,\n previewData: {\n title:\n (typeof initialValues?.name === 'string' && initialValues.name.trim().length\n ? initialValues.name\n : variantId),\n metadata: {\n [t('catalog.variants.form.skuLabel')]:\n (typeof initialValues?.sku === 'string' && initialValues.sku.trim().length\n ? initialValues.sku\n : '-'),\n [t('catalog.variants.form.pricesLabel')]:\n resolveVariantPriceLabel(initialValues?.prices) ?? '-',\n },\n },\n }}\n viewHref={`/backend/catalog/products/${currentProductId}/variants/${variantId}`}\n />\n )}\n fields={[]}\n groups={groups}\n entityId={E.catalog.catalog_product_variant}\n customFieldsetBindings={{ [E.catalog.catalog_product_variant]: { valueKey: 'customFieldsetCode' } }}\n initialValues={initialValues ?? undefined}\n isLoading={loading}\n loadingMessage={t('catalog.variants.form.loading', 'Loading variant...')}\n submitLabel={t('catalog.variants.form.save', 'Save changes')}\n cancelHref={productVariantsHref}\n onSubmit={async (values) => {\n const name = values.name?.trim()\n if (!name) {\n const message = t('catalog.variants.form.errors.nameRequired', 'Provide the variant name.')\n throw createCrudFormError(message, { name: message })\n }\n const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices)\n if (invalidPriceKinds.length) {\n const message = t('catalog.variants.form.errors.invalidPrice', 'Provide a valid non-negative price.')\n throw createCrudFormError(message, { prices: message })\n }\n const resolveTaxRateValue = (taxRateId?: string | null) => {\n if (!taxRateId) return null\n const match = taxRates.find((rate) => rate.id === taxRateId)\n return typeof match?.rate === 'number' && Number.isFinite(match.rate) ? match.rate : null\n }\n const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null\n const resolvedTaxRateValue =\n values.taxRateId && resolvedTaxRateId\n ? resolveTaxRateValue(resolvedTaxRateId)\n : productTaxRateId\n ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate\n : productTaxRate ?? null\n const metadata = typeof values.metadata === 'object' && values.metadata ? { ...values.metadata } : {}\n const defaultMediaEntry = values.defaultMediaId\n ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId)\n : null\n const defaultMediaUrl = defaultMediaEntry\n ? buildAttachmentImageUrl(defaultMediaEntry.id, {\n slug: slugifyAttachmentFileName(defaultMediaEntry.fileName),\n })\n : null\n const payload: Record<string, unknown> = {\n id: variantId,\n productId: currentProductId,\n name,\n sku: values.sku?.trim() || undefined,\n barcode: values.barcode?.trim() || undefined,\n isDefault: Boolean(values.isDefault),\n isActive: values.isActive !== false,\n optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : undefined,\n metadata,\n defaultMediaId: values.defaultMediaId ?? undefined,\n defaultMediaUrl: defaultMediaUrl ?? undefined,\n customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : undefined,\n taxRateId: resolvedTaxRateId,\n taxRate: resolvedTaxRateValue,\n }\n const customFields = collectCustomFieldValues(values)\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n await updateCrud('catalog/variants', payload)\n await syncVariantPricesUpdate({\n priceKinds,\n priceDrafts: values.prices ?? {},\n existingPriceIds,\n productId: currentProductId,\n variantId,\n taxRates,\n taxRateId: values.taxRateId,\n productTaxRateId,\n productTaxRate,\n })\n flash(t('catalog.variants.form.updated', 'Variant updated.'), 'success')\n router.push(productVariantsHref)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/variants', variantId!, {\n errorMessage: t('catalog.variants.form.deleteError', 'Failed to delete variant.'),\n })\n flash(t('catalog.variants.form.deleted', 'Variant deleted.'), 'success')\n router.push(productVariantsHref)\n }}\n deleteRedirect={productVariantsHref}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction reconcileOptionValues(\n optionValues: Record<string, string>,\n optionDefinitions: OptionDefinition[],\n): Record<string, string> {\n if (!optionValues || !optionDefinitions.length) {\n return optionValues ?? {}\n }\n const remaining = new Map(Object.entries(optionValues))\n const normalized: Record<string, string> = {}\n\n for (const option of optionDefinitions) {\n const code = option.code?.trim()\n if (!code) continue\n if (remaining.has(code)) {\n const value = remaining.get(code)\n if (value !== undefined) {\n normalized[code] = value\n }\n remaining.delete(code)\n continue\n }\n const matchKey = findOptionKeyByValue(remaining, option.values)\n if (matchKey) {\n const value = remaining.get(matchKey)\n if (value !== undefined) {\n normalized[code] = value\n }\n remaining.delete(matchKey)\n }\n }\n\n remaining.forEach((value, key) => {\n if (normalized[key] === undefined) {\n normalized[key] = value\n }\n })\n\n return normalized\n}\n\nfunction findOptionKeyByValue(\n candidates: Map<string, string>,\n optionValues: { id: string; label: string }[],\n): string | null {\n if (!optionValues.length) return null\n const matches: string[] = []\n candidates.forEach((value, key) => {\n if (optionValues.some((entry) => entry.label === value)) {\n matches.push(key)\n }\n })\n return matches.length === 1 ? matches[0] : null\n}\n\nasync function fetchVariantAttachments(variantId: string): Promise<ProductMediaItem[]> {\n try {\n const res = await apiCall<AttachmentListResponse>(\n `/api/attachments?entityId=${encodeURIComponent(E.catalog.catalog_product_variant)}&recordId=${encodeURIComponent(variantId)}`,\n )\n if (!res.ok) return []\n return Array.isArray(res.result?.items) ? res.result?.items ?? [] : []\n } catch (err) {\n console.error('catalog.variants.attachments.load', err)\n return []\n }\n}\n\nasync function loadVariantPrices(variantId: string, priceKinds: PriceKindSummary[]): Promise<Record<string, VariantPriceDraft>> {\n const kindDisplayModes = new Map(priceKinds.map((k) => [k.id, k.displayMode]))\n const drafts: Record<string, VariantPriceDraft> = {}\n const pageSize = 100\n let page = 1\n try {\n while (true) {\n const res = await apiCall<PriceListResponse>(\n `/api/catalog/prices?variantId=${encodeURIComponent(variantId)}&page=${page}&pageSize=${pageSize}`,\n )\n if (!res.ok) break\n const items = Array.isArray(res.result?.items) ? res.result?.items : []\n for (const item of items) {\n const draft = mapPriceItemToDraft(item as Record<string, unknown>, kindDisplayModes)\n if (draft) drafts[draft.priceKindId] = draft\n }\n if (items.length < pageSize) break\n page += 1\n }\n } catch (err) {\n console.error('catalog.variants.prices.load', err)\n }\n return drafts\n}\n\nasync function syncVariantPricesUpdate({\n priceKinds,\n priceDrafts,\n existingPriceIds,\n productId,\n variantId,\n taxRates,\n taxRateId,\n productTaxRateId,\n productTaxRate,\n}: {\n priceKinds: PriceKindSummary[]\n priceDrafts: Record<string, VariantPriceDraft>\n existingPriceIds: Record<string, string>\n productId: string\n variantId: string\n taxRates: TaxRateSummary[]\n taxRateId: string | null\n productTaxRateId?: string | null\n productTaxRate?: number | null\n}): Promise<void> {\n const selectedTaxRate = taxRates.find((rate) => rate.id === taxRateId) ?? null\n const fallbackProductTaxRate =\n !selectedTaxRate && productTaxRateId\n ? taxRates.find((rate) => rate.id === productTaxRateId) ?? null\n : null\n const resolvedTaxRateValue =\n selectedTaxRate?.rate ??\n fallbackProductTaxRate?.rate ??\n (Number.isFinite(productTaxRate ?? null) ? productTaxRate ?? null : null)\n const resolvedTaxRateId = (selectedTaxRate ?? fallbackProductTaxRate)?.id ?? null\n for (const kind of priceKinds) {\n const draft = priceDrafts?.[kind.id]\n const amount = typeof draft?.amount === 'string' ? draft.amount.trim() : ''\n const existingId = draft?.priceId ?? existingPriceIds[kind.id]\n if (!amount) {\n if (existingId) {\n try {\n await deleteCrud('catalog/prices', existingId)\n } catch (err) {\n console.error('catalog.prices.delete', err)\n }\n }\n continue\n }\n const numeric = parseNumericInput(amount)\n if (!Number.isFinite(numeric) || numeric < 0) continue\n const payload: Record<string, unknown> = {\n productId,\n variantId,\n priceKindId: kind.id,\n currencyCode: kind.currencyCode ?? undefined,\n }\n if (resolvedTaxRateId) payload.taxRateId = resolvedTaxRateId\n else if (typeof resolvedTaxRateValue === 'number' && Number.isFinite(resolvedTaxRateValue)) payload.taxRate = resolvedTaxRateValue\n if (kind.displayMode === 'including-tax') payload.unitPriceGross = numeric\n else payload.unitPriceNet = numeric\n if (existingId) {\n await updateCrud('catalog/prices', { id: existingId, ...payload })\n } else {\n await createCrud('catalog/prices', payload)\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud, 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 { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ErrorMessage } 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 { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport {\n type VariantFormValues,\n type VariantPriceDraft,\n type OptionDefinition,\n createVariantInitialValues,\n normalizeOptionSchema,\n mapPriceItemToDraft,\n findInvalidVariantPriceKinds,\n} from '@open-mercato/core/modules/catalog/components/products/variantForm'\nimport {\n type PriceKindSummary,\n type PriceKindApiPayload,\n type TaxRateSummary,\n normalizePriceKindSummary,\n} from '@open-mercato/core/modules/catalog/components/products/productForm'\nimport { parseNumericInput } from '@open-mercato/core/modules/catalog/components/products/productFormUtils'\nimport {\n VariantBasicsSection,\n VariantOptionValuesSection,\n VariantDimensionsSection,\n VariantMetadataSection,\n VariantPricesSection,\n VariantMediaSection,\n} from '@open-mercato/core/modules/catalog/components/products/VariantBuilder'\nimport type { ProductMediaItem } from '@open-mercato/core/modules/catalog/components/products/ProductMediaManager'\nimport { buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { fetchOptionSchemaTemplate } from '../../../optionSchemaClient'\nimport CreateVariantPage from '../create/page'\n\ntype VariantResponse = {\n items?: Array<Record<string, unknown>>\n}\n\ntype ProductResponse = {\n items?: Array<{\n id?: string\n title?: string | null\n metadata?: Record<string, unknown> | null\n tax_rate_id?: string | null\n taxRateId?: string | null\n tax_rate?: number | string | null\n taxRate?: number | string | null\n }>\n}\n\ntype PriceListResponse = {\n items?: Array<Record<string, unknown>>\n}\n\ntype AttachmentListResponse = {\n items?: ProductMediaItem[]\n}\n\nfunction resolveVariantPriceLabel(prices: Record<string, VariantPriceDraft> | undefined): string | null {\n if (!prices || typeof prices !== 'object') return null\n const entries = Object.values(prices)\n for (const entry of entries) {\n const amount = typeof entry?.amount === 'string' ? entry.amount.trim() : ''\n if (!amount) continue\n const currencyCode =\n typeof entry.currencyCode === 'string' && entry.currencyCode.trim().length\n ? entry.currencyCode.trim().toUpperCase()\n : null\n return currencyCode ? `${currencyCode} ${amount}` : amount\n }\n return null\n}\n\nexport default function EditVariantPage({ params }: { params?: { productId?: string; variantId?: string } }) {\n const router = useRouter()\n const t = useT()\n const productId = params?.productId ? String(params.productId) : null\n const variantId = params?.variantId ? String(params.variantId) : null\n const isCreateSentinel = variantId === 'create'\n const [priceKinds, setPriceKinds] = React.useState<PriceKindSummary[]>([])\n const [taxRates, setTaxRates] = React.useState<TaxRateSummary[]>([])\n const [optionDefinitions, setOptionDefinitions] = React.useState<OptionDefinition[]>([])\n const [initialValues, setInitialValues] = React.useState<VariantFormValues | null>(null)\n const [existingPriceIds, setExistingPriceIds] = React.useState<Record<string, string>>({})\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [currentProductId, setCurrentProductId] = React.useState<string | null>(productId)\n const [productTitle, setProductTitle] = React.useState<string>('')\n const [productTaxRateId, setProductTaxRateId] = React.useState<string | null>(null)\n const [productTaxRate, setProductTaxRate] = React.useState<number | null>(null)\n\n React.useEffect(() => {\n const loadPriceKinds = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n '/api/catalog/price-kinds?pageSize=100',\n undefined,\n { errorMessage: t('catalog.priceKinds.errors.load', 'Failed to load price kinds.') },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setPriceKinds(items.map((item) => normalizePriceKindSummary(item)).filter((item): item is PriceKindSummary => !!item))\n } catch (err) {\n console.error('catalog.price-kinds.fetch failed', err)\n setPriceKinds([])\n }\n }\n loadPriceKinds().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n const loadTaxRates = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(\n '/api/sales/tax-rates?pageSize=200',\n undefined,\n { errorMessage: t('catalog.products.create.taxRates.error', 'Failed to load tax rates.'), fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setTaxRates(\n items.map((item) => {\n const rawRate = typeof item.rate === 'number' ? item.rate : Number(item.rate ?? Number.NaN)\n return {\n id: String(item.id),\n name:\n typeof item.name === 'string' && item.name.trim().length\n ? item.name\n : t('catalog.products.create.taxRates.unnamed', 'Untitled tax rate'),\n code: typeof item.code === 'string' && item.code.trim().length ? item.code : null,\n rate: Number.isFinite(rawRate) ? rawRate : null,\n isDefault: Boolean(\n typeof item.isDefault === 'boolean'\n ? item.isDefault\n : typeof item.is_default === 'boolean'\n ? item.is_default\n : false,\n ),\n }\n }),\n )\n } catch (err) {\n console.error('sales.tax-rates.fetch failed', err)\n setTaxRates([])\n }\n }\n loadTaxRates().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n if (!variantId || isCreateSentinel || priceKinds.length === 0) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const variantRes = await apiCall<VariantResponse>(\n `/api/catalog/variants?id=${encodeURIComponent(variantId!)}&page=1&pageSize=1`,\n )\n if (!variantRes.ok) throw new Error(t('catalog.variants.form.errors.load', 'Failed to load variant.'))\n const record = Array.isArray(variantRes.result?.items) ? variantRes.result?.items?.[0] : undefined\n if (!record) throw new Error(t('catalog.variants.form.errors.notFound', 'Variant not found.'))\n const resolvedProductId =\n typeof record.product_id === 'string'\n ? record.product_id\n : typeof record.productId === 'string'\n ? record.productId\n : currentProductId\n if (resolvedProductId) setCurrentProductId(resolvedProductId)\n const metadata = typeof record.metadata === 'object' && record.metadata ? { ...(record.metadata as Record<string, unknown>) } : {}\n const attachments = await fetchVariantAttachments(variantId!)\n const priceDrafts = await loadVariantPrices(variantId!, priceKinds)\n const priceIdMap: Record<string, string> = {}\n Object.entries(priceDrafts).forEach(([kindId, draft]) => {\n if (draft.priceId) priceIdMap[kindId] = draft.priceId\n })\n setExistingPriceIds(priceIdMap)\n const customDefaults = extractCustomFieldEntries(record)\n let loadedOptionDefinitions: OptionDefinition[] = []\n if (resolvedProductId) {\n const productRes = await apiCall<ProductResponse>(\n `/api/catalog/products?id=${encodeURIComponent(resolvedProductId)}&page=1&pageSize=1`,\n )\n if (productRes.ok) {\n const product = Array.isArray(productRes.result?.items) ? productRes.result?.items?.[0] : undefined\n if (product) {\n setProductTitle(typeof product.title === 'string' ? product.title : '')\n const taxRateId =\n typeof (product as any).tax_rate_id === 'string'\n ? (product as any).tax_rate_id\n : typeof (product as any).taxRateId === 'string'\n ? (product as any).taxRateId\n : null\n const taxRateValueRaw =\n typeof (product as any).tax_rate === 'number'\n ? (product as any).tax_rate\n : typeof (product as any).tax_rate === 'string'\n ? Number((product as any).tax_rate)\n : typeof (product as any).taxRate === 'number'\n ? (product as any).taxRate\n : typeof (product as any).taxRate === 'string'\n ? Number((product as any).taxRate)\n : null\n const taxRateValue = Number.isFinite(taxRateValueRaw) ? Number(taxRateValueRaw) : null\n setProductTaxRateId(taxRateId)\n setProductTaxRate(taxRateValue)\n const productMetadata = (product.metadata ?? {}) as Record<string, unknown>\n const optionSchemaId =\n typeof (product as any).option_schema_id === 'string'\n ? (product as any).option_schema_id\n : typeof (product as any).optionSchemaId === 'string'\n ? (product as any).optionSchemaId\n : null\n let schemaSource: unknown =\n productMetadata.optionSchema ?? (productMetadata.option_schema as unknown)\n if (optionSchemaId) {\n const template = await fetchOptionSchemaTemplate(optionSchemaId)\n if (template?.schema?.options) {\n schemaSource = template.schema.options.map((option) => ({\n code: option.code,\n label: option.label,\n values: Array.isArray(option.choices)\n ? option.choices.map((choice) => ({\n id: choice.code ?? undefined,\n label: choice.label ?? choice.code ?? '',\n }))\n : [],\n }))\n }\n }\n loadedOptionDefinitions = normalizeOptionSchema(schemaSource)\n setOptionDefinitions(loadedOptionDefinitions)\n }\n }\n }\n if (!cancelled) {\n const optionValues =\n typeof record.option_values === 'object' && record.option_values\n ? { ...(record.option_values as Record<string, string>) }\n : typeof record.optionValues === 'object' && record.optionValues\n ? { ...(record.optionValues as Record<string, string>) }\n : {}\n const normalizedOptionValues = reconcileOptionValues(optionValues, loadedOptionDefinitions)\n const defaultMediaId =\n typeof record.default_media_id === 'string'\n ? record.default_media_id\n : typeof record.defaultMediaId === 'string'\n ? record.defaultMediaId\n : attachments[0]?.id ?? null\n const defaultMediaUrl =\n typeof record.default_media_url === 'string'\n ? record.default_media_url\n : typeof record.defaultMediaUrl === 'string'\n ? record.defaultMediaUrl\n : ''\n const base = createVariantInitialValues()\n setInitialValues({\n ...base,\n mediaDraftId: variantId!,\n name: typeof record.name === 'string' ? record.name : '',\n sku: typeof record.sku === 'string' ? record.sku : '',\n barcode: typeof record.barcode === 'string' ? record.barcode : '',\n isDefault: record.is_default === true || record.isDefault === true,\n isActive: record.is_active !== false && record.isActive !== false,\n optionValues: normalizedOptionValues,\n metadata,\n mediaItems: attachments,\n defaultMediaId,\n defaultMediaUrl,\n prices: priceDrafts,\n taxRateId:\n typeof (record as any).tax_rate_id === 'string'\n ? (record as any).tax_rate_id\n : typeof (record as any).taxRateId === 'string'\n ? (record as any).taxRateId\n : null,\n customFieldsetCode:\n typeof record.custom_fieldset_code === 'string'\n ? record.custom_fieldset_code\n : typeof record.customFieldsetCode === 'string'\n ? record.customFieldsetCode\n : null,\n ...customDefaults,\n })\n }\n } catch (err) {\n console.error('catalog.variants.load.failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message ? err.message : t('catalog.variants.form.errors.load', 'Failed to load variant.')\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [variantId, t, currentProductId, priceKinds])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const list: CrudFormGroup[] = [\n {\n id: 'general',\n column: 1,\n title: t('catalog.variants.form.general', 'General'),\n component: ({ values, setValue, errors }) => (\n <VariantBasicsSection values={values as VariantFormValues} setValue={setValue} errors={errors} />\n ),\n },\n {\n id: 'metadata',\n column: 1,\n title: t('catalog.products.edit.metadata.title', 'Metadata'),\n description: t('catalog.products.edit.metadata.hint', 'Attach structured key/value pairs for integrations.'),\n component: ({ values, setValue }) => (\n <VariantMetadataSection values={values as VariantFormValues} setValue={setValue} showIntro={false} embedded />\n ),\n },\n {\n id: 'prices',\n column: 1,\n title: t('catalog.variants.form.pricesLabel', 'Prices'),\n description: t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.'),\n component: ({ values, setValue }) => (\n <VariantPricesSection\n values={values as VariantFormValues}\n setValue={setValue}\n priceKinds={priceKinds}\n taxRates={taxRates}\n showHeader={false}\n embedded\n />\n ),\n },\n {\n id: 'media',\n column: 1,\n title: t('catalog.variants.form.media', 'Media'),\n component: ({ values, setValue }) => (\n <VariantMediaSection values={values as VariantFormValues} setValue={setValue} showLabel={false} />\n ),\n },\n ]\n\n if (optionDefinitions.length) {\n list.push({\n id: 'options',\n column: 2,\n title: t('catalog.variants.form.options', 'Option values'),\n component: ({ values, setValue }) => (\n <VariantOptionValuesSection\n values={values as VariantFormValues}\n setValue={setValue}\n optionDefinitions={optionDefinitions}\n showHeading={false}\n />\n ),\n })\n }\n\n list.push({\n id: 'dimensions',\n column: 2,\n title: t('catalog.variants.form.dimensions', 'Dimensions & weight'),\n component: ({ values, setValue }) => (\n <VariantDimensionsSection values={values as VariantFormValues} setValue={setValue} showHeading={false} />\n ),\n })\n\n list.push({\n id: 'custom',\n column: 2,\n title: t('catalog.variants.form.customFields', 'Custom attributes'),\n kind: 'customFields',\n })\n\n return list\n }, [optionDefinitions, priceKinds, t, taxRates])\n\n if (isCreateSentinel) {\n if (!productId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.productMissing', 'Product identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n return <CreateVariantPage params={{ productId }} />\n }\n\n if (!variantId || !currentProductId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.variantMissing', 'Variant identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const formTitle = productTitle\n ? t('catalog.variants.form.editTitleFor', 'Edit variant \u2022 {{title}}').replace('{{title}}', productTitle)\n : t('catalog.variants.form.editTitle', 'Edit variant')\n const productVariantsHref = `/backend/catalog/products/${currentProductId}#variants`\n\n return (\n <Page>\n <PageBody>\n {error ? (\n <ErrorMessage label={error} className=\"mb-4\" />\n ) : null}\n <CrudForm<VariantFormValues>\n title={formTitle}\n backHref={productVariantsHref}\n versionHistory={{ resourceKind: 'catalog.variant', resourceId: variantId ? String(variantId) : '' }}\n extraActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'variant',\n entityId: variantId,\n previewData: {\n title:\n (typeof initialValues?.name === 'string' && initialValues.name.trim().length\n ? initialValues.name\n : variantId),\n metadata: {\n [t('catalog.variants.form.skuLabel')]:\n (typeof initialValues?.sku === 'string' && initialValues.sku.trim().length\n ? initialValues.sku\n : '-'),\n [t('catalog.variants.form.pricesLabel')]:\n resolveVariantPriceLabel(initialValues?.prices) ?? '-',\n },\n },\n }}\n viewHref={`/backend/catalog/products/${currentProductId}/variants/${variantId}`}\n />\n )}\n fields={[]}\n groups={groups}\n entityId={E.catalog.catalog_product_variant}\n customFieldsetBindings={{ [E.catalog.catalog_product_variant]: { valueKey: 'customFieldsetCode' } }}\n initialValues={initialValues ?? undefined}\n isLoading={loading}\n loadingMessage={t('catalog.variants.form.loading', 'Loading variant...')}\n submitLabel={t('catalog.variants.form.save', 'Save changes')}\n cancelHref={productVariantsHref}\n onSubmit={async (values) => {\n const name = values.name?.trim()\n if (!name) {\n const message = t('catalog.variants.form.errors.nameRequired', 'Provide the variant name.')\n throw createCrudFormError(message, { name: message })\n }\n const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices)\n if (invalidPriceKinds.length) {\n const message = t('catalog.variants.form.errors.invalidPrice', 'Provide a valid non-negative price.')\n throw createCrudFormError(message, { prices: message })\n }\n const resolveTaxRateValue = (taxRateId?: string | null) => {\n if (!taxRateId) return null\n const match = taxRates.find((rate) => rate.id === taxRateId)\n return typeof match?.rate === 'number' && Number.isFinite(match.rate) ? match.rate : null\n }\n const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null\n const resolvedTaxRateValue =\n values.taxRateId && resolvedTaxRateId\n ? resolveTaxRateValue(resolvedTaxRateId)\n : productTaxRateId\n ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate\n : productTaxRate ?? null\n const metadata = typeof values.metadata === 'object' && values.metadata ? { ...values.metadata } : {}\n const defaultMediaEntry = values.defaultMediaId\n ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId)\n : null\n const defaultMediaUrl = defaultMediaEntry\n ? buildAttachmentImageUrl(defaultMediaEntry.id, {\n slug: slugifyAttachmentFileName(defaultMediaEntry.fileName),\n })\n : null\n const payload: Record<string, unknown> = {\n id: variantId,\n productId: currentProductId,\n name,\n sku: values.sku?.trim() || undefined,\n barcode: values.barcode?.trim() || undefined,\n isDefault: Boolean(values.isDefault),\n isActive: values.isActive !== false,\n optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : undefined,\n metadata,\n defaultMediaId: values.defaultMediaId ?? undefined,\n defaultMediaUrl: defaultMediaUrl ?? undefined,\n customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : undefined,\n taxRateId: resolvedTaxRateId,\n taxRate: resolvedTaxRateValue,\n }\n const customFields = collectCustomFieldValues(values)\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n await updateCrud('catalog/variants', payload)\n await syncVariantPricesUpdate({\n priceKinds,\n priceDrafts: values.prices ?? {},\n existingPriceIds,\n productId: currentProductId,\n variantId,\n taxRates,\n taxRateId: values.taxRateId,\n productTaxRateId,\n productTaxRate,\n })\n flash(t('catalog.variants.form.updated', 'Variant updated.'), 'success')\n router.push(productVariantsHref)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/variants', variantId!, {\n errorMessage: t('catalog.variants.form.deleteError', 'Failed to delete variant.'),\n })\n flash(t('catalog.variants.form.deleted', 'Variant deleted.'), 'success')\n router.push(productVariantsHref)\n }}\n deleteRedirect={productVariantsHref}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction reconcileOptionValues(\n optionValues: Record<string, string>,\n optionDefinitions: OptionDefinition[],\n): Record<string, string> {\n if (!optionValues || !optionDefinitions.length) {\n return optionValues ?? {}\n }\n const remaining = new Map(Object.entries(optionValues))\n const normalized: Record<string, string> = {}\n\n for (const option of optionDefinitions) {\n const code = option.code?.trim()\n if (!code) continue\n if (remaining.has(code)) {\n const value = remaining.get(code)\n if (value !== undefined) {\n normalized[code] = value\n }\n remaining.delete(code)\n continue\n }\n const matchKey = findOptionKeyByValue(remaining, option.values)\n if (matchKey) {\n const value = remaining.get(matchKey)\n if (value !== undefined) {\n normalized[code] = value\n }\n remaining.delete(matchKey)\n }\n }\n\n remaining.forEach((value, key) => {\n if (normalized[key] === undefined) {\n normalized[key] = value\n }\n })\n\n return normalized\n}\n\nfunction findOptionKeyByValue(\n candidates: Map<string, string>,\n optionValues: { id: string; label: string }[],\n): string | null {\n if (!optionValues.length) return null\n const matches: string[] = []\n candidates.forEach((value, key) => {\n if (optionValues.some((entry) => entry.label === value)) {\n matches.push(key)\n }\n })\n return matches.length === 1 ? matches[0] : null\n}\n\nasync function fetchVariantAttachments(variantId: string): Promise<ProductMediaItem[]> {\n try {\n const res = await apiCall<AttachmentListResponse>(\n `/api/attachments?entityId=${encodeURIComponent(E.catalog.catalog_product_variant)}&recordId=${encodeURIComponent(variantId)}`,\n )\n if (!res.ok) return []\n return Array.isArray(res.result?.items) ? res.result?.items ?? [] : []\n } catch (err) {\n console.error('catalog.variants.attachments.load', err)\n return []\n }\n}\n\nasync function loadVariantPrices(variantId: string, priceKinds: PriceKindSummary[]): Promise<Record<string, VariantPriceDraft>> {\n const kindDisplayModes = new Map(priceKinds.map((k) => [k.id, k.displayMode]))\n const drafts: Record<string, VariantPriceDraft> = {}\n const pageSize = 100\n let page = 1\n try {\n while (true) {\n const res = await apiCall<PriceListResponse>(\n `/api/catalog/prices?variantId=${encodeURIComponent(variantId)}&page=${page}&pageSize=${pageSize}`,\n )\n if (!res.ok) break\n const items = Array.isArray(res.result?.items) ? res.result?.items : []\n for (const item of items) {\n const draft = mapPriceItemToDraft(item as Record<string, unknown>, kindDisplayModes)\n if (draft) drafts[draft.priceKindId] = draft\n }\n if (items.length < pageSize) break\n page += 1\n }\n } catch (err) {\n console.error('catalog.variants.prices.load', err)\n }\n return drafts\n}\n\nasync function syncVariantPricesUpdate({\n priceKinds,\n priceDrafts,\n existingPriceIds,\n productId,\n variantId,\n taxRates,\n taxRateId,\n productTaxRateId,\n productTaxRate,\n}: {\n priceKinds: PriceKindSummary[]\n priceDrafts: Record<string, VariantPriceDraft>\n existingPriceIds: Record<string, string>\n productId: string\n variantId: string\n taxRates: TaxRateSummary[]\n taxRateId: string | null\n productTaxRateId?: string | null\n productTaxRate?: number | null\n}): Promise<void> {\n const selectedTaxRate = taxRates.find((rate) => rate.id === taxRateId) ?? null\n const fallbackProductTaxRate =\n !selectedTaxRate && productTaxRateId\n ? taxRates.find((rate) => rate.id === productTaxRateId) ?? null\n : null\n const resolvedTaxRateValue =\n selectedTaxRate?.rate ??\n fallbackProductTaxRate?.rate ??\n (Number.isFinite(productTaxRate ?? null) ? productTaxRate ?? null : null)\n const resolvedTaxRateId = (selectedTaxRate ?? fallbackProductTaxRate)?.id ?? null\n for (const kind of priceKinds) {\n const draft = priceDrafts?.[kind.id]\n const amount = typeof draft?.amount === 'string' ? draft.amount.trim() : ''\n const existingId = draft?.priceId ?? existingPriceIds[kind.id]\n if (!amount) {\n if (existingId) {\n try {\n await deleteCrud('catalog/prices', existingId)\n } catch (err) {\n console.error('catalog.prices.delete', err)\n }\n }\n continue\n }\n const numeric = parseNumericInput(amount)\n if (!Number.isFinite(numeric) || numeric < 0) continue\n const payload: Record<string, unknown> = {\n productId,\n variantId,\n priceKindId: kind.id,\n currencyCode: kind.currencyCode ?? undefined,\n }\n if (resolvedTaxRateId) payload.taxRateId = resolvedTaxRateId\n else if (typeof resolvedTaxRateValue === 'number' && Number.isFinite(resolvedTaxRateValue)) payload.taxRate = resolvedTaxRateValue\n if (kind.displayMode === 'including-tax') payload.unitPriceGross = numeric\n else payload.unitPriceNet = numeric\n if (existingId) {\n await updateCrud('catalog/prices', { id: existingId, ...payload })\n } else {\n await createCrud('catalog/prices', payload)\n }\n }\n}\n"],
5
+ "mappings": ";AA2TU,cA2GJ,YA3GI;AAzTV,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gBAAoC;AAC7C,SAAS,YAAY,YAAY,kBAAkB;AACnD,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AACzC,SAAS,SAAS,4BAA4B;AAC9C,SAAS,aAAa;AACtB,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AACrB,SAAS,iCAAiC;AAC1C,SAAS,SAAS;AAClB,SAAS,+BAA+B;AACxC;AAAA,EAIE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAIE;AAAA,OACK;AACP,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB,iCAAiC;AACnE,SAAS,iCAAiC;AAC1C,OAAO,uBAAuB;AA0B9B,SAAS,yBAAyB,QAAsE;AACtG,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,QAAM,UAAU,OAAO,OAAO,MAAM;AACpC,aAAW,SAAS,SAAS;AAC3B,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,MAAM,OAAO,KAAK,IAAI;AACzE,QAAI,CAAC,OAAQ;AACb,UAAM,eACJ,OAAO,MAAM,iBAAiB,YAAY,MAAM,aAAa,KAAK,EAAE,SAChE,MAAM,aAAa,KAAK,EAAE,YAAY,IACtC;AACN,WAAO,eAAe,GAAG,YAAY,IAAI,MAAM,KAAK;AAAA,EACtD;AACA,SAAO;AACT;AAEe,SAAR,gBAAiC,EAAE,OAAO,GAA4D;AAC3G,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AACf,QAAM,YAAY,QAAQ,YAAY,OAAO,OAAO,SAAS,IAAI;AACjE,QAAM,YAAY,QAAQ,YAAY,OAAO,OAAO,SAAS,IAAI;AACjE,QAAM,mBAAmB,cAAc;AACvC,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAA6B,CAAC,CAAC;AACzE,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAA2B,CAAC,CAAC;AACnE,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAA6B,CAAC,CAAC;AACvF,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAmC,IAAI;AACvF,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAiC,CAAC,CAAC;AACzF,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAwB,SAAS;AACvF,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAiB,EAAE;AACjE,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAwB,IAAI;AAClF,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAwB,IAAI;AAE9E,QAAM,UAAU,MAAM;AACpB,UAAM,iBAAiB,YAAY;AACjC,UAAI;AACF,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,UACA,EAAE,cAAc,EAAE,kCAAkC,6BAA6B,EAAE;AAAA,QACrF;AACA,cAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,sBAAc,MAAM,IAAI,CAAC,SAAS,0BAA0B,IAAI,CAAC,EAAE,OAAO,CAAC,SAAmC,CAAC,CAAC,IAAI,CAAC;AAAA,MACvH,SAAS,KAAK;AACZ,gBAAQ,MAAM,oCAAoC,GAAG;AACrD,sBAAc,CAAC,CAAC;AAAA,MAClB;AAAA,IACF;AACA,mBAAe,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACjC,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,UAAM,eAAe,YAAY;AAC/B,UAAI;AACF,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,UACA,EAAE,cAAc,EAAE,0CAA0C,2BAA2B,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,QACpH;AACA,cAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D;AAAA,UACE,MAAM,IAAI,CAAC,SAAS;AAClB,kBAAM,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,OAAO,KAAK,QAAQ,OAAO,GAAG;AAC1F,mBAAO;AAAA,cACL,IAAI,OAAO,KAAK,EAAE;AAAA,cAClB,MACE,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAC9C,KAAK,OACL,EAAE,4CAA4C,mBAAmB;AAAA,cACvE,MAAM,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAAS,KAAK,OAAO;AAAA,cAC7E,MAAM,OAAO,SAAS,OAAO,IAAI,UAAU;AAAA,cAC3C,WAAW;AAAA,gBACT,OAAO,KAAK,cAAc,YACtB,KAAK,YACL,OAAO,KAAK,eAAe,YACzB,KAAK,aACL;AAAA,cACR;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,gCAAgC,GAAG;AACjD,oBAAY,CAAC,CAAC;AAAA,MAChB;AAAA,IACF;AACA,iBAAa,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC/B,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa,oBAAoB,WAAW,WAAW,EAAG;AAC/D,QAAI,YAAY;AAChB,mBAAe,OAAO;AACpB,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,UAAI;AACF,cAAM,aAAa,MAAM;AAAA,UACvB,4BAA4B,mBAAmB,SAAU,CAAC;AAAA,QAC5D;AACA,YAAI,CAAC,WAAW,GAAI,OAAM,IAAI,MAAM,EAAE,qCAAqC,yBAAyB,CAAC;AACrG,cAAM,SAAS,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,QAAQ,QAAQ,CAAC,IAAI;AACzF,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,EAAE,yCAAyC,oBAAoB,CAAC;AAC7F,cAAM,oBACJ,OAAO,OAAO,eAAe,WACzB,OAAO,aACP,OAAO,OAAO,cAAc,WAC1B,OAAO,YACP;AACR,YAAI,kBAAmB,qBAAoB,iBAAiB;AAC5D,cAAM,WAAW,OAAO,OAAO,aAAa,YAAY,OAAO,WAAW,EAAE,GAAI,OAAO,SAAqC,IAAI,CAAC;AACjI,cAAM,cAAc,MAAM,wBAAwB,SAAU;AAC5D,cAAM,cAAc,MAAM,kBAAkB,WAAY,UAAU;AAClE,cAAM,aAAqC,CAAC;AAC5C,eAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK,MAAM;AACvD,cAAI,MAAM,QAAS,YAAW,MAAM,IAAI,MAAM;AAAA,QAChD,CAAC;AACD,4BAAoB,UAAU;AAC9B,cAAM,iBAAiB,0BAA0B,MAAM;AACvD,YAAI,0BAA8C,CAAC;AACnD,YAAI,mBAAmB;AACrB,gBAAM,aAAa,MAAM;AAAA,YACvB,4BAA4B,mBAAmB,iBAAiB,CAAC;AAAA,UACnE;AACA,cAAI,WAAW,IAAI;AACjB,kBAAM,UAAU,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,QAAQ,QAAQ,CAAC,IAAI;AAC1F,gBAAI,SAAS;AACX,8BAAgB,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,EAAE;AACtE,oBAAM,YACJ,OAAQ,QAAgB,gBAAgB,WACnC,QAAgB,cACjB,OAAQ,QAAgB,cAAc,WACnC,QAAgB,YACjB;AACR,oBAAM,kBACJ,OAAQ,QAAgB,aAAa,WAChC,QAAgB,WACjB,OAAQ,QAAgB,aAAa,WACnC,OAAQ,QAAgB,QAAQ,IAChC,OAAQ,QAAgB,YAAY,WACjC,QAAgB,UACjB,OAAQ,QAAgB,YAAY,WAClC,OAAQ,QAAgB,OAAO,IAC/B;AACZ,oBAAM,eAAe,OAAO,SAAS,eAAe,IAAI,OAAO,eAAe,IAAI;AAClF,kCAAoB,SAAS;AAC7B,gCAAkB,YAAY;AAC9B,oBAAM,kBAAmB,QAAQ,YAAY,CAAC;AAC9C,oBAAM,iBACJ,OAAQ,QAAgB,qBAAqB,WACxC,QAAgB,mBACjB,OAAQ,QAAgB,mBAAmB,WACxC,QAAgB,iBACjB;AACR,kBAAI,eACF,gBAAgB,gBAAiB,gBAAgB;AACnD,kBAAI,gBAAgB;AAClB,sBAAM,WAAW,MAAM,0BAA0B,cAAc;AAC/D,oBAAI,UAAU,QAAQ,SAAS;AAC7B,iCAAe,SAAS,OAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,oBACtD,MAAM,OAAO;AAAA,oBACb,OAAO,OAAO;AAAA,oBACd,QAAQ,MAAM,QAAQ,OAAO,OAAO,IAChC,OAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,sBAC9B,IAAI,OAAO,QAAQ;AAAA,sBACnB,OAAO,OAAO,SAAS,OAAO,QAAQ;AAAA,oBACxC,EAAE,IACF,CAAC;AAAA,kBACP,EAAE;AAAA,gBACJ;AAAA,cACF;AACA,wCAA0B,sBAAsB,YAAY;AAC5D,mCAAqB,uBAAuB;AAAA,YAC9C;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,WAAW;AACd,gBAAM,eACJ,OAAO,OAAO,kBAAkB,YAAY,OAAO,gBAC/C,EAAE,GAAI,OAAO,cAAyC,IACtD,OAAO,OAAO,iBAAiB,YAAY,OAAO,eAChD,EAAE,GAAI,OAAO,aAAwC,IACrD,CAAC;AACT,gBAAM,yBAAyB,sBAAsB,cAAc,uBAAuB;AAC1F,gBAAM,iBACJ,OAAO,OAAO,qBAAqB,WAC/B,OAAO,mBACP,OAAO,OAAO,mBAAmB,WAC/B,OAAO,iBACP,YAAY,CAAC,GAAG,MAAM;AAC9B,gBAAM,kBACJ,OAAO,OAAO,sBAAsB,WAChC,OAAO,oBACP,OAAO,OAAO,oBAAoB,WAChC,OAAO,kBACP;AACR,gBAAM,OAAO,2BAA2B;AACxC,2BAAiB;AAAA,YACf,GAAG;AAAA,YACH,cAAc;AAAA,YACd,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,YACtD,KAAK,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM;AAAA,YACnD,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,YAC/D,WAAW,OAAO,eAAe,QAAQ,OAAO,cAAc;AAAA,YAC9D,UAAU,OAAO,cAAc,SAAS,OAAO,aAAa;AAAA,YAC5D,cAAc;AAAA,YACd;AAAA,YACA,YAAY;AAAA,YACZ;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,YACR,WACE,OAAQ,OAAe,gBAAgB,WAClC,OAAe,cAChB,OAAQ,OAAe,cAAc,WAClC,OAAe,YAChB;AAAA,YACR,oBACE,OAAO,OAAO,yBAAyB,WACnC,OAAO,uBACP,OAAO,OAAO,uBAAuB,WACnC,OAAO,qBACP;AAAA,YACR,GAAG;AAAA,UACL,CAAC;AAAA,QACH;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,gCAAgC,GAAG;AACjD,YAAI,CAAC,WAAW;AACd,gBAAM,UAAU,eAAe,SAAS,IAAI,UAAU,IAAI,UAAU,EAAE,qCAAqC,yBAAyB;AACpI,mBAAS,OAAO;AAAA,QAClB;AAAA,MACF,UAAE;AACA,YAAI,CAAC,UAAW,YAAW,KAAK;AAAA,MAClC;AAAA,IACF;AACA,SAAK;AACL,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,WAAW,GAAG,kBAAkB,UAAU,CAAC;AAE/C,QAAM,SAAS,MAAM,QAAyB,MAAM;AAClD,UAAM,OAAwB;AAAA,MAC5B;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,OAAO,EAAE,iCAAiC,SAAS;AAAA,QACnD,WAAW,CAAC,EAAE,QAAQ,UAAU,OAAO,MACrC,oBAAC,wBAAqB,QAAqC,UAAoB,QAAgB;AAAA,MAEnG;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,OAAO,EAAE,wCAAwC,UAAU;AAAA,QAC3D,aAAa,EAAE,uCAAuC,qDAAqD;AAAA,QAC3G,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B,oBAAC,0BAAuB,QAAqC,UAAoB,WAAW,OAAO,UAAQ,MAAC;AAAA,MAEhH;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,OAAO,EAAE,qCAAqC,QAAQ;AAAA,QACtD,aAAa,EAAE,oCAAoC,sCAAsC;AAAA,QACzF,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ,UAAQ;AAAA;AAAA,QACV;AAAA,MAEJ;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,OAAO,EAAE,+BAA+B,OAAO;AAAA,QAC/C,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B,oBAAC,uBAAoB,QAAqC,UAAoB,WAAW,OAAO;AAAA,MAEpG;AAAA,IACF;AAEA,QAAI,kBAAkB,QAAQ;AAC5B,WAAK,KAAK;AAAA,QACR,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,OAAO,EAAE,iCAAiC,eAAe;AAAA,QACzD,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa;AAAA;AAAA,QACf;AAAA,MAEJ,CAAC;AAAA,IACH;AAEA,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO,EAAE,oCAAoC,qBAAqB;AAAA,MAClE,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B,oBAAC,4BAAyB,QAAqC,UAAoB,aAAa,OAAO;AAAA,IAE3G,CAAC;AAED,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO,EAAE,sCAAsC,mBAAmB;AAAA,MAClE,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,mBAAmB,YAAY,GAAG,QAAQ,CAAC;AAE/C,MAAI,kBAAkB;AACpB,QAAI,CAAC,WAAW;AACd,aACE,oBAAC,QACC,8BAAC,YACC,8BAAC,SAAI,WAAU,6FACZ,YAAE,+CAA+C,gCAAgC,GACpF,GACF,GACF;AAAA,IAEJ;AACA,WAAO,oBAAC,qBAAkB,QAAQ,EAAE,UAAU,GAAG;AAAA,EACnD;AAEA,MAAI,CAAC,aAAa,CAAC,kBAAkB;AACnC,WACE,oBAAC,QACC,8BAAC,YACC,8BAAC,SAAI,WAAU,6FACZ,YAAE,+CAA+C,gCAAgC,GACpF,GACF,GACF;AAAA,EAEJ;AAEA,QAAM,YAAY,eACd,EAAE,sCAAsC,+BAA0B,EAAE,QAAQ,aAAa,YAAY,IACrG,EAAE,mCAAmC,cAAc;AACvD,QAAM,sBAAsB,6BAA6B,gBAAgB;AAEzE,SACE,oBAAC,QACC,+BAAC,YACE;AAAA,YACC,oBAAC,gBAAa,OAAO,OAAO,WAAU,QAAO,IAC3C;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,UAAU;AAAA,QACV,gBAAgB,EAAE,cAAc,mBAAmB,YAAY,YAAY,OAAO,SAAS,IAAI,GAAG;AAAA,QAClG,cACE;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,cACN,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,aAAa;AAAA,gBACX,OACG,OAAO,eAAe,SAAS,YAAY,cAAc,KAAK,KAAK,EAAE,SAClE,cAAc,OACd;AAAA,gBACN,UAAU;AAAA,kBACR,CAAC,EAAE,gCAAgC,CAAC,GACjC,OAAO,eAAe,QAAQ,YAAY,cAAc,IAAI,KAAK,EAAE,SAChE,cAAc,MACd;AAAA,kBACN,CAAC,EAAE,mCAAmC,CAAC,GACrC,yBAAyB,eAAe,MAAM,KAAK;AAAA,gBACvD;AAAA,cACF;AAAA,YACF;AAAA,YACA,UAAU,6BAA6B,gBAAgB,aAAa,SAAS;AAAA;AAAA,QAC/E;AAAA,QAEF,QAAQ,CAAC;AAAA,QACT;AAAA,QACA,UAAU,EAAE,QAAQ;AAAA,QACpB,wBAAwB,EAAE,CAAC,EAAE,QAAQ,uBAAuB,GAAG,EAAE,UAAU,qBAAqB,EAAE;AAAA,QAClG,eAAe,iBAAiB;AAAA,QAChC,WAAW;AAAA,QACX,gBAAgB,EAAE,iCAAiC,oBAAoB;AAAA,QACvE,aAAa,EAAE,8BAA8B,cAAc;AAAA,QAC3D,YAAY;AAAA,QACZ,UAAU,OAAO,WAAW;AAC1B,gBAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,cAAI,CAAC,MAAM;AACT,kBAAM,UAAU,EAAE,6CAA6C,2BAA2B;AAC1F,kBAAM,oBAAoB,SAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,UACtD;AACA,gBAAM,oBAAoB,6BAA6B,YAAY,OAAO,MAAM;AAChF,cAAI,kBAAkB,QAAQ;AAC5B,kBAAM,UAAU,EAAE,6CAA6C,qCAAqC;AACpG,kBAAM,oBAAoB,SAAS,EAAE,QAAQ,QAAQ,CAAC;AAAA,UACxD;AACA,gBAAM,sBAAsB,CAAC,cAA8B;AACzD,gBAAI,CAAC,UAAW,QAAO;AACvB,kBAAM,QAAQ,SAAS,KAAK,CAAC,SAAS,KAAK,OAAO,SAAS;AAC3D,mBAAO,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,MAAM,IAAI,IAAI,MAAM,OAAO;AAAA,UACvF;AACA,gBAAM,oBAAoB,OAAO,aAAa,oBAAoB;AAClE,gBAAM,uBACJ,OAAO,aAAa,oBAChB,oBAAoB,iBAAiB,IACrC,mBACE,oBAAoB,gBAAgB,KAAK,iBACzC,kBAAkB;AAC1B,gBAAM,WAAW,OAAO,OAAO,aAAa,YAAY,OAAO,WAAW,EAAE,GAAG,OAAO,SAAS,IAAI,CAAC;AACpG,gBAAM,oBAAoB,OAAO,kBAC5B,MAAM,QAAQ,OAAO,UAAU,IAAI,OAAO,aAAa,CAAC,GAAG,KAAK,CAAC,SAAS,KAAK,OAAO,OAAO,cAAc,IAC5G;AACJ,gBAAM,kBAAkB,oBACpB,wBAAwB,kBAAkB,IAAI;AAAA,YAC5C,MAAM,0BAA0B,kBAAkB,QAAQ;AAAA,UAC5D,CAAC,IACD;AACJ,gBAAM,UAAmC;AAAA,YACvC,IAAI;AAAA,YACJ,WAAW;AAAA,YACX;AAAA,YACA,KAAK,OAAO,KAAK,KAAK,KAAK;AAAA,YAC3B,SAAS,OAAO,SAAS,KAAK,KAAK;AAAA,YACnC,WAAW,QAAQ,OAAO,SAAS;AAAA,YACnC,UAAU,OAAO,aAAa;AAAA,YAC9B,cAAc,OAAO,KAAK,OAAO,gBAAgB,CAAC,CAAC,EAAE,SAAS,OAAO,eAAe;AAAA,YACpF;AAAA,YACA,gBAAgB,OAAO,kBAAkB;AAAA,YACzC,iBAAiB,mBAAmB;AAAA,YACpC,oBAAoB,OAAO,oBAAoB,KAAK,EAAE,SAAS,OAAO,qBAAqB;AAAA,YAC3F,WAAW;AAAA,YACX,SAAS;AAAA,UACX;AACA,gBAAM,eAAe,yBAAyB,MAAM;AACpD,cAAI,OAAO,KAAK,YAAY,EAAE,OAAQ,SAAQ,eAAe;AAE7D,gBAAM,WAAW,oBAAoB,OAAO;AAC5C,gBAAM,wBAAwB;AAAA,YAC5B;AAAA,YACA,aAAa,OAAO,UAAU,CAAC;AAAA,YAC/B;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA;AAAA,YACA,WAAW,OAAO;AAAA,YAClB;AAAA,YACA;AAAA,UACF,CAAC;AACD,gBAAM,EAAE,iCAAiC,kBAAkB,GAAG,SAAS;AACvE,iBAAO,KAAK,mBAAmB;AAAA,QACjC;AAAA,QACA,UAAU,YAAY;AACpB,gBAAM,WAAW,oBAAoB,WAAY;AAAA,YAC/C,cAAc,EAAE,qCAAqC,2BAA2B;AAAA,UAClF,CAAC;AACD,gBAAM,EAAE,iCAAiC,kBAAkB,GAAG,SAAS;AACvE,iBAAO,KAAK,mBAAmB;AAAA,QACjC;AAAA,QACA,gBAAgB;AAAA;AAAA,IAClB;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,sBACP,cACA,mBACwB;AACxB,MAAI,CAAC,gBAAgB,CAAC,kBAAkB,QAAQ;AAC9C,WAAO,gBAAgB,CAAC;AAAA,EAC1B;AACA,QAAM,YAAY,IAAI,IAAI,OAAO,QAAQ,YAAY,CAAC;AACtD,QAAM,aAAqC,CAAC;AAE5C,aAAW,UAAU,mBAAmB;AACtC,UAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,QAAI,CAAC,KAAM;AACX,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,YAAM,QAAQ,UAAU,IAAI,IAAI;AAChC,UAAI,UAAU,QAAW;AACvB,mBAAW,IAAI,IAAI;AAAA,MACrB;AACA,gBAAU,OAAO,IAAI;AACrB;AAAA,IACF;AACA,UAAM,WAAW,qBAAqB,WAAW,OAAO,MAAM;AAC9D,QAAI,UAAU;AACZ,YAAM,QAAQ,UAAU,IAAI,QAAQ;AACpC,UAAI,UAAU,QAAW;AACvB,mBAAW,IAAI,IAAI;AAAA,MACrB;AACA,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AAAA,EACF;AAEA,YAAU,QAAQ,CAAC,OAAO,QAAQ;AAChC,QAAI,WAAW,GAAG,MAAM,QAAW;AACjC,iBAAW,GAAG,IAAI;AAAA,IACpB;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,SAAS,qBACP,YACA,cACe;AACf,MAAI,CAAC,aAAa,OAAQ,QAAO;AACjC,QAAM,UAAoB,CAAC;AAC3B,aAAW,QAAQ,CAAC,OAAO,QAAQ;AACjC,QAAI,aAAa,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK,GAAG;AACvD,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF,CAAC;AACD,SAAO,QAAQ,WAAW,IAAI,QAAQ,CAAC,IAAI;AAC7C;AAEA,eAAe,wBAAwB,WAAgD;AACrF,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,6BAA6B,mBAAmB,EAAE,QAAQ,uBAAuB,CAAC,aAAa,mBAAmB,SAAS,CAAC;AAAA,IAC9H;AACA,QAAI,CAAC,IAAI,GAAI,QAAO,CAAC;AACrB,WAAO,MAAM,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,SAAS,CAAC,IAAI,CAAC;AAAA,EACvE,SAAS,KAAK;AACZ,YAAQ,MAAM,qCAAqC,GAAG;AACtD,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,kBAAkB,WAAmB,YAA4E;AAC9H,QAAM,mBAAmB,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAC7E,QAAM,SAA4C,CAAC;AACnD,QAAM,WAAW;AACjB,MAAI,OAAO;AACX,MAAI;AACF,WAAO,MAAM;AACX,YAAM,MAAM,MAAM;AAAA,QAChB,iCAAiC,mBAAmB,SAAS,CAAC,SAAS,IAAI,aAAa,QAAQ;AAAA,MAClG;AACA,UAAI,CAAC,IAAI,GAAI;AACb,YAAM,QAAQ,MAAM,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,QAAQ,CAAC;AACtE,iBAAW,QAAQ,OAAO;AACxB,cAAM,QAAQ,oBAAoB,MAAiC,gBAAgB;AACnF,YAAI,MAAO,QAAO,MAAM,WAAW,IAAI;AAAA,MACzC;AACA,UAAI,MAAM,SAAS,SAAU;AAC7B,cAAQ;AAAA,IACV;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,gCAAgC,GAAG;AAAA,EACnD;AACA,SAAO;AACT;AAEA,eAAe,wBAAwB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUkB;AAChB,QAAM,kBAAkB,SAAS,KAAK,CAAC,SAAS,KAAK,OAAO,SAAS,KAAK;AAC1E,QAAM,yBACJ,CAAC,mBAAmB,mBAChB,SAAS,KAAK,CAAC,SAAS,KAAK,OAAO,gBAAgB,KAAK,OACzD;AACN,QAAM,uBACJ,iBAAiB,QACjB,wBAAwB,SACvB,OAAO,SAAS,kBAAkB,IAAI,IAAI,kBAAkB,OAAO;AACtE,QAAM,qBAAqB,mBAAmB,yBAAyB,MAAM;AAC7E,aAAW,QAAQ,YAAY;AAC7B,UAAM,QAAQ,cAAc,KAAK,EAAE;AACnC,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,MAAM,OAAO,KAAK,IAAI;AACzE,UAAM,aAAa,OAAO,WAAW,iBAAiB,KAAK,EAAE;AAC7D,QAAI,CAAC,QAAQ;AACX,UAAI,YAAY;AACd,YAAI;AACF,gBAAM,WAAW,kBAAkB,UAAU;AAAA,QAC/C,SAAS,KAAK;AACZ,kBAAQ,MAAM,yBAAyB,GAAG;AAAA,QAC5C;AAAA,MACF;AACA;AAAA,IACF;AACA,UAAM,UAAU,kBAAkB,MAAM;AACxC,QAAI,CAAC,OAAO,SAAS,OAAO,KAAK,UAAU,EAAG;AAC9C,UAAM,UAAmC;AAAA,MACvC;AAAA,MACA;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,cAAc,KAAK,gBAAgB;AAAA,IACrC;AACA,QAAI,kBAAmB,SAAQ,YAAY;AAAA,aAClC,OAAO,yBAAyB,YAAY,OAAO,SAAS,oBAAoB,EAAG,SAAQ,UAAU;AAC9G,QAAI,KAAK,gBAAgB,gBAAiB,SAAQ,iBAAiB;AAAA,QAC9D,SAAQ,eAAe;AAC5B,QAAI,YAAY;AACd,YAAM,WAAW,kBAAkB,EAAE,IAAI,YAAY,GAAG,QAAQ,CAAC;AAAA,IACnE,OAAO;AACL,YAAM,WAAW,kBAAkB,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -9,6 +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
13
  import { useT } from "@open-mercato/shared/lib/i18n/context";
13
14
  import { E } from "../../../../../../../../generated/entities.ids.generated.js";
14
15
  import {
@@ -102,7 +103,7 @@ function CreateVariantPage({ params }) {
102
103
  const res = await apiCall(
103
104
  `/api/catalog/products?id=${encodeURIComponent(productId)}&page=1&pageSize=1`
104
105
  );
105
- if (!res.ok) throw new Error("load_failed");
106
+ if (!res.ok) throw new Error(t("catalog.variants.form.errors.load", "Failed to load product context."));
106
107
  const record = Array.isArray(res.result?.items) ? res.result?.items?.[0] : void 0;
107
108
  if (!record) throw new Error(t("catalog.products.edit.errors.notFound", "Product not found."));
108
109
  const metadata = record.metadata ?? {};
@@ -218,7 +219,7 @@ function CreateVariantPage({ params }) {
218
219
  }
219
220
  const formTitle = productTitle ? t("catalog.variants.form.createTitleFor", "Create variant for {{title}}").replace("{{title}}", productTitle) : t("catalog.variants.form.createTitle", "Create variant");
220
221
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs(PageBody, { children: [
221
- error ? /* @__PURE__ */ jsx("div", { className: "mb-4 rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive", children: error }) : null,
222
+ error ? /* @__PURE__ */ jsx(ErrorMessage, { label: error, className: "mb-4" }) : null,
222
223
  /* @__PURE__ */ jsx(
223
224
  CrudForm,
224
225
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../../src/modules/catalog/backend/catalog/products/%5BproductId%5D/variants/create/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } 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 { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n type VariantFormValues,\n type VariantPriceDraft,\n type OptionDefinition,\n createVariantInitialValues,\n normalizeOptionSchema,\n findInvalidVariantPriceKinds,\n} from '@open-mercato/core/modules/catalog/components/products/variantForm'\nimport {\n type PriceKindSummary,\n type PriceKindApiPayload,\n type TaxRateSummary,\n normalizePriceKindSummary,\n} from '@open-mercato/core/modules/catalog/components/products/productForm'\nimport { parseNumericInput } from '@open-mercato/core/modules/catalog/components/products/productFormUtils'\nimport {\n VariantBasicsSection,\n VariantOptionValuesSection,\n VariantDimensionsSection,\n VariantMetadataSection,\n VariantPricesSection,\n VariantMediaSection,\n} from '@open-mercato/core/modules/catalog/components/products/VariantBuilder'\nimport type { ProductMediaItem } from '@open-mercato/core/modules/catalog/components/products/ProductMediaManager'\nimport { buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { fetchOptionSchemaTemplate } from '../../../optionSchemaClient'\n\ntype ProductResponse = {\n items?: Array<{\n id?: string\n title?: string | null\n metadata?: Record<string, unknown> | null\n custom_fieldset_code?: string | null\n customFieldsetCode?: string | null\n tax_rate_id?: string | null\n taxRateId?: string | null\n tax_rate?: number | string | null\n }>\n}\n\ntype VariantCreateResult = {\n id?: string\n variantId?: string\n}\n\nexport default function CreateVariantPage({ params }: { params?: { productId?: string } }) {\n const productId = params?.productId ? String(params.productId) : null\n const t = useT()\n const router = useRouter()\n const [optionDefinitions, setOptionDefinitions] = React.useState<OptionDefinition[]>([])\n const [priceKinds, setPriceKinds] = React.useState<PriceKindSummary[]>([])\n const [taxRates, setTaxRates] = React.useState<TaxRateSummary[]>([])\n const [initialValues, setInitialValues] = React.useState<VariantFormValues | null>(null)\n const [productTitle, setProductTitle] = React.useState<string>('')\n const [productTaxRateId, setProductTaxRateId] = React.useState<string | null>(null)\n const [productTaxRate, setProductTaxRate] = React.useState<number | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n const loadPriceKinds = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n '/api/catalog/price-kinds?pageSize=100',\n undefined,\n { errorMessage: t('catalog.priceKinds.errors.load', 'Failed to load price kinds.') },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setPriceKinds(items.map((item) => normalizePriceKindSummary(item)).filter((item): item is PriceKindSummary => !!item))\n } catch (err) {\n console.error('catalog.price-kinds.fetch failed', err)\n setPriceKinds([])\n }\n }\n loadPriceKinds().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n const loadTaxRates = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(\n '/api/sales/tax-rates?pageSize=200',\n undefined,\n { errorMessage: t('catalog.products.create.taxRates.error', 'Failed to load tax rates.'), fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setTaxRates(\n items.map((item) => {\n const rawRate = typeof item.rate === 'number' ? item.rate : Number(item.rate ?? Number.NaN)\n return {\n id: String(item.id),\n name:\n typeof item.name === 'string' && item.name.trim().length\n ? item.name\n : t('catalog.products.create.taxRates.unnamed', 'Untitled tax rate'),\n code: typeof item.code === 'string' && item.code.trim().length ? item.code : null,\n rate: Number.isFinite(rawRate) ? rawRate : null,\n isDefault: Boolean(\n typeof item.isDefault === 'boolean'\n ? item.isDefault\n : typeof item.is_default === 'boolean'\n ? item.is_default\n : false,\n ),\n }\n }),\n )\n } catch (err) {\n console.error('sales.tax-rates.fetch failed', err)\n setTaxRates([])\n }\n }\n loadTaxRates().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n if (!productId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const res = await apiCall<ProductResponse>(\n `/api/catalog/products?id=${encodeURIComponent(productId!)}&page=1&pageSize=1`,\n )\n if (!res.ok) throw new Error('load_failed')\n const record = Array.isArray(res.result?.items) ? res.result?.items?.[0] : undefined\n if (!record) throw new Error(t('catalog.products.edit.errors.notFound', 'Product not found.'))\n const metadata = (record.metadata ?? {}) as Record<string, unknown>\n const taxRateId =\n typeof (record as any).tax_rate_id === 'string'\n ? (record as any).tax_rate_id\n : typeof (record as any).taxRateId === 'string'\n ? (record as any).taxRateId\n : null\n const taxRateValueRaw =\n typeof (record as any).tax_rate === 'number'\n ? (record as any).tax_rate\n : typeof (record as any).tax_rate === 'string'\n ? Number((record as any).tax_rate)\n : typeof (record as any).taxRate === 'number'\n ? (record as any).taxRate\n : typeof (record as any).taxRate === 'string'\n ? Number((record as any).taxRate)\n : null\n const taxRateValue = Number.isFinite(taxRateValueRaw) ? Number(taxRateValueRaw) : null\n const optionSchemaId =\n typeof (record as any).option_schema_id === 'string'\n ? (record as any).option_schema_id\n : typeof (record as any).optionSchemaId === 'string'\n ? (record as any).optionSchemaId\n : null\n let schemaSource: unknown = metadata.optionSchema ?? (metadata.option_schema as unknown)\n if (optionSchemaId) {\n const template = await fetchOptionSchemaTemplate(optionSchemaId)\n if (template?.schema?.options) {\n schemaSource = template.schema.options.map((option) => ({\n code: option.code,\n label: option.label,\n values: Array.isArray(option.choices)\n ? option.choices.map((choice) => ({ id: choice.code ?? undefined, label: choice.label ?? choice.code ?? '' }))\n : [],\n }))\n }\n }\n if (!cancelled) {\n setOptionDefinitions(normalizeOptionSchema(schemaSource))\n setProductTitle(typeof record.title === 'string' ? record.title : '')\n setProductTaxRateId(taxRateId)\n setProductTaxRate(taxRateValue)\n const base = createVariantInitialValues()\n setInitialValues(base)\n }\n } catch (err) {\n console.error('catalog.variants.loadProduct failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message ? err.message : t('catalog.variants.form.errors.load', 'Failed to load product context.')\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [productId, t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const list: CrudFormGroup[] = [\n {\n id: 'general',\n column: 1,\n title: t('catalog.variants.form.general', 'General'),\n component: ({ values, setValue, errors }) => (\n <VariantBasicsSection values={values as VariantFormValues} setValue={setValue} errors={errors} />\n ),\n },\n {\n id: 'metadata',\n column: 1,\n title: t('catalog.products.edit.metadata.title', 'Metadata'),\n description: t('catalog.products.edit.metadata.hint', 'Attach structured key/value pairs for integrations.'),\n component: ({ values, setValue }) => (\n <VariantMetadataSection values={values as VariantFormValues} setValue={setValue} showIntro={false} embedded />\n ),\n },\n {\n id: 'prices',\n column: 1,\n title: t('catalog.variants.form.pricesLabel', 'Prices'),\n description: t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.'),\n component: ({ values, setValue }) => (\n <VariantPricesSection\n values={values as VariantFormValues}\n setValue={setValue}\n priceKinds={priceKinds}\n taxRates={taxRates}\n showHeader={false}\n embedded\n />\n ),\n },\n {\n id: 'media',\n column: 1,\n title: t('catalog.variants.form.media', 'Media'),\n component: ({ values, setValue }) => (\n <VariantMediaSection values={values as VariantFormValues} setValue={setValue} showLabel={false} />\n ),\n },\n ]\n\n if (optionDefinitions.length) {\n list.push({\n id: 'options',\n column: 2,\n title: t('catalog.variants.form.options', 'Option values'),\n component: ({ values, setValue }) => (\n <VariantOptionValuesSection\n values={values as VariantFormValues}\n setValue={setValue}\n optionDefinitions={optionDefinitions}\n showHeading={false}\n />\n ),\n })\n }\n\n list.push({\n id: 'dimensions',\n column: 2,\n title: t('catalog.variants.form.dimensions', 'Dimensions & weight'),\n component: ({ values, setValue }) => (\n <VariantDimensionsSection values={values as VariantFormValues} setValue={setValue} showHeading={false} />\n ),\n })\n\n list.push({\n id: 'custom',\n column: 2,\n title: t('catalog.variants.form.customFields', 'Custom attributes'),\n kind: 'customFields',\n })\n\n return list\n }, [optionDefinitions, priceKinds, t, taxRates])\n\n if (!productId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.productMissing', 'Product identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const formTitle = productTitle\n ? t('catalog.variants.form.createTitleFor', 'Create variant for {{title}}').replace('{{title}}', productTitle)\n : t('catalog.variants.form.createTitle', 'Create variant')\n\n return (\n <Page>\n <PageBody>\n {error ? (\n <div className=\"mb-4 rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">{error}</div>\n ) : null}\n <CrudForm<VariantFormValues>\n title={formTitle}\n backHref={`/backend/catalog/products/${productId}`}\n fields={[]}\n groups={groups}\n entityId={E.catalog.catalog_product_variant}\n customFieldsetBindings={{ [E.catalog.catalog_product_variant]: { valueKey: 'customFieldsetCode' } }}\n initialValues={initialValues ?? undefined}\n isLoading={loading}\n loadingMessage={t('catalog.variants.form.loading', 'Loading form...')}\n submitLabel={t('catalog.variants.form.createAction', 'Create variant')}\n cancelHref={`/backend/catalog/products/${productId}`}\n onSubmit={async (values) => {\n const name = values.name?.trim()\n if (!name) {\n const message = t('catalog.variants.form.errors.nameRequired', 'Provide the variant name.')\n throw createCrudFormError(message, { name: message })\n }\n const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices)\n if (invalidPriceKinds.length) {\n const message = t('catalog.variants.form.errors.invalidPrice', 'Provide a valid non-negative price.')\n throw createCrudFormError(message, { prices: message })\n }\n const resolveTaxRateValue = (taxRateId?: string | null) => {\n if (!taxRateId) return null\n const match = taxRates.find((rate) => rate.id === taxRateId)\n return typeof match?.rate === 'number' && Number.isFinite(match.rate) ? match.rate : null\n }\n const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null\n const resolvedTaxRateValue =\n values.taxRateId && resolvedTaxRateId\n ? resolveTaxRateValue(resolvedTaxRateId)\n : productTaxRateId\n ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate\n : productTaxRate ?? null\n const metadata = typeof values.metadata === 'object' && values.metadata ? { ...values.metadata } : {}\n const defaultMediaEntry = values.defaultMediaId\n ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId)\n : null\n const defaultMediaUrl = defaultMediaEntry\n ? buildAttachmentImageUrl(defaultMediaEntry.id, {\n slug: slugifyAttachmentFileName(defaultMediaEntry.fileName),\n })\n : null\n const payload: Record<string, unknown> = {\n productId,\n name,\n sku: values.sku?.trim() || undefined,\n barcode: values.barcode?.trim() || undefined,\n isDefault: Boolean(values.isDefault),\n isActive: values.isActive !== false,\n optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : undefined,\n metadata,\n defaultMediaId: values.defaultMediaId ?? undefined,\n defaultMediaUrl: defaultMediaUrl ?? undefined,\n customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : undefined,\n taxRateId: resolvedTaxRateId,\n taxRate: resolvedTaxRateValue,\n }\n // CrudForm injects a sentinel `id` (\"create\") while the record is new; never send it to the API.\n Reflect.deleteProperty(payload, 'id')\n const customFields = collectCustomFieldValues(values)\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n const { result } = await createCrud<VariantCreateResult>('catalog/variants', payload)\n const variantId = result?.variantId ?? result?.id\n if (!variantId) {\n throw createCrudFormError(t('catalog.variants.form.errors.idMissing', 'Variant id missing after create.'))\n }\n await transferVariantMedia({\n draftId: values.mediaDraftId,\n variantId,\n mediaItems: Array.isArray(values.mediaItems) ? values.mediaItems : [],\n })\n await syncVariantPrices({\n priceKinds,\n priceDrafts: values.prices ?? {},\n productId,\n variantId,\n taxRates,\n taxRateId: values.taxRateId,\n productTaxRateId,\n productTaxRate,\n })\n flash(t('catalog.variants.form.createSuccess', 'Variant created.'), 'success')\n router.push(`/backend/catalog/products/${productId}#variants`)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\nasync function transferVariantMedia({\n draftId,\n variantId,\n mediaItems,\n}: {\n draftId?: string | null\n variantId: string\n mediaItems: ProductMediaItem[]\n}): Promise<void> {\n if (!draftId || !variantId) return\n const attachmentIds = mediaItems.map((item) => item.id).filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (!attachmentIds.length) return\n await apiCall(\n '/api/attachments/transfer',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: E.catalog.catalog_product_variant,\n attachmentIds,\n fromRecordId: draftId,\n toRecordId: variantId,\n }),\n },\n { fallback: null },\n )\n}\n\nasync function syncVariantPrices({\n priceKinds,\n priceDrafts,\n productId,\n variantId,\n taxRates,\n taxRateId,\n productTaxRateId,\n productTaxRate,\n}: {\n priceKinds: PriceKindSummary[]\n priceDrafts: Record<string, VariantPriceDraft>\n productId: string\n variantId: string\n taxRates: TaxRateSummary[]\n taxRateId: string | null\n productTaxRateId?: string | null\n productTaxRate?: number | null\n}): Promise<void> {\n const selectedTaxRate = taxRates.find((rate) => rate.id === taxRateId) ?? null\n const fallbackProductTaxRate =\n !selectedTaxRate && productTaxRateId\n ? taxRates.find((rate) => rate.id === productTaxRateId) ?? null\n : null\n const resolvedTaxRateValue =\n selectedTaxRate?.rate ??\n fallbackProductTaxRate?.rate ??\n (Number.isFinite(productTaxRate ?? null) ? productTaxRate ?? null : null)\n const resolvedTaxRateId = (selectedTaxRate ?? fallbackProductTaxRate)?.id ?? null\n for (const kind of priceKinds) {\n const draft = priceDrafts?.[kind.id]\n const amount = typeof draft?.amount === 'string' ? draft.amount.trim() : ''\n if (!amount) continue\n const numeric = parseNumericInput(amount)\n if (!Number.isFinite(numeric) || numeric < 0) continue\n const payload: Record<string, unknown> = {\n productId,\n variantId,\n priceKindId: kind.id,\n currencyCode: kind.currencyCode ?? undefined,\n }\n if (resolvedTaxRateId) {\n payload.taxRateId = resolvedTaxRateId\n } else if (typeof resolvedTaxRateValue === 'number' && Number.isFinite(resolvedTaxRateValue)) {\n payload.taxRate = resolvedTaxRateValue\n }\n if (kind.displayMode === 'including-tax') payload.unitPriceGross = numeric\n else payload.unitPriceNet = numeric\n await createCrud('catalog/prices', payload)\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } 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 { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n type VariantFormValues,\n type VariantPriceDraft,\n type OptionDefinition,\n createVariantInitialValues,\n normalizeOptionSchema,\n findInvalidVariantPriceKinds,\n} from '@open-mercato/core/modules/catalog/components/products/variantForm'\nimport {\n type PriceKindSummary,\n type PriceKindApiPayload,\n type TaxRateSummary,\n normalizePriceKindSummary,\n} from '@open-mercato/core/modules/catalog/components/products/productForm'\nimport { parseNumericInput } from '@open-mercato/core/modules/catalog/components/products/productFormUtils'\nimport {\n VariantBasicsSection,\n VariantOptionValuesSection,\n VariantDimensionsSection,\n VariantMetadataSection,\n VariantPricesSection,\n VariantMediaSection,\n} from '@open-mercato/core/modules/catalog/components/products/VariantBuilder'\nimport type { ProductMediaItem } from '@open-mercato/core/modules/catalog/components/products/ProductMediaManager'\nimport { buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { fetchOptionSchemaTemplate } from '../../../optionSchemaClient'\n\ntype ProductResponse = {\n items?: Array<{\n id?: string\n title?: string | null\n metadata?: Record<string, unknown> | null\n custom_fieldset_code?: string | null\n customFieldsetCode?: string | null\n tax_rate_id?: string | null\n taxRateId?: string | null\n tax_rate?: number | string | null\n }>\n}\n\ntype VariantCreateResult = {\n id?: string\n variantId?: string\n}\n\nexport default function CreateVariantPage({ params }: { params?: { productId?: string } }) {\n const productId = params?.productId ? String(params.productId) : null\n const t = useT()\n const router = useRouter()\n const [optionDefinitions, setOptionDefinitions] = React.useState<OptionDefinition[]>([])\n const [priceKinds, setPriceKinds] = React.useState<PriceKindSummary[]>([])\n const [taxRates, setTaxRates] = React.useState<TaxRateSummary[]>([])\n const [initialValues, setInitialValues] = React.useState<VariantFormValues | null>(null)\n const [productTitle, setProductTitle] = React.useState<string>('')\n const [productTaxRateId, setProductTaxRateId] = React.useState<string | null>(null)\n const [productTaxRate, setProductTaxRate] = React.useState<number | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n const loadPriceKinds = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n '/api/catalog/price-kinds?pageSize=100',\n undefined,\n { errorMessage: t('catalog.priceKinds.errors.load', 'Failed to load price kinds.') },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setPriceKinds(items.map((item) => normalizePriceKindSummary(item)).filter((item): item is PriceKindSummary => !!item))\n } catch (err) {\n console.error('catalog.price-kinds.fetch failed', err)\n setPriceKinds([])\n }\n }\n loadPriceKinds().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n const loadTaxRates = async () => {\n try {\n const payload = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(\n '/api/sales/tax-rates?pageSize=200',\n undefined,\n { errorMessage: t('catalog.products.create.taxRates.error', 'Failed to load tax rates.'), fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setTaxRates(\n items.map((item) => {\n const rawRate = typeof item.rate === 'number' ? item.rate : Number(item.rate ?? Number.NaN)\n return {\n id: String(item.id),\n name:\n typeof item.name === 'string' && item.name.trim().length\n ? item.name\n : t('catalog.products.create.taxRates.unnamed', 'Untitled tax rate'),\n code: typeof item.code === 'string' && item.code.trim().length ? item.code : null,\n rate: Number.isFinite(rawRate) ? rawRate : null,\n isDefault: Boolean(\n typeof item.isDefault === 'boolean'\n ? item.isDefault\n : typeof item.is_default === 'boolean'\n ? item.is_default\n : false,\n ),\n }\n }),\n )\n } catch (err) {\n console.error('sales.tax-rates.fetch failed', err)\n setTaxRates([])\n }\n }\n loadTaxRates().catch(() => {})\n }, [t])\n\n React.useEffect(() => {\n if (!productId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const res = await apiCall<ProductResponse>(\n `/api/catalog/products?id=${encodeURIComponent(productId!)}&page=1&pageSize=1`,\n )\n if (!res.ok) throw new Error(t('catalog.variants.form.errors.load', 'Failed to load product context.'))\n const record = Array.isArray(res.result?.items) ? res.result?.items?.[0] : undefined\n if (!record) throw new Error(t('catalog.products.edit.errors.notFound', 'Product not found.'))\n const metadata = (record.metadata ?? {}) as Record<string, unknown>\n const taxRateId =\n typeof (record as any).tax_rate_id === 'string'\n ? (record as any).tax_rate_id\n : typeof (record as any).taxRateId === 'string'\n ? (record as any).taxRateId\n : null\n const taxRateValueRaw =\n typeof (record as any).tax_rate === 'number'\n ? (record as any).tax_rate\n : typeof (record as any).tax_rate === 'string'\n ? Number((record as any).tax_rate)\n : typeof (record as any).taxRate === 'number'\n ? (record as any).taxRate\n : typeof (record as any).taxRate === 'string'\n ? Number((record as any).taxRate)\n : null\n const taxRateValue = Number.isFinite(taxRateValueRaw) ? Number(taxRateValueRaw) : null\n const optionSchemaId =\n typeof (record as any).option_schema_id === 'string'\n ? (record as any).option_schema_id\n : typeof (record as any).optionSchemaId === 'string'\n ? (record as any).optionSchemaId\n : null\n let schemaSource: unknown = metadata.optionSchema ?? (metadata.option_schema as unknown)\n if (optionSchemaId) {\n const template = await fetchOptionSchemaTemplate(optionSchemaId)\n if (template?.schema?.options) {\n schemaSource = template.schema.options.map((option) => ({\n code: option.code,\n label: option.label,\n values: Array.isArray(option.choices)\n ? option.choices.map((choice) => ({ id: choice.code ?? undefined, label: choice.label ?? choice.code ?? '' }))\n : [],\n }))\n }\n }\n if (!cancelled) {\n setOptionDefinitions(normalizeOptionSchema(schemaSource))\n setProductTitle(typeof record.title === 'string' ? record.title : '')\n setProductTaxRateId(taxRateId)\n setProductTaxRate(taxRateValue)\n const base = createVariantInitialValues()\n setInitialValues(base)\n }\n } catch (err) {\n console.error('catalog.variants.loadProduct failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message ? err.message : t('catalog.variants.form.errors.load', 'Failed to load product context.')\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [productId, t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const list: CrudFormGroup[] = [\n {\n id: 'general',\n column: 1,\n title: t('catalog.variants.form.general', 'General'),\n component: ({ values, setValue, errors }) => (\n <VariantBasicsSection values={values as VariantFormValues} setValue={setValue} errors={errors} />\n ),\n },\n {\n id: 'metadata',\n column: 1,\n title: t('catalog.products.edit.metadata.title', 'Metadata'),\n description: t('catalog.products.edit.metadata.hint', 'Attach structured key/value pairs for integrations.'),\n component: ({ values, setValue }) => (\n <VariantMetadataSection values={values as VariantFormValues} setValue={setValue} showIntro={false} embedded />\n ),\n },\n {\n id: 'prices',\n column: 1,\n title: t('catalog.variants.form.pricesLabel', 'Prices'),\n description: t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.'),\n component: ({ values, setValue }) => (\n <VariantPricesSection\n values={values as VariantFormValues}\n setValue={setValue}\n priceKinds={priceKinds}\n taxRates={taxRates}\n showHeader={false}\n embedded\n />\n ),\n },\n {\n id: 'media',\n column: 1,\n title: t('catalog.variants.form.media', 'Media'),\n component: ({ values, setValue }) => (\n <VariantMediaSection values={values as VariantFormValues} setValue={setValue} showLabel={false} />\n ),\n },\n ]\n\n if (optionDefinitions.length) {\n list.push({\n id: 'options',\n column: 2,\n title: t('catalog.variants.form.options', 'Option values'),\n component: ({ values, setValue }) => (\n <VariantOptionValuesSection\n values={values as VariantFormValues}\n setValue={setValue}\n optionDefinitions={optionDefinitions}\n showHeading={false}\n />\n ),\n })\n }\n\n list.push({\n id: 'dimensions',\n column: 2,\n title: t('catalog.variants.form.dimensions', 'Dimensions & weight'),\n component: ({ values, setValue }) => (\n <VariantDimensionsSection values={values as VariantFormValues} setValue={setValue} showHeading={false} />\n ),\n })\n\n list.push({\n id: 'custom',\n column: 2,\n title: t('catalog.variants.form.customFields', 'Custom attributes'),\n kind: 'customFields',\n })\n\n return list\n }, [optionDefinitions, priceKinds, t, taxRates])\n\n if (!productId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('catalog.variants.form.errors.productMissing', 'Product identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const formTitle = productTitle\n ? t('catalog.variants.form.createTitleFor', 'Create variant for {{title}}').replace('{{title}}', productTitle)\n : t('catalog.variants.form.createTitle', 'Create variant')\n\n return (\n <Page>\n <PageBody>\n {error ? (\n <ErrorMessage label={error} className=\"mb-4\" />\n ) : null}\n <CrudForm<VariantFormValues>\n title={formTitle}\n backHref={`/backend/catalog/products/${productId}`}\n fields={[]}\n groups={groups}\n entityId={E.catalog.catalog_product_variant}\n customFieldsetBindings={{ [E.catalog.catalog_product_variant]: { valueKey: 'customFieldsetCode' } }}\n initialValues={initialValues ?? undefined}\n isLoading={loading}\n loadingMessage={t('catalog.variants.form.loading', 'Loading form...')}\n submitLabel={t('catalog.variants.form.createAction', 'Create variant')}\n cancelHref={`/backend/catalog/products/${productId}`}\n onSubmit={async (values) => {\n const name = values.name?.trim()\n if (!name) {\n const message = t('catalog.variants.form.errors.nameRequired', 'Provide the variant name.')\n throw createCrudFormError(message, { name: message })\n }\n const invalidPriceKinds = findInvalidVariantPriceKinds(priceKinds, values.prices)\n if (invalidPriceKinds.length) {\n const message = t('catalog.variants.form.errors.invalidPrice', 'Provide a valid non-negative price.')\n throw createCrudFormError(message, { prices: message })\n }\n const resolveTaxRateValue = (taxRateId?: string | null) => {\n if (!taxRateId) return null\n const match = taxRates.find((rate) => rate.id === taxRateId)\n return typeof match?.rate === 'number' && Number.isFinite(match.rate) ? match.rate : null\n }\n const resolvedTaxRateId = values.taxRateId ?? productTaxRateId ?? null\n const resolvedTaxRateValue =\n values.taxRateId && resolvedTaxRateId\n ? resolveTaxRateValue(resolvedTaxRateId)\n : productTaxRateId\n ? resolveTaxRateValue(productTaxRateId) ?? productTaxRate\n : productTaxRate ?? null\n const metadata = typeof values.metadata === 'object' && values.metadata ? { ...values.metadata } : {}\n const defaultMediaEntry = values.defaultMediaId\n ? (Array.isArray(values.mediaItems) ? values.mediaItems : []).find((item) => item.id === values.defaultMediaId)\n : null\n const defaultMediaUrl = defaultMediaEntry\n ? buildAttachmentImageUrl(defaultMediaEntry.id, {\n slug: slugifyAttachmentFileName(defaultMediaEntry.fileName),\n })\n : null\n const payload: Record<string, unknown> = {\n productId,\n name,\n sku: values.sku?.trim() || undefined,\n barcode: values.barcode?.trim() || undefined,\n isDefault: Boolean(values.isDefault),\n isActive: values.isActive !== false,\n optionValues: Object.keys(values.optionValues ?? {}).length ? values.optionValues : undefined,\n metadata,\n defaultMediaId: values.defaultMediaId ?? undefined,\n defaultMediaUrl: defaultMediaUrl ?? undefined,\n customFieldsetCode: values.customFieldsetCode?.trim().length ? values.customFieldsetCode : undefined,\n taxRateId: resolvedTaxRateId,\n taxRate: resolvedTaxRateValue,\n }\n // CrudForm injects a sentinel `id` (\"create\") while the record is new; never send it to the API.\n Reflect.deleteProperty(payload, 'id')\n const customFields = collectCustomFieldValues(values)\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n const { result } = await createCrud<VariantCreateResult>('catalog/variants', payload)\n const variantId = result?.variantId ?? result?.id\n if (!variantId) {\n throw createCrudFormError(t('catalog.variants.form.errors.idMissing', 'Variant id missing after create.'))\n }\n await transferVariantMedia({\n draftId: values.mediaDraftId,\n variantId,\n mediaItems: Array.isArray(values.mediaItems) ? values.mediaItems : [],\n })\n await syncVariantPrices({\n priceKinds,\n priceDrafts: values.prices ?? {},\n productId,\n variantId,\n taxRates,\n taxRateId: values.taxRateId,\n productTaxRateId,\n productTaxRate,\n })\n flash(t('catalog.variants.form.createSuccess', 'Variant created.'), 'success')\n router.push(`/backend/catalog/products/${productId}#variants`)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\nasync function transferVariantMedia({\n draftId,\n variantId,\n mediaItems,\n}: {\n draftId?: string | null\n variantId: string\n mediaItems: ProductMediaItem[]\n}): Promise<void> {\n if (!draftId || !variantId) return\n const attachmentIds = mediaItems.map((item) => item.id).filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (!attachmentIds.length) return\n await apiCall(\n '/api/attachments/transfer',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: E.catalog.catalog_product_variant,\n attachmentIds,\n fromRecordId: draftId,\n toRecordId: variantId,\n }),\n },\n { fallback: null },\n )\n}\n\nasync function syncVariantPrices({\n priceKinds,\n priceDrafts,\n productId,\n variantId,\n taxRates,\n taxRateId,\n productTaxRateId,\n productTaxRate,\n}: {\n priceKinds: PriceKindSummary[]\n priceDrafts: Record<string, VariantPriceDraft>\n productId: string\n variantId: string\n taxRates: TaxRateSummary[]\n taxRateId: string | null\n productTaxRateId?: string | null\n productTaxRate?: number | null\n}): Promise<void> {\n const selectedTaxRate = taxRates.find((rate) => rate.id === taxRateId) ?? null\n const fallbackProductTaxRate =\n !selectedTaxRate && productTaxRateId\n ? taxRates.find((rate) => rate.id === productTaxRateId) ?? null\n : null\n const resolvedTaxRateValue =\n selectedTaxRate?.rate ??\n fallbackProductTaxRate?.rate ??\n (Number.isFinite(productTaxRate ?? null) ? productTaxRate ?? null : null)\n const resolvedTaxRateId = (selectedTaxRate ?? fallbackProductTaxRate)?.id ?? null\n for (const kind of priceKinds) {\n const draft = priceDrafts?.[kind.id]\n const amount = typeof draft?.amount === 'string' ? draft.amount.trim() : ''\n if (!amount) continue\n const numeric = parseNumericInput(amount)\n if (!Number.isFinite(numeric) || numeric < 0) continue\n const payload: Record<string, unknown> = {\n productId,\n variantId,\n priceKindId: kind.id,\n currencyCode: kind.currencyCode ?? undefined,\n }\n if (resolvedTaxRateId) {\n payload.taxRateId = resolvedTaxRateId\n } else if (typeof resolvedTaxRateValue === 'number' && Number.isFinite(resolvedTaxRateValue)) {\n payload.taxRate = resolvedTaxRateValue\n }\n if (kind.displayMode === 'including-tax') payload.unitPriceGross = numeric\n else payload.unitPriceNet = numeric\n await createCrud('catalog/prices', payload)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,6 +9,11 @@ import {
9
9
  previewCachePurge
10
10
  } from "./lib/cache-cli.js";
11
11
  import { touchGeneratedBarrels } from "./lib/touchGeneratedBarrels.js";
12
+ const STRUCTURAL_CACHE_REQUESTS = [
13
+ { kind: "pattern", pattern: "nav:*" },
14
+ { kind: "segment", segment: "admin-nav" },
15
+ { kind: "segment", segment: "portal-nav" }
16
+ ];
12
17
  function parseArgs(rest) {
13
18
  const args = {};
14
19
  for (let i = 0; i < rest.length; i += 1) {
@@ -125,7 +130,7 @@ function printCacheHelp() {
125
130
  console.log("\u2139\uFE0F Notes:");
126
131
  console.log(" `stats` mirrors the cache admin page segment overview for CRUD/widget caches.");
127
132
  console.log(" `purge --id` removes every key whose name contains the provided token (for example a user id or entity id).");
128
- console.log(" `structural` targets navigation caches (`nav:*`) and is the recommended post-step after module/sidebar structure changes.");
133
+ console.log(" `structural` targets navigation/sidebar caches and is the recommended post-step after module/sidebar structure changes.");
129
134
  console.log(" When no scope flag is supplied, this command uses the global cache scope only.");
130
135
  }
131
136
  async function disposeContainer(container) {
@@ -164,11 +169,10 @@ async function runCacheStats(args) {
164
169
  await disposeContainer(container);
165
170
  }
166
171
  }
167
- async function runCachePurge(args) {
172
+ async function runCachePurgeRequest(args, request, emitOutput = true) {
168
173
  const json = flagEnabled(args, "json");
169
174
  const quiet = flagEnabled(args, "quiet");
170
175
  const dryRun = flagEnabled(args, "dry-run", "dryRun");
171
- const request = resolveCachePurgeRequest(args);
172
176
  const container = await createRequestContainer();
173
177
  try {
174
178
  const em = container.resolve("em");
@@ -190,12 +194,12 @@ async function runCachePurge(args) {
190
194
  note: result.note
191
195
  });
192
196
  }
193
- if (json) {
197
+ if (json && emitOutput) {
194
198
  console.log(JSON.stringify(results, null, 2));
195
- return;
199
+ return results;
196
200
  }
197
- if (quiet) {
198
- return;
201
+ if (quiet || !emitOutput) {
202
+ return results;
199
203
  }
200
204
  for (const result of results) {
201
205
  console.log(`${result.dryRun ? "\u{1F9EA}" : "\u{1F9F9}"} [cache] scope=${result.scope} deleted=${result.deleted}${result.dryRun ? " (dry-run)" : ""}`);
@@ -206,21 +210,29 @@ async function runCachePurge(args) {
206
210
  }
207
211
  }
208
212
  }
213
+ return results;
209
214
  } finally {
210
215
  await disposeContainer(container);
211
216
  }
212
217
  }
218
+ async function runCachePurge(args) {
219
+ await runCachePurgeRequest(args, resolveCachePurgeRequest(args));
220
+ }
213
221
  async function runStructuralCachePurge(args) {
214
- const nextArgs = {
215
- ...args,
216
- pattern: "nav:*"
217
- };
218
- await runCachePurge(nextArgs);
222
+ const json = flagEnabled(args, "json");
223
+ const structuralResults = [];
224
+ for (const request of STRUCTURAL_CACHE_REQUESTS) {
225
+ const results = await runCachePurgeRequest(args, request, !json);
226
+ structuralResults.push({ request, results });
227
+ }
228
+ if (json) {
229
+ console.log(JSON.stringify(structuralResults, null, 2));
230
+ }
219
231
  const quiet = flagEnabled(args, "quiet");
220
232
  try {
221
- touchGeneratedBarrels({ quiet });
233
+ touchGeneratedBarrels({ quiet: quiet || json });
222
234
  } catch (err) {
223
- if (!quiet) {
235
+ if (!quiet && !json) {
224
236
  console.warn(
225
237
  `[structural] failed to touch generated barrels: ${err.message ?? err}`
226
238
  );
@@ -309,6 +321,7 @@ const cacheCommand = {
309
321
  };
310
322
  var cli_default = [restoreDefaults, cacheCommand, help];
311
323
  export {
324
+ STRUCTURAL_CACHE_REQUESTS,
312
325
  cli_default as default
313
326
  };
314
327
  //# sourceMappingURL=cli.js.map