Build [v1.10.4]

This commit is contained in:
2026-04-15 18:10:04 +03:00
parent 6760ab0abf
commit 2d162ff3c0
10 changed files with 237 additions and 226 deletions

View File

@@ -252,10 +252,10 @@ export default function InventoryPage() {
<div className="p-3 md:p-4 bg-primary/10 rounded-3xl text-primary border border-primary/20 shadow-xl shadow-primary/5">
<Package size={28} className="md:w-8 md:h-8" />
</div>
<div>
<h1 className="text-2xl md:text-3xl font-black tracking-tight text-white leading-tight">Inventory Catalog</h1>
<p className="text-[10px] md:text-xs text-slate-500 font-bold mt-0.5">Enterprise Stock Overview</p>
</div>
<div>
<h1 className="text-2xl md:text-3xl font-black tracking-tight text-white leading-tight">Inventory Catalog</h1>
<p className="text-xs md:text-sm text-slate-400 font-bold mt-1 uppercase tracking-widest">Enterprise Stock Overview</p>
</div>
<button
onClick={() => setShowBoxManager(true)}
className="ml-auto p-3 bg-slate-900 border border-slate-800 text-slate-400 rounded-2xl hover:text-primary transition-all active:scale-95 shadow-xl"
@@ -311,12 +311,12 @@ export default function InventoryPage() {
<div className="w-10 h-10 rounded-2xl bg-primary/10 flex items-center justify-center text-primary transition-colors">
<Layers size={20} />
</div>
<div className="text-left">
<h3 className="font-bold text-lg">{cat}</h3>
<p className="text-[9px] font-black text-slate-400">
{inventory.filter(i => i.category === cat).length} Item types in stock
</p>
</div>
<div className="text-left">
<h3 className="font-bold text-lg">{cat}</h3>
<p className="text-xs font-bold text-slate-400 mt-1 uppercase tracking-tight">
{inventory.filter(i => i.category === cat).length} Item types in stock
</p>
</div>
</div>
<div className="flex items-center gap-3">
{expandedCategory === cat ? <ChevronDown size={20} className="text-primary" /> : <ChevronRight size={20} className="text-slate-600" />}
@@ -353,20 +353,20 @@ export default function InventoryPage() {
<div className="w-8 h-8 rounded-xl bg-green-500/10 flex items-center justify-center text-green-500 shrink-0">
<Package size={14} />
</div>
<div className="truncate">
<h4 className="font-bold text-slate-200 truncate">{item.name}</h4>
<p className="text-[10px] text-slate-500 truncate mt-0.5">{item.specs}</p>
</div>
<div className="truncate">
<h4 className="font-bold text-slate-200 truncate">{item.name}</h4>
<p className="text-xs text-slate-400 truncate mt-1">{item.specs}</p>
</div>
</div>
<div className="text-right shrink-0">
<span className={cn(
"text-lg font-black",
item.quantity <= item.min_quantity ? "text-amber-500" : "text-primary"
)}>
{item.quantity}
</span>
<p className="text-xs text-slate-600 font-bold">Stock</p>
</div>
{item.quantity}
</span>
<p className="text-sm text-slate-500 font-bold uppercase tracking-tight">Stock</p>
</div>
</div>
))}
</div>
@@ -389,12 +389,12 @@ export default function InventoryPage() {
<div className="w-full max-w-lg bg-slate-900 border-x border-t sm:border border-slate-800 rounded-t-[2.5rem] sm:rounded-[2.5rem] shadow-2xl p-5 sm:p-8 overflow-hidden animate-in slide-in-from-bottom-10 duration-300">
<div className="flex justify-between items-center mb-6">
<h3 className="text-xl font-black tracking-tight flex items-center gap-2">
{isEditing ? "Edit Item" : selectedItem.name}
{!isEditing && (
<span className="text-[10px] bg-slate-800 text-slate-400 px-2 py-0.5 rounded-md font-black uppercase">
In Stock: {selectedItem.quantity}
</span>
)}
{isEditing ? "Edit Item" : selectedItem.name}
{!isEditing && (
<span className="text-xs bg-slate-800 text-slate-300 px-3 py-1 rounded-lg font-bold uppercase tracking-tight">
In Stock: {selectedItem.quantity}
</span>
)}
</h3>
<div className="flex gap-2">
{!isEditing && (
@@ -431,8 +431,8 @@ export default function InventoryPage() {
{isEditing ? (
<div className="max-h-[60vh] overflow-y-auto pr-2 space-y-4 mb-6 scrollbar-hide">
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Item Name</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Item Name</label>
<input
type="text"
value={editedItem.name || ''}
@@ -440,8 +440,8 @@ export default function InventoryPage() {
className="w-full bg-slate-950 border border-slate-800 rounded-xl py-3 px-4 text-sm font-bold outline-none text-slate-100 placeholder:text-slate-700"
/>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Part Number</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Part Number</label>
<input
type="text"
value={editedItem.part_number || ''}
@@ -450,8 +450,8 @@ export default function InventoryPage() {
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Category</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Category</label>
<input
type="text"
list="existing-categories"
@@ -466,8 +466,8 @@ export default function InventoryPage() {
))}
</datalist>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Item Type</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Item Type</label>
<input
type="text"
list="existing-types"
@@ -476,8 +476,8 @@ export default function InventoryPage() {
className="w-full bg-slate-950 border border-slate-800 rounded-xl py-3 px-4 text-sm font-bold outline-none text-slate-100"
/>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Connector</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Connector</label>
<input
type="text"
value={editedItem.connector || ''}
@@ -486,8 +486,8 @@ export default function InventoryPage() {
placeholder="e.g. LC/UPC"
/>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Size / Length</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Size / Length</label>
<input
type="text"
value={editedItem.size || ''}
@@ -496,8 +496,8 @@ export default function InventoryPage() {
placeholder="e.g. 1.6TB"
/>
</div>
<div className="col-span-2">
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Item Color</label>
<div className="col-span-2">
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Item Color</label>
<input
type="text"
value={editedItem.color || ''}
@@ -506,8 +506,8 @@ export default function InventoryPage() {
placeholder="e.g. Blue"
/>
</div>
<div className="col-span-2">
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Box / Container Label</label>
<div className="col-span-2">
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Box / Container Label</label>
<div className="relative flex items-center">
<input
type="text"
@@ -534,16 +534,16 @@ export default function InventoryPage() {
</div>
</div>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">Specs / Comments</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Specs / Comments</label>
<textarea
value={editedItem.specs || ''}
onChange={e => setEditedItem({...editedItem, specs: e.target.value})}
className="w-full bg-slate-950 border border-slate-800 rounded-xl py-3 px-4 text-sm font-bold outline-none text-slate-100 h-20 resize-none"
/>
</div>
<div>
<label className="text-[11px] font-black text-slate-500 ml-1 uppercase tracking-wider">OCR Matching Key</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">OCR Matching Key</label>
<textarea
value={editedItem.ocr_text || ''}
onChange={e => setEditedItem({...editedItem, ocr_text: e.target.value})}
@@ -567,9 +567,9 @@ export default function InventoryPage() {
adjustType === t.id ? "bg-slate-800 shadow-lg" : "text-slate-500"
)}
>
<t.icon size={20} className={adjustType === t.id ? t.color : ""} />
<span className="text-xs font-black mt-1">{t.label}</span>
</button>
<t.icon size={20} className={adjustType === t.id ? t.color : ""} />
<span className="text-sm font-bold mt-1.5 uppercase tracking-tight">{t.label}</span>
</button>
))}
</div>
@@ -641,8 +641,8 @@ export default function InventoryPage() {
</div>
<div className="space-y-4">
<div>
<label className="text-xs font-black text-slate-500 ml-1">Name</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Name</label>
<input
type="text"
value={catEditedName}
@@ -650,8 +650,8 @@ export default function InventoryPage() {
className="w-full bg-slate-950 border border-slate-800 rounded-xl py-3 px-4 text-sm outline-none text-slate-100"
/>
</div>
<div>
<label className="text-xs font-black text-slate-500 ml-1">Description</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 uppercase tracking-tight">Description</label>
<textarea
value={catEditedDesc}
onChange={e => setCatEditedDesc(e.target.value)}
@@ -736,18 +736,18 @@ export default function InventoryPage() {
<p className="text-xs text-slate-500 font-bold mt-0.5">{itemCount} items linked</p>
</div>
<div className="flex gap-2 shrink-0">
<button
onClick={() => setSelectedBoxLabel(box)}
className="flex-1 py-3 bg-primary text-white text-[11px] font-black rounded-xl flex items-center justify-center gap-2 hover:bg-blue-500 transition-colors shadow-lg shadow-primary/10 active:scale-95"
>
<Printer size={14} /> Print Label
</button>
<button
onClick={() => { setSearchQuery(box); setShowBoxManager(false); setBoxSearchQuery(''); }}
className="px-4 py-3 bg-slate-900 border border-slate-800 text-slate-400 text-[11px] font-bold rounded-xl hover:bg-slate-800 active:scale-95"
>
View
</button>
<button
onClick={() => setSelectedBoxLabel(box)}
className="flex-1 py-3 bg-primary text-white text-xs font-black rounded-xl flex items-center justify-center gap-2 hover:bg-blue-500 transition-colors shadow-lg shadow-primary/10 active:scale-95"
>
<Printer size={14} /> Print Label
</button>
<button
onClick={() => { setSearchQuery(box); setShowBoxManager(false); setBoxSearchQuery(''); }}
className="px-4 py-3 bg-slate-900 border border-slate-800 text-slate-400 text-xs font-bold rounded-xl hover:bg-slate-800 active:scale-95"
>
View
</button>
</div>
</div>
);
@@ -757,9 +757,9 @@ export default function InventoryPage() {
</div>
<div className="p-6 py-4 bg-slate-950/50 border-t border-slate-800 text-center flex items-center justify-center gap-2">
<div className="w-1 h-1 rounded-full bg-primary animate-pulse" />
<p className="text-[10px] text-slate-500 font-bold font-mono">TFM aInventory Box management mode</p>
</div>
<div className="w-1 h-1 rounded-full bg-primary animate-pulse" />
<p className="text-xs text-slate-400 font-bold font-mono">TFM aInventory Box management mode</p>
</div>
</div>
</div>
)}
@@ -775,11 +775,10 @@ export default function InventoryPage() {
</h2>
<div className="w-full aspect-[2/1] bg-white flex flex-col items-center justify-center overflow-hidden" dangerouslySetInnerHTML={{ __html: generateBarcode128(selectedBoxLabel) }} />
<div className="flex flex-col items-center gap-1">
<p className="text-[10px] font-black tracking-[0.2em] text-black/50">TFM INVENTORY BOX LABEL</p>
<img src={getQRCodeURL(selectedBoxLabel)} className="w-24 h-24" alt="QR Code" />
</div>
<div className="flex flex-col items-center gap-1">
<p className="text-xs font-black tracking-[0.2em] text-black/50">TFM INVENTORY BOX LABEL</p>
<img src={getQRCodeURL(selectedBoxLabel)} className="w-24 h-24" alt="QR Code" />
</div>
</div>
<div className="flex flex-col gap-3 no-print">