84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
'use client';
|
|
import { useState } from 'react';
|
|
import { formatPrice } from '@/lib/money';
|
|
|
|
interface DiscountPanelProps {
|
|
/** Unit price in cents of the selected item. */
|
|
unitPriceCents: number;
|
|
/** Called when a discount is applied. */
|
|
onApply: (discountCents: number) => void;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function DiscountPanel({ unitPriceCents, onApply, onClose }: DiscountPanelProps) {
|
|
const [mode, setMode] = useState<'percent' | 'fixed'>('percent');
|
|
const [value, setValue] = useState('');
|
|
const [error, setError] = useState('');
|
|
|
|
const numericValue = Number(value.replace(',', '.'));
|
|
const discountCents = Number.isFinite(numericValue)
|
|
? mode === 'percent'
|
|
? Math.round((numericValue / 100) * unitPriceCents)
|
|
: Math.round(numericValue * 100)
|
|
: 0;
|
|
|
|
const handleApply = () => {
|
|
if (!value || numericValue <= 0) return;
|
|
if (discountCents > unitPriceCents) { setError('Descuento mayor al precio'); return; }
|
|
onApply(discountCents);
|
|
onClose();
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white rounded-2xl shadow-xl p-6 w-80 space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<h2 className="text-lg font-bold" style={{ color: 'var(--color-primary)' }}>Aplicar descuento</h2>
|
|
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-xl">✕</button>
|
|
</div>
|
|
|
|
<div className="flex gap-2">
|
|
<button
|
|
onClick={() => { setMode('percent'); setValue(''); setError(''); }}
|
|
className={`flex-1 py-2 rounded-xl font-medium ${mode === 'percent' ? 'bg-[#2D6A4F] text-white' : 'bg-gray-100'}`}
|
|
>
|
|
%
|
|
</button>
|
|
<button
|
|
onClick={() => { setMode('fixed'); setValue(''); setError(''); }}
|
|
className={`flex-1 py-2 rounded-xl font-medium ${mode === 'fixed' ? 'bg-[#2D6A4F] text-white' : 'bg-gray-100'}`}
|
|
>
|
|
Fijo
|
|
</button>
|
|
</div>
|
|
|
|
<div>
|
|
<input
|
|
type="text"
|
|
inputMode="decimal"
|
|
value={value}
|
|
onChange={(e) => { setValue(e.target.value); setError(''); }}
|
|
placeholder={mode === 'percent' ? 'Porcentaje (%)' : 'Cantidad (€), ej. 3,50'}
|
|
className="w-full px-4 py-3 border-2 border-gray-200 rounded-xl text-lg focus:border-[#2D6A4F] outline-none"
|
|
aria-label={mode === 'percent' ? 'Porcentaje de descuento' : 'Descuento en euros'}
|
|
autoFocus
|
|
/>
|
|
{error && <p className="text-sm text-red-500 mt-1">{error}</p>}
|
|
</div>
|
|
|
|
<div className="bg-gray-50 rounded-xl p-3 space-y-1 text-sm">
|
|
<div className="flex justify-between"><span>Precio original</span><span className="font-medium">{formatPrice(unitPriceCents)}</span></div>
|
|
<div className="flex justify-between"><span>Descuento</span><span className="font-medium text-red-500">-{formatPrice(discountCents)}</span></div>
|
|
<div className="flex justify-between border-t pt-1"><span>Precio final</span><span className="font-bold" style={{ color: 'var(--color-primary)' }}>{formatPrice(unitPriceCents - discountCents)}</span></div>
|
|
</div>
|
|
|
|
<button
|
|
onClick={handleApply}
|
|
disabled={!value || discountCents <= 0 || discountCents > unitPriceCents}
|
|
className="w-full py-3 bg-[#2D6A4F] hover:bg-[#1B4332] disabled:opacity-40 text-white font-bold rounded-xl transition-colors"
|
|
>
|
|
Aplicar
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|