From e5b90b2d972ac6bbd68db3f0e8dbf7b3fece39e8 Mon Sep 17 00:00:00 2001 From: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:18:38 +0200 Subject: [PATCH] fix(dashboard): Fixes to campaign and promotions domains (#9022) --- .../common/code-cell/code-cell.tsx | 7 +- .../use-promotion-table-columns.tsx | 0 .../use-promotion-table-filters.tsx | 13 - .../use-promotion-table-query.tsx | 0 .../dashboard/src/i18n/translations/en.json | 19 +- .../admin/dashboard/src/lib/promotions.ts | 4 +- .../providers/router-provider/route-map.tsx | 5 + .../add-campaign-promotions-form.tsx | 4 +- .../campaign-configuration.tsx | 33 + .../campaign-configuration-form.tsx | 133 +++ .../campaign-configuration-form/index.ts | 1 + .../campaigns/campaign-configuration/index.ts | 1 + .../create-campaign-form.tsx | 14 +- .../campaign-detail/campaign-detail.tsx | 86 +- .../campaign-configuration-section.tsx | 43 + .../campaign-configuration-section/index.ts | 1 + .../campaign-general-section.tsx | 21 - .../campaign-promotion-section.tsx | 4 +- .../product-create-form.tsx | 11 +- .../add-campaign-promotion-form.tsx | 33 +- .../promotion-add-campaign.tsx | 2 +- .../create-promotion-form.tsx | 840 +++++++++--------- .../promotion-create/promotion-create.tsx | 6 +- .../campaign-section/campaign-section.tsx | 118 +-- .../promotion-conditions-section.tsx | 6 +- .../promotion-general-section.tsx | 60 +- .../promotion-detail/promotion-detail.tsx | 78 +- .../edit-promotion-details-form.tsx | 47 +- .../promotion-list-table.tsx | 6 +- 29 files changed, 886 insertions(+), 710 deletions(-) rename packages/admin/dashboard/src/hooks/table/{columns-v2 => columns}/use-promotion-table-columns.tsx (100%) delete mode 100644 packages/admin/dashboard/src/hooks/table/filters-v2/use-promotion-table-filters.tsx rename packages/admin/dashboard/src/hooks/table/{query-v2 => query}/use-promotion-table-query.tsx (100%) create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-configuration/campaign-configuration.tsx create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/campaign-configuration-form.tsx create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/index.ts create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-configuration/index.ts create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/campaign-configuration-section.tsx create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/index.ts diff --git a/packages/admin/dashboard/src/components/table/table-cells/common/code-cell/code-cell.tsx b/packages/admin/dashboard/src/components/table/table-cells/common/code-cell/code-cell.tsx index 62ab371009..1f72501e41 100644 --- a/packages/admin/dashboard/src/components/table/table-cells/common/code-cell/code-cell.tsx +++ b/packages/admin/dashboard/src/components/table/table-cells/common/code-cell/code-cell.tsx @@ -1,3 +1,5 @@ +import { Badge } from "@medusajs/ui" + type CellProps = { code: string } @@ -9,10 +11,9 @@ type HeaderProps = { export const CodeCell = ({ code }: CellProps) => { return (
- {/* // TODO: border color inversion*/} - + {code} - +
) } diff --git a/packages/admin/dashboard/src/hooks/table/columns-v2/use-promotion-table-columns.tsx b/packages/admin/dashboard/src/hooks/table/columns/use-promotion-table-columns.tsx similarity index 100% rename from packages/admin/dashboard/src/hooks/table/columns-v2/use-promotion-table-columns.tsx rename to packages/admin/dashboard/src/hooks/table/columns/use-promotion-table-columns.tsx diff --git a/packages/admin/dashboard/src/hooks/table/filters-v2/use-promotion-table-filters.tsx b/packages/admin/dashboard/src/hooks/table/filters-v2/use-promotion-table-filters.tsx deleted file mode 100644 index 246191a7cc..0000000000 --- a/packages/admin/dashboard/src/hooks/table/filters-v2/use-promotion-table-filters.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useTranslation } from "react-i18next" -import { Filter } from "../../../components/table/data-table" - -export const usePromotionTableFilters = () => { - const { t } = useTranslation() - - let filters: Filter[] = [ - { label: t("fields.createdAt"), key: "created_at", type: "date" }, - { label: t("fields.updatedAt"), key: "updated_at", type: "date" }, - ] - - return filters -} diff --git a/packages/admin/dashboard/src/hooks/table/query-v2/use-promotion-table-query.tsx b/packages/admin/dashboard/src/hooks/table/query/use-promotion-table-query.tsx similarity index 100% rename from packages/admin/dashboard/src/hooks/table/query-v2/use-promotion-table-query.tsx rename to packages/admin/dashboard/src/hooks/table/query/use-promotion-table-query.tsx diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 95dccebaf8..4c639606e4 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -1694,8 +1694,15 @@ "title": "Edit buy rules" } }, - "addToCampaign": { - "title": "Promotion's Campaign" + "campaign": { + "header": "Campaign", + "edit": { + "header": "Edit Campaign", + "successToast": "Successfully updated the campaign of the promotion." + }, + "actions": { + "goToCampaign": "Go to campaign" + } }, "campaign_currency": { "tooltip": "This is the promotion's currency. Change it from the Details tab." @@ -1800,6 +1807,14 @@ "header": "Edit Campaign", "successToast": "Campaign '{{name}}' was successfully updated." }, + "configuration": { + "header": "Configuration", + "edit": { + "header": "Edit Campaign Configuration", + "description": "Edit the configuration of the campaign.", + "successToast": "Campaign configuration was successfully updated." + } + }, "create": { "hint": "Create a promotional campaign.", "header": "Create Campaign", diff --git a/packages/admin/dashboard/src/lib/promotions.ts b/packages/admin/dashboard/src/lib/promotions.ts index 0627e711d5..e13d1db445 100644 --- a/packages/admin/dashboard/src/lib/promotions.ts +++ b/packages/admin/dashboard/src/lib/promotions.ts @@ -1,4 +1,4 @@ -import { PromotionDTO } from "@medusajs/types" +import { HttpTypes } from "@medusajs/types" export enum PromotionStatus { SCHEDULED = "SCHEDULED", @@ -7,7 +7,7 @@ export enum PromotionStatus { DISABLED = "DISABLED", } -export const getPromotionStatus = (promotion: PromotionDTO) => { +export const getPromotionStatus = (promotion: HttpTypes.AdminPromotion) => { const date = new Date() const campaign = promotion.campaign diff --git a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx index 168a7e857d..54d9a3c7c5 100644 --- a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx +++ b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx @@ -355,6 +355,11 @@ export const RouteMap: RouteObject[] = [ path: "edit", lazy: () => import("../../routes/campaigns/campaign-edit"), }, + { + path: "configuration", + lazy: () => + import("../../routes/campaigns/campaign-configuration"), + }, { path: "edit-budget", lazy: () => diff --git a/packages/admin/dashboard/src/routes/campaigns/add-campaign-promotions/components/add-campaign-promotions-form.tsx b/packages/admin/dashboard/src/routes/campaigns/add-campaign-promotions/components/add-campaign-promotions-form.tsx index 5167b12802..3a0559d026 100644 --- a/packages/admin/dashboard/src/routes/campaigns/add-campaign-promotions/components/add-campaign-promotions-form.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/add-campaign-promotions/components/add-campaign-promotions-form.tsx @@ -15,9 +15,9 @@ import { RouteFocusModal, useRouteModal } from "../../../../components/modals" import { DataTable } from "../../../../components/table/data-table" import { useAddOrRemoveCampaignPromotions } from "../../../../hooks/api/campaigns" import { usePromotions } from "../../../../hooks/api/promotions" -import { usePromotionTableColumns } from "../../../../hooks/table/columns-v2/use-promotion-table-columns" +import { usePromotionTableColumns } from "../../../../hooks/table/columns/use-promotion-table-columns" import { usePromotionTableFilters } from "../../../../hooks/table/filters/use-promotion-table-filters" -import { usePromotionTableQuery } from "../../../../hooks/table/query-v2/use-promotion-table-query" +import { usePromotionTableQuery } from "../../../../hooks/table/query/use-promotion-table-query" import { useDataTable } from "../../../../hooks/use-data-table" type AddCampaignPromotionsFormProps = { diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/campaign-configuration.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/campaign-configuration.tsx new file mode 100644 index 0000000000..e63618f92d --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/campaign-configuration.tsx @@ -0,0 +1,33 @@ +import { Heading } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { useParams } from "react-router-dom" +import { RouteDrawer } from "../../../components/modals" +import { useCampaign } from "../../../hooks/api/campaigns" +import { CampaignConfigurationForm } from "./components/campaign-configuration-form" + +export const CampaignConfiguration = () => { + const { t } = useTranslation() + + const { id } = useParams() + const { campaign, isLoading, isError, error } = useCampaign(id!) + + if (isError) { + throw error + } + + return ( + + + + {t("campaigns.configuration.edit.header")} + + + {t("campaigns.configuration.edit.description")} + + + {!isLoading && campaign && ( + + )} + + ) +} diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/campaign-configuration-form.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/campaign-configuration-form.tsx new file mode 100644 index 0000000000..5159523b9d --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/campaign-configuration-form.tsx @@ -0,0 +1,133 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import { AdminCampaign } from "@medusajs/types" +import { Button, DatePicker, toast } from "@medusajs/ui" +import { useForm } from "react-hook-form" +import { useTranslation } from "react-i18next" +import { z } from "zod" + +import { Form } from "../../../../../components/common/form" +import { RouteDrawer, useRouteModal } from "../../../../../components/modals" +import { useUpdateCampaign } from "../../../../../hooks/api/campaigns" + +type CampaignConfigurationFormProps = { + campaign: AdminCampaign +} + +const CampaignConfigurationSchema = z.object({ + starts_at: z.date().nullable(), + ends_at: z.date().nullable(), +}) + +export const CampaignConfigurationForm = ({ + campaign, +}: CampaignConfigurationFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + starts_at: campaign.starts_at ? new Date(campaign.starts_at) : undefined, + ends_at: campaign.ends_at ? new Date(campaign.ends_at) : undefined, + }, + resolver: zodResolver(CampaignConfigurationSchema), + }) + + const { mutateAsync, isPending } = useUpdateCampaign(campaign.id) + + const handleSubmit = form.handleSubmit(async (data) => { + await mutateAsync( + { + starts_at: data.starts_at || null, + ends_at: data.ends_at || null, + }, + { + onSuccess: ({ campaign }) => { + toast.success( + t("campaigns.configuration.edit.successToast", { + name: campaign.name, + }) + ) + + handleSuccess() + }, + onError: (error) => { + toast.error(error.message) + }, + } + ) + }) + + return ( + +
+ +
+ { + return ( + + {t("campaigns.fields.start_date")} + + + + + + + + ) + }} + /> + + { + return ( + + {t("campaigns.fields.end_date")} + + + + + + + + ) + }} + /> +
+
+ + +
+ + + + + +
+
+
+
+ ) +} diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/index.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/index.ts new file mode 100644 index 0000000000..b6f67aaaea --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/components/campaign-configuration-form/index.ts @@ -0,0 +1 @@ +export * from "./campaign-configuration-form" diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/index.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/index.ts new file mode 100644 index 0000000000..246c41fc8c --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-configuration/index.ts @@ -0,0 +1 @@ +export { CampaignConfiguration as Component } from "./campaign-configuration" diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx index 49c5611a40..71ecf142a7 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx @@ -78,8 +78,12 @@ export const CreateCampaignForm = () => { return ( -
- + + + + + +
-
- - - - +
) diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx index 8355fbb38c..bc1fd4aed1 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx @@ -1,6 +1,5 @@ -import { Outlet, useLoaderData, useParams } from "react-router-dom" +import { useLoaderData, useParams } from "react-router-dom" -import { JsonViewSection } from "../../../components/common/json-view-section" import { useCampaign } from "../../../hooks/api/campaigns" import { CampaignBudget } from "./components/campaign-budget" import { CampaignGeneralSection } from "./components/campaign-general-section" @@ -12,6 +11,9 @@ import after from "virtual:medusa/widgets/campaign/details/after" import before from "virtual:medusa/widgets/campaign/details/before" import sideAfter from "virtual:medusa/widgets/campaign/details/side/after" import sideBefore from "virtual:medusa/widgets/campaign/details/side/before" +import { TwoColumnPageSkeleton } from "../../../components/common/skeleton" +import { TwoColumnPage } from "../../../components/layout/pages" +import { CampaignConfigurationSection } from "./components/campaign-configuration-section" export const CampaignDetail = () => { const initialData = useLoaderData() as Awaited< @@ -26,7 +28,14 @@ export const CampaignDetail = () => { ) if (isLoading || !campaign) { - return
Loading...
+ return ( + + ) } if (isError) { @@ -34,54 +43,27 @@ export const CampaignDetail = () => { } return ( -
- {before.widgets.map((w, i) => { - return ( -
- -
- ) - })} -
-
- - - {after.widgets.map((w, i) => { - return ( -
- -
- ) - })} -
- -
-
- -
- {sideBefore.widgets.map((w, i) => { - return ( -
- -
- ) - })} - - - {sideAfter.widgets.map((w, i) => { - return ( -
- -
- ) - })} -
- -
-
-
- - -
+ + + + + + + + + + + ) } diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/campaign-configuration-section.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/campaign-configuration-section.tsx new file mode 100644 index 0000000000..1d7094baaa --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/campaign-configuration-section.tsx @@ -0,0 +1,43 @@ +import { HttpTypes } from "@medusajs/types" +import { Container, Heading } from "@medusajs/ui" + +import { PencilSquare } from "@medusajs/icons" +import { useTranslation } from "react-i18next" +import { ActionMenu } from "../../../../../components/common/action-menu" +import { DateRangeDisplay } from "../../../../../components/common/date-range-display" + +type CampaignConfigurationSectionProps = { + campaign: HttpTypes.AdminCampaign +} + +export const CampaignConfigurationSection = ({ + campaign, +}: CampaignConfigurationSectionProps) => { + const { t } = useTranslation() + + return ( + +
+ {t("campaigns.configuration.header")} + , + to: "configuration", + }, + ], + }, + ]} + /> +
+ +
+ ) +} diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/index.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/index.ts new file mode 100644 index 0000000000..942cf8d4f6 --- /dev/null +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-configuration-section/index.ts @@ -0,0 +1 @@ +export * from "./campaign-configuration-section"; diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-general-section/campaign-general-section.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-general-section/campaign-general-section.tsx index b6f317cc24..d69b45f6fa 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-general-section/campaign-general-section.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-general-section/campaign-general-section.tsx @@ -12,7 +12,6 @@ import { import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" -import { formatDate } from "../../../../../components/common/date" import { useDeleteCampaign } from "../../../../../hooks/api/campaigns" import { currencies } from "../../../../../lib/data/currencies" import { @@ -133,26 +132,6 @@ export const CampaignGeneralSection = ({ )} - -
- - {t("campaigns.fields.start_date")} - - - - {campaign.starts_at ? formatDate(campaign.starts_at) : "-"} - -
- -
- - {t("campaigns.fields.end_date")} - - - - {campaign.ends_at ? formatDate(campaign.ends_at) : "-"} - -
) } diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-promotion-section/campaign-promotion-section.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-promotion-section/campaign-promotion-section.tsx index 3f730e6543..e684783551 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-promotion-section/campaign-promotion-section.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/components/campaign-promotion-section/campaign-promotion-section.tsx @@ -10,9 +10,9 @@ import { ActionMenu } from "../../../../../components/common/action-menu" import { DataTable } from "../../../../../components/table/data-table" import { useAddOrRemoveCampaignPromotions } from "../../../../../hooks/api/campaigns" import { usePromotions } from "../../../../../hooks/api/promotions" -import { usePromotionTableColumns } from "../../../../../hooks/table/columns-v2/use-promotion-table-columns" +import { usePromotionTableColumns } from "../../../../../hooks/table/columns/use-promotion-table-columns" import { usePromotionTableFilters } from "../../../../../hooks/table/filters/use-promotion-table-filters" -import { usePromotionTableQuery } from "../../../../../hooks/table/query-v2/use-promotion-table-query" +import { usePromotionTableQuery } from "../../../../../hooks/table/query/use-promotion-table-query" import { useDataTable } from "../../../../../hooks/use-data-table" type CampaignPromotionSectionProps = { diff --git a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx index 0e61863103..6d540f66be 100644 --- a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx @@ -74,13 +74,10 @@ export const ProductCreateForm = ({ return {} } - return regions.reduce( - (acc, reg) => { - acc[reg.id] = reg.currency_code - return acc - }, - {} as Record - ) + return regions.reduce((acc, reg) => { + acc[reg.id] = reg.currency_code + return acc + }, {} as Record) }, [regions]) /** 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 44e9b5106c..ab56e02d80 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,6 +1,6 @@ import { zodResolver } from "@hookform/resolvers/zod" import { AdminCampaign, AdminPromotion } from "@medusajs/types" -import { Button, RadioGroup, Select, Text } from "@medusajs/ui" +import { Button, RadioGroup, Select, Text, toast } from "@medusajs/ui" import { useEffect } from "react" import { useForm, useWatch } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" @@ -44,7 +44,7 @@ export const AddCampaignPromotionFields = ({ const selectedCampaign = campaigns.find((c) => c.id === watchCampaignId) return ( -
+
>({ defaultValues: { campaign_id: campaign?.id, @@ -162,11 +164,21 @@ export const AddCampaignPromotionForm = ({ resolver: zodResolver(EditPromotionSchema), }) + const { setValue } = form + const { mutateAsync, isPending } = useUpdatePromotion(promotion.id) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync( { campaign_id: data.campaign_id }, - { onSuccess: () => handleSuccess() } + { + onSuccess: () => { + toast.success(t("promotions.campaign.edit.successToast")) + handleSuccess() + }, + onError: (e) => { + toast.error(e.message) + }, + } ) }) @@ -177,18 +189,21 @@ export const AddCampaignPromotionForm = ({ useEffect(() => { if (watchCampaignChoice === "none") { - form.setValue("campaign_id", null) + setValue("campaign_id", null) } if (watchCampaignChoice === "existing") { - form.setValue("campaign_id", campaign?.id) + setValue("campaign_id", originalId) } - }, [watchCampaignChoice]) + }, [watchCampaignChoice, setValue, originalId]) return ( -
- + + { return ( - {t("promotions.addToCampaign.title")} + {t("promotions.campaign.edit.header")} {!isPending && !areCampaignsLoading && promotion && campaigns && ( diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx index 9223c7ba1f..8ab48929fd 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx @@ -326,17 +326,15 @@ export const CreatePromotionForm = () => { return ( - + handleTabChange(tab as Tab)} + className="flex h-full flex-col overflow-hidden" >
-
+
{
- -
- - - - - {tab === Tab.CAMPAIGN ? ( - - ) : ( - - )} -
- - - { - return ( - - {t("promotions.fields.type")} - - - - {templates.map((template) => { - return ( - - ) - })} - - - - - ) - }} - /> - - + - - {t(`promotions.sections.details`)} - - {currentTemplate?.title && ( - - {currentTemplate?.title} - - )} - - - {form.formState.errors.root && ( - - {form.formState.errors.root.message} - - )} - - { - return ( - - Method - - - - - - - - - - - ) - }} - /> - -
- { - return ( - - - {t("promotions.form.code.title")} - - - - - - - - ]} - /> - - - ) - }} - /> -
- - {!currentTemplate?.hiddenFields?.includes("type") && ( - { - return ( - - {t("promotions.fields.type")} - - - - - - - - - - ) - }} - /> - )} - - - - - - - - {!currentTemplate?.hiddenFields?.includes( - "application_method.type" - ) && ( - { - return ( - - - {t("promotions.fields.value_type")} - - - - - - - - - - - ) - }} - /> - )} - -
- {!currentTemplate?.hiddenFields?.includes( - "application_method.value" - ) && ( +
+
{ - const currencyCode = - form.getValues().application_method.currency_code - + name="template_id" + render={({ field }) => { return ( - - - {t("promotions.form.value.title")} - + + {t("promotions.fields.type")} - {isFixedValueType ? ( - { - onChange(value ? parseInt(value) : "") - }} - code={currencyCode} - symbol={ - currencyCode - ? getCurrencySymbol(currencyCode) - : "" - } - value={value} - disabled={!currencyCode} - /> - ) : ( - { - onChange( - e.target.value === "" - ? null - : parseInt(e.target.value) - ) - }} - /> - )} + + {templates.map((template) => { + return ( + + ) + })} + - - ]} - /> - ) }} /> - )} - - {isTypeStandard && watchAllocation === "each" && ( - { - return ( - - - {t("promotions.form.max_quantity.title")} - - - - - - - - ]} - /> - - - ) - }} - /> - )} +
+ + + +
+
+ + {t(`promotions.sections.details`)} + + {currentTemplate?.title && ( + + {currentTemplate?.title} + + )} + + + {form.formState.errors.root && ( + + {form.formState.errors.root.message} + + )} - {isTypeStandard && - !currentTemplate?.hiddenFields?.includes( - "application_method.allocation" - ) && ( { return ( - - {t("promotions.fields.allocation")} - + Method @@ -789,41 +474,376 @@ export const CreatePromotionForm = () => { ) }} /> - )} - {!isTypeStandard && ( - <> - - - )} +
+ { + return ( + + + {t("promotions.form.code.title")} + + + + + + + + ]} + /> + + + ) + }} + /> +
+ + {!currentTemplate?.hiddenFields?.includes("type") && ( + { + return ( + + + {t("promotions.fields.type")} + + + + + + + + + + + ) + }} + /> + )} - {!isTargetTypeOrder && ( - <> - - - )} + + + + + + {!currentTemplate?.hiddenFields?.includes( + "application_method.type" + ) && ( + { + return ( + + + {t("promotions.fields.value_type")} + + + + + + + + + + + ) + }} + /> + )} + +
+ {!currentTemplate?.hiddenFields?.includes( + "application_method.value" + ) && ( + { + const currencyCode = + form.getValues().application_method.currency_code + + return ( + + + {t("promotions.form.value.title")} + + + + {isFixedValueType ? ( + { + onChange(value ? parseInt(value) : "") + }} + code={currencyCode || "USD"} + symbol={ + currencyCode + ? getCurrencySymbol(currencyCode) + : "$" + } + value={value} + disabled={!currencyCode} + /> + ) : ( + { + onChange( + e.target.value === "" + ? null + : parseInt(e.target.value) + ) + }} + /> + )} + + + ]} + /> + + + + ) + }} + /> + )} + + {isTypeStandard && watchAllocation === "each" && ( + { + return ( + + + {t("promotions.form.max_quantity.title")} + + + + + + + + ]} + /> + + + ) + }} + /> + )} +
+ + {isTypeStandard && + !currentTemplate?.hiddenFields?.includes( + "application_method.allocation" + ) && ( + { + return ( + + + {t("promotions.fields.allocation")} + + + + + + + + + + + + ) + }} + /> + )} + + {!isTypeStandard && ( + <> + + + )} + + {!isTargetTypeOrder && ( + <> + + + + )} +
+
- +
+
+ +
+
+ +
+ + + + + {tab === Tab.CAMPAIGN ? ( + + ) : ( + + )} +
+
) diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-create/promotion-create.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-create/promotion-create.tsx index 011f7909aa..90e6832858 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-create/promotion-create.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-create/promotion-create.tsx @@ -2,5 +2,9 @@ import { RouteFocusModal } from "../../../components/modals" import { CreatePromotionForm } from "./components/create-promotion-form/create-promotion-form" export const PromotionCreate = () => { - return {} + return ( + + + + ) } diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/components/campaign-section/campaign-section.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-detail/components/campaign-section/campaign-section.tsx index 094eb0a719..0c57399dca 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-detail/components/campaign-section/campaign-section.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/components/campaign-section/campaign-section.tsx @@ -1,97 +1,73 @@ -import { PencilSquare } from "@medusajs/icons" -import { CampaignDTO } from "@medusajs/types" +import { ArrowUpRightOnBox, PencilSquare } from "@medusajs/icons" +import { HttpTypes } from "@medusajs/types" import { Container, Heading, Text } from "@medusajs/ui" -import { format } from "date-fns" -import { Fragment } from "react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" +import { DateRangeDisplay } from "../../../../../components/common/date-range-display" import { NoRecords } from "../../../../../components/common/empty-table-content" -function formatDate(date?: string | Date) { - if (!date) { - return "-" - } - - return format(new Date(date), "dd MMM yyyy") -} - -const CampaignDetailSection = ({ campaign }: { campaign: CampaignDTO }) => { - const { t } = useTranslation() - +const CampaignDetailSection = ({ + campaign, +}: { + campaign: HttpTypes.AdminCampaign +}) => { return ( - -
- - {t("campaigns.fields.name")} +
+
+ + {campaign.name} - -
- - {campaign?.name} - -
-
- -
- - {t("campaigns.fields.identifier")} + + ยท - -
- - {campaign?.campaign_identifier} - -
-
- -
- - {t("campaigns.fields.start_date")} + + {campaign.campaign_identifier} - -
- - {formatDate(campaign?.starts_at)} - -
- -
- - {t("campaigns.fields.end_date") || "-"} - - -
- - {formatDate(campaign?.ends_at)} - -
-
- + +
) } -export const CampaignSection = ({ campaign }: { campaign: CampaignDTO }) => { +export const CampaignSection = ({ + campaign, +}: { + campaign: HttpTypes.AdminCampaign | null +}) => { const { t } = useTranslation() const { id } = useParams() + const actions = [ + { + label: t("actions.edit"), + to: "add-to-campaign", + icon: , + }, + ] + + if (campaign) { + actions.unshift({ + label: t("promotions.campaign.actions.goToCampaign"), + to: `/campaigns/${campaign.id}`, + icon: , + }) + } + return ( - -
+ +
{t("promotions.fields.campaign")} , - }, - ], + actions, }, ]} /> @@ -101,7 +77,7 @@ export const CampaignSection = ({ campaign }: { campaign: CampaignDTO }) => { ) : (
@@ -113,18 +139,15 @@ export const PromotionGeneralSection = ({ {t("fields.code")} -
- + {promotion.code} - - - -
+ +
@@ -142,17 +165,16 @@ export const PromotionGeneralSection = ({ {t("promotions.fields.value")} - - - {promotion.application_method?.value} +
+ + {displayValue || "-"} - {promotion?.application_method?.type === "fixed" && ( - - {promotion?.application_method?.currency_code} + + {promotion?.application_method?.currency_code?.toUpperCase()} )} - +
diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx index c5b4549309..7609e74974 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx @@ -1,6 +1,7 @@ -import { Outlet, useLoaderData, useParams } from "react-router-dom" +import { useLoaderData, useParams } from "react-router-dom" -import { JsonViewSection } from "../../../components/common/json-view-section" +import { TwoColumnPageSkeleton } from "../../../components/common/skeleton" +import { TwoColumnPage } from "../../../components/layout/pages" import { usePromotion, usePromotionRules } from "../../../hooks/api/promotions" import { CampaignSection } from "./components/campaign-section" import { PromotionConditionsSection } from "./components/promotion-conditions-section" @@ -9,6 +10,8 @@ import { promotionLoader } from "./loader" import after from "virtual:medusa/widgets/promotion/details/after" import before from "virtual:medusa/widgets/promotion/details/before" +import sideAfter from "virtual:medusa/widgets/promotion/details/side/after" +import sideBefore from "virtual:medusa/widgets/promotion/details/side/before" export const PromotionDetail = () => { const initialData = useLoaderData() as Awaited< @@ -28,51 +31,40 @@ export const PromotionDetail = () => { const { rules: buyRules } = usePromotionRules(id!, "buy-rules", query) if (isLoading || !promotion) { - return
Loading...
+ return ( + + ) } return ( -
- {before.widgets.map((w, i) => { - return ( -
- -
- ) - })} -
-
- - + + + + + + {promotion.type === "buyget" && ( - {promotion.type === "buyget" && ( - - )} - {after.widgets.map((w, i) => { - return ( -
- -
- ) - })} -
- -
-
-
- -
- -
-
-
- -
+ )} + + + + + ) } diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx index 3b7978abe4..4d038de92b 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-edit-details/components/edit-promotion-form/edit-promotion-details-form.tsx @@ -1,23 +1,13 @@ import { zodResolver } from "@hookform/resolvers/zod" import { PromotionDTO } from "@medusajs/types" -import { - Button, - clx, - CurrencyInput, - Input, - RadioGroup, - Text, -} from "@medusajs/ui" +import { Button, CurrencyInput, Input, RadioGroup, Text } from "@medusajs/ui" import { useForm, useWatch } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" import * as zod from "zod" import { Form } from "../../../../../components/common/form" import { DeprecatedPercentageInput } from "../../../../../components/inputs/percentage-input" -import { - RouteDrawer, - useRouteModal, -} from "../../../../../components/modals" +import { RouteDrawer, useRouteModal } from "../../../../../components/modals" import { useUpdatePromotion } from "../../../../../hooks/api/promotions" import { getCurrencySymbol } from "../../../../../lib/data/currencies" @@ -80,9 +70,12 @@ export const EditPromotionDetailsForm = ({ return ( -
- -
+ + +