/** * EmployeeSelector Component * * Bottom sheet modal for searching and selecting employees. * Supports lazy word search (e.g., "fab her" matches "Fabian Herbst"). */ export default { name: 'EmployeeSelector', emits: ['select', 'close'], props: { show: { type: Boolean, default: false }, excludeIds: { type: Array, default: () => [] } }, setup(props, { emit }) { const { ref, computed, watch } = Vue; const searchQuery = ref(''); const employees = ref([]); const isLoading = ref(false); const searchTimeout = ref(null); // Filter out already selected employees const filteredEmployees = computed(() => { return employees.value.filter(emp => !props.excludeIds.includes(emp.id)); }); // Search employees when query changes watch(searchQuery, (newVal) => { if (searchTimeout.value) { clearTimeout(searchTimeout.value); } // Debounce search searchTimeout.value = setTimeout(() => { searchEmployees(newVal); }, 300); }); // Load employees when modal opens watch(() => props.show, (newVal) => { if (newVal) { searchQuery.value = ''; searchEmployees(''); } }); const searchEmployees = async (query) => { isLoading.value = true; try { const params = new URLSearchParams(); if (query) params.append('query', query); const response = await fetch(`/MobileApp/Lager/ShippingNote/searchEmployees?${params}`, { credentials: 'include' }); const data = await response.json(); if (data.success) { employees.value = data.employees; } } catch (error) { console.error('Error searching employees:', error); } finally { isLoading.value = false; } }; const selectEmployee = (employee) => { emit('select', employee); emit('close'); }; const close = () => { emit('close'); }; return { searchQuery, filteredEmployees, isLoading, selectEmployee, close }; }, template: `

Mitarbeiter auswählen

Keine Mitarbeiter gefunden

` };