From b7fef5b7ef3bec53d9ea4d836f5f97da541816cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frane=20Poli=C4=87?= <16856471+fPolic@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:07:29 +0200 Subject: [PATCH] fix(dashboard): promotion decimal value definition (#13371) * fix(dashboard): pormotion decimal value definition * fix: typo * fix: fixed value decimals * fix: translation --- .changeset/new-cooks-count.md | 5 ++++ .../src/i18n/translations/$schema.json | 5 +++- .../dashboard/src/i18n/translations/en.json | 3 +- .../create-promotion-form.tsx | 23 +++++++++++---- .../create-promotion-form/form-schema.ts | 2 +- .../edit-promotion-details-form.tsx | 29 ++++++++++++++----- 6 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 .changeset/new-cooks-count.md diff --git a/.changeset/new-cooks-count.md b/.changeset/new-cooks-count.md new file mode 100644 index 0000000000..a6c798313d --- /dev/null +++ b/.changeset/new-cooks-count.md @@ -0,0 +1,5 @@ +--- +"@medusajs/dashboard": patch +--- + +fix(dashboard): promotion decimal value definition diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json index 33b50f67bf..643fb44273 100644 --- a/packages/admin/dashboard/src/i18n/translations/$schema.json +++ b/packages/admin/dashboard/src/i18n/translations/$schema.json @@ -7997,9 +7997,12 @@ "properties": { "title": { "type": "string" + }, + "invalid": { + "type": "string" } }, - "required": ["title"], + "required": ["title", "invalid"], "additionalProperties": false }, "value_type": { diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 3b936b121c..4a2ea633ee 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -2151,7 +2151,8 @@ "description": "The code your customers will enter during checkout." }, "value": { - "title": "Promotion Value" + "title": "Promotion Value", + "invalid": "Invalid promotion value" }, "value_type": { "fixed": { diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx index 7a430990fd..b76b773240 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx @@ -36,7 +36,10 @@ import { import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { useCampaigns } from "../../../../../hooks/api/campaigns" import { useCreatePromotion } from "../../../../../hooks/api/promotions" -import { getCurrencySymbol } from "../../../../../lib/data/currencies" +import { + currencies, + getCurrencySymbol, +} from "../../../../../lib/data/currencies" import { DEFAULT_CAMPAIGN_VALUES } from "../../../../campaigns/common/constants" import { RulesFormField } from "../../../common/edit-rules/components/rules-form-field" import { AddCampaignPromotionFields } from "../../../promotion-add-campaign/components/add-campaign-promotion-form" @@ -142,6 +145,7 @@ export const CreatePromotionForm = () => { application_method: { ...applicationMethodData, ...applicationMethodRuleData, + value: parseFloat(applicationMethodData.value as string) as number, target_rules: buildRulesData(targetRulesData), buy_rules: buildRulesData(buyRulesData), }, @@ -742,6 +746,9 @@ export const CreatePromotionForm = () => { const currencyCode = form.getValues().application_method.currency_code + const currencyInfo = + currencies[currencyCode?.toUpperCase() || "USD"] + return ( { { - onChange(value ? parseInt(value) : "") - }} code={currencyCode || "USD"} + onValueChange={(_value, _name, values) => + onChange(values?.value) + } + decimalScale={ + currencyInfo?.decimal_digits ?? 2 + } + decimalsLimit={ + currencyInfo?.decimal_digits ?? 2 + } symbol={ currencyCode ? getCurrencySymbol(currencyCode) @@ -783,7 +796,7 @@ export const CreatePromotionForm = () => { onChange( e.target.value === "" ? null - : parseInt(e.target.value) + : parseFloat(e.target.value) ) }} /> diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/form-schema.ts b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/form-schema.ts index 4cc69f24e9..9dbb81bc11 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/form-schema.ts +++ b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/form-schema.ts @@ -30,7 +30,7 @@ export const CreatePromotionSchema = z is_tax_inclusive: z.boolean().optional(), application_method: z.object({ allocation: z.enum(["each", "across"]), - value: z.number().min(0), + value: z.number().min(0).or(z.string().min(1)), currency_code: z.string().optional(), max_quantity: z.number().optional().nullable(), target_rules: RuleSchema, diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx index 96294aeadf..f9a570679e 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx @@ -11,7 +11,10 @@ import { DeprecatedPercentageInput } from "../../../../../components/inputs/perc import { RouteDrawer, useRouteModal } from "../../../../../components/modals" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { useUpdatePromotion } from "../../../../../hooks/api/promotions" -import { getCurrencySymbol } from "../../../../../lib/data/currencies" +import { + currencies, + getCurrencySymbol, +} from "../../../../../lib/data/currencies" import { SwitchBox } from "../../../../../components/common/switch-box" type EditPromotionFormProps = { @@ -24,7 +27,7 @@ const EditPromotionSchema = zod.object({ is_tax_inclusive: zod.boolean().optional(), status: zod.enum(["active", "inactive", "draft"]), value_type: zod.enum(["fixed", "percentage"]), - value: zod.number(), + value: zod.number().min(0).or(zod.string().min(1)), allocation: zod.enum(["each", "across"]), target_type: zod.enum(["order", "shipping_methods", "items"]), }) @@ -59,6 +62,13 @@ export const EditPromotionDetailsForm = ({ const { mutateAsync, isPending } = useUpdatePromotion(promotion.id) const handleSubmit = form.handleSubmit(async (data) => { + const value = parseFloat(data.value) + + if (isNaN(value) || value < 0) { + form.setError("value", { message: t("promotions.form.value.invalid") }) + return + } + await mutateAsync( { is_automatic: data.is_automatic === "true", @@ -66,7 +76,7 @@ export const EditPromotionDetailsForm = ({ status: data.status, is_tax_inclusive: data.is_tax_inclusive, application_method: { - value: data.value, + value: parseFloat(data.value), type: data.value_type as any, allocation: data.allocation as any, }, @@ -269,6 +279,9 @@ export const EditPromotionDetailsForm = ({ const currencyCode = promotion.application_method?.currency_code ?? "USD" + const currencyInfo = + currencies[currencyCode?.toUpperCase() || "USD"] + return ( @@ -280,9 +293,11 @@ export const EditPromotionDetailsForm = ({ {isFixedValueType ? ( - onChange(val ? parseInt(val) : null) - } + onValueChange={(val) => onChange(val)} + decimalSeparator="." + groupSeparator="," + decimalScale={currencyInfo.decimal_digits} + decimalsLimit={currencyInfo.decimal_digits} code={currencyCode} symbol={getCurrencySymbol(currencyCode)} {...field} @@ -299,7 +314,7 @@ export const EditPromotionDetailsForm = ({ onChange( e.target.value === "" ? null - : parseInt(e.target.value) + : parseFloat(e.target.value) ) }} />