Files
ember-market-frontend/components/forms/pricing-tiers.tsx
NotII 2452a3c5f6 Sort pricing tiers by minQuantity in UI
Pricing tiers are now displayed sorted by minQuantity, improving clarity for users. Event handlers are updated to use the original index to ensure correct tier manipulation after sorting.
2025-07-27 00:24:57 +02:00

131 lines
4.0 KiB
TypeScript

"use client";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Trash, PlusCircle } from "lucide-react";
interface PricingTiersProps {
pricing: any[];
handleTierChange: (
e: React.ChangeEvent<HTMLInputElement>,
index: number
) => void;
handleRemoveTier: (index: number) => void;
handleAddTier: () => void;
}
export const PricingTiers = ({
pricing,
handleTierChange,
handleRemoveTier,
handleAddTier,
}: PricingTiersProps) => {
const formatNumber = (num: number) => {
return Number(num.toFixed(2)).toString();
};
const formatTotal = (num: number) => {
return num.toFixed(2);
};
const calculateTotal = (quantity: number, pricePerUnit: number) => {
return formatTotal(quantity * pricePerUnit);
};
const handleTotalChange = (
e: React.ChangeEvent<HTMLInputElement>,
index: number,
minQuantity: number
) => {
const totalPrice = Number(e.target.value);
const pricePerUnit = minQuantity > 0 ? totalPrice / minQuantity : 0;
const syntheticEvent = {
target: {
name: 'pricePerUnit',
value: formatNumber(pricePerUnit)
}
} as React.ChangeEvent<HTMLInputElement>;
handleTierChange(syntheticEvent, index);
};
return (
<div>
<h3 className="text-sm font-medium">Tiered Pricing</h3>
{pricing?.length > 0 ? (
<>
<div className="grid grid-cols-[1fr_1fr_1fr_auto] gap-2 mt-2 mb-1">
<div className="text-xs text-muted-foreground">Quantity</div>
<div className="text-xs text-muted-foreground">Price Per Unit</div>
<div className="text-xs text-muted-foreground">Total Price</div>
<div className="w-8" />
</div>
{[...pricing]
.sort((a, b) => a.minQuantity - b.minQuantity)
.map((tier, sortedIndex) => {
// Find the original index for proper event handling
const originalIndex = pricing.findIndex(p =>
p === tier || (p.minQuantity === tier.minQuantity && p.pricePerUnit === tier.pricePerUnit)
);
return (
<div
key={tier._id || originalIndex}
className="grid grid-cols-[1fr_1fr_1fr_auto] gap-2 mt-2"
>
<Input
name="minQuantity"
type="number"
placeholder="Min Quantity"
value={tier.minQuantity === 0 ? "" : tier.minQuantity}
onChange={(e) => handleTierChange(e, originalIndex)}
className="h-8 text-sm px-2"
/>
<Input
name="pricePerUnit"
type="number"
placeholder="Price per unit"
value={tier.pricePerUnit === 0 ? "" : formatNumber(tier.pricePerUnit)}
onChange={(e) => handleTierChange(e, originalIndex)}
className="h-8 text-sm px-2"
/>
<Input
type="number"
placeholder="Total price"
value={
tier.minQuantity && tier.pricePerUnit
? calculateTotal(tier.minQuantity, tier.pricePerUnit)
: ""
}
onChange={(e) => handleTotalChange(e, originalIndex, tier.minQuantity)}
className="h-8 text-sm px-2"
/>
<Button
variant="ghost"
size="icon"
className="text-red-500 hover:bg-red-100"
onClick={() => handleRemoveTier(originalIndex)}
>
<Trash className="h-5 w-5" />
</Button>
</div>
);
})}
</>
) : (
<p className="text-sm text-gray-500 mt-2">No pricing tiers added.</p>
)}
<Button variant="outline" size="sm" className="mt-2" onClick={handleAddTier}>
<PlusCircle className="w-4 h-4 mr-1" />
Add Tier
</Button>
</div>
);
};