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

@@ -459,21 +459,8 @@ export default function Home() {
/>
</div>
<div>
<h1 className="text-lg md:text-xl font-black tracking-normal text-white leading-none">
TFM <span className="font-mono text-primary bg-primary/5 px-2 py-0.5 rounded-lg border border-primary/10 ml-1">aInventory</span>
</h1>
<div className="flex items-center gap-2 mt-1">
<p className="text-xs font-bold text-slate-500 font-mono">
Version {versionData.version}
</p>
<span className="w-1 h-1 rounded-full bg-slate-800" />
<button
className="text-xs font-black text-primary/80 hover:text-primary transition-colors flex items-center gap-1"
>
<User size={8} />
{currentUser?.username || 'Guest'}
</button>
</div>
<h1 className="text-2xl md:text-3xl font-black tracking-tight text-white leading-tight">Admin Control</h1>
<p className="text-xs md:text-sm text-slate-400 font-bold tracking-tight mt-1 uppercase tracking-widest leading-relaxed">System Configuration & Security</p>
</div>
</div>
@@ -482,19 +469,25 @@ export default function Home() {
{isScannerReady && (
<div className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]" />
<span className="text-[10px] sm:text-xs font-black text-green-500/90 whitespace-nowrap">
<span className="text-xs font-black text-green-500/90 whitespace-nowrap">
Scanner: OK
</span>
</div>
)}
<div className="flex items-center gap-2">
<div className={`w-1.5 h-1.5 rounded-full ${isOnline ? 'bg-green-500 animate-pulse shadow-[0_0_8px_rgba(34,197,94,0.6)]' : 'bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.6)]'}`} />
<span className={`text-[10px] sm:text-xs font-black whitespace-nowrap ${isOnline ? 'text-green-500/90' : 'text-rose-500/90'}`}>
<span className={`text-xs font-black whitespace-nowrap ${isOnline ? 'text-green-500/90' : 'text-rose-500/90'}`}>
Sync: {isOnline ? 'Active' : 'Offline'}
</span>
</div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => { setIsSelecting(false); setCapturedImage(null); setCountdown(4); }}
className="w-full py-4 bg-slate-800 hover:bg-slate-700 text-white rounded-2xl font-black text-xs uppercase tracking-widest transition-all active:scale-95 border border-slate-700 shadow-xl"
>
Abort Cycle
</button>
<button
onClick={handleSync}
disabled={syncing}
@@ -534,11 +527,11 @@ export default function Home() {
<div className="space-y-4">
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold">scanning...</h2>
<button
onClick={() => setShowScanner(false)}
className="text-sm text-slate-400 hover:text-white"
<button
onClick={() => setIsEnterprise(false)}
className="text-xs font-black text-primary hover:underline uppercase tracking-tighter"
>
Cancel
Profile Swap
</button>
</div>
<Scanner onScanSuccess={onScanSuccess} onOCRMatch={onOCRMatch} />
@@ -553,13 +546,21 @@ export default function Home() {
</button>
<div>
<p className="text-lg font-medium">tap to start scanning</p>
<p className="text-sm text-slate-400">Scan labels to {mode.replace('_', ' ')} items</p>
</div>
<h2 className="text-3xl font-black text-white tracking-tight">Protocol Access</h2>
<p className="text-slate-400 text-xs font-bold uppercase tracking-widest mt-1">Select operator profile to initialize</p>
</div>
</div>
<div className="w-full h-px bg-slate-800/50 my-2" />
<div className="w-full flex justify-center">
<button
onClick={() => setIsEnterprise(true)}
className="flex items-center justify-center gap-2 py-4 rounded-2xl border border-dashed border-slate-700 text-slate-400 hover:text-white hover:border-slate-500 transition-all font-bold text-xs"
>
<Lock size={12} />
Enterprise
</button>
<button
onClick={() => setShowOnboarding(true)}
className="w-full flex flex-col items-center justify-center p-8 rounded-[2rem] bg-indigo-500/5 border border-indigo-500/20 group hover:border-indigo-500/50 transition-all font-black text-indigo-400 gap-4"
@@ -592,11 +593,14 @@ export default function Home() {
{selectedItem && (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-slate-950/80 backdrop-blur-sm animate-in fade-in duration-200">
<div className="w-full max-w-lg bg-slate-900 border border-slate-800 rounded-[2.5rem] shadow-2xl p-6 overflow-hidden animate-in slide-in-from-bottom-10 duration-300">
<div className="flex justify-between items-center px-1">
<p className="text-xs font-black text-slate-400 uppercase tracking-widest italic">LDAP Authentication</p>
</div>
<div className="flex justify-between items-center mb-6">
<h3 className="text-xl font-black tracking-tight flex items-center gap-2">
{isEditing ? "Edit Metadata" : selectedItem.name}
{!isEditing && (
<span className="text-[10px] bg-slate-800 text-slate-400 px-2 py-0.5 rounded-md font-black uppercase tracking-tight shadow-sm border border-slate-700/50">
<span className="text-[11px] bg-slate-800 text-slate-400 px-2 py-0.5 rounded-md font-black uppercase tracking-tight shadow-sm border border-slate-700/50">
In Stock: {selectedItem.quantity}
</span>
)}
@@ -621,6 +625,16 @@ export default function Home() {
<Trash2 size={20} />
</button>
)}
<button
onClick={() => {
setSelectedUserForLogin({ username: '' });
// We use an empty username object to trigger the manual input view
}}
className="flex items-center justify-center gap-2 py-4 rounded-2xl border border-primary/20 bg-primary/5 text-primary hover:bg-primary/10 transition-all font-bold text-xs"
>
<User size={12} />
Manual Login
</button>
<button
onClick={() => {
setSelectedItem(null);
@@ -635,18 +649,19 @@ export default function Home() {
{isEditing ? (
<div className="space-y-4 mb-8">
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Item Name</label>
<input
type="text"
value={editedItem.name || ''}
onChange={e => setEditedItem({ ...editedItem, name: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-xl py-3 px-4 text-sm outline-none text-slate-100 placeholder-slate-700"
placeholder="e.g. Solid State Drive"
/>
<div>
<div className="bg-slate-900/80 py-2.5 px-4 rounded-[1.2rem] border border-slate-800 focus-within:border-primary/50 transition-colors group">
<label className="text-xs text-slate-400 font-bold mb-0.5 block group-focus-within:text-primary transition-colors tracking-tight uppercase">Item Name</label>
<textarea
value={editedItem.name || ''}
onChange={(e) => setEditedItem({ ...editedItem, name: e.target.value })}
className="bg-transparent w-full text-lg font-bold outline-none text-white placeholder:text-slate-700 resize-none h-8 leading-tight selection:bg-primary/30 py-0"
placeholder="SSD, SFP, Cable..."
/>
</div>
</div>
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Part Number</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Part Number</label>
<input
type="text"
value={editedItem.part_number || ''}
@@ -656,8 +671,8 @@ export default function Home() {
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Category Group</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Category Group</label>
<input
type="text"
list="existing-categories"
@@ -672,8 +687,8 @@ export default function Home() {
))}
</datalist>
</div>
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Item Type</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Item Type</label>
<input
type="text"
list="existing-types"
@@ -683,8 +698,8 @@ export default function Home() {
placeholder="e.g. spare parts"
/>
</div>
<div className="col-span-2">
<label className="text-xs font-black text-slate-500 ml-1">Box / Container Label</label>
<div className="col-span-2">
<label className="text-sm font-bold text-slate-400 ml-1">Box / Container Label</label>
<div className="relative flex items-center">
<input
type="text"
@@ -710,8 +725,8 @@ export default function Home() {
</button>
</div>
</div>
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Connector</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Connector</label>
<input
type="text"
value={editedItem.connector || ''}
@@ -720,8 +735,8 @@ export default function Home() {
placeholder="e.g. LC/UPC"
/>
</div>
<div>
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Size / Length</label>
<div>
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Size / Length</label>
<input
type="text"
value={editedItem.size || ''}
@@ -730,8 +745,8 @@ export default function Home() {
placeholder="e.g. 5m / 1600GB"
/>
</div>
<div className="col-span-2">
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">Item Color</label>
<div className="col-span-2">
<label className="text-sm font-bold text-slate-400 ml-1 tracking-tight">Item Color</label>
<input
type="text"
value={editedItem.color || ''}
@@ -740,8 +755,8 @@ export default function Home() {
placeholder="e.g. Black"
/>
</div>
<div className="col-span-2">
<label className="text-xs font-black text-slate-500 ml-1">Description</label>
<div className="col-span-2">
<label className="text-sm font-bold text-slate-400 ml-1">Description</label>
<textarea
value={editedItem.description || ''}
onChange={e => setEditedItem({ ...editedItem, description: e.target.value })}
@@ -749,8 +764,8 @@ export default function Home() {
placeholder="Item description..."
/>
</div>
<div className="col-span-2">
<label className="text-xs font-black text-slate-500 ml-1 tracking-tight">OCR Matching Key</label>
<div className="bg-slate-900/80 py-2.5 px-4 rounded-[1.2rem] border border-slate-800 focus-within:border-primary/50 transition-colors group">
<label className="text-xs text-slate-400 font-bold mb-0.5 block group-focus-within:text-primary transition-colors tracking-tight uppercase">OCR Matching Key</label>
<textarea
value={editedItem.ocr_text || ''}
onChange={e => setEditedItem({ ...editedItem, ocr_text: e.target.value })}
@@ -792,8 +807,9 @@ export default function Home() {
<Minus size={24} />
</button>
<div className="text-center">
<span className="text-5xl font-black tabular-nums">{adjustQty}</span>
</div>
<span className="text-xs font-black tabular-nums">{zoom.toFixed(1)}x</span>
<span className="text-[10px] text-primary/80 font-bold uppercase tracking-tight">Zoom</span>
</div>
<button
onClick={() => setAdjustQty(adjustQty + 1)}
className="w-12 h-12 rounded-full border border-slate-800 flex items-center justify-center text-slate-400 active:bg-slate-800"
@@ -876,23 +892,19 @@ export default function Home() {
className="w-full text-left bg-slate-950/50 hover:bg-slate-800 border border-slate-800/80 p-4 rounded-2xl flex items-center gap-4 transition-all active:scale-[0.98] group"
>
<div className="flex-1 min-w-0">
<p className="text-sm font-black text-white group-hover:text-primary transition-colors truncate">{item.name}</p>
<div className="flex items-center gap-2 mt-1">
<span className="text-[10px] font-mono text-slate-500">{item.part_number}</span>
<span className="w-1 h-1 rounded-full bg-slate-800" />
<span className="text-[10px] font-bold text-slate-400">Stock: {item.quantity}</span>
</div>
<p className="text-sm font-black text-white italic text-center">Protocol Detected</p>
<p className="text-xs text-slate-400 font-bold uppercase tracking-widest text-center mt-1">Select identity from label matrix</p>
</div>
<ChevronRight size={18} className="text-slate-600 group-hover:text-primary" />
</button>
))}
</div>
<button
onClick={() => setBoxMatches([])}
className="w-full py-4 mt-2 rounded-[1.5rem] font-black text-sm bg-slate-800 text-white hover:bg-slate-700 transition-colors shrink-0"
>
Cancel
</button>
<button
onClick={handleLogin}
className="w-full bg-primary text-white font-black py-5 rounded-[1.5rem] shadow-2xl shadow-primary/20 hover:shadow-primary/30 active:scale-95 transition-all uppercase text-xs tracking-widest border border-primary/20"
>
Initialize Session
</button>
</div>
</div>
)}
@@ -902,7 +914,7 @@ export default function Home() {
<footer className="mt-20 mb-8 flex flex-col items-center gap-2 opacity-30">
<p className="text-xs font-bold">Powered by TFM Group Software</p>
<div className="h-px w-12 bg-slate-800" />
<p className="text-[9px] font-mono">v{versionData.version} {versionData.last_build} BUILD: dev-{(versionData as any).commit || 'N/A'}</p>
<p className="text-[11px] font-mono text-slate-500">v{versionData.version} {versionData.last_build} BUILD: dev-{(versionData as any).commit || 'N/A'}</p>
</footer>
</div>
</PageShell>