2026-03-14 17:13:13 +05:30

159 lines
9.1 KiB
JavaScript

import React, { useState } from 'react';
import { X, RefreshCw, Calendar, MessageSquare, Info } from 'lucide-react';
export default function AdjustStockModal({ isOpen, onClose, onSave, product }) {
const [formData, setFormData] = useState({
adjustment_qty: '',
adjustment_date: new Date().toISOString().split('T')[0],
reason: 'Adjustment',
remarks: ''
});
const [loading, setLoading] = useState(false);
if (!isOpen || !product) return null;
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
const res = await fetch(`/api/inventory/products/${product.id}/adjust`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(formData)
});
if (res.ok) {
const updatedProduct = await res.json();
onSave(updatedProduct);
setFormData({
adjustment_qty: '',
adjustment_date: new Date().toISOString().split('T')[0],
reason: 'Adjustment',
remarks: ''
});
onClose();
}
} catch (error) {
console.error('Error adjusting stock:', error);
} finally {
setLoading(false);
}
};
const newStockLevel = parseInt(product.current_stock) + parseInt(formData.adjustment_qty || 0);
return (
<div className="fixed inset-0 bg-[#00171F]/40 backdrop-blur-sm z-[999] flex items-center justify-center p-4">
<div className="bg-white rounded-[32px] w-full max-w-lg overflow-hidden shadow-2xl animate-in zoom-in-95 duration-300">
<div className="p-8 border-b border-gray-100 flex items-center justify-between bg-gray-50/50">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-blue-50 rounded-2xl flex items-center justify-center text-blue-600 border border-blue-100/50">
<RefreshCw size={24} />
</div>
<div>
<h2 className="text-2xl font-black text-gray-900 tracking-tight">Adjust Stock</h2>
<p className="text-xs text-gray-500 font-bold uppercase tracking-widest mt-0.5">{product.name}</p>
</div>
</div>
<button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-xl transition-colors">
<X size={24} className="text-gray-400" />
</button>
</div>
<form onSubmit={handleSubmit} className="p-8 space-y-6">
<div className="bg-blue-50/50 border border-blue-100/50 p-4 rounded-2xl flex items-center justify-between">
<div>
<p className="text-[10px] font-black text-blue-400 uppercase tracking-widest mb-1">Current Stock</p>
<p className="text-2xl font-black text-blue-600">{product.current_stock}</p>
</div>
<div className="text-right">
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-1">New Level</p>
<p className={`text-2xl font-black ${newStockLevel < 0 ? 'text-red-500' : 'text-gray-900'}`}>{newStockLevel}</p>
</div>
</div>
<div className="space-y-4">
<div>
<label className="block text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2 ml-1">Adjustment Qty (+ or -)</label>
<div className="relative">
<Plus className="absolute left-6 top-1/2 -translate-y-1/2 text-gray-300" size={18} />
<input
required type="number"
className="w-full pl-14 pr-6 py-4 bg-gray-50/50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-bold text-gray-900"
placeholder="e.g. 5 or -5"
value={formData.adjustment_qty}
onChange={e => setFormData({...formData, adjustment_qty: e.target.value})}
/>
</div>
</div>
<div>
<label className="block text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2 ml-1">Adjustment Date</label>
<div className="relative">
<Calendar className="absolute left-6 top-1/2 -translate-y-1/2 text-gray-300" size={18} />
<input
required type="date"
className="w-full pl-14 pr-6 py-4 bg-gray-50/50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-bold text-gray-900"
value={formData.adjustment_date}
onChange={e => setFormData({...formData, adjustment_date: e.target.value})}
/>
</div>
</div>
<div>
<label className="block text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2 ml-1">Reason</label>
<select
required
className="w-full max-w-full px-6 py-4 bg-gray-50/50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-bold text-gray-900 appearance-none truncate"
value={formData.reason}
onChange={e => setFormData({...formData, reason: e.target.value})}
>
<option value="Adjustment">Normal Adjustment</option>
<option value="Purchase">Stock Purchase</option>
<option value="Damage">Damaged Goods</option>
<option value="Return">Customer Return</option>
</select>
</div>
<div>
<label className="block text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2 ml-1">Remarks</label>
<div className="relative">
<MessageSquare className="absolute left-6 top-6 text-gray-300" size={18} />
<textarea
className="w-full pl-14 pr-6 py-4 bg-gray-50/50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-bold text-gray-900 min-h-[100px]"
placeholder="Internal notes..."
value={formData.remarks}
onChange={e => setFormData({...formData, remarks: e.target.value})}
/>
</div>
</div>
</div>
<div className="pt-6 border-t border-gray-100 flex gap-4">
<button
type="button"
onClick={onClose}
className="flex-1 py-4 bg-gray-50 text-gray-400 rounded-2xl font-black text-xs uppercase tracking-widest hover:bg-gray-100 transition-all"
>
Cancel
</button>
<button
disabled={loading || !formData.adjustment_qty || newStockLevel < 0}
type="submit"
className="flex-1 py-4 bg-blue-600 text-white rounded-2xl font-black text-xs uppercase tracking-widest hover:bg-blue-700 transition-all shadow-lg shadow-blue-100 disabled:opacity-50"
>
{loading ? 'Adjusting...' : 'Update Stock'}
</button>
</div>
</form>
</div>
</div>
);
}
const Plus = ({ className, size }) => (
<svg className={className} width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
);