fix(dashboard): campaign UI improvements (#13723)

* fix(dashboard): campaign UI improvements

* fix: camel case translation key
This commit is contained in:
Frane Polić
2025-10-09 16:15:26 +02:00
committed by GitHub
parent 21fbc0756f
commit c6896ffa6a
8 changed files with 66 additions and 17 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/dashboard": patch
---
fix(dashboard): campaign UI improvements
@@ -8312,6 +8312,9 @@
"total_used": { "total_used": {
"type": "string" "type": "string"
}, },
"totalUsedByAttribute": {
"type": "string"
},
"budget_limit": { "budget_limit": {
"type": "string" "type": "string"
}, },
@@ -8333,6 +8336,7 @@
"end_date", "end_date",
"total_spend", "total_spend",
"total_used", "total_used",
"totalUsedByAttribute",
"budget_limit", "budget_limit",
"campaign_id" "campaign_id"
], ],
@@ -8378,10 +8382,7 @@
"budgetAttributeTooltip": { "budgetAttributeTooltip": {
"type": "string" "type": "string"
}, },
"limitBudgetAttributeCustomer": { "totalUsedByAttribute": {
"type": "string"
},
"limitBudgetAttributeEmail": {
"type": "string" "type": "string"
} }
}, },
@@ -8392,8 +8393,7 @@
"used", "used",
"budgetAttribute", "budgetAttribute",
"budgetAttributeTooltip", "budgetAttributeTooltip",
"limitBudgetAttributeCustomer", "totalUsedByAttribute"
"limitBudgetAttributeEmail"
], ],
"additionalProperties": false "additionalProperties": false
}, },
@@ -8425,9 +8425,22 @@
}, },
"required": ["title", "description"], "required": ["title", "description"],
"additionalProperties": false "additionalProperties": false
},
"useByAttribute": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": ["title", "description"],
"additionalProperties": false
} }
}, },
"required": ["spend", "usage"], "required": ["spend", "usage", "useByAttribute"],
"additionalProperties": false "additionalProperties": false
}, },
"edit": { "edit": {
@@ -11162,6 +11175,9 @@
"discountable": { "discountable": {
"type": "string" "type": "string"
}, },
"promotionCode": {
"type": "string"
},
"handle": { "handle": {
"type": "string" "type": "string"
}, },
@@ -11588,6 +11604,7 @@
"category", "category",
"collection", "collection",
"discountable", "discountable",
"promotionCode",
"handle", "handle",
"subtitle", "subtitle",
"by", "by",
@@ -2233,6 +2233,7 @@
"end_date": "End date", "end_date": "End date",
"total_spend": "Budget spent", "total_spend": "Budget spent",
"total_used": "Budget used", "total_used": "Budget used",
"totalUsedByAttribute": "Total used",
"budget_limit": "Budget limit", "budget_limit": "Budget limit",
"campaign_id": { "campaign_id": {
"hint": "Disabled campaigns have budget in a different currency than the promotion." "hint": "Disabled campaigns have budget in a different currency than the promotion."
@@ -2251,8 +2252,7 @@
"used": "Used", "used": "Used",
"budgetAttribute": "Limit usage per", "budgetAttribute": "Limit usage per",
"budgetAttributeTooltip": "Define how many times the promotion can be used by a specific customer or email.", "budgetAttributeTooltip": "Define how many times the promotion can be used by a specific customer or email.",
"limitBudgetAttributeCustomer": "Budget limit per customer", "totalUsedByAttribute": "Budget limit per: {{attribute}}"
"limitBudgetAttributeEmail": "Budget limit per email"
}, },
"type": { "type": {
"spend": { "spend": {
@@ -2262,6 +2262,10 @@
"usage": { "usage": {
"title": "Usage", "title": "Usage",
"description": "Set a limit on how many times the promotion can be used." "description": "Set a limit on how many times the promotion can be used."
},
"useByAttribute": {
"title": "Usage by attribute (customer id, email, etc.)",
"description": "Set a limit on how many times the promotion can be used by a specific attribute value."
} }
}, },
"edit": { "edit": {
@@ -3008,6 +3012,7 @@
"category": "Category", "category": "Category",
"collection": "Collection", "collection": "Collection",
"discountable": "Discountable", "discountable": "Discountable",
"promotionCode": "Promotion code",
"handle": "Handle", "handle": "Handle",
"subtitle": "Subtitle", "subtitle": "Subtitle",
"by": "By", "by": "By",
@@ -40,6 +40,7 @@ export const CreateCampaignForm = () => {
const handleSubmit = form.handleSubmit(async (data) => { const handleSubmit = form.handleSubmit(async (data) => {
const attribute = data.budget.attribute || null const attribute = data.budget.attribute || null
const type = attribute ? "use_by_attribute" : data.budget.type const type = attribute ? "use_by_attribute" : data.budget.type
await mutateAsync( await mutateAsync(
@@ -26,9 +26,9 @@ export const CampaignBudget = ({ campaign }: CampaignBudgetProps) => {
level="h3" level="h3"
> >
{campaign.budget?.type === "use_by_attribute" {campaign.budget?.type === "use_by_attribute"
? campaign.budget?.attribute === "customer_id" ? t("campaigns.budget.fields.totalUsedByAttribute", {
? t("campaigns.budget.fields.limitBudgetAttributeCustomer") attribute: campaign.budget?.attribute,
: t("campaigns.budget.fields.limitBudgetAttributeEmail") })
: t("campaigns.fields.budget_limit")} : t("campaigns.fields.budget_limit")}
</Heading> </Heading>
</div> </div>
@@ -20,9 +20,11 @@ export const CampaignSpend = ({ campaign }: CampaignSpendProps) => {
</div> </div>
<Heading level="h3" className="text-ui-fg-subtle font-normal"> <Heading level="h3" className="text-ui-fg-subtle font-normal">
{campaign.budget?.type === "spend" {campaign.budget?.type === "use_by_attribute"
? t("campaigns.fields.total_spend") ? t("campaigns.fields.totalUsedByAttribute")
: t("campaigns.fields.total_used")} : campaign.budget?.type === "spend"
? t("campaigns.fields.total_spend")
: t("campaigns.fields.total_used")}
</Heading> </Heading>
</div> </div>
@@ -382,6 +382,10 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
label: t("fields.email"), label: t("fields.email"),
value: "customer_email", value: "customer_email",
}, },
{
label: t("fields.promotionCode"),
value: "promotion_code",
},
]} ]}
></Combobox> ></Combobox>
</Form.Control> </Form.Control>
@@ -3,6 +3,12 @@ import { Heading, Text } from "@medusajs/ui"
import { Fragment } from "react" import { Fragment } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
const translationKeyMap = {
spend: "spend",
usage: "usage",
use_by_attribute: "useByAttribute",
}
type CampaignDetailsProps = { type CampaignDetailsProps = {
campaign?: AdminCampaign campaign?: AdminCampaign
} }
@@ -77,7 +83,14 @@ export const CampaignDetails = ({ campaign }: CampaignDetailsProps) => {
</Text> </Text>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Text className="txt-small">{campaign.budget?.type || "-"}</Text> <Text className="txt-small truncate">
{t(
`campaigns.budget.type.${translationKeyMap[campaign.budget?.type]}.title`,
{
defaultValue: "-",
}
)}
</Text>
</div> </div>
</div> </div>
@@ -105,7 +118,9 @@ export const CampaignDetails = ({ campaign }: CampaignDetailsProps) => {
<div className="text-ui-fg-subtle grid grid-cols-2 items-center py-1"> <div className="text-ui-fg-subtle grid grid-cols-2 items-center py-1">
<Text className="txt-small-plus"> <Text className="txt-small-plus">
{t("campaigns.budget.fields.used")} {campaign.budget?.type === "use_by_attribute"
? t("campaigns.fields.totalUsedByAttribute")
: t("campaigns.budget.fields.used")}
</Text> </Text>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">