Merge all role-dispatcher pages into single files; add FileBrowser with file-type icons

- DashboardPage, Projects, RequestsPage, ProjectDetailPage, RequestDetail: each now handles team/external/client in one file via role flags — removed 10 old role-specific sub-files
- Layout: client Company nav link goes directly to /company/:id when user has a single company
- FileBrowser: replace emoji icons with colored extension-text badges (square); folder icon stays 📁; Adobe/Figma/design-tool colors for design files
- CompaniesPage: merged team Companies + client company routing (single-company redirect, multi-company list)
- FileSharing: integrated FileBrowser component
- Removed: seafile API + lib, old ServerStatus, TaskDetail, role-split page files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krao Hasanee
2026-05-19 22:11:34 -04:00
parent f9e66dfced
commit b9a4c4a353
47 changed files with 5202 additions and 7217 deletions
+28
View File
@@ -0,0 +1,28 @@
import { useState } from 'react';
export function useSortable(defaultKey = '', defaultDir = 'asc') {
const [sortKey, setSortKey] = useState(defaultKey);
const [sortDir, setSortDir] = useState(defaultDir);
const toggle = (key) => {
if (sortKey === key) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
else { setSortKey(key); setSortDir('asc'); }
};
const sort = (data, getVal) => {
if (!sortKey) return data;
return [...data].sort((a, b) => {
const av = getVal ? getVal(a, sortKey) : a[sortKey];
const bv = getVal ? getVal(b, sortKey) : b[sortKey];
if (av == null && bv == null) return 0;
if (av == null) return 1;
if (bv == null) return -1;
const cmp = typeof av === 'number' && typeof bv === 'number'
? av - bv
: String(av).localeCompare(String(bv), undefined, { numeric: true, sensitivity: 'base' });
return sortDir === 'asc' ? cmp : -cmp;
});
};
return { sortKey, sortDir, toggle, sort };
}