+
+ {t("fields.conditions")}
+
+
+ ]}
/>
diff --git a/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/create-discount-form.tsx b/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/create-discount-form.tsx
index c93622d141..e2af1b7a69 100644
--- a/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/create-discount-form.tsx
+++ b/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/create-discount-form.tsx
@@ -2,19 +2,104 @@ import * as zod from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { UseFormReturn, useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
+import { formatISODuration } from "date-fns"
import { Button } from "@medusajs/ui"
-import { useAdminCreateDiscount } from "medusa-react"
+import { useAdminCreateDiscount, useAdminRegions } from "medusa-react"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
-import { CreateDiscountDetails } from "./create-discount-details.tsx"
+import { CreateDiscountDetails } from "./create-discount-details"
+import { DiscountRuleType } from "./types"
+import { getDbAmount } from "../../../../../lib/money-amount-helpers"
-const CreateDiscountSchema = zod.object({
- code: zod.string(),
-})
+/**
+ * There is some duplication here but we cannot achieve
+ * expected behaviour from the form with only union + discriminateUnion
+ */
+const CreateDiscountSchema = zod.discriminatedUnion("type", [
+ zod.object({
+ code: zod.string(),
+ regions: zod.array(zod.string()).min(1),
+ is_dynamic: zod.boolean(),
+ start_date: zod.date().optional(),
+ end_date: zod.date().optional(),
+ usage_limit: zod.number().optional(),
+ description: zod.string().optional(),
+
+ start_date_enabled: zod.boolean().optional(),
+ end_date_enabled: zod.boolean().optional(),
+ usage_limit_enabled: zod.boolean().optional(),
+ valid_duration_enabled: zod.boolean().optional(),
+
+ years: zod.number().optional(),
+ months: zod.number().optional(),
+ days: zod.number().optional(),
+ hours: zod.number().optional(),
+ minutes: zod.number().optional(),
+ value: zod.number().min(0).max(100),
+ type: zod.literal(DiscountRuleType.PERCENTAGE),
+ }),
+ zod.object({
+ code: zod.string(),
+ regions: zod.array(zod.string()).min(1),
+ is_dynamic: zod.boolean(),
+ start_date: zod.date().optional(),
+ end_date: zod.date().optional(),
+ usage_limit: zod.number().optional(),
+ description: zod.string().optional(),
+
+ start_date_enabled: zod.boolean().optional(),
+ end_date_enabled: zod.boolean().optional(),
+ usage_limit_enabled: zod.boolean().optional(),
+ valid_duration_enabled: zod.boolean().optional(),
+
+ years: zod.number().optional(),
+ months: zod.number().optional(),
+ days: zod.number().optional(),
+ hours: zod.number().optional(),
+ minutes: zod.number().optional(),
+
+ value: zod.union([zod.string(), zod.number()]).refine((value) => {
+ if (value === "") {
+ return false
+ }
+
+ const num = Number(value)
+
+ if (isNaN(num)) {
+ return false
+ }
+
+ return num >= 0
+ }, "Amount must be a positive number"),
+ type: zod.literal(DiscountRuleType.FIXED),
+ }),
+ zod.object({
+ code: zod.string(),
+ regions: zod.array(zod.string()).min(1),
+ is_dynamic: zod.boolean(),
+ start_date: zod.date().optional(),
+ end_date: zod.date().optional(),
+ usage_limit: zod.number().optional(),
+ description: zod.string().optional(),
+
+ start_date_enabled: zod.boolean().optional(),
+ end_date_enabled: zod.boolean().optional(),
+ usage_limit_enabled: zod.boolean().optional(),
+ valid_duration_enabled: zod.boolean().optional(),
+
+ years: zod.number().optional(),
+ months: zod.number().optional(),
+ days: zod.number().optional(),
+ hours: zod.number().optional(),
+ minutes: zod.number().optional(),
+ value: zod.undefined(),
+ type: zod.literal(DiscountRuleType.FREE_SHIPPING),
+ }),
+])
type Schema = zod.infer
export type CreateDiscountFormReturn = UseFormReturn
@@ -25,17 +110,65 @@ export const CreateDiscountForm = () => {
const form = useForm({
defaultValues: {
- code: "",
+ regions: [],
+ is_dynamic: false,
+ type: DiscountRuleType.PERCENTAGE,
},
resolver: zodResolver(CreateDiscountSchema),
})
const { mutateAsync, isLoading } = useAdminCreateDiscount()
+ const { regions } = useAdminRegions()
+
+ const handleSubmit = form.handleSubmit(async (values: Schema) => {
+ const getValue = () => {
+ if (values.type === DiscountRuleType.FREE_SHIPPING) {
+ return 0
+ }
+
+ if (values.type === DiscountRuleType.PERCENTAGE) {
+ return values.value
+ }
+
+ const amount =
+ typeof values.value === "string" ? Number(values.value) : values.value
+
+ const region = regions!.find((r) => r.id === values.regions[0])
+
+ return getDbAmount(amount, region!.currency_code)
+ }
+
+ const duration = {
+ years: values.years,
+ months: values.months,
+ days: values.days,
+ hours: values.hours,
+ minutes: values.minutes,
+ }
+
+ const isDurationEmpty = Object.values(duration).every((v) => !v)
- const handleSubmit = form.handleSubmit(async (values) => {
await mutateAsync(
{
code: values.code,
+ regions: values.regions,
+ is_dynamic: values.is_dynamic,
+ starts_at: values.start_date_enabled ? values.start_date : undefined,
+ ends_at: values.end_date_enabled ? values.end_date : undefined,
+ is_disabled: false,
+ usage_limit: values.usage_limit_enabled
+ ? values.usage_limit
+ : undefined,
+ valid_duration:
+ values.valid_duration_enabled && !isDurationEmpty
+ ? formatISODuration(duration)
+ : undefined,
+ rule: {
+ value: getValue(),
+ type: values.type,
+ description: values.description,
+ allocation: "total" as any,
+ },
},
{
onSuccess: ({ discount }) => {
diff --git a/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/types.ts b/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/types.ts
new file mode 100644
index 0000000000..64c4ec69cb
--- /dev/null
+++ b/packages/admin-next/dashboard/src/routes/discounts/create/components/create-discount-form/types.ts
@@ -0,0 +1,5 @@
+export enum DiscountRuleType {
+ FIXED = "fixed",
+ PERCENTAGE = "percentage",
+ FREE_SHIPPING = "free_shipping",
+}
diff --git a/packages/admin-next/dashboard/src/routes/discounts/edit-configuration/components/edit-discount-form/edit-discount-configuration-form.tsx b/packages/admin-next/dashboard/src/routes/discounts/edit-configuration/components/edit-discount-form/edit-discount-configuration-form.tsx
index 800a4696ca..1c7808b819 100644
--- a/packages/admin-next/dashboard/src/routes/discounts/edit-configuration/components/edit-discount-form/edit-discount-configuration-form.tsx
+++ b/packages/admin-next/dashboard/src/routes/discounts/edit-configuration/components/edit-discount-form/edit-discount-configuration-form.tsx
@@ -79,16 +79,18 @@ export const EditDiscountConfigurationForm = ({
const { mutateAsync, isLoading } = useAdminUpdateDiscount(discount.id)
const handleSubmit = form.handleSubmit(async (data) => {
+ const duration = pick(data, ["years", "months", "days", "hours", "minutes"])
+ const isDurationEmpty = Object.values(duration).every((v) => !v)
+
await mutateAsync(
{
starts_at: data.start_date,
ends_at: data.end_date_enabled ? data.end_date : null,
usage_limit: data.enable_usage_limit ? data.usage_limit : null,
- valid_duration: data.enable_duration
- ? formatISODuration(
- pick(data, ["years", "months", "days", "hours", "minutes"])
- )
- : null,
+ valid_duration:
+ data.enable_duration && !isDurationEmpty
+ ? formatISODuration(duration)
+ : null,
},
{
onSuccess: () => {
@@ -189,40 +191,34 @@ export const EditDiscountConfigurationForm = ({
)
}}
/>
- {
- return (
-
-
-
- {
- onChange(v ?? null)
- }}
- {...field}
- /**
- * TODO: FIX bug in the picker when a placeholder is provided it resets selected value to undefined
- */
- // placeholder="DD/MM/YYYY HH:MM"
- /*
- * Disable input here. If set on Field it wont properly set the value.
- */
- disabled={!form.watch("end_date_enabled")}
- />
-
-
+ {form.watch("end_date_enabled") && (
+ {
+ return (
+
+
+
+ {
+ onChange(v ?? null)
+ }}
+ {...field}
+ />
+
+
-
-
- )
- }}
- />
+
+
+ )
+ }}
+ />
+ )}
@@ -254,34 +250,35 @@ export const EditDiscountConfigurationForm = ({
}}
/>
-
{
- return (
-
-
- {
- const value = e.target.value
+ {form.watch("enable_usage_limit") && (
+ {
+ return (
+
+
+ {
+ const value = e.target.value
- if (value === "") {
- field.onChange(null)
- } else {
- field.onChange(Number(value))
- }
- }}
- />
-
-
-
- )
- }}
- />
+ if (value === "") {
+ field.onChange(null)
+ } else {
+ field.onChange(Number(value))
+ }
+ }}
+ />
+
+
+
+ )
+ }}
+ />
+ )}