Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | "use client";
import { Icon } from "@/components/ui/icons";
import { cn } from "@/lib/core";
import type { SavingsBreakdownItem } from "@/lib/promotions/types";
interface AppliedPromotionsProps {
promotions: SavingsBreakdownItem[];
totalSavings: number;
onRemove?: (promotionId: number) => void;
removablePromotionIds?: number[];
className?: string;
}
export function AppliedPromotions({
promotions,
totalSavings,
onRemove,
removablePromotionIds = [],
className}: AppliedPromotionsProps) {
if (promotions.length === 0) {
return null;
}
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"}).format(amount);
};
const getPromotionIcon = (type: string): "tag" | "package" | "star" | "shopping-bag" => {
switch (type) {
case "PERCENTAGE_OFF":
case "FIXED_AMOUNT_OFF":
return "tag";
case "FREE_SHIPPING":
return "package";
case "BOGO":
return "shopping-bag";
case "BUNDLE":
return "package";
case "FLASH_SALE":
return "tag";
case "LOYALTY_REDEMPTION":
return "star";
default:
return "tag";
}
};
return (
<div className={cn("space-y-3", className)}>
<h4 className="text-sm font-semibold text-gray-700 flex items-center gap-2">
<Icon name="check-circle" size={16} className="text-green-500" />
Applied Discounts
</h4>
<div className="space-y-2">
{promotions.map((promo) => {
const isRemovable = removablePromotionIds.includes(promo.promotionId);
return (
<div
key={promo.promotionId}
className="flex items-center justify-between p-2 bg-green-50 border border-green-100 rounded-lg"
>
<div className="flex items-center gap-2">
<Icon
name={getPromotionIcon(promo.type)}
size={16}
className="text-green-600"
/>
<span className="text-sm text-green-800">
{promo.displayName || promo.promotionName}
</span>
</div>
<div className="flex items-center gap-2">
<span className="text-sm font-semibold text-green-700">
-{formatCurrency(promo.discountAmount)}
</span>
{isRemovable && onRemove && (
<button
onClick={() => onRemove(promo.promotionId)}
className="text-green-500 hover:text-green-700 transition-colors"
aria-label={`Remove ${promo.promotionName}`}
>
<Icon name="close" size={14} />
</button>
)}
</div>
</div>
);
})}
</div>
{promotions.length > 1 && (
<div className="flex justify-between items-center pt-2 border-t border-green-200">
<span className="text-sm font-semibold text-green-800">
Total Savings
</span>
<span className="text-base font-bold text-green-700">
-{formatCurrency(totalSavings)}
</span>
</div>
)}
</div>
);
}
export default AppliedPromotions;
|