|
@@ -5,6 +5,7 @@ import { X, Loader2, Package, Check, Search } from 'lucide-react';
|
|
|
import { api } from '../api/client';
|
|
import { api } from '../api/client';
|
|
|
import type { InventorySpool, SpoolAssignment } from '../api/client';
|
|
import type { InventorySpool, SpoolAssignment } from '../api/client';
|
|
|
import { Button } from './Button';
|
|
import { Button } from './Button';
|
|
|
|
|
+import { ConfirmModal } from './ConfirmModal';
|
|
|
import { useToast } from '../contexts/ToastContext';
|
|
import { useToast } from '../contexts/ToastContext';
|
|
|
|
|
|
|
|
interface AssignSpoolModalProps {
|
|
interface AssignSpoolModalProps {
|
|
@@ -26,6 +27,8 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
|
|
const { showToast } = useToast();
|
|
const { showToast } = useToast();
|
|
|
const [selectedSpoolId, setSelectedSpoolId] = useState<number | null>(null);
|
|
const [selectedSpoolId, setSelectedSpoolId] = useState<number | null>(null);
|
|
|
const [searchFilter, setSearchFilter] = useState('');
|
|
const [searchFilter, setSearchFilter] = useState('');
|
|
|
|
|
+ const [pendingAssignId, setPendingAssignId] = useState<number | null>(null);
|
|
|
|
|
+ const [showMismatchConfirm, setShowMismatchConfirm] = useState(false);
|
|
|
|
|
|
|
|
const { data: spools, isLoading } = useQuery({
|
|
const { data: spools, isLoading } = useQuery({
|
|
|
queryKey: ['inventory-spools'],
|
|
queryKey: ['inventory-spools'],
|
|
@@ -53,6 +56,8 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
|
|
});
|
|
});
|
|
|
queryClient.invalidateQueries({ queryKey: ['spool-assignments'] });
|
|
queryClient.invalidateQueries({ queryKey: ['spool-assignments'] });
|
|
|
showToast(t('inventory.assignSuccess'), 'success');
|
|
showToast(t('inventory.assignSuccess'), 'success');
|
|
|
|
|
+ setShowMismatchConfirm(false);
|
|
|
|
|
+ setPendingAssignId(null);
|
|
|
onClose();
|
|
onClose();
|
|
|
},
|
|
},
|
|
|
onError: (error: Error) => {
|
|
onError: (error: Error) => {
|
|
@@ -84,10 +89,37 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+ const normalizeMaterial = (value: string | undefined | null) =>
|
|
|
|
|
+ (value ?? '').trim().toUpperCase();
|
|
|
|
|
+
|
|
|
|
|
+ const materialsMatch = (spoolMaterial: string, trayMaterial: string) => {
|
|
|
|
|
+ const normalizedSpool = normalizeMaterial(spoolMaterial);
|
|
|
|
|
+ const normalizedTray = normalizeMaterial(trayMaterial);
|
|
|
|
|
+ if (!normalizedSpool || !normalizedTray) return true;
|
|
|
|
|
+ if (normalizedTray.includes(normalizedSpool)) return true;
|
|
|
|
|
+ if (normalizedSpool.includes(normalizedTray)) return true;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const handleAssign = () => {
|
|
const handleAssign = () => {
|
|
|
- if (selectedSpoolId) {
|
|
|
|
|
- assignMutation.mutate(selectedSpoolId);
|
|
|
|
|
|
|
+ if (!selectedSpoolId) return;
|
|
|
|
|
+ const selectedSpool = spools?.find((spool: InventorySpool) => spool.id === selectedSpoolId);
|
|
|
|
|
+ if (selectedSpool && trayInfo?.type) {
|
|
|
|
|
+ const mismatch = !materialsMatch(selectedSpool.material, trayInfo.type);
|
|
|
|
|
+ if (mismatch) {
|
|
|
|
|
+ setPendingAssignId(selectedSpoolId);
|
|
|
|
|
+ setShowMismatchConfirm(true);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ assignMutation.mutate(selectedSpoolId);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleConfirmMismatch = () => {
|
|
|
|
|
+ if (!pendingAssignId) return;
|
|
|
|
|
+ assignMutation.mutate(pendingAssignId);
|
|
|
|
|
+ setShowMismatchConfirm(false);
|
|
|
|
|
+ setPendingAssignId(null);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
@@ -226,6 +258,28 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
|
|
</div>
|
|
</div>
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ {showMismatchConfirm && trayInfo && selectedSpoolId && (
|
|
|
|
|
+ <ConfirmModal
|
|
|
|
|
+ title={t('inventory.assignMismatchTitle')}
|
|
|
|
|
+ message={t('inventory.assignMismatchMessage', {
|
|
|
|
|
+ spoolMaterial: spools?.find((spool: InventorySpool) => spool.id === selectedSpoolId)?.material ?? '',
|
|
|
|
|
+ trayMaterial: trayInfo.type,
|
|
|
|
|
+ location: trayInfo.location,
|
|
|
|
|
+ })}
|
|
|
|
|
+ confirmText={t('inventory.assignMismatchConfirm')}
|
|
|
|
|
+ confirmClassName="!text-black"
|
|
|
|
|
+ variant="warning"
|
|
|
|
|
+ isLoading={assignMutation.isPending}
|
|
|
|
|
+ onConfirm={handleConfirmMismatch}
|
|
|
|
|
+ onCancel={() => {
|
|
|
|
|
+ if (!assignMutation.isPending) {
|
|
|
|
|
+ setShowMismatchConfirm(false);
|
|
|
|
|
+ setPendingAssignId(null);
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|