Files
tfm_ainventory/frontend/components/inventory/QuantityDisplay.tsx
Daniel Bedeleanu 9a87064dbe fix(design): replace all 40+ hardcoded colors with DESIGN.md semantic system
Phase 10 Implementation: Bulk color system compliance across frontend

Applied DESIGN_COLOR_RULES.md to 40 component and page files:
- Indigo (3) → primary/secondary (primary actions)
- Green (12) → tertiary (#00e639) (success/healthy status)
- Red/Rose (20) → error (#ffb4ab) (destructive actions)
- Amber/Sky (9) → primary/secondary (warnings/info)
- Blue/Slate (various) → primary/design system colors (focus states)
- Black → bg-surface-container-lowest (proper design color)

Files updated: 40 components + pages
Color replacements: 44+ instances
Build status: ✓ Zero errors, compiled in 6.3s
Test status: Pending (npm run test)

All colors now follow DESIGN.md Industrial Precision system:
 Primary: #ffb781 (caution orange)
 Secondary: #c8c6c5 (gray)
 Tertiary: #00e639 (healthy green)
 Error: #ffb4ab (destructive red)
 Design system enforced across all UI/UX

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-25 17:19:53 +03:00

132 lines
3.7 KiB
TypeScript

'use client';
import { useState, useRef, useEffect } from 'react';
import { Plus, Minus } from 'lucide-react';
interface QuantityDisplayProps {
itemId: string;
currentQuantity: number;
onQuantityChange: (newQty: number) => Promise<void>;
}
export default function QuantityDisplay({
itemId,
currentQuantity,
onQuantityChange,
}: QuantityDisplayProps) {
const [isEditing, setIsEditing] = useState(false);
const [localQuantity, setLocalQuantity] = useState(currentQuantity);
const [isLoading, setIsLoading] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
setLocalQuantity(currentQuantity);
}, [currentQuantity]);
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
inputRef.current.select();
}
}, [isEditing]);
const handleTapToEdit = () => {
setIsEditing(true);
};
const handleIncrement = () => {
setLocalQuantity(prev => Math.max(0, prev + 1));
};
const handleDecrement = () => {
setLocalQuantity(prev => Math.max(0, prev - 1));
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
if (value === '' || /^\d+$/.test(value)) {
setLocalQuantity(value === '' ? 0 : parseInt(value, 10));
}
};
const handleCommit = async () => {
if (localQuantity === currentQuantity) {
setIsEditing(false);
return;
}
try {
setIsLoading(true);
await onQuantityChange(localQuantity);
setIsEditing(false);
} catch (error) {
// Revert on error
setLocalQuantity(currentQuantity);
setIsEditing(false);
} finally {
setIsLoading(false);
}
};
const handleCancel = () => {
setLocalQuantity(currentQuantity);
setIsEditing(false);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handleCommit();
} else if (e.key === 'Escape') {
handleCancel();
}
};
if (isEditing) {
return (
<div className="flex items-center gap-2 bg-surface-container-lowest border border-border px-3 py-2">
<button
onClick={handleDecrement}
disabled={isLoading}
aria-label="Decrease quantity"
className="p-1 hover:bg-surface-container-lowest border border-transparent hover:border-border text-secondary hover:text-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<Minus size={16} />
</button>
<input
ref={inputRef}
type="text"
inputMode="numeric"
value={localQuantity}
onChange={handleInputChange}
onBlur={handleCommit}
onKeyDown={handleKeyDown}
disabled={isLoading}
aria-label="Quantity"
className="w-12 text-center bg-transparent text-primary font-normal focus:outline-none disabled:opacity-50"
/>
<button
onClick={handleIncrement}
disabled={isLoading}
aria-label="Increase quantity"
className="p-1 hover:bg-surface-container-lowest border border-transparent hover:border-border text-secondary hover:text-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<Plus size={16} />
</button>
</div>
);
}
return (
<button
onClick={handleTapToEdit}
disabled={isLoading}
aria-label={`Quantity: ${currentQuantity}. Tap to edit`}
className="text-lg font-normal text-primary hover:bg-surface-container-lowest border border-transparent hover:border-border px-3 py-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{currentQuantity}
</button>
);
}