fix(dashboard): edit promotion campaign w/wo currrency (#13404)
**What** - a promotion couldn't be added to a campaign without a currency budget (on promotion details screen) - fix fetching campaigns pagination issue - move select to Combobox - fix currency restriction and move warning description to the label hint
This commit is contained in:
@@ -130,6 +130,7 @@ export const useAddOrRemoveCampaignPromotions = (
|
||||
onSuccess: (data, variables, context) => {
|
||||
queryClient.invalidateQueries({ queryKey: campaignsQueryKeys.details() })
|
||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.lists() })
|
||||
queryClient.invalidateQueries({ queryKey: promotionsQueryKeys.details() })
|
||||
options?.onSuccess?.(data, variables, context)
|
||||
},
|
||||
...options,
|
||||
|
||||
@@ -2234,7 +2234,7 @@
|
||||
"total_used": "Budget used",
|
||||
"budget_limit": "Budget limit",
|
||||
"campaign_id": {
|
||||
"hint": "Only campaigns with the same currency code as the promotion are shown in this list."
|
||||
"hint": "Disabled campaigns have budget in a different currency than the promotion."
|
||||
}
|
||||
},
|
||||
"budget": {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { AdminCampaign, AdminPromotion } from "@medusajs/types"
|
||||
import { Button, RadioGroup, Select, Text, toast } from "@medusajs/ui"
|
||||
import { Button, RadioGroup, toast } from "@medusajs/ui"
|
||||
import { useEffect } from "react"
|
||||
import { useForm, useWatch } from "react-hook-form"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
|
||||
@@ -11,11 +11,14 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
||||
import { useUpdatePromotion } from "../../../../../hooks/api/promotions"
|
||||
import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields"
|
||||
import { CampaignDetails } from "./campaign-details"
|
||||
import { sdk } from "../../../../../lib/client"
|
||||
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
|
||||
import { Combobox } from "../../../../../components/inputs/combobox"
|
||||
import { useCampaign } from "../../../../../hooks/api/campaigns"
|
||||
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
|
||||
|
||||
type EditPromotionFormProps = {
|
||||
promotion: AdminPromotion
|
||||
campaigns: AdminCampaign[]
|
||||
}
|
||||
|
||||
const EditPromotionSchema = zod.object({
|
||||
@@ -25,14 +28,16 @@ const EditPromotionSchema = zod.object({
|
||||
|
||||
export const AddCampaignPromotionFields = ({
|
||||
form,
|
||||
campaigns,
|
||||
withNewCampaign = true,
|
||||
promotionCurrencyCode,
|
||||
}: {
|
||||
form: any
|
||||
campaigns: AdminCampaign[]
|
||||
withNewCampaign?: boolean
|
||||
promotionCurrencyCode?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const direction = useDocumentDirection()
|
||||
|
||||
const watchCampaignId = useWatch({
|
||||
control: form.control,
|
||||
name: "campaign_id",
|
||||
@@ -43,8 +48,31 @@ export const AddCampaignPromotionFields = ({
|
||||
name: "campaign_choice",
|
||||
})
|
||||
|
||||
const selectedCampaign = campaigns.find((c) => c.id === watchCampaignId)
|
||||
const direction = useDocumentDirection()
|
||||
const campaignsCombobox = useComboboxData({
|
||||
queryFn: (params) =>
|
||||
sdk.admin.campaign.list({
|
||||
...params,
|
||||
}),
|
||||
queryKey: ["campaigns"],
|
||||
getOptions: (data) =>
|
||||
data.campaigns.map((campaign) => ({
|
||||
label: campaign.name.toUpperCase(),
|
||||
value: campaign.id,
|
||||
disabled:
|
||||
campaign.budget?.currency_code &&
|
||||
campaign.budget?.currency_code?.toLowerCase() !==
|
||||
promotionCurrencyCode?.toLowerCase(), // also cannot add promotion which doesn't have currency defined to a campaign with a currency amount budget
|
||||
})),
|
||||
})
|
||||
|
||||
const { campaign: selectedCampaign } = useCampaign(
|
||||
watchCampaignId as string,
|
||||
undefined,
|
||||
{
|
||||
enabled: !!watchCampaignId,
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-8">
|
||||
<Form.Field
|
||||
@@ -99,58 +127,24 @@ export const AddCampaignPromotionFields = ({
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="campaign_id"
|
||||
render={({ field: { onChange, ref, ...field } }) => {
|
||||
render={({ field: { onChange, ...field } }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
<Form.Label tooltip={t("campaigns.fields.campaign_id.hint")}>
|
||||
{t("promotions.form.campaign.existing.title")}
|
||||
</Form.Label>
|
||||
|
||||
<Form.Control>
|
||||
<Select
|
||||
<Combobox
|
||||
dir={direction}
|
||||
onValueChange={onChange}
|
||||
options={campaignsCombobox.options}
|
||||
searchValue={campaignsCombobox.searchValue}
|
||||
onSearchValueChange={campaignsCombobox.onSearchValueChange}
|
||||
onChange={onChange}
|
||||
{...field}
|
||||
>
|
||||
<Select.Trigger ref={ref}>
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
|
||||
<Select.Content>
|
||||
{!campaigns.length && (
|
||||
<div className="flex h-[120px] flex-col items-center justify-center gap-2 p-2">
|
||||
<span className="txt-small text-ui-fg-subtle font-medium">
|
||||
{t(
|
||||
"promotions.form.campaign.existing.placeholder.title"
|
||||
)}
|
||||
</span>
|
||||
<span className="txt-small text-ui-fg-muted">
|
||||
{t(
|
||||
"promotions.form.campaign.existing.placeholder.desc"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{campaigns.map((c) => (
|
||||
<Select.Item key={c.id} value={c.id}>
|
||||
{c.name?.toUpperCase()}
|
||||
</Select.Item>
|
||||
))}
|
||||
</Select.Content>
|
||||
</Select>
|
||||
></Combobox>
|
||||
</Form.Control>
|
||||
|
||||
<Text
|
||||
size="small"
|
||||
leading="compact"
|
||||
className="text-ui-fg-subtle"
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="campaigns.fields.campaign_id.hint"
|
||||
components={[<br key="break" />]}
|
||||
/>
|
||||
</Text>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
@@ -162,14 +156,13 @@ export const AddCampaignPromotionFields = ({
|
||||
<CreateCampaignFormFields form={form} fieldScope="campaign." />
|
||||
)}
|
||||
|
||||
<CampaignDetails campaign={selectedCampaign} />
|
||||
<CampaignDetails campaign={selectedCampaign as AdminCampaign} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const AddCampaignPromotionForm = ({
|
||||
promotion,
|
||||
campaigns,
|
||||
}: EditPromotionFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleSuccess } = useRouteModal()
|
||||
@@ -227,8 +220,8 @@ export const AddCampaignPromotionForm = ({
|
||||
<RouteDrawer.Body className="size-full overflow-auto">
|
||||
<AddCampaignPromotionFields
|
||||
form={form}
|
||||
campaigns={campaigns}
|
||||
withNewCampaign={false}
|
||||
promotionCurrencyCode={promotion.application_method?.currency_code}
|
||||
/>
|
||||
</RouteDrawer.Body>
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useTranslation } from "react-i18next"
|
||||
import { useParams } from "react-router-dom"
|
||||
|
||||
import { RouteDrawer } from "../../../components/modals"
|
||||
import { useCampaigns } from "../../../hooks/api/campaigns"
|
||||
import { usePromotion } from "../../../hooks/api/promotions"
|
||||
import { AddCampaignPromotionForm } from "./components/add-campaign-promotion-form"
|
||||
|
||||
@@ -12,24 +11,8 @@ export const PromotionAddCampaign = () => {
|
||||
const { t } = useTranslation()
|
||||
const { promotion, isPending, isError, error } = usePromotion(id!)
|
||||
|
||||
let campaignQuery = {}
|
||||
|
||||
if (promotion?.application_method?.currency_code) {
|
||||
campaignQuery = {
|
||||
budget: {
|
||||
currency_code: promotion?.application_method?.currency_code,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
campaigns,
|
||||
isPending: areCampaignsLoading,
|
||||
isError: isCampaignError,
|
||||
error: campaignError,
|
||||
} = useCampaigns(campaignQuery)
|
||||
if (isError || isCampaignError) {
|
||||
throw error || campaignError
|
||||
if (isError) {
|
||||
throw error
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -38,8 +21,8 @@ export const PromotionAddCampaign = () => {
|
||||
<Heading>{t("promotions.campaign.edit.header")}</Heading>
|
||||
</RouteDrawer.Header>
|
||||
|
||||
{!isPending && !areCampaignsLoading && promotion && campaigns && (
|
||||
<AddCampaignPromotionForm promotion={promotion} campaigns={campaigns} />
|
||||
{!isPending && promotion && (
|
||||
<AddCampaignPromotionForm promotion={promotion} />
|
||||
)}
|
||||
</RouteDrawer>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user