chore: buyget templates add default target + buy rules (#7500)
* chore: buyget templates add default target + buy rules * chore: reposition * chore: address comments * chore: added fixes * chore: fix typo * chore: fix strictness checks
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
import { AdminGetPromotionsParams } from "@medusajs/medusa"
|
import { AdminGetPromotionsParams } from "@medusajs/medusa"
|
||||||
import { AdminRuleValueOptionsListResponse } from "@medusajs/types"
|
import {
|
||||||
|
AdminPromotionRuleListResponse,
|
||||||
|
AdminRuleAttributeOptionsListResponse,
|
||||||
|
AdminRuleOperatorOptionsListResponse,
|
||||||
|
AdminRuleValueOptionsListResponse,
|
||||||
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
QueryKey,
|
QueryKey,
|
||||||
useMutation,
|
useMutation,
|
||||||
@@ -21,21 +26,23 @@ import {
|
|||||||
PromotionDeleteRes,
|
PromotionDeleteRes,
|
||||||
PromotionListRes,
|
PromotionListRes,
|
||||||
PromotionRes,
|
PromotionRes,
|
||||||
PromotionRuleAttributesListRes,
|
|
||||||
PromotionRuleOperatorsListRes,
|
|
||||||
PromotionRulesListRes,
|
|
||||||
} from "../../types/api-responses"
|
} from "../../types/api-responses"
|
||||||
import { campaignsQueryKeys } from "./campaigns"
|
import { campaignsQueryKeys } from "./campaigns"
|
||||||
|
|
||||||
const PROMOTIONS_QUERY_KEY = "promotions" as const
|
const PROMOTIONS_QUERY_KEY = "promotions" as const
|
||||||
export const promotionsQueryKeys = {
|
export const promotionsQueryKeys = {
|
||||||
...queryKeysFactory(PROMOTIONS_QUERY_KEY),
|
...queryKeysFactory(PROMOTIONS_QUERY_KEY),
|
||||||
listRules: (id: string | null, ruleType: string) => [
|
// TODO: handle invalidations properly
|
||||||
|
listRules: (
|
||||||
|
id: string | null,
|
||||||
|
ruleType: string,
|
||||||
|
query?: Record<string, string>
|
||||||
|
) => [PROMOTIONS_QUERY_KEY, id, ruleType, query],
|
||||||
|
listRuleAttributes: (ruleType: string, promotionType?: string) => [
|
||||||
PROMOTIONS_QUERY_KEY,
|
PROMOTIONS_QUERY_KEY,
|
||||||
id,
|
|
||||||
ruleType,
|
ruleType,
|
||||||
|
promotionType,
|
||||||
],
|
],
|
||||||
listRuleAttributes: (ruleType: string) => [PROMOTIONS_QUERY_KEY, ruleType],
|
|
||||||
listRuleValues: (ruleType: string, ruleValue: string, query: object) => [
|
listRuleValues: (ruleType: string, ruleValue: string, query: object) => [
|
||||||
PROMOTIONS_QUERY_KEY,
|
PROMOTIONS_QUERY_KEY,
|
||||||
ruleType,
|
ruleType,
|
||||||
@@ -64,19 +71,20 @@ export const usePromotion = (
|
|||||||
export const usePromotionRules = (
|
export const usePromotionRules = (
|
||||||
id: string | null,
|
id: string | null,
|
||||||
ruleType: string,
|
ruleType: string,
|
||||||
|
query?: Record<string, string>,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<
|
UseQueryOptions<
|
||||||
PromotionRulesListRes,
|
AdminPromotionRuleListResponse,
|
||||||
Error,
|
Error,
|
||||||
PromotionRulesListRes,
|
AdminPromotionRuleListResponse,
|
||||||
QueryKey
|
QueryKey
|
||||||
>,
|
>,
|
||||||
"queryFn" | "queryKey"
|
"queryFn" | "queryKey"
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
const { data, ...rest } = useQuery({
|
const { data, ...rest } = useQuery({
|
||||||
queryKey: promotionsQueryKeys.listRules(id, ruleType),
|
queryKey: promotionsQueryKeys.listRules(id, ruleType, query),
|
||||||
queryFn: async () => client.promotions.listRules(id, ruleType),
|
queryFn: async () => client.promotions.listRules(id, ruleType, query),
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -102,9 +110,9 @@ export const usePromotions = (
|
|||||||
export const usePromotionRuleOperators = (
|
export const usePromotionRuleOperators = (
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<
|
UseQueryOptions<
|
||||||
PromotionListRes,
|
AdminRuleOperatorOptionsListResponse,
|
||||||
Error,
|
Error,
|
||||||
PromotionRuleOperatorsListRes,
|
AdminRuleOperatorOptionsListResponse,
|
||||||
QueryKey
|
QueryKey
|
||||||
>,
|
>,
|
||||||
"queryFn" | "queryKey"
|
"queryFn" | "queryKey"
|
||||||
@@ -121,19 +129,21 @@ export const usePromotionRuleOperators = (
|
|||||||
|
|
||||||
export const usePromotionRuleAttributes = (
|
export const usePromotionRuleAttributes = (
|
||||||
ruleType: string,
|
ruleType: string,
|
||||||
|
promotionType?: string,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<
|
UseQueryOptions<
|
||||||
PromotionListRes,
|
AdminRuleAttributeOptionsListResponse,
|
||||||
Error,
|
Error,
|
||||||
PromotionRuleAttributesListRes,
|
AdminRuleAttributeOptionsListResponse,
|
||||||
QueryKey
|
QueryKey
|
||||||
>,
|
>,
|
||||||
"queryFn" | "queryKey"
|
"queryFn" | "queryKey"
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
const { data, ...rest } = useQuery({
|
const { data, ...rest } = useQuery({
|
||||||
queryKey: promotionsQueryKeys.listRuleAttributes(ruleType),
|
queryKey: promotionsQueryKeys.listRuleAttributes(ruleType, promotionType),
|
||||||
queryFn: async () => client.promotions.listRuleAttributes(ruleType),
|
queryFn: async () =>
|
||||||
|
client.promotions.listRuleAttributes(ruleType, promotionType),
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -207,10 +217,7 @@ export const useUpdatePromotion = (
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (payload) => client.promotions.update(id, payload),
|
mutationFn: (payload) => client.promotions.update(id, payload),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.all })
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: promotionsQueryKeys.detail(id),
|
|
||||||
})
|
|
||||||
|
|
||||||
options?.onSuccess?.(data, variables, context)
|
options?.onSuccess?.(data, variables, context)
|
||||||
},
|
},
|
||||||
@@ -226,10 +233,7 @@ export const usePromotionAddRules = (
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (payload) => client.promotions.addRules(id, ruleType, payload),
|
mutationFn: (payload) => client.promotions.addRules(id, ruleType, payload),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.all })
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: promotionsQueryKeys.detail(id),
|
|
||||||
})
|
|
||||||
|
|
||||||
options?.onSuccess?.(data, variables, context)
|
options?.onSuccess?.(data, variables, context)
|
||||||
},
|
},
|
||||||
@@ -250,10 +254,7 @@ export const usePromotionRemoveRules = (
|
|||||||
mutationFn: (payload) =>
|
mutationFn: (payload) =>
|
||||||
client.promotions.removeRules(id, ruleType, payload),
|
client.promotions.removeRules(id, ruleType, payload),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.all })
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: promotionsQueryKeys.detail(id),
|
|
||||||
})
|
|
||||||
|
|
||||||
options?.onSuccess?.(data, variables, context)
|
options?.onSuccess?.(data, variables, context)
|
||||||
},
|
},
|
||||||
@@ -274,13 +275,7 @@ export const usePromotionUpdateRules = (
|
|||||||
mutationFn: (payload) =>
|
mutationFn: (payload) =>
|
||||||
client.promotions.updateRules(id, ruleType, payload),
|
client.promotions.updateRules(id, ruleType, payload),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.all })
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: promotionsQueryKeys.listRules(id, ruleType),
|
|
||||||
})
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: promotionsQueryKeys.detail(id),
|
|
||||||
})
|
|
||||||
|
|
||||||
options?.onSuccess?.(data, variables, context)
|
options?.onSuccess?.(data, variables, context)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -981,15 +981,15 @@
|
|||||||
"conditions": {
|
"conditions": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"title": "Who can use this code?",
|
"title": "Who can use this code?",
|
||||||
"description": "Is the customer allowed to add the promotion code? Discount code can be used by all customers if left untouched. Choose between attributes, operators, and values to set up the conditions."
|
"description": "Is the customer allowed to add the promotion code? Discount code can be used by all customers if left untouched."
|
||||||
},
|
},
|
||||||
"target-rules": {
|
"target-rules": {
|
||||||
"title": "What needs to be in the cart to unlock the promotion?",
|
"title": "What will the promotion be applied to?",
|
||||||
"description": "If these conditions match, we enable a promotion action on the target items. Choose between attributes, operators, and values to set up the conditions."
|
"description": "The promotion will be applied to items that match the following conditions"
|
||||||
},
|
},
|
||||||
"buy-rules": {
|
"buy-rules": {
|
||||||
"title": "What will the promotion be applied to?",
|
"title": "What needs to be in the cart to unlock the promotion?",
|
||||||
"description": "The promotion will be applied to items that match these conditions"
|
"description": "If these conditions match, we enable the promotion on the target items."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -81,15 +81,23 @@ async function removePromotionRules(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listPromotionRules(id: string | null, ruleType: string) {
|
async function listPromotionRules(
|
||||||
|
id: string | null,
|
||||||
|
ruleType: string,
|
||||||
|
query?: Record<string, string>
|
||||||
|
) {
|
||||||
return getRequest<PromotionRuleAttributesListRes>(
|
return getRequest<PromotionRuleAttributesListRes>(
|
||||||
`/admin/promotions/${id}/${ruleType}`
|
`/admin/promotions/${id}/${ruleType}`,
|
||||||
|
query
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listPromotionRuleAttributes(ruleType: string) {
|
async function listPromotionRuleAttributes(
|
||||||
|
ruleType: string,
|
||||||
|
promotionType?: string
|
||||||
|
) {
|
||||||
return getRequest<PromotionRuleAttributesListRes>(
|
return getRequest<PromotionRuleAttributesListRes>(
|
||||||
`/admin/promotions/rule-attribute-options/${ruleType}`
|
`/admin/promotions/rule-attribute-options/${ruleType}?promotion_type=${promotionType}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-34
@@ -3,25 +3,23 @@ import { PromotionDTO, PromotionRuleDTO } from "@medusajs/types"
|
|||||||
import { Button } from "@medusajs/ui"
|
import { Button } from "@medusajs/ui"
|
||||||
import i18n from "i18next"
|
import i18n from "i18next"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useFieldArray, useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import * as zod from "zod"
|
import * as zod from "zod"
|
||||||
import { RouteDrawer } from "../../../../../../components/route-modal"
|
import { RouteDrawer } from "../../../../../../components/route-modal"
|
||||||
import { RuleTypeValues } from "../../edit-rules"
|
import { RuleTypeValues } from "../../edit-rules"
|
||||||
import { RulesFormField } from "../rules-form-field"
|
import { RulesFormField } from "../rules-form-field"
|
||||||
import { getDisguisedRules } from "./utils"
|
|
||||||
|
|
||||||
type EditPromotionFormProps = {
|
type EditPromotionFormProps = {
|
||||||
promotion: PromotionDTO
|
promotion: PromotionDTO
|
||||||
rules: PromotionRuleDTO[]
|
rules: PromotionRuleDTO[]
|
||||||
ruleType: RuleTypeValues
|
ruleType: RuleTypeValues
|
||||||
attributes: any[]
|
|
||||||
operators: any[]
|
|
||||||
handleSubmit: any
|
handleSubmit: any
|
||||||
isSubmitting: boolean
|
isSubmitting: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditRules = zod.object({
|
const EditRules = zod.object({
|
||||||
|
type: zod.string().optional(),
|
||||||
rules: zod.array(
|
rules: zod.array(
|
||||||
zod.object({
|
zod.object({
|
||||||
id: zod.string().optional(),
|
id: zod.string().optional(),
|
||||||
@@ -39,6 +37,7 @@ const EditRules = zod.object({
|
|||||||
.min(1, { message: i18n.t("promotions.form.required") }),
|
.min(1, { message: i18n.t("promotions.form.required") }),
|
||||||
]),
|
]),
|
||||||
required: zod.boolean().optional(),
|
required: zod.boolean().optional(),
|
||||||
|
disguised: zod.boolean().optional(),
|
||||||
field_type: zod.string().optional(),
|
field_type: zod.string().optional(),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
@@ -46,41 +45,18 @@ const EditRules = zod.object({
|
|||||||
|
|
||||||
export const EditRulesForm = ({
|
export const EditRulesForm = ({
|
||||||
promotion,
|
promotion,
|
||||||
rules,
|
|
||||||
ruleType,
|
ruleType,
|
||||||
attributes,
|
|
||||||
operators,
|
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
}: EditPromotionFormProps) => {
|
}: EditPromotionFormProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const requiredAttributes = attributes?.filter((ra) => ra.required) || []
|
|
||||||
const requiredAttributeValues = requiredAttributes?.map((ra) => ra.value)
|
|
||||||
const disguisedRules =
|
|
||||||
getDisguisedRules(promotion, requiredAttributes, ruleType) || []
|
|
||||||
const [rulesToRemove, setRulesToRemove] = useState([])
|
const [rulesToRemove, setRulesToRemove] = useState([])
|
||||||
|
|
||||||
const form = useForm<zod.infer<typeof EditRules>>({
|
const form = useForm<zod.infer<typeof EditRules>>({
|
||||||
defaultValues: {
|
defaultValues: { rules: [], type: promotion.type },
|
||||||
rules: [...disguisedRules, ...rules].map((rule) => ({
|
|
||||||
id: rule.id,
|
|
||||||
required: requiredAttributeValues.includes(rule.attribute),
|
|
||||||
attribute: rule.attribute!,
|
|
||||||
operator: rule.operator!,
|
|
||||||
values: Array.isArray(rule?.values)
|
|
||||||
? rule?.values?.map((v: any) => v.value!)
|
|
||||||
: rule.values!,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
resolver: zodResolver(EditRules),
|
resolver: zodResolver(EditRules),
|
||||||
})
|
})
|
||||||
|
|
||||||
const { fields, append, remove, update } = useFieldArray({
|
|
||||||
control: form.control,
|
|
||||||
name: "rules",
|
|
||||||
keyName: "rules_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleFormSubmit = form.handleSubmit(handleSubmit(rulesToRemove))
|
const handleFormSubmit = form.handleSubmit(handleSubmit(rulesToRemove))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -90,14 +66,9 @@ export const EditRulesForm = ({
|
|||||||
<RulesFormField
|
<RulesFormField
|
||||||
form={form}
|
form={form}
|
||||||
ruleType={ruleType}
|
ruleType={ruleType}
|
||||||
attributes={attributes}
|
|
||||||
operators={operators}
|
|
||||||
fields={fields}
|
|
||||||
setRulesToRemove={setRulesToRemove}
|
setRulesToRemove={setRulesToRemove}
|
||||||
rulesToRemove={rulesToRemove}
|
rulesToRemove={rulesToRemove}
|
||||||
appendRule={append}
|
promotionId={promotion.id}
|
||||||
removeRule={remove}
|
|
||||||
updateRule={update}
|
|
||||||
/>
|
/>
|
||||||
</RouteDrawer.Body>
|
</RouteDrawer.Body>
|
||||||
|
|
||||||
|
|||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
import { PromotionDTO } from "@medusajs/types"
|
|
||||||
import { RuleType } from "../../edit-rules"
|
|
||||||
|
|
||||||
// We are disguising couple of database columns as rules here, namely
|
|
||||||
// apply_to_quantity and buy_rules_min_quantity.
|
|
||||||
// We need to transform the database value into a disugised "rule" shape
|
|
||||||
// for the form
|
|
||||||
export function getDisguisedRules(
|
|
||||||
promotion: PromotionDTO,
|
|
||||||
requiredAttributes: any[],
|
|
||||||
ruleType: string
|
|
||||||
) {
|
|
||||||
if (ruleType === RuleType.RULES && !requiredAttributes?.length) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const applyToQuantityRule = requiredAttributes.find(
|
|
||||||
(attr) => attr.id === "apply_to_quantity"
|
|
||||||
)
|
|
||||||
|
|
||||||
const buyRulesMinQuantityRule = requiredAttributes.find(
|
|
||||||
(attr) => attr.id === "buy_rules_min_quantity"
|
|
||||||
)
|
|
||||||
|
|
||||||
const currencyCodeRule = requiredAttributes.find(
|
|
||||||
(attr) => attr.id === "currency_code"
|
|
||||||
)
|
|
||||||
|
|
||||||
if (ruleType === RuleType.RULES) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: "currency_code",
|
|
||||||
attribute: "currency_code",
|
|
||||||
operator: "eq",
|
|
||||||
required: currencyCodeRule?.required,
|
|
||||||
values: promotion?.application_method?.currency_code?.toLowerCase(),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ruleType === RuleType.TARGET_RULES) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: "apply_to_quantity",
|
|
||||||
attribute: "apply_to_quantity",
|
|
||||||
operator: "eq",
|
|
||||||
required: applyToQuantityRule?.required,
|
|
||||||
values: promotion?.application_method?.apply_to_quantity,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ruleType === RuleType.BUY_RULES) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: "buy_rules_min_quantity",
|
|
||||||
attribute: "buy_rules_min_quantity",
|
|
||||||
operator: "eq",
|
|
||||||
required: buyRulesMinQuantityRule?.required,
|
|
||||||
values: [
|
|
||||||
{ value: promotion?.application_method?.buy_rules_min_quantity },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+10
-46
@@ -2,19 +2,19 @@ import {
|
|||||||
CreatePromotionRuleDTO,
|
CreatePromotionRuleDTO,
|
||||||
PromotionDTO,
|
PromotionDTO,
|
||||||
PromotionRuleDTO,
|
PromotionRuleDTO,
|
||||||
|
PromotionRuleOperatorValues,
|
||||||
|
PromotionRuleResponse,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { useRouteModal } from "../../../../../../components/route-modal"
|
import { useRouteModal } from "../../../../../../components/route-modal"
|
||||||
import {
|
import {
|
||||||
usePromotionAddRules,
|
usePromotionAddRules,
|
||||||
usePromotionRemoveRules,
|
usePromotionRemoveRules,
|
||||||
usePromotionRuleAttributes,
|
|
||||||
usePromotionRuleOperators,
|
|
||||||
usePromotionUpdateRules,
|
usePromotionUpdateRules,
|
||||||
useUpdatePromotion,
|
useUpdatePromotion,
|
||||||
} from "../../../../../../hooks/api/promotions"
|
} from "../../../../../../hooks/api/promotions"
|
||||||
import { RuleTypeValues } from "../../edit-rules"
|
import { RuleTypeValues } from "../../edit-rules"
|
||||||
import { EditRulesForm } from "../edit-rules-form"
|
import { EditRulesForm } from "../edit-rules-form"
|
||||||
import { getDisguisedRules } from "../edit-rules-form/utils"
|
import { getRuleValue } from "./utils"
|
||||||
|
|
||||||
type EditPromotionFormProps = {
|
type EditPromotionFormProps = {
|
||||||
promotion: PromotionDTO
|
promotion: PromotionDTO
|
||||||
@@ -28,26 +28,6 @@ export const EditRulesWrapper = ({
|
|||||||
ruleType,
|
ruleType,
|
||||||
}: EditPromotionFormProps) => {
|
}: EditPromotionFormProps) => {
|
||||||
const { handleSuccess } = useRouteModal()
|
const { handleSuccess } = useRouteModal()
|
||||||
const {
|
|
||||||
attributes,
|
|
||||||
isError: isAttributesError,
|
|
||||||
error: attributesError,
|
|
||||||
} = usePromotionRuleAttributes(ruleType!)
|
|
||||||
|
|
||||||
const {
|
|
||||||
operators,
|
|
||||||
isError: isOperatorsError,
|
|
||||||
error: operatorsError,
|
|
||||||
} = usePromotionRuleOperators()
|
|
||||||
|
|
||||||
if (isAttributesError || isOperatorsError) {
|
|
||||||
throw attributesError || operatorsError
|
|
||||||
}
|
|
||||||
|
|
||||||
const requiredAttributes = attributes?.filter((ra) => ra.required) || []
|
|
||||||
const disguisedRules =
|
|
||||||
getDisguisedRules(promotion, requiredAttributes, ruleType) || []
|
|
||||||
|
|
||||||
const { mutateAsync: updatePromotion } = useUpdatePromotion(promotion.id)
|
const { mutateAsync: updatePromotion } = useUpdatePromotion(promotion.id)
|
||||||
const { mutateAsync: addPromotionRules } = usePromotionAddRules(
|
const { mutateAsync: addPromotionRules } = usePromotionAddRules(
|
||||||
promotion.id,
|
promotion.id,
|
||||||
@@ -63,33 +43,21 @@ export const EditRulesWrapper = ({
|
|||||||
usePromotionUpdateRules(promotion.id, ruleType)
|
usePromotionUpdateRules(promotion.id, ruleType)
|
||||||
|
|
||||||
const handleSubmit = (rulesToRemove?: { id: string }[]) => {
|
const handleSubmit = (rulesToRemove?: { id: string }[]) => {
|
||||||
return async function (data: { rules: PromotionRuleDTO[] }) {
|
return async function (data: { rules: PromotionRuleResponse[] }) {
|
||||||
const applicationMethodData: Record<any, any> = {}
|
const applicationMethodData: Record<any, any> = {}
|
||||||
const { rules: allRules = [] } = data
|
const { rules: allRules = [] } = data
|
||||||
const disguisedRulesData = allRules.filter((rule) =>
|
const disguisedRules = allRules.filter((rule) => rule.disguised)
|
||||||
disguisedRules.map((rule) => rule.id).includes(rule.id!)
|
|
||||||
)
|
|
||||||
|
|
||||||
// For all the rules that were disguised, convert them to actual values in the
|
// For all the rules that were disguised, convert them to actual values in the
|
||||||
// database, they are currently all under application_method. If more of these are coming
|
// database, they are currently all under application_method. If more of these are coming
|
||||||
// up, abstract this away.
|
// up, abstract this away.
|
||||||
for (const rule of disguisedRulesData) {
|
for (const rule of disguisedRules) {
|
||||||
const currentAttribute = attributes?.find(
|
applicationMethodData[rule.attribute] = getRuleValue(rule)
|
||||||
(attr) => attr.value === rule.attribute
|
|
||||||
)
|
|
||||||
|
|
||||||
applicationMethodData[rule.id!] =
|
|
||||||
currentAttribute?.field_type === "number"
|
|
||||||
? parseInt(rule.values as unknown as string)
|
|
||||||
: rule.values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This variable will contain the rules that are actual rule objects, without the disguised
|
// This variable will contain the rules that are actual rule objects, without the disguised
|
||||||
// objects
|
// objects
|
||||||
const rulesData = allRules.filter(
|
const rulesData = allRules.filter((rule) => !rule.disguised)
|
||||||
(rule) => !disguisedRules.map((rule) => rule.id).includes(rule.id!)
|
|
||||||
)
|
|
||||||
|
|
||||||
const rulesToCreate: CreatePromotionRuleDTO[] = rulesData.filter(
|
const rulesToCreate: CreatePromotionRuleDTO[] = rulesData.filter(
|
||||||
(rule) => !("id" in rule)
|
(rule) => !("id" in rule)
|
||||||
)
|
)
|
||||||
@@ -121,11 +89,11 @@ export const EditRulesWrapper = ({
|
|||||||
|
|
||||||
rulesToUpdate.length &&
|
rulesToUpdate.length &&
|
||||||
(await updatePromotionRules({
|
(await updatePromotionRules({
|
||||||
rules: rulesToUpdate.map((rule: PromotionRuleDTO) => {
|
rules: rulesToUpdate.map((rule: PromotionRuleResponse) => {
|
||||||
return {
|
return {
|
||||||
id: rule.id!,
|
id: rule.id!,
|
||||||
attribute: rule.attribute,
|
attribute: rule.attribute,
|
||||||
operator: rule.operator,
|
operator: rule.operator as PromotionRuleOperatorValues,
|
||||||
values: rule.values as unknown as string | string[],
|
values: rule.values as unknown as string | string[],
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -135,17 +103,13 @@ export const EditRulesWrapper = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes && operators) {
|
|
||||||
return (
|
return (
|
||||||
<EditRulesForm
|
<EditRulesForm
|
||||||
promotion={promotion}
|
promotion={promotion}
|
||||||
rules={rules}
|
rules={rules}
|
||||||
ruleType={ruleType}
|
ruleType={ruleType}
|
||||||
attributes={attributes}
|
|
||||||
operators={operators}
|
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
isSubmitting={isPending}
|
isSubmitting={isPending}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
import { PromotionRuleResponse } from "@medusajs/types"
|
||||||
|
|
||||||
|
export const getRuleValue = (rule: PromotionRuleResponse) => {
|
||||||
|
if (rule.field_type === "number") {
|
||||||
|
return parseInt(rule.values as unknown as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.field_type === "select") {
|
||||||
|
return rule.values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule.values
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
export const requiredProductRule = {
|
||||||
|
id: "product",
|
||||||
|
attribute: "items.product.id",
|
||||||
|
attribute_label: "Product",
|
||||||
|
operator: "eq",
|
||||||
|
operator_label: "Equal",
|
||||||
|
values: [],
|
||||||
|
required: true,
|
||||||
|
field_type: "select",
|
||||||
|
disguised: false,
|
||||||
|
}
|
||||||
+102
-39
@@ -1,31 +1,23 @@
|
|||||||
import { XMarkMini } from "@medusajs/icons"
|
import { XMarkMini } from "@medusajs/icons"
|
||||||
import {
|
import { PromotionRuleResponse } from "@medusajs/types"
|
||||||
RuleAttributeOptionsResponse,
|
|
||||||
RuleOperatorOptionsResponse,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import { Badge, Button, Heading, Select, Text } from "@medusajs/ui"
|
import { Badge, Button, Heading, Select, Text } from "@medusajs/ui"
|
||||||
import { Fragment } from "react"
|
import { Fragment, useEffect } from "react"
|
||||||
import {
|
import { useFieldArray, UseFormReturn, useWatch } from "react-hook-form"
|
||||||
FieldValues,
|
|
||||||
Path,
|
|
||||||
UseFieldArrayAppend,
|
|
||||||
UseFieldArrayRemove,
|
|
||||||
UseFieldArrayUpdate,
|
|
||||||
UseFormReturn,
|
|
||||||
} from "react-hook-form"
|
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { Form } from "../../../../../../components/common/form"
|
import { Form } from "../../../../../../components/common/form"
|
||||||
|
import {
|
||||||
|
usePromotionRuleAttributes,
|
||||||
|
usePromotionRuleOperators,
|
||||||
|
usePromotionRules,
|
||||||
|
} from "../../../../../../hooks/api/promotions"
|
||||||
|
import { CreatePromotionSchemaType } from "../../../../promotion-create/components/create-promotion-form/form-schema"
|
||||||
import { RuleValueFormField } from "../rule-value-form-field"
|
import { RuleValueFormField } from "../rule-value-form-field"
|
||||||
|
import { requiredProductRule } from "./constants"
|
||||||
|
|
||||||
type RulesFormFieldType<TSchema extends FieldValues> = {
|
type RulesFormFieldType = {
|
||||||
form: UseFormReturn<TSchema>
|
promotionId?: string
|
||||||
|
form: UseFormReturn<CreatePromotionSchemaType>
|
||||||
ruleType: "rules" | "target-rules" | "buy-rules"
|
ruleType: "rules" | "target-rules" | "buy-rules"
|
||||||
fields: any[]
|
|
||||||
attributes: RuleAttributeOptionsResponse[]
|
|
||||||
operators: RuleOperatorOptionsResponse[]
|
|
||||||
removeRule: UseFieldArrayRemove
|
|
||||||
updateRule: UseFieldArrayUpdate<TSchema>
|
|
||||||
appendRule: UseFieldArrayAppend<TSchema>
|
|
||||||
setRulesToRemove?: any
|
setRulesToRemove?: any
|
||||||
rulesToRemove?: any
|
rulesToRemove?: any
|
||||||
scope?:
|
scope?:
|
||||||
@@ -34,20 +26,91 @@ type RulesFormFieldType<TSchema extends FieldValues> = {
|
|||||||
| "application_method.target_rules"
|
| "application_method.target_rules"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RulesFormField = <TSchema extends FieldValues>({
|
const generateRuleAttributes = (rules?: PromotionRuleResponse[]) =>
|
||||||
|
(rules || []).map((rule) => ({
|
||||||
|
id: rule.id,
|
||||||
|
required: rule.required,
|
||||||
|
field_type: rule.field_type,
|
||||||
|
disguised: rule.disguised,
|
||||||
|
attribute: rule.attribute!,
|
||||||
|
operator: rule.operator!,
|
||||||
|
values:
|
||||||
|
rule.field_type === "number"
|
||||||
|
? rule.values
|
||||||
|
: rule?.values?.map((v: { value: string }) => v.value!),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const RulesFormField = ({
|
||||||
form,
|
form,
|
||||||
ruleType,
|
ruleType,
|
||||||
fields,
|
|
||||||
attributes,
|
|
||||||
operators,
|
|
||||||
removeRule,
|
|
||||||
updateRule,
|
|
||||||
appendRule,
|
|
||||||
setRulesToRemove,
|
setRulesToRemove,
|
||||||
rulesToRemove,
|
rulesToRemove,
|
||||||
scope = "rules",
|
scope = "rules",
|
||||||
}: RulesFormFieldType<TSchema>) => {
|
promotionId,
|
||||||
|
}: RulesFormFieldType) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const formData = form.getValues()
|
||||||
|
const { attributes } = usePromotionRuleAttributes(ruleType, formData.type)
|
||||||
|
const { operators } = usePromotionRuleOperators()
|
||||||
|
|
||||||
|
const { fields, append, remove, update, replace } = useFieldArray({
|
||||||
|
control: form.control,
|
||||||
|
name: scope,
|
||||||
|
keyName: scope,
|
||||||
|
})
|
||||||
|
|
||||||
|
const promotionType: string = useWatch({
|
||||||
|
control: form.control,
|
||||||
|
name: "type",
|
||||||
|
})
|
||||||
|
|
||||||
|
const query: Record<string, string> = promotionType
|
||||||
|
? { promotion_type: promotionType }
|
||||||
|
: {}
|
||||||
|
|
||||||
|
const { rules, isLoading } = usePromotionRules(
|
||||||
|
promotionId || null,
|
||||||
|
ruleType,
|
||||||
|
query,
|
||||||
|
{
|
||||||
|
enabled: !!promotionType,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ruleType === "rules" && !fields.length) {
|
||||||
|
replace(generateRuleAttributes(rules) as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ruleType === "rules" && promotionType === "standard") {
|
||||||
|
form.resetField("application_method.buy_rules")
|
||||||
|
form.resetField("application_method.target_rules")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
["buy-rules", "target-rules"].includes(ruleType) &&
|
||||||
|
promotionType === "standard"
|
||||||
|
) {
|
||||||
|
form.resetField(scope)
|
||||||
|
replace([])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
["buy-rules", "target-rules"].includes(ruleType) &&
|
||||||
|
promotionType === "buyget"
|
||||||
|
) {
|
||||||
|
form.resetField(scope)
|
||||||
|
const rulesToAppend = promotionId
|
||||||
|
? rules
|
||||||
|
: [...rules, requiredProductRule]
|
||||||
|
|
||||||
|
replace(generateRuleAttributes(rulesToAppend) as any)
|
||||||
|
}
|
||||||
|
}, [promotionType, isLoading])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
@@ -62,17 +125,17 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
{fields.map((fieldRule: any, index) => {
|
{fields.map((fieldRule: any, index) => {
|
||||||
const identifier = fieldRule.id
|
const identifier = fieldRule.id
|
||||||
const { ref: attributeRef, ...attributeField } = form.register(
|
const { ref: attributeRef, ...attributeField } = form.register(
|
||||||
`${scope}.${index}.attribute` as Path<TSchema>
|
`${scope}.${index}.attribute`
|
||||||
)
|
)
|
||||||
const { ref: operatorRef, ...operatorsField } = form.register(
|
const { ref: operatorRef, ...operatorsField } = form.register(
|
||||||
`${scope}.${index}.operator` as Path<TSchema>
|
`${scope}.${index}.operator`
|
||||||
)
|
)
|
||||||
const { ref: valuesRef, ...valuesField } = form.register(
|
const { ref: valuesRef, ...valuesField } = form.register(
|
||||||
`${scope}.${index}.values` as Path<TSchema>
|
`${scope}.${index}.values`
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={`${fieldRule.id}.${index}`}>
|
<Fragment key={`${fieldRule.id}.${index}.${fieldRule.attribute}`}>
|
||||||
<div className="bg-ui-bg-subtle border-ui-border-base flex flex-row gap-2 rounded-xl border px-2 py-2">
|
<div className="bg-ui-bg-subtle border-ui-border-base flex flex-row gap-2 rounded-xl border px-2 py-2">
|
||||||
<div className="grow">
|
<div className="grow">
|
||||||
<Form.Field
|
<Form.Field
|
||||||
@@ -102,10 +165,10 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
<Select
|
<Select
|
||||||
{...field}
|
{...field}
|
||||||
onValueChange={(e) => {
|
onValueChange={(e) => {
|
||||||
updateRule(index, { ...fieldRule, values: [] })
|
update(index, { ...fieldRule, values: [] })
|
||||||
onChange(e)
|
onChange(e)
|
||||||
}}
|
}}
|
||||||
disabled={fieldRule.required}
|
disabled={fieldRule.disguised}
|
||||||
>
|
>
|
||||||
<Select.Trigger
|
<Select.Trigger
|
||||||
ref={attributeRef}
|
ref={attributeRef}
|
||||||
@@ -149,7 +212,7 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
<Select
|
<Select
|
||||||
{...field}
|
{...field}
|
||||||
onValueChange={onChange}
|
onValueChange={onChange}
|
||||||
disabled={fieldRule.required}
|
disabled={fieldRule.disguised}
|
||||||
>
|
>
|
||||||
<Select.Trigger
|
<Select.Trigger
|
||||||
ref={operatorRef}
|
ref={operatorRef}
|
||||||
@@ -203,7 +266,7 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
setRulesToRemove &&
|
setRulesToRemove &&
|
||||||
setRulesToRemove([...rulesToRemove, fieldRule])
|
setRulesToRemove([...rulesToRemove, fieldRule])
|
||||||
|
|
||||||
removeRule(index)
|
remove(index)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -229,7 +292,7 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="inline-block"
|
className="inline-block"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appendRule({
|
append({
|
||||||
attribute: "",
|
attribute: "",
|
||||||
operator: "",
|
operator: "",
|
||||||
values: [],
|
values: [],
|
||||||
@@ -251,7 +314,7 @@ export const RulesFormField = <TSchema extends FieldValues>({
|
|||||||
|
|
||||||
setRulesToRemove &&
|
setRulesToRemove &&
|
||||||
setRulesToRemove(fields.filter((field: any) => !field.required))
|
setRulesToRemove(fields.filter((field: any) => !field.required))
|
||||||
removeRule(indicesToRemove)
|
remove(indicesToRemove)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("promotions.fields.clearAll")}
|
{t("promotions.fields.clearAll")}
|
||||||
|
|||||||
+18
-118
@@ -11,16 +11,11 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
} from "@medusajs/ui"
|
} from "@medusajs/ui"
|
||||||
import { useEffect, useMemo, useState } from "react"
|
import { useEffect, useMemo, useState } from "react"
|
||||||
import { useFieldArray, useForm, useWatch } from "react-hook-form"
|
import { useForm, useWatch } from "react-hook-form"
|
||||||
import { Trans, useTranslation } from "react-i18next"
|
import { Trans, useTranslation } from "react-i18next"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import {
|
import { PromotionRuleOperatorValues } from "@medusajs/types"
|
||||||
PromotionRuleOperatorValues,
|
|
||||||
PromotionRuleResponse,
|
|
||||||
RuleAttributeOptionsResponse,
|
|
||||||
RuleOperatorOptionsResponse,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import { Divider } from "../../../../../components/common/divider"
|
import { Divider } from "../../../../../components/common/divider"
|
||||||
import { Form } from "../../../../../components/common/form"
|
import { Form } from "../../../../../components/common/form"
|
||||||
import { PercentageInput } from "../../../../../components/inputs/percentage-input"
|
import { PercentageInput } from "../../../../../components/inputs/percentage-input"
|
||||||
@@ -38,42 +33,13 @@ import { Tab } from "./constants"
|
|||||||
import { CreatePromotionSchema } from "./form-schema"
|
import { CreatePromotionSchema } from "./form-schema"
|
||||||
import { templates } from "./templates"
|
import { templates } from "./templates"
|
||||||
|
|
||||||
type CreatePromotionFormProps = {
|
export const CreatePromotionForm = () => {
|
||||||
ruleAttributes: RuleAttributeOptionsResponse[]
|
|
||||||
targetRuleAttributes: RuleAttributeOptionsResponse[]
|
|
||||||
buyRuleAttributes: RuleAttributeOptionsResponse[]
|
|
||||||
operators: RuleOperatorOptionsResponse[]
|
|
||||||
rules: PromotionRuleResponse[]
|
|
||||||
targetRules: PromotionRuleResponse[]
|
|
||||||
buyRules: PromotionRuleResponse[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CreatePromotionForm = ({
|
|
||||||
ruleAttributes,
|
|
||||||
targetRuleAttributes,
|
|
||||||
buyRuleAttributes,
|
|
||||||
operators,
|
|
||||||
rules,
|
|
||||||
targetRules,
|
|
||||||
buyRules,
|
|
||||||
}: CreatePromotionFormProps) => {
|
|
||||||
const [tab, setTab] = useState<Tab>(Tab.TYPE)
|
const [tab, setTab] = useState<Tab>(Tab.TYPE)
|
||||||
const [detailsValidated, setDetailsValidated] = useState(false)
|
const [detailsValidated, setDetailsValidated] = useState(false)
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleSuccess } = useRouteModal()
|
const { handleSuccess } = useRouteModal()
|
||||||
|
|
||||||
const generateRuleAttributes = (rules: PromotionRuleResponse[]) =>
|
|
||||||
rules.map((rule) => ({
|
|
||||||
id: rule.id,
|
|
||||||
required: rule.required,
|
|
||||||
field_type: rule.field_type,
|
|
||||||
disguised: rule.disguised,
|
|
||||||
attribute: rule.attribute!,
|
|
||||||
operator: rule.operator!,
|
|
||||||
values: rule?.values?.map((v: { value: string }) => v.value!),
|
|
||||||
}))
|
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof CreatePromotionSchema>>({
|
const form = useForm<z.infer<typeof CreatePromotionSchema>>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
campaign_id: undefined,
|
campaign_id: undefined,
|
||||||
@@ -82,53 +48,20 @@ export const CreatePromotionForm = ({
|
|||||||
is_automatic: "false",
|
is_automatic: "false",
|
||||||
code: "",
|
code: "",
|
||||||
type: "standard",
|
type: "standard",
|
||||||
rules: generateRuleAttributes(rules),
|
rules: [],
|
||||||
application_method: {
|
application_method: {
|
||||||
allocation: "each",
|
allocation: "each",
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "items",
|
target_type: "items",
|
||||||
max_quantity: 1,
|
max_quantity: 1,
|
||||||
target_rules: generateRuleAttributes(targetRules),
|
target_rules: [],
|
||||||
buy_rules: generateRuleAttributes(buyRules),
|
buy_rules: [],
|
||||||
},
|
},
|
||||||
campaign: undefined,
|
campaign: undefined,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(CreatePromotionSchema),
|
resolver: zodResolver(CreatePromotionSchema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
|
||||||
fields: ruleFields,
|
|
||||||
append: appendRule,
|
|
||||||
remove: removeRule,
|
|
||||||
update: updateRule,
|
|
||||||
} = useFieldArray({
|
|
||||||
control: form.control,
|
|
||||||
name: "rules",
|
|
||||||
keyName: "rules_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
const {
|
|
||||||
fields: targetRuleFields,
|
|
||||||
append: appendTargetRule,
|
|
||||||
remove: removeTargetRule,
|
|
||||||
update: updateTargetRule,
|
|
||||||
} = useFieldArray({
|
|
||||||
control: form.control,
|
|
||||||
name: "application_method.target_rules",
|
|
||||||
keyName: "target_rules_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
const {
|
|
||||||
fields: buyRuleFields,
|
|
||||||
append: appendBuyRule,
|
|
||||||
remove: removeBuyRule,
|
|
||||||
update: updateBuyRule,
|
|
||||||
} = useFieldArray({
|
|
||||||
control: form.control,
|
|
||||||
name: "application_method.buy_rules",
|
|
||||||
keyName: "buy_rules_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
const { mutateAsync: createPromotion } = useCreatePromotion()
|
const { mutateAsync: createPromotion } = useCreatePromotion()
|
||||||
|
|
||||||
const handleSubmit = form.handleSubmit(
|
const handleSubmit = form.handleSubmit(
|
||||||
@@ -265,14 +198,11 @@ export const CreatePromotionForm = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const isFixedValueType = watchValueType === "fixed"
|
const isFixedValueType = watchValueType === "fixed"
|
||||||
|
|
||||||
const watchAllocation = useWatch({
|
const watchAllocation = useWatch({
|
||||||
control: form.control,
|
control: form.control,
|
||||||
name: "application_method.allocation",
|
name: "application_method.allocation",
|
||||||
})
|
})
|
||||||
|
|
||||||
const isAllocationEach = watchAllocation === "each"
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (watchAllocation === "across") {
|
if (watchAllocation === "across") {
|
||||||
form.setValue("application_method.max_quantity", null)
|
form.setValue("application_method.max_quantity", null)
|
||||||
@@ -296,17 +226,6 @@ export const CreatePromotionForm = ({
|
|||||||
|
|
||||||
const { campaigns } = useCampaigns(campaignQuery)
|
const { campaigns } = useCampaigns(campaignQuery)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isTypeStandard) {
|
|
||||||
form.setValue("application_method.buy_rules", undefined)
|
|
||||||
} else {
|
|
||||||
form.setValue(
|
|
||||||
"application_method.buy_rules",
|
|
||||||
generateRuleAttributes(buyRules)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [isTypeStandard])
|
|
||||||
|
|
||||||
const detailsProgress = useMemo(() => {
|
const detailsProgress = useMemo(() => {
|
||||||
if (detailsValidated) {
|
if (detailsValidated) {
|
||||||
return "completed"
|
return "completed"
|
||||||
@@ -592,16 +511,7 @@ export const CreatePromotionForm = ({
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<RulesFormField
|
<RulesFormField form={form} ruleType={"rules"} />
|
||||||
form={form}
|
|
||||||
ruleType={"rules"}
|
|
||||||
attributes={ruleAttributes}
|
|
||||||
operators={operators}
|
|
||||||
fields={ruleFields}
|
|
||||||
appendRule={appendRule}
|
|
||||||
removeRule={removeRule}
|
|
||||||
updateRule={updateRule}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
@@ -756,7 +666,7 @@ export const CreatePromotionForm = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isTypeStandard && isAllocationEach && (
|
{isTypeStandard && watchAllocation === "each" && (
|
||||||
<div className="flex gap-y-4">
|
<div className="flex gap-y-4">
|
||||||
<Form.Field
|
<Form.Field
|
||||||
control={form.control}
|
control={form.control}
|
||||||
@@ -800,33 +710,23 @@ export const CreatePromotionForm = ({
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<RulesFormField
|
|
||||||
form={form}
|
|
||||||
ruleType={"target-rules"}
|
|
||||||
attributes={targetRuleAttributes}
|
|
||||||
operators={operators}
|
|
||||||
fields={targetRuleFields}
|
|
||||||
appendRule={appendTargetRule}
|
|
||||||
removeRule={removeTargetRule}
|
|
||||||
updateRule={updateTargetRule}
|
|
||||||
scope="application_method.target_rules"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{!isTypeStandard && (
|
{!isTypeStandard && (
|
||||||
|
<>
|
||||||
<RulesFormField
|
<RulesFormField
|
||||||
form={form}
|
form={form}
|
||||||
ruleType={"buy-rules"}
|
ruleType={"buy-rules"}
|
||||||
attributes={buyRuleAttributes}
|
|
||||||
operators={operators}
|
|
||||||
fields={buyRuleFields}
|
|
||||||
appendRule={appendBuyRule}
|
|
||||||
removeRule={removeBuyRule}
|
|
||||||
updateRule={updateBuyRule}
|
|
||||||
scope="application_method.buy_rules"
|
scope="application_method.buy_rules"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<RulesFormField
|
||||||
|
form={form}
|
||||||
|
ruleType={"target-rules"}
|
||||||
|
scope="application_method.target_rules"
|
||||||
|
/>
|
||||||
</ProgressTabs.Content>
|
</ProgressTabs.Content>
|
||||||
|
|
||||||
<ProgressTabs.Content
|
<ProgressTabs.Content
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ export const CreatePromotionSchema = z
|
|||||||
currency_code: z.string(),
|
currency_code: z.string(),
|
||||||
max_quantity: z.number().optional().nullable(),
|
max_quantity: z.number().optional().nullable(),
|
||||||
target_rules: RuleSchema,
|
target_rules: RuleSchema,
|
||||||
buy_rules: RuleSchema.min(2).optional(),
|
buy_rules: RuleSchema,
|
||||||
type: z.enum(["fixed", "percentage"]),
|
type: z.enum(["fixed", "percentage"]),
|
||||||
target_type: z.enum(["order", "shipping_methods", "items"]),
|
target_type: z.enum(["order", "shipping_methods", "items"]),
|
||||||
}),
|
}),
|
||||||
|
|||||||
+1
-37
@@ -1,42 +1,6 @@
|
|||||||
import { RouteFocusModal } from "../../../components/route-modal"
|
import { RouteFocusModal } from "../../../components/route-modal"
|
||||||
import {
|
|
||||||
usePromotionRuleAttributes,
|
|
||||||
usePromotionRuleOperators,
|
|
||||||
usePromotionRules,
|
|
||||||
} from "../../../hooks/api/promotions"
|
|
||||||
import { CreatePromotionForm } from "./components/create-promotion-form/create-promotion-form"
|
import { CreatePromotionForm } from "./components/create-promotion-form/create-promotion-form"
|
||||||
|
|
||||||
export const PromotionCreate = () => {
|
export const PromotionCreate = () => {
|
||||||
const { attributes: ruleAttributes } = usePromotionRuleAttributes("rules")
|
return <RouteFocusModal>{<CreatePromotionForm />}</RouteFocusModal>
|
||||||
const { attributes: targetRuleAttributes } =
|
|
||||||
usePromotionRuleAttributes("target-rules")
|
|
||||||
const { attributes: buyRuleAttributes } =
|
|
||||||
usePromotionRuleAttributes("buy-rules")
|
|
||||||
|
|
||||||
const { rules } = usePromotionRules(null, "rules")
|
|
||||||
const { rules: targetRules } = usePromotionRules(null, "target-rules")
|
|
||||||
const { rules: buyRules } = usePromotionRules(null, "buy-rules")
|
|
||||||
const { operators } = usePromotionRuleOperators()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RouteFocusModal>
|
|
||||||
{rules &&
|
|
||||||
buyRules &&
|
|
||||||
targetRules &&
|
|
||||||
operators &&
|
|
||||||
ruleAttributes &&
|
|
||||||
targetRuleAttributes &&
|
|
||||||
buyRuleAttributes && (
|
|
||||||
<CreatePromotionForm
|
|
||||||
ruleAttributes={ruleAttributes}
|
|
||||||
targetRuleAttributes={targetRuleAttributes}
|
|
||||||
buyRuleAttributes={buyRuleAttributes}
|
|
||||||
operators={operators}
|
|
||||||
rules={rules}
|
|
||||||
targetRules={targetRules}
|
|
||||||
buyRules={buyRules}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</RouteFocusModal>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -30,7 +30,11 @@ function RuleBlock({ rule }: RuleProps) {
|
|||||||
<BadgeListSummary
|
<BadgeListSummary
|
||||||
inline
|
inline
|
||||||
className="!txt-compact-small-plus"
|
className="!txt-compact-small-plus"
|
||||||
list={rule.values.map((v) => v.label)}
|
list={
|
||||||
|
rule.field_type === "number"
|
||||||
|
? [rule.values]
|
||||||
|
: rule.values?.map((v) => v.label)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+9
-3
@@ -17,9 +17,15 @@ export const PromotionDetail = () => {
|
|||||||
|
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
const { promotion, isLoading } = usePromotion(id!, { initialData })
|
const { promotion, isLoading } = usePromotion(id!, { initialData })
|
||||||
const { rules } = usePromotionRules(id!, "rules")
|
const query: Record<string, string> = {}
|
||||||
const { rules: targetRules } = usePromotionRules(id!, "target-rules")
|
|
||||||
const { rules: buyRules } = usePromotionRules(id!, "buy-rules")
|
if (promotion?.type === "buyget") {
|
||||||
|
query.promotion_type = promotion.type
|
||||||
|
}
|
||||||
|
|
||||||
|
const { rules } = usePromotionRules(id!, "rules", query)
|
||||||
|
const { rules: targetRules } = usePromotionRules(id!, "target-rules", query)
|
||||||
|
const { rules: buyRules } = usePromotionRules(id!, "buy-rules", query)
|
||||||
|
|
||||||
if (isLoading || !promotion) {
|
if (isLoading || !promotion) {
|
||||||
return <div>Loading...</div>
|
return <div>Loading...</div>
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ export interface PromotionRuleResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminPromotionRuleListResponse {
|
export interface AdminPromotionRuleListResponse {
|
||||||
attributes: PromotionRuleResponse[]
|
rules: PromotionRuleResponse[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ import { CreatePromotionRuleDTO, PromotionRuleDTO } from "./promotion-rule"
|
|||||||
*/
|
*/
|
||||||
export type PromotionTypeValues = "standard" | "buyget"
|
export type PromotionTypeValues = "standard" | "buyget"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The promotion's possible rule types.
|
||||||
|
*/
|
||||||
|
export type RuleTypeValues = "rules" | "buy-rules" | "target-rules"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The promotion details.
|
* The promotion details.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../types/routing"
|
} from "../../../../../types/routing"
|
||||||
import {
|
import {
|
||||||
|
getRuleAttributesMap,
|
||||||
operatorsMap,
|
operatorsMap,
|
||||||
ruleAttributesMap,
|
|
||||||
ruleQueryConfigurations,
|
ruleQueryConfigurations,
|
||||||
validateRuleType,
|
validateRuleType,
|
||||||
} from "../../utils"
|
} from "../../utils"
|
||||||
@@ -33,7 +33,9 @@ export const GET = async (
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [promotion] = await remoteQuery(queryObject)
|
const [promotion] = await remoteQuery(queryObject)
|
||||||
const ruleAttributes = ruleAttributesMap[ruleType]
|
const ruleAttributes = getRuleAttributesMap(
|
||||||
|
promotion?.type || req.query.promotion_type
|
||||||
|
)[ruleType]
|
||||||
const promotionRules: any[] = []
|
const promotionRules: any[] = []
|
||||||
|
|
||||||
if (dasherizedRuleType === RuleType.RULES) {
|
if (dasherizedRuleType === RuleType.RULES) {
|
||||||
@@ -49,8 +51,19 @@ export const GET = async (
|
|||||||
const requiredRules = ruleAttributes.filter((attr) => !!attr.required)
|
const requiredRules = ruleAttributes.filter((attr) => !!attr.required)
|
||||||
|
|
||||||
for (const disguisedRule of disguisedRules) {
|
for (const disguisedRule of disguisedRules) {
|
||||||
|
const getValues = () => {
|
||||||
const value = promotion?.application_method?.[disguisedRule.id]
|
const value = promotion?.application_method?.[disguisedRule.id]
|
||||||
const values = value ? [{ label: value, value }] : []
|
|
||||||
|
if (disguisedRule.field_type === "number") {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
return [{ label: value, value }]
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
transformedRules.push({
|
transformedRules.push({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@@ -60,7 +73,7 @@ export const GET = async (
|
|||||||
hydrate: disguisedRule.hydrate || false,
|
hydrate: disguisedRule.hydrate || false,
|
||||||
operator: RuleOperator.EQ,
|
operator: RuleOperator.EQ,
|
||||||
operator_label: operatorsMap[RuleOperator.EQ].label,
|
operator_label: operatorsMap[RuleOperator.EQ].label,
|
||||||
values,
|
values: getValues(),
|
||||||
disguised: true,
|
disguised: true,
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@@ -90,7 +103,7 @@ export const GET = async (
|
|||||||
entryPoint: queryConfig.entryPoint,
|
entryPoint: queryConfig.entryPoint,
|
||||||
variables: {
|
variables: {
|
||||||
filters: {
|
filters: {
|
||||||
[queryConfig.valueAttr]: promotionRule.values.map((v) => v.value),
|
[queryConfig.valueAttr]: promotionRule.values?.map((v) => v.value),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fields: [queryConfig.labelAttr, queryConfig.valueAttr],
|
fields: [queryConfig.labelAttr, queryConfig.valueAttr],
|
||||||
@@ -104,10 +117,11 @@ export const GET = async (
|
|||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
promotionRule.values = promotionRule.values.map((value) => ({
|
promotionRule.values =
|
||||||
|
promotionRule.values?.map((value) => ({
|
||||||
value: value.value,
|
value: value.value,
|
||||||
label: valueLabelMap.get(value.value) || value.value,
|
label: valueLabelMap.get(value.value) || value.value,
|
||||||
}))
|
})) || promotionRule.values
|
||||||
|
|
||||||
if (!currentRuleAttribute.hydrate) {
|
if (!currentRuleAttribute.hydrate) {
|
||||||
transformedRules.push({
|
transformedRules.push({
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
|
import { unlessPath } from "../../utils/unless-path"
|
||||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
import { createBatchBody } from "../../utils/validators"
|
import { createBatchBody } from "../../utils/validators"
|
||||||
@@ -62,9 +63,12 @@ export const adminPromotionRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/promotions/:id/:rule_type",
|
matcher: "/admin/promotions/:id/:rule_type",
|
||||||
middlewares: [
|
middlewares: [
|
||||||
|
unlessPath(
|
||||||
|
/.*\/promotions\/rule-attribute-options/,
|
||||||
validateAndTransformQuery(
|
validateAndTransformQuery(
|
||||||
AdminGetPromotionRuleTypeParams,
|
AdminGetPromotionRuleTypeParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -118,4 +122,14 @@ export const adminPromotionRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/promotions/rule-attribute-options/:rule_type",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetPromotionRuleParams,
|
||||||
|
QueryConfig.listRuleTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
+5
-3
@@ -2,17 +2,19 @@ import {
|
|||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../types/routing"
|
} from "../../../../../types/routing"
|
||||||
import { ruleAttributesMap, validateRuleType } from "../../utils"
|
import { getRuleAttributesMap, validateRuleType } from "../../utils"
|
||||||
|
import { AdminGetPromotionRuleParamsType } from "../../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest<AdminGetPromotionRuleParamsType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const { rule_type: ruleType } = req.params
|
const { rule_type: ruleType } = req.params
|
||||||
|
|
||||||
validateRuleType(ruleType)
|
validateRuleType(ruleType)
|
||||||
|
|
||||||
const attributes = ruleAttributesMap[ruleType] || []
|
const attributes =
|
||||||
|
getRuleAttributesMap(req.query.promotion_type as string)[ruleType] || []
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
attributes,
|
attributes,
|
||||||
|
|||||||
+8
-3
@@ -11,12 +11,17 @@ import {
|
|||||||
validateRuleAttribute,
|
validateRuleAttribute,
|
||||||
validateRuleType,
|
validateRuleType,
|
||||||
} from "../../../utils"
|
} from "../../../utils"
|
||||||
|
import { AdminGetPromotionRuleParamsType } from "../../../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest<AdminGetPromotionRuleParamsType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const { rule_type: ruleType, rule_attribute_id: ruleAttributeId } = req.params
|
const {
|
||||||
|
rule_type: ruleType,
|
||||||
|
rule_attribute_id: ruleAttributeId,
|
||||||
|
promotion_type: promotionType,
|
||||||
|
} = req.params
|
||||||
const queryConfig = ruleQueryConfigurations[ruleAttributeId]
|
const queryConfig = ruleQueryConfigurations[ruleAttributeId]
|
||||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
const filterableFields = req.filterableFields
|
const filterableFields = req.filterableFields
|
||||||
@@ -28,7 +33,7 @@ export const GET = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
validateRuleType(ruleType)
|
validateRuleType(ruleType)
|
||||||
validateRuleAttribute(ruleType, ruleAttributeId)
|
validateRuleAttribute(promotionType, ruleType, ruleAttributeId)
|
||||||
|
|
||||||
const { rows } = await remoteQuery(
|
const { rows } = await remoteQuery(
|
||||||
remoteQueryObjectFromString({
|
remoteQueryObjectFromString({
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
|
import { PromotionType } from "@medusajs/utils"
|
||||||
|
|
||||||
export enum DisguisedRule {
|
export enum DisguisedRule {
|
||||||
APPLY_TO_QUANTITY = "apply_to_quantity",
|
APPLY_TO_QUANTITY = "apply_to_quantity",
|
||||||
BUY_RULES_MIN_QUANTITY = "buy_rules_min_quantity",
|
BUY_RULES_MIN_QUANTITY = "buy_rules_min_quantity",
|
||||||
CURRENCY_CODE = "currency_code",
|
CURRENCY_CODE = "currency_code",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const disguisedRulesMap = {
|
|
||||||
[DisguisedRule.APPLY_TO_QUANTITY]: {
|
|
||||||
relation: "application_method",
|
|
||||||
},
|
|
||||||
[DisguisedRule.BUY_RULES_MIN_QUANTITY]: {
|
|
||||||
relation: "application_method",
|
|
||||||
},
|
|
||||||
[DisguisedRule.CURRENCY_CODE]: {
|
|
||||||
relation: "application_method",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const ruleAttributes = [
|
const ruleAttributes = [
|
||||||
{
|
{
|
||||||
id: DisguisedRule.CURRENCY_CODE,
|
id: DisguisedRule.CURRENCY_CODE,
|
||||||
@@ -94,7 +84,7 @@ const commonAttributes = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const buyRuleAttributes = [
|
const buyGetBuyRules = [
|
||||||
{
|
{
|
||||||
id: DisguisedRule.BUY_RULES_MIN_QUANTITY,
|
id: DisguisedRule.BUY_RULES_MIN_QUANTITY,
|
||||||
value: DisguisedRule.BUY_RULES_MIN_QUANTITY,
|
value: DisguisedRule.BUY_RULES_MIN_QUANTITY,
|
||||||
@@ -103,10 +93,9 @@ const buyRuleAttributes = [
|
|||||||
required: true,
|
required: true,
|
||||||
disguised: true,
|
disguised: true,
|
||||||
},
|
},
|
||||||
...commonAttributes,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const targetRuleAttributes = [
|
const buyGetTargetRules = [
|
||||||
{
|
{
|
||||||
id: DisguisedRule.APPLY_TO_QUANTITY,
|
id: DisguisedRule.APPLY_TO_QUANTITY,
|
||||||
value: DisguisedRule.APPLY_TO_QUANTITY,
|
value: DisguisedRule.APPLY_TO_QUANTITY,
|
||||||
@@ -115,11 +104,19 @@ const targetRuleAttributes = [
|
|||||||
required: true,
|
required: true,
|
||||||
disguised: true,
|
disguised: true,
|
||||||
},
|
},
|
||||||
...commonAttributes,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
export const ruleAttributesMap = {
|
export const getRuleAttributesMap = (promotionType?: string) => {
|
||||||
rules: ruleAttributes,
|
const map = {
|
||||||
"target-rules": targetRuleAttributes,
|
rules: [...ruleAttributes],
|
||||||
"buy-rules": buyRuleAttributes,
|
"target-rules": [...commonAttributes],
|
||||||
|
"buy-rules": [...commonAttributes],
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promotionType === PromotionType.BUYGET) {
|
||||||
|
map["buy-rules"].push(...buyGetBuyRules)
|
||||||
|
map["target-rules"].push(...buyGetTargetRules)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { MedusaError } from "@medusajs/utils"
|
import { MedusaError } from "@medusajs/utils"
|
||||||
import { ruleAttributesMap } from "./rule-attributes-map"
|
import { getRuleAttributesMap } from "./rule-attributes-map"
|
||||||
|
|
||||||
export function validateRuleAttribute(
|
export function validateRuleAttribute(
|
||||||
|
promotionType: string | undefined,
|
||||||
ruleType: string,
|
ruleType: string,
|
||||||
ruleAttributeId: string
|
ruleAttributeId: string
|
||||||
) {
|
) {
|
||||||
const ruleAttributes = ruleAttributesMap[ruleType] || []
|
const ruleAttributes = getRuleAttributesMap(promotionType)[ruleType] || []
|
||||||
const ruleAttribute = ruleAttributes.find((obj) => obj.id === ruleAttributeId)
|
const ruleAttribute = ruleAttributes.find((obj) => obj.id === ruleAttributeId)
|
||||||
|
|
||||||
if (!ruleAttribute) {
|
if (!ruleAttribute) {
|
||||||
|
|||||||
@@ -47,12 +47,18 @@ export const AdminGetPromotionsParams = createFindParams({
|
|||||||
export type AdminGetPromotionRuleParamsType = z.infer<
|
export type AdminGetPromotionRuleParamsType = z.infer<
|
||||||
typeof AdminGetPromotionRuleParams
|
typeof AdminGetPromotionRuleParams
|
||||||
>
|
>
|
||||||
export const AdminGetPromotionRuleParams = createSelectParams()
|
export const AdminGetPromotionRuleParams = z.object({
|
||||||
|
promotion_type: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
export type AdminGetPromotionRuleTypeParamsType = z.infer<
|
export type AdminGetPromotionRuleTypeParamsType = z.infer<
|
||||||
typeof AdminGetPromotionRuleTypeParams
|
typeof AdminGetPromotionRuleTypeParams
|
||||||
>
|
>
|
||||||
export const AdminGetPromotionRuleTypeParams = createSelectParams()
|
export const AdminGetPromotionRuleTypeParams = createSelectParams().merge(
|
||||||
|
z.object({
|
||||||
|
promotion_type: z.string().optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
export type AdminGetPromotionsRuleValueParamsType = z.infer<
|
export type AdminGetPromotionsRuleValueParamsType = z.infer<
|
||||||
typeof AdminGetPromotionsRuleValueParams
|
typeof AdminGetPromotionsRuleValueParams
|
||||||
|
|||||||
Reference in New Issue
Block a user