mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-22 03:49:18 +02:00
[Feature] Improve AssignSpoolModal filtering logic (#889)
[Feature] Improve AssignSpoolModal filtering logic (#889)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { X, Loader2, Package, Search } from 'lucide-react';
|
||||
@@ -27,7 +27,11 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const { showToast } = useToast();
|
||||
const [disableFiltering, setDisableFiltering] = useState(false);
|
||||
const [selectedSpoolId, setSelectedSpoolId] = useState<number | null>(null);
|
||||
useEffect(() => {
|
||||
setSelectedSpoolId(null);
|
||||
}, [disableFiltering]);
|
||||
const [searchFilter, setSearchFilter] = useState('');
|
||||
const [pendingAssignId, setPendingAssignId] = useState<number | null>(null);
|
||||
const [showMismatchConfirm, setShowMismatchConfirm] = useState(false);
|
||||
@@ -39,6 +43,12 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
trayProfile?: string;
|
||||
} | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setDisableFiltering(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const { data: spools, isLoading } = useQuery({
|
||||
queryKey: ['inventory-spools'],
|
||||
queryFn: () => api.getSpools(),
|
||||
@@ -128,16 +138,28 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
!assignedSpoolIds.has(spool.id) && (isExternalSlot || (!spool.tag_uid && !spool.tray_uuid))
|
||||
);
|
||||
|
||||
const filteredSpools = manualSpools?.filter((spool: InventorySpool) => {
|
||||
if (!searchFilter) return true;
|
||||
// Filtering logic with toggle: search filter always applies, AMS tray profile filter is optional
|
||||
let filteredSpools = manualSpools;
|
||||
if (!disableFiltering) {
|
||||
if (trayInfo?.profile || trayInfo?.type) {
|
||||
const trayProfile = normalizeValue(trayInfo.profile || trayInfo.type);
|
||||
filteredSpools = filteredSpools?.filter((spool: InventorySpool) => {
|
||||
const spoolProfile = normalizeValue(spool.slicer_filament_name || spool.slicer_filament);
|
||||
return trayProfile && spoolProfile && spoolProfile === trayProfile;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (searchFilter && filteredSpools) {
|
||||
const q = searchFilter.toLowerCase();
|
||||
return (
|
||||
spool.material.toLowerCase().includes(q) ||
|
||||
(spool.brand?.toLowerCase().includes(q) ?? false) ||
|
||||
(spool.color_name?.toLowerCase().includes(q) ?? false) ||
|
||||
(spool.subtype?.toLowerCase().includes(q) ?? false)
|
||||
);
|
||||
});
|
||||
filteredSpools = filteredSpools.filter((spool: InventorySpool) => {
|
||||
return (
|
||||
spool.material.toLowerCase().includes(q) ||
|
||||
(spool.brand?.toLowerCase().includes(q) ?? false) ||
|
||||
(spool.color_name?.toLowerCase().includes(q) ?? false) ||
|
||||
(spool.subtype?.toLowerCase().includes(q) ?? false)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const handleAssign = () => {
|
||||
if (!selectedSpoolId) return;
|
||||
@@ -192,13 +214,13 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div className="fixed inset-0 z-50 flex items-start sm:items-center justify-center p-4 overflow-y-auto">
|
||||
<div
|
||||
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
/>
|
||||
|
||||
<div className="relative w-full max-w-2xl mx-4 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-xl shadow-2xl">
|
||||
<div className="relative w-full max-w-2xl bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-xl shadow-2xl max-h-[90vh] overflow-hidden flex flex-col my-auto">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -214,7 +236,7 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="p-4 space-y-4 overflow-y-auto">
|
||||
{/* Tray info */}
|
||||
{trayInfo && (
|
||||
<div className="p-3 bg-bambu-dark rounded-lg border border-bambu-dark-tertiary">
|
||||
@@ -295,27 +317,41 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex justify-end gap-2 p-4 border-t border-bambu-dark-tertiary">
|
||||
<Button variant="secondary" onClick={onClose}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAssign}
|
||||
disabled={!selectedSpoolId || assignMutation.isPending}
|
||||
>
|
||||
{assignMutation.isPending ? (
|
||||
<>
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
{t('inventory.assigning')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Package className="w-4 h-4" />
|
||||
{t('inventory.assignSpool')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
{/* Footer with filtering toggle */}
|
||||
<div className="flex justify-between items-center p-4 border-t border-bambu-dark-tertiary">
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
id="disable-filtering-toggle"
|
||||
type="checkbox"
|
||||
checked={disableFiltering}
|
||||
onChange={() => setDisableFiltering(v => !v)}
|
||||
className="accent-bambu-green w-4 h-4 rounded focus:ring-0 border-bambu-dark-tertiary"
|
||||
/>
|
||||
<label htmlFor="disable-filtering-toggle" className="text-xs text-bambu-gray select-none cursor-pointer">
|
||||
{t('inventory.showAllSpools')}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="secondary" onClick={onClose}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAssign}
|
||||
disabled={!selectedSpoolId || assignMutation.isPending}
|
||||
>
|
||||
{assignMutation.isPending ? (
|
||||
<>
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
{t('inventory.assigning')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Package className="w-4 h-4" />
|
||||
{t('inventory.assignSpool')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -3028,6 +3028,7 @@ export default {
|
||||
assigned: 'Zugewiesen',
|
||||
assigning: 'Wird zugewiesen...',
|
||||
searchSpools: 'Spulen suchen...',
|
||||
showAllSpools: 'Alle Spulen anzeigen',
|
||||
allMaterials: 'Alle Materialien',
|
||||
filterByBrand: 'Nach Marke filtern...',
|
||||
showArchived: 'Archivierte anzeigen',
|
||||
|
||||
@@ -3029,6 +3029,7 @@ export default {
|
||||
assigned: 'Assigned',
|
||||
assigning: 'Assigning...',
|
||||
searchSpools: 'Search spools...',
|
||||
showAllSpools: 'Show all spools',
|
||||
allMaterials: 'All Materials',
|
||||
filterByBrand: 'Filter by brand...',
|
||||
showArchived: 'Show archived',
|
||||
|
||||
@@ -3015,6 +3015,7 @@ export default {
|
||||
assigned: 'Assigné',
|
||||
assigning: 'Assignation...',
|
||||
searchSpools: 'Chercher bobines...',
|
||||
showAllSpools: 'Afficher toutes les bobines',
|
||||
allMaterials: 'Tous Matériaux',
|
||||
filterByBrand: 'Filtrer par marque...',
|
||||
showArchived: 'Afficher archivées',
|
||||
|
||||
@@ -3014,6 +3014,7 @@ export default {
|
||||
assigned: 'Assegnato',
|
||||
assigning: 'Assegnazione...',
|
||||
searchSpools: 'Cerca bobine...',
|
||||
showAllSpools: 'Mostra tutte le bobine',
|
||||
allMaterials: 'Tutti i Materiali',
|
||||
filterByBrand: 'Filtra per marchio...',
|
||||
showArchived: 'Mostra archiviate',
|
||||
|
||||
@@ -3027,6 +3027,7 @@ export default {
|
||||
assigned: '割り当て済み',
|
||||
assigning: '割り当て中...',
|
||||
searchSpools: 'スプールを検索...',
|
||||
showAllSpools: 'すべてのスプールを表示',
|
||||
allMaterials: 'すべての素材',
|
||||
filterByBrand: 'ブランドで絞り込み...',
|
||||
showArchived: 'アーカイブ済みを表示',
|
||||
|
||||
@@ -3014,6 +3014,7 @@ export default {
|
||||
assigned: 'Atribuído',
|
||||
assigning: 'Atribuindo...',
|
||||
searchSpools: 'Pesquisar carretéis...',
|
||||
showAllSpools: 'Mostrar todos os carretéis',
|
||||
allMaterials: 'Todos os Materiais',
|
||||
filterByBrand: 'Filtrar por marca...',
|
||||
showArchived: 'Mostrar arquivados',
|
||||
|
||||
@@ -3019,6 +3019,7 @@ export default {
|
||||
assigned: '已分配',
|
||||
assigning: '分配中...',
|
||||
searchSpools: '搜索耗材...',
|
||||
showAllSpools: '显示所有耗材',
|
||||
allMaterials: '所有材料',
|
||||
filterByBrand: '按品牌筛选...',
|
||||
showArchived: '显示已归档',
|
||||
|
||||
Reference in New Issue
Block a user