From 294c37564ca035dc9b658bdce1f6afb4ced3d916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frane=20Poli=C4=87?= <16856471+fPolic@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:24:11 +0200 Subject: [PATCH] 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 --- .changeset/blue-hounds-unite.md | 5 + .../dashboard/src/hooks/api/campaigns.tsx | 1 + .../dashboard/src/i18n/translations/en.json | 2 +- .../add-campaign-promotion-form.tsx | 97 +++++++++---------- .../promotion-add-campaign.tsx | 25 +---- 5 files changed, 56 insertions(+), 74 deletions(-) create mode 100644 .changeset/blue-hounds-unite.md diff --git a/.changeset/blue-hounds-unite.md b/.changeset/blue-hounds-unite.md new file mode 100644 index 0000000000..842d2de948 --- /dev/null +++ b/.changeset/blue-hounds-unite.md @@ -0,0 +1,5 @@ +--- +"@medusajs/dashboard": patch +--- + +fix(dashboard): add campaign without currency to promotion diff --git a/packages/admin/dashboard/src/hooks/api/campaigns.tsx b/packages/admin/dashboard/src/hooks/api/campaigns.tsx index 1657ab2d8f..6d5f5824a2 100644 --- a/packages/admin/dashboard/src/hooks/api/campaigns.tsx +++ b/packages/admin/dashboard/src/hooks/api/campaigns.tsx @@ -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, diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 7bcc278506..3be87b4f4a 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -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": { diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/components/add-campaign-promotion-form/add-campaign-promotion-form.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/components/add-campaign-promotion-form/add-campaign-promotion-form.tsx index 3b18547ef1..ee5aaf6d74 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/components/add-campaign-promotion-form/add-campaign-promotion-form.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/components/add-campaign-promotion-form/add-campaign-promotion-form.tsx @@ -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 (
{ + render={({ field: { onChange, ...field } }) => { return ( - + {t("promotions.form.campaign.existing.title")} - + > - - ]} - /> - ) @@ -162,14 +156,13 @@ export const AddCampaignPromotionFields = ({ )} - +
) } export const AddCampaignPromotionForm = ({ promotion, - campaigns, }: EditPromotionFormProps) => { const { t } = useTranslation() const { handleSuccess } = useRouteModal() @@ -227,8 +220,8 @@ export const AddCampaignPromotionForm = ({ diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/promotion-add-campaign.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/promotion-add-campaign.tsx index 8d6ed05d3e..1f53c37c96 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/promotion-add-campaign.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-add-campaign/promotion-add-campaign.tsx @@ -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 = () => { {t("promotions.campaign.edit.header")} - {!isPending && !areCampaignsLoading && promotion && campaigns && ( - + {!isPending && promotion && ( + )} )