diff --git a/components/forms/pricing-tiers.tsx b/components/forms/pricing-tiers.tsx index 407e93a..578a3ef 100644 --- a/components/forms/pricing-tiers.tsx +++ b/components/forms/pricing-tiers.tsx @@ -2,10 +2,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Card, CardContent } from "@/components/ui/card"; -import { Trash, PlusCircle, Info } from "lucide-react"; -import { useState } from "react"; +import { Trash, PlusCircle } from "lucide-react"; interface PricingTiersProps { pricing: any[]; @@ -23,175 +20,112 @@ export const PricingTiers = ({ handleRemoveTier, handleAddTier, }: PricingTiersProps) => { - const [showHelp, setShowHelp] = useState(false); - const formatNumber = (num: number) => { - if (num === 0) return ""; + // Only format to 2 decimal places if the number has decimal places + // This prevents cursor jumping when user types whole numbers return num % 1 === 0 ? num.toString() : num.toFixed(2); }; + const formatTotal = (num: number) => { + return num.toFixed(2); + }; + const calculateTotal = (quantity: number, pricePerUnit: number) => { - return (quantity * pricePerUnit).toFixed(2); + return formatTotal(quantity * pricePerUnit); }; - const validateTier = (tier: any, index: number) => { - const errors = []; + const handleTotalChange = ( + e: React.ChangeEvent, + index: number, + minQuantity: number + ) => { + const totalPrice = Number(e.target.value); + const pricePerUnit = minQuantity > 0 ? totalPrice / minQuantity : 0; - // Only validate if both fields have values - if (tier.minQuantity > 0 && tier.pricePerUnit > 0) { - // Check for duplicate quantities only if both fields are complete - const duplicateIndex = pricing.findIndex((p, i) => - i !== index && p.minQuantity === tier.minQuantity && p.minQuantity > 0 - ); - - if (duplicateIndex !== -1) { - errors.push("Duplicate quantity found"); + const syntheticEvent = { + target: { + name: 'pricePerUnit', + value: formatNumber(pricePerUnit) } - } + } as React.ChangeEvent; - // Only show validation errors for completed fields - if (tier.minQuantity !== 0 && tier.minQuantity <= 0) { - errors.push("Quantity must be greater than 0"); - } - - if (tier.pricePerUnit !== 0 && tier.pricePerUnit <= 0) { - errors.push("Price must be greater than 0"); - } - - return errors; + handleTierChange(syntheticEvent, index); }; - const sortedPricing = [...pricing].sort((a, b) => a.minQuantity - b.minQuantity); - return ( -
-
-

Pricing Tiers

- -
- - {showHelp && ( - - -

- How it works: Set different prices based on quantity. - For example: 1-10 units at £5 each, 11-50 units at £4 each, 51+ units at £3 each. - Quantities should be in ascending order. -

-
-
- )} +
+

Tiered Pricing

{pricing?.length > 0 ? ( -
- {sortedPricing.map((tier, sortedIndex) => { - const originalIndex = pricing.findIndex(p => p === tier); - const errors = validateTier(tier, originalIndex); - const total = tier.minQuantity && tier.pricePerUnit - ? calculateTotal(tier.minQuantity, tier.pricePerUnit) - : "0.00"; + <> +
+
Quantity
+
Price Per Unit
+
Total Price
+
+
- return ( - 0 ? 'border-red-200 bg-red-50' : 'border-gray-200'}`}> -
-
- - handleTierChange(e, originalIndex)} - className={`h-10 ${errors.some(e => e.includes('Quantity') || e.includes('Duplicate')) ? 'border-red-500' : ''}`} - /> - {errors.some(e => e.includes('Quantity')) && ( -

{errors.find(e => e.includes('Quantity'))}

- )} -
+ {[...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 ( +
+ handleTierChange(e, originalIndex)} + className="h-8 text-sm px-2" + /> -
- - handleTierChange(e, originalIndex)} - className={`h-10 ${errors.some(e => e.includes('Price')) ? 'border-red-500' : ''}`} - /> - {errors.some(e => e.includes('Price')) && ( -

{errors.find(e => e.includes('Price'))}

- )} -
+ handleTierChange(e, originalIndex)} + className="h-8 text-sm px-2" + /> -
- -
- £{total} -
-

- {tier.minQuantity} × £{formatNumber(tier.pricePerUnit)} -

-
-
+ handleTotalChange(e, originalIndex, tier.minQuantity)} + className="h-8 text-sm px-2" + /> - {errors.some(e => e.includes('Duplicate')) && tier.minQuantity > 0 && tier.pricePerUnit > 0 && ( -

- ⚠️ This quantity is already used in another tier -

- )} - -
- -
- + +
); })} -
+ ) : ( - - -

No pricing tiers added yet

-

Add your first tier to get started

-
-
+

No pricing tiers added.

)} -
);