WFDASHDRIVER-APP/components/CollectModal.tsx

149 lines
5.1 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Collection } from '@/lib/types';
import { cn, formatCurrency } from '@/lib/utils';
import { X, Minus, Plus } from 'lucide-react';
interface CollectModalProps {
collection: Collection | null;
isOpen: boolean;
onClose: () => void;
onConfirm: (collection: Collection, receivedQty: number, notes: string) => void;
}
export default function CollectModal({
collection,
isOpen,
onClose,
onConfirm,
}: CollectModalProps) {
const [receivedQty, setReceivedQty] = useState<string>('');
const [notes, setNotes] = useState('');
const [error, setError] = useState('');
if (!isOpen || !collection) return null;
const expectedQty = collection.quantity || collection.expand?.orders_orderitem?.quantity || 0;
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setError('');
const qty = parseFloat(receivedQty);
if (isNaN(qty) || qty <= 0) {
setError('Please enter a valid quantity');
return;
}
onConfirm(collection, qty, notes);
setReceivedQty('');
setNotes('');
setError('');
};
const adjustQty = (delta: number) => {
const current = parseFloat(receivedQty) || 0;
const newQty = Math.max(0, current + delta);
setReceivedQty(newQty.toString());
};
const isPartial = parseFloat(receivedQty) > 0 && parseFloat(receivedQty) < expectedQty;
return (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center">
<div className="absolute inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose} />
<div className="relative bg-white rounded-t-2xl sm:rounded-2xl w-full max-w-md p-6 animate-slide-up">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-bold">Collect Item</h2>
<button
onClick={onClose}
className="p-1 rounded-full hover:bg-gray-100 active:bg-gray-200 transition-colors"
>
<X size={20} />
</button>
</div>
<div className="mb-4 p-3 bg-gray-50 rounded-lg">
<p className="text-sm font-medium truncate">
{collection.is_manual
? collection.description
: collection.expand?.orders_orderitem?.description || 'Unknown item'}
</p>
<p className="text-xs text-gray-500 mt-1">
Expected: {expectedQty} {collection.unit || collection.expand?.orders_orderitem?.unit || 'units'}
</p>
{collection.expand?.orders_orderitem?.selling_price && (
<p className="text-xs text-green-600 mt-1">
Unit price: {formatCurrency(collection.expand.orders_orderitem.selling_price)}
</p>
)}
</div>
<form onSubmit={handleSubmit}>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-2">
Received Quantity *
</label>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => adjustQty(-1)}
className="p-3 rounded-lg bg-gray-100 active:bg-gray-200 transition-colors"
>
<Minus size={18} />
</button>
<input
type="number"
step="0.01"
inputMode="decimal"
value={receivedQty}
onChange={(e) => setReceivedQty(e.target.value)}
className="flex-1 p-3 text-center text-lg font-semibold border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-transparent"
placeholder="0.00"
autoFocus
/>
<button
type="button"
onClick={() => adjustQty(1)}
className="p-3 rounded-lg bg-gray-100 active:bg-gray-200 transition-colors"
>
<Plus size={18} />
</button>
</div>
{isPartial && (
<p className="text-xs text-amber-600 mt-1">
Partial collection: {receivedQty} of {expectedQty} units
</p>
)}
{error && <p className="text-xs text-red-500 mt-1">{error}</p>}
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-2">
Notes (optional)
</label>
<textarea
value={notes}
onChange={(e) => setNotes(e.target.value)}
className="w-full p-3 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-transparent resize-none"
rows={2}
placeholder="Add any notes..."
/>
</div>
<button
type="submit"
className={cn(
'w-full py-3.5 px-4 rounded-xl text-white font-semibold text-base',
'bg-green-500 active:bg-green-600 transition-colors',
'touch-manipulation flex items-center justify-center gap-2'
)}
>
Confirm Collection
</button>
</form>
</div>
</div>
);
}