diff --git a/src/app/projects/page.js b/src/app/projects/page.js index e07c795..63e927c 100644 --- a/src/app/projects/page.js +++ b/src/app/projects/page.js @@ -29,6 +29,10 @@ export default function ProjectListPage() { }); const [customers, setCustomers] = useState([]); + const [sortConfig, setSortConfig] = useState({ + key: 'finish_date', + direction: 'desc' + }); // Load phoneOnly filter from localStorage after mount to avoid hydration issues useEffect(() => { @@ -125,8 +129,44 @@ export default function ProjectListPage() { setSearchMatchType(null); } + // Apply sorting + if (sortConfig.key) { + filtered = [...filtered].sort((a, b) => { + let aVal = a[sortConfig.key]; + let bVal = b[sortConfig.key]; + + // Handle null/undefined + if (!aVal && !bVal) return 0; + if (!aVal) return sortConfig.direction === 'asc' ? 1 : -1; + if (!bVal) return sortConfig.direction === 'asc' ? -1 : 1; + + // Handle dates + if (sortConfig.key === 'finish_date') { + aVal = new Date(aVal); + bVal = new Date(bVal); + } + // Handle numbers (project_number) + else if (sortConfig.key === 'project_number') { + // Extract numeric part if it's a string like "P-123" or "123" + const aNum = parseInt(String(aVal).replace(/\D/g, '')) || 0; + const bNum = parseInt(String(bVal).replace(/\D/g, '')) || 0; + aVal = aNum; + bVal = bNum; + } + // Handle strings + else if (typeof aVal === 'string') { + aVal = aVal.toLowerCase(); + bVal = String(bVal).toLowerCase(); + } + + if (aVal < bVal) return sortConfig.direction === 'asc' ? -1 : 1; + if (aVal > bVal) return sortConfig.direction === 'asc' ? 1 : -1; + return 0; + }); + } + setFilteredProjects(filtered); - }, [searchTerm, projects, filters, session]); + }, [searchTerm, projects, filters, session, sortConfig]); async function handleDelete(id) { const confirmed = confirm(t('projects.deleteConfirm')); @@ -171,6 +211,13 @@ export default function ProjectListPage() { setSearchTerm(''); }; + const handleSort = (key) => { + setSortConfig(prev => ({ + key, + direction: prev.key === key && prev.direction === 'asc' ? 'desc' : 'asc' + })); + }; + const handleExportExcel = async () => { try { const response = await fetch('/api/projects/export'); @@ -228,6 +275,42 @@ export default function ProjectListPage() { default: return "-"; } }; + + // Sortable header component + const SortableHeader = ({ columnKey, label, className = "" }) => { + const isSorted = sortConfig.key === columnKey; + const direction = isSorted ? sortConfig.direction : null; + + return ( +
| - Nr. - | -- {t('projects.projectName')} - | -- {t('projects.address')} - | -- WP - | -- {t('projects.city')} - | -- {t('projects.plot')} - | -- {t('projects.finishDate')} - | -- {t('common.type') || 'Typ'} - | -- {t('common.status') || 'Status'} - | -- {t('projects.assigned') || 'Przypisany'} - | +
|---|