feat: implement core pharmacy management dashboard and navigation infrastructure
This commit is contained in:
+41
-35
@@ -55,8 +55,8 @@ const columns = [
|
||||
}
|
||||
}),
|
||||
columnHelper.accessor('price', {
|
||||
header: 'Price',
|
||||
size: 120,
|
||||
header: 'Purchase Price / MRP',
|
||||
size: 150,
|
||||
cell: info => <span className="text-slate-800 font-medium text-[14px]">{info.getValue()}</span>
|
||||
}),
|
||||
columnHelper.accessor('manufacture', {
|
||||
@@ -89,6 +89,7 @@ const Pharmacy = () => {
|
||||
form: 'tablet',
|
||||
strength: '',
|
||||
mrp: '',
|
||||
pack_size: '1',
|
||||
schedule: 'H'
|
||||
});
|
||||
|
||||
@@ -160,7 +161,7 @@ const Pharmacy = () => {
|
||||
setIsAdding(true);
|
||||
await addMedicine(addFormData);
|
||||
setIsAddModalOpen(false);
|
||||
setAddFormData({ brand_name: '', generic_name: '', manufacturer: '', form: 'tablet', strength: '', mrp: '', schedule: 'H' });
|
||||
setAddFormData({ brand_name: '', generic_name: '', manufacturer: '', form: 'tablet', strength: '', mrp: '', pack_size: '1', schedule: 'H' });
|
||||
await loadData();
|
||||
} catch (err) {
|
||||
console.error("Failed to add medicine", err);
|
||||
@@ -177,8 +178,8 @@ const Pharmacy = () => {
|
||||
subtitle: drug.generic_name || '',
|
||||
badge: drug.schedule || '',
|
||||
stock: parseInt(drug.total_stock) || 0,
|
||||
rawPrice: parseFloat(drug.mrp) || 0,
|
||||
price: new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR' }).format(parseFloat(drug.mrp) || 0),
|
||||
rawPrice: parseFloat(drug.purchase_price) || parseFloat(drug.mrp) || 0,
|
||||
price: new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR' }).format(parseFloat(drug.purchase_price) || parseFloat(drug.mrp) || 0),
|
||||
manufacture: drug.manufacturer || 'Unknown',
|
||||
type: drug.form || 'Unknown'
|
||||
}));
|
||||
@@ -250,39 +251,48 @@ const Pharmacy = () => {
|
||||
|
||||
return (
|
||||
<div className="max-w-[1400px] mx-auto flex flex-col w-full">
|
||||
<header className="mb-6 shrink-0 flex items-center justify-between">
|
||||
<div>
|
||||
<h1>Pharmacy Overview</h1>
|
||||
<div className="flex flex-col mb-8 gap-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-blue-100 p-3 rounded-xl flex items-center justify-center">
|
||||
<Package className="text-blue-600" size={26} />
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold text-slate-900 m-0 leading-none">Pharmacy Overview</h1>
|
||||
</div>
|
||||
</header>
|
||||
<p className="text-slate-500 mt-2">Manage your pharmacy inventory, add medicines, and handle manual dispensing.</p>
|
||||
</div>
|
||||
|
||||
{/* Metrics Row */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 shrink-0" style={{ marginBottom: '32px' }}>
|
||||
<div className="bg-white rounded-xl p-5 border border-slate-200 shadow-sm flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center shrink-0">
|
||||
<Package className="text-blue-600" size={24} />
|
||||
<div className="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm hover:shadow-md transition-shadow flex items-center gap-5">
|
||||
<div className="p-4 rounded-2xl bg-gradient-to-br from-blue-50 to-blue-100 border border-blue-200/50 flex items-center justify-center shrink-0 shadow-sm">
|
||||
<Package className="text-blue-600" size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-slate-500 text-[13px] font-medium mb-1">Total Medicines</p>
|
||||
<h3 className="text-2xl font-bold text-slate-900">{inventory.length}</h3>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-slate-500 text-sm font-semibold tracking-wide uppercase mb-1">Total Medicines</p>
|
||||
<h3 className="text-3xl font-extrabold text-slate-900">{inventory.length}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl p-5 border border-slate-200 shadow-sm flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-red-50 flex items-center justify-center shrink-0">
|
||||
<AlertCircle className="text-red-500" size={24} />
|
||||
|
||||
<div className="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm hover:shadow-md transition-shadow flex items-center gap-5 relative overflow-hidden">
|
||||
{lowStockCount > 0 && (
|
||||
<div className="absolute top-0 right-0 w-2 h-full bg-red-500"></div>
|
||||
)}
|
||||
<div className="p-4 rounded-2xl bg-gradient-to-br from-red-50 to-red-100 border border-red-200/50 flex items-center justify-center shrink-0 shadow-sm">
|
||||
<AlertCircle className="text-red-600" size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-slate-500 text-[13px] font-medium mb-1">Low Stock Alerts</p>
|
||||
<h3 className="text-2xl font-bold text-slate-900">{lowStockCount}</h3>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-slate-500 text-sm font-semibold tracking-wide uppercase mb-1">Low Stock Alerts</p>
|
||||
<h3 className={`text-3xl font-extrabold ${lowStockCount > 0 ? 'text-red-600' : 'text-slate-900'}`}>{lowStockCount}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl p-5 border border-slate-200 shadow-sm flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-indigo-50 flex items-center justify-center shrink-0">
|
||||
<Layers className="text-indigo-500" size={24} />
|
||||
|
||||
<div className="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm hover:shadow-md transition-shadow flex items-center gap-5">
|
||||
<div className="p-4 rounded-2xl bg-gradient-to-br from-indigo-50 to-indigo-100 border border-indigo-200/50 flex items-center justify-center shrink-0 shadow-sm">
|
||||
<Layers className="text-indigo-600" size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-slate-500 text-[13px] font-medium mb-1">Unique Categories</p>
|
||||
<h3 className="text-2xl font-bold text-slate-900">{uniqueCategories}</h3>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-slate-500 text-sm font-semibold tracking-wide uppercase mb-1">Unique Categories</p>
|
||||
<h3 className="text-3xl font-extrabold text-slate-900">{uniqueCategories}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -311,14 +321,6 @@ const Pharmacy = () => {
|
||||
<Package size={18} strokeWidth={2.5} />
|
||||
Manual Dispense
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setIsAddModalOpen(true)}
|
||||
className="flex items-center gap-2 bg-blue-600 text-white px-5 py-2.5 rounded-xl font-semibold hover:bg-blue-700 transition-colors shadow-sm whitespace-nowrap"
|
||||
>
|
||||
<Plus size={18} strokeWidth={2.5} />
|
||||
Add Medicine
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -422,6 +424,10 @@ const Pharmacy = () => {
|
||||
<label className="block text-xs font-bold uppercase tracking-wider text-slate-500" style={{ marginBottom: '8px' }}>MRP (₹)</label>
|
||||
<input required type="number" step="0.01" value={addFormData.mrp} onChange={e => setAddFormData({...addFormData, mrp: e.target.value})} className="w-full bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500" placeholder="0.00" style={{ padding: '12px 16px' }} />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-bold uppercase tracking-wider text-slate-500" style={{ marginBottom: '8px' }}>Pack Size</label>
|
||||
<input type="number" value={addFormData.pack_size} onChange={e => setAddFormData({...addFormData, pack_size: e.target.value})} className="w-full bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500" placeholder="1" style={{ padding: '12px 16px' }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end border-t border-slate-100" style={{ paddingTop: '16px', gap: '12px' }}>
|
||||
|
||||
Reference in New Issue
Block a user