feat(dashboard): show promo tooltip on the edit flows (#14121)
## Summary
**What** — What changes are introduced in this PR?
Display a tootlipt on line items when creating OrderEdit/Exchange to show which promotions are applied on the items.
---
## Checklist
Please ensure the following before requesting a review:
- [x] I have added a **changeset** for this PR
- Every non-breaking change should be marked as a **patch**
- To add a changeset, run `yarn changeset` and follow the prompts
- [ ] The changes are covered by relevant **tests**
- [x] I have verified the code works as intended locally
- [ ] I have linked the related issue(s) if applicable
<img width="786" height="910" alt="Screenshot 2025-11-25 at 14 11 22" src="https://github.com/user-attachments/assets/644bea00-b8ab-4a70-9a43-7c912ac21208" />
<img width="775" height="792" alt="Screenshot 2025-11-25 at 14 23 26" src="https://github.com/user-attachments/assets/ed935dad-9c2b-4ebd-8b9f-00d929add1ff" />
This commit is contained in:
1 parent
1cfc88ee55
commit
1e761345be
4 files changed
+85
-11
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(dashboard): show promo tooltip on edit flows
|
||||||
+28
-3
@@ -1,6 +1,11 @@
|
|||||||
import { ArrowUturnLeft, DocumentSeries, XCircle } from "@medusajs/icons"
|
import {
|
||||||
|
ArrowUturnLeft,
|
||||||
|
DocumentSeries,
|
||||||
|
ReceiptPercent,
|
||||||
|
XCircle,
|
||||||
|
} from "@medusajs/icons"
|
||||||
import { AdminOrderLineItem } from "@medusajs/types"
|
import { AdminOrderLineItem } from "@medusajs/types"
|
||||||
import { Badge, Input, Text, toast } from "@medusajs/ui"
|
import { Badge, Input, Text, toast, Tooltip } from "@medusajs/ui"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
|
||||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||||
@@ -45,6 +50,10 @@ function OrderEditItem({ item, currencyCode, orderId }: OrderEditItemProps) {
|
|||||||
return !!updateAction && item.quantity === item.detail.fulfilled_quantity
|
return !!updateAction && item.quantity === item.detail.fulfilled_quantity
|
||||||
}, [item])
|
}, [item])
|
||||||
|
|
||||||
|
const appliedPromoCodes = useMemo(() => {
|
||||||
|
return (item.adjustments || []).map((adjustment) => adjustment.code)
|
||||||
|
}, [item])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HANDLERS
|
* HANDLERS
|
||||||
*/
|
*/
|
||||||
@@ -166,7 +175,7 @@ function OrderEditItem({ item, currencyCode, orderId }: OrderEditItemProps) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-1 justify-between">
|
<div className="flex flex-1 items-center justify-between">
|
||||||
<div className="flex flex-grow items-center gap-2">
|
<div className="flex flex-grow items-center gap-2">
|
||||||
<Input
|
<Input
|
||||||
className="bg-ui-bg-base txt-small w-[67px] rounded-lg [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
className="bg-ui-bg-base txt-small w-[67px] rounded-lg [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||||
@@ -186,6 +195,22 @@ function OrderEditItem({ item, currencyCode, orderId }: OrderEditItemProps) {
|
|||||||
<Text className="txt-small text-ui-fg-subtle">
|
<Text className="txt-small text-ui-fg-subtle">
|
||||||
{t("fields.qty")}
|
{t("fields.qty")}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
{appliedPromoCodes.length > 0 && (
|
||||||
|
<div className="flex flex-shrink pt-[2px]">
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<span className="text-pretty">
|
||||||
|
{appliedPromoCodes.map((code) => (
|
||||||
|
<div key={code}>{code}</div>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ReceiptPercent className="text-ui-fg-subtle font-normal" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-ui-fg-subtle txt-small mr-2 flex flex-shrink-0">
|
<div className="text-ui-fg-subtle txt-small mr-2 flex flex-shrink-0">
|
||||||
|
|||||||
+29
-4
@@ -1,6 +1,12 @@
|
|||||||
import { ChatBubble, DocumentText, XCircle, XMark } from "@medusajs/icons"
|
import {
|
||||||
|
ChatBubble,
|
||||||
|
DocumentText,
|
||||||
|
ReceiptPercent,
|
||||||
|
XCircle,
|
||||||
|
XMark,
|
||||||
|
} from "@medusajs/icons"
|
||||||
import { AdminOrderLineItem, HttpTypes } from "@medusajs/types"
|
import { AdminOrderLineItem, HttpTypes } from "@medusajs/types"
|
||||||
import { IconButton, Input, Text } from "@medusajs/ui"
|
import { IconButton, Input, Text, Tooltip } from "@medusajs/ui"
|
||||||
import { UseFormReturn } from "react-hook-form"
|
import { UseFormReturn } from "react-hook-form"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
|
||||||
@@ -39,13 +45,17 @@ function ExchangeInboundItem({
|
|||||||
const showReturnReason = typeof formItem.reason_id === "string"
|
const showReturnReason = typeof formItem.reason_id === "string"
|
||||||
const showNote = typeof formItem.note === "string"
|
const showNote = typeof formItem.note === "string"
|
||||||
|
|
||||||
|
const appliedPromoCodes = (previewItem.adjustments || []).map(
|
||||||
|
(adjustment) => adjustment.code
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ">
|
<div className="bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ">
|
||||||
<div className="flex flex-col items-center gap-x-2 gap-y-2 p-3 text-sm md:flex-row">
|
<div className="flex flex-col items-center gap-x-3 gap-y-2 p-3 text-sm md:flex-row">
|
||||||
<div className="flex flex-1 items-center gap-x-3">
|
<div className="flex flex-1 items-center gap-x-3">
|
||||||
<Thumbnail src={item.thumbnail} />
|
<Thumbnail src={item.thumbnail} />
|
||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-grow flex-col">
|
||||||
<div>
|
<div>
|
||||||
<Text className="txt-small" as="span" weight="plus">
|
<Text className="txt-small" as="span" weight="plus">
|
||||||
{item.title}{" "}
|
{item.title}{" "}
|
||||||
@@ -57,6 +67,21 @@ function ExchangeInboundItem({
|
|||||||
{item.product_title}
|
{item.product_title}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
{appliedPromoCodes.length > 0 && (
|
||||||
|
<div className="flex flex-shrink">
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<span className="text-pretty">
|
||||||
|
{appliedPromoCodes.map((code) => (
|
||||||
|
<div key={code}>{code}</div>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ReceiptPercent className="text-ui-fg-subtle" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-1 justify-between">
|
<div className="flex flex-1 justify-between">
|
||||||
|
|||||||
+23
-4
@@ -1,6 +1,6 @@
|
|||||||
import { XCircle } from "@medusajs/icons"
|
import { ReceiptPercent, XCircle } from "@medusajs/icons"
|
||||||
import { AdminOrderLineItem, HttpTypes } from "@medusajs/types"
|
import { AdminOrderLineItem, HttpTypes } from "@medusajs/types"
|
||||||
import { Input, Text } from "@medusajs/ui"
|
import { Input, Text, Tooltip } from "@medusajs/ui"
|
||||||
import { UseFormReturn } from "react-hook-form"
|
import { UseFormReturn } from "react-hook-form"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
|
||||||
@@ -32,13 +32,17 @@ function ExchangeOutboundItem({
|
|||||||
}: ExchangeOutboundItemProps) {
|
}: ExchangeOutboundItemProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const appliedPromoCodes = (previewItem.adjustments || []).map(
|
||||||
|
(adjustment) => adjustment.code
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ">
|
<div className="bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ">
|
||||||
<div className="flex flex-col items-center gap-x-2 gap-y-2 p-3 text-sm md:flex-row">
|
<div className="flex flex-col items-center gap-x-3 gap-y-2 p-3 text-sm md:flex-row">
|
||||||
<div className="flex flex-1 items-center gap-x-3">
|
<div className="flex flex-1 items-center gap-x-3">
|
||||||
<Thumbnail src={previewItem.thumbnail} />
|
<Thumbnail src={previewItem.thumbnail} />
|
||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-grow flex-col">
|
||||||
<div>
|
<div>
|
||||||
<Text className="txt-small" as="span" weight="plus">
|
<Text className="txt-small" as="span" weight="plus">
|
||||||
{previewItem.title}{" "}
|
{previewItem.title}{" "}
|
||||||
@@ -52,6 +56,21 @@ function ExchangeOutboundItem({
|
|||||||
{previewItem.subtitle}
|
{previewItem.subtitle}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
{appliedPromoCodes.length > 0 && (
|
||||||
|
<div className="flex flex-shrink">
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<span className="text-pretty">
|
||||||
|
{appliedPromoCodes.map((code) => (
|
||||||
|
<div key={code}>{code}</div>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ReceiptPercent className="text-ui-fg-subtle" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-1 justify-between">
|
<div className="flex flex-1 justify-between">
|
||||||
|
|||||||
Reference in new issue
Block a user