fix(dashboard): promotion decimal value definition (#13371)

* fix(dashboard): pormotion decimal value definition

* fix: typo

* fix: fixed value decimals

* fix: translation
This commit is contained in:
Frane Polić
2025-09-04 16:07:29 +02:00
committed by GitHub
parent 21c31a2ab2
commit b7fef5b7ef
6 changed files with 52 additions and 15 deletions

View File

@@ -7997,9 +7997,12 @@
"properties": {
"title": {
"type": "string"
},
"invalid": {
"type": "string"
}
},
"required": ["title"],
"required": ["title", "invalid"],
"additionalProperties": false
},
"value_type": {

View File

@@ -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": {

View File

@@ -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 (
<Form.Item className="basis-1/2">
<Form.Label
@@ -759,10 +766,16 @@ export const CreatePromotionForm = () => {
<CurrencyInput
{...field}
min={0}
onValueChange={(value) => {
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)
)
}}
/>

View File

@@ -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,

View File

@@ -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 (
<Form.Item>
<Form.Label>
@@ -280,9 +293,11 @@ export const EditPromotionDetailsForm = ({
{isFixedValueType ? (
<CurrencyInput
min={0}
onValueChange={(val) =>
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)
)
}}
/>