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:
+63
-33
@@ -1,22 +1,36 @@
|
||||
import { lazy, Suspense } from 'react';
|
||||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { lazy, Suspense, Component } from 'react';
|
||||
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
||||
import { AuthProvider } from './context/AuthContext';
|
||||
import ProtectedRoute from './components/ProtectedRoute';
|
||||
import PageLoader from './components/PageLoader';
|
||||
|
||||
class ChunkErrorBoundary extends Component {
|
||||
state = { error: null };
|
||||
static getDerivedStateFromError(error) { return { error }; }
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '60vh', gap: 16 }}>
|
||||
<div style={{ fontSize: 14, color: 'var(--text-secondary)' }}>Page failed to load.</div>
|
||||
<button className="btn btn-primary" onClick={() => { this.setState({ error: null }); window.location.reload(); }}>
|
||||
Reload
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
import Login from './pages/Login';
|
||||
import PayInvoice from './pages/PayInvoice';
|
||||
|
||||
const Settings = lazy(() => import('./pages/Settings'));
|
||||
const Dashboard = lazy(() => import('./pages/team/Dashboard'));
|
||||
const Companies = lazy(() => import('./pages/team/Companies'));
|
||||
const CompaniesPage = lazy(() => import('./pages/CompaniesPage'));
|
||||
const CompanyDetail = lazy(() => import('./pages/team/CompanyDetail'));
|
||||
const ProjectDetail = lazy(() => import('./pages/team/ProjectDetail'));
|
||||
const TeamProjects = lazy(() => import('./pages/team/TeamProjects'));
|
||||
const Requests = lazy(() => import('./pages/team/Requests'));
|
||||
const Invoices = lazy(() => import('./pages/team/Invoices'));
|
||||
const MeetingNotes = lazy(() => import('./pages/team/MeetingNotes'));
|
||||
const TaskDetail = lazy(() => import('./pages/team/TaskDetail'));
|
||||
const RequestDetail = lazy(() => import('./pages/RequestDetail'));
|
||||
const CreateInvoice = lazy(() => import('./pages/team/CreateInvoice'));
|
||||
const CreateSubcontractorPO = lazy(() => import('./pages/team/CreateSubcontractorPO'));
|
||||
const InvoiceDetail = lazy(() => import('./pages/team/InvoiceDetail'));
|
||||
@@ -25,40 +39,55 @@ const SubInvoiceDetail = lazy(() => import('./pages/team/SubInvoiceDetail'));
|
||||
const SurveyMaker = lazy(() => import('./pages/team/SurveyMaker'));
|
||||
const BrandBook = lazy(() => import('./pages/team/BrandBook'));
|
||||
const Converters = lazy(() => import('./pages/team/Converters'));
|
||||
const ServerStatus = lazy(() => import('./pages/team/ServerStatus'));
|
||||
const FileSharing = lazy(() => import('./pages/team/FileSharing'));
|
||||
const FourgePasswords = lazy(() => import('./pages/team/FourgePasswords'));
|
||||
const ExternalMyRequests = lazy(() => import('./pages/external/MyRequests'));
|
||||
const MyPurchaseOrders = lazy(() => import('./pages/external/MyPurchaseOrders'));
|
||||
const ExternalMyInvoices = lazy(() => import('./pages/external/MyInvoices'));
|
||||
const ExternalProjects = lazy(() => import('./pages/external/ExternalProjects'));
|
||||
const ExternalMyInvoiceDetail = lazy(() => import('./pages/external/MyInvoiceDetail'));
|
||||
const ExternalMyInvoiceCreate = lazy(() => import('./pages/external/MyInvoiceCreate'));
|
||||
const ClientDashboard = lazy(() => import('./pages/client/ClientDashboard'));
|
||||
const MyCompany = lazy(() => import('./pages/client/MyCompany'));
|
||||
const MyRequests = lazy(() => import('./pages/client/MyRequests'));
|
||||
const MyProjects = lazy(() => import('./pages/client/MyProjects'));
|
||||
const MyProjectDetail = lazy(() => import('./pages/client/MyProjectDetail'));
|
||||
const Projects = lazy(() => import('./pages/Projects'));
|
||||
const ProjectDetailPage = lazy(() => import('./pages/ProjectDetailPage'));
|
||||
const DashboardPage = lazy(() => import('./pages/DashboardPage'));
|
||||
const RequestsPage = lazy(() => import('./pages/RequestsPage'));
|
||||
const MyInvoices = lazy(() => import('./pages/client/MyInvoices'));
|
||||
const RequestDetail = lazy(() => import('./pages/client/RequestDetail'));
|
||||
const NewRequest = lazy(() => import('./pages/client/NewRequest'));
|
||||
const NewProject = lazy(() => import('./pages/client/NewProject'));
|
||||
|
||||
function RedirectProjectDetail() {
|
||||
const { id } = useParams();
|
||||
return <Navigate to={`/projects/${id}`} replace />;
|
||||
}
|
||||
|
||||
function RedirectRequestDetail() {
|
||||
const { id } = useParams();
|
||||
return <Navigate to={`/requests/${id}`} replace />;
|
||||
}
|
||||
|
||||
function NavigateCompanyDetail() {
|
||||
const { id } = useParams();
|
||||
return <Navigate to={`/company/${id}`} replace />;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<BrowserRouter>
|
||||
<ChunkErrorBoundary>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Routes>
|
||||
<Route path="/" element={<Login />} />
|
||||
|
||||
<Route path="/dashboard" element={<ProtectedRoute role={['team', 'external']}><Dashboard /></ProtectedRoute>} />
|
||||
<Route path="/projects/:id" element={<ProtectedRoute role={['team', 'external']}><ProjectDetail /></ProtectedRoute>} />
|
||||
<Route path="/tasks/:id" element={<ProtectedRoute role={['team', 'external']}><TaskDetail /></ProtectedRoute>} />
|
||||
<Route path="/companies" element={<ProtectedRoute role="team"><Companies /></ProtectedRoute>} />
|
||||
<Route path="/companies/:id" element={<ProtectedRoute role="team"><CompanyDetail /></ProtectedRoute>} />
|
||||
<Route path="/requests" element={<ProtectedRoute role="team"><Requests /></ProtectedRoute>} />
|
||||
<Route path="/team-projects" element={<ProtectedRoute role="team"><TeamProjects /></ProtectedRoute>} />
|
||||
<Route path="/dashboard" element={<ProtectedRoute role={['team', 'external', 'client']}><DashboardPage /></ProtectedRoute>} />
|
||||
<Route path="/projects" element={<ProtectedRoute role={['team', 'external', 'client']}><Projects /></ProtectedRoute>} />
|
||||
<Route path="/projects/:id" element={<ProtectedRoute role={['team', 'external', 'client']}><ProjectDetailPage /></ProtectedRoute>} />
|
||||
<Route path="/tasks/:id" element={<RedirectRequestDetail />} />
|
||||
<Route path="/requests/:id" element={<ProtectedRoute role={['team', 'external', 'client']}><RequestDetail /></ProtectedRoute>} />
|
||||
<Route path="/company" element={<ProtectedRoute role={['team', 'client']}><CompaniesPage /></ProtectedRoute>} />
|
||||
<Route path="/company/:id" element={<ProtectedRoute role={['team', 'client']}><CompanyDetail /></ProtectedRoute>} />
|
||||
<Route path="/companies" element={<Navigate to="/company" replace />} />
|
||||
<Route path="/companies/:id" element={<NavigateCompanyDetail />} />
|
||||
<Route path="/requests" element={<ProtectedRoute role={['team', 'external', 'client']}><RequestsPage /></ProtectedRoute>} />
|
||||
<Route path="/team-projects" element={<Navigate to="/projects" replace />} />
|
||||
<Route path="/meeting-notes" element={<ProtectedRoute role="team"><MeetingNotes /></ProtectedRoute>} />
|
||||
<Route path="/invoices" element={<ProtectedRoute role="team"><Invoices /></ProtectedRoute>} />
|
||||
<Route path="/invoices/new" element={<ProtectedRoute role="team"><CreateInvoice /></ProtectedRoute>} />
|
||||
@@ -72,22 +101,22 @@ export default function App() {
|
||||
<Route path="/file-sharing" element={<ProtectedRoute role={['team', 'external', 'client']}><FileSharing /></ProtectedRoute>} />
|
||||
<Route path="/file-uploads" element={<Navigate to="/file-sharing" replace />} />
|
||||
<Route path="/fourge-passwords" element={<ProtectedRoute role="team"><FourgePasswords /></ProtectedRoute>} />
|
||||
<Route path="/server-status" element={<ProtectedRoute role="team"><ServerStatus /></ProtectedRoute>} />
|
||||
<Route path="/assigned-requests" element={<ProtectedRoute role="external"><ExternalMyRequests /></ProtectedRoute>} />
|
||||
<Route path="/server-status" element={<Navigate to="/dashboard" replace />} />
|
||||
<Route path="/assigned-requests" element={<Navigate to="/requests" replace />} />
|
||||
<Route path="/my-purchase-orders" element={<ProtectedRoute role="external"><MyPurchaseOrders /></ProtectedRoute>} />
|
||||
<Route path="/my-projects-sub" element={<ProtectedRoute role="external"><ExternalProjects /></ProtectedRoute>} />
|
||||
<Route path="/my-projects-sub" element={<Navigate to="/projects" replace />} />
|
||||
<Route path="/my-invoices-sub" element={<ProtectedRoute role="external"><ExternalMyInvoices /></ProtectedRoute>} />
|
||||
<Route path="/my-invoices-sub/new" element={<ProtectedRoute role="external"><ExternalMyInvoiceCreate /></ProtectedRoute>} />
|
||||
<Route path="/my-invoices-sub/:id" element={<ProtectedRoute role="external"><ExternalMyInvoiceDetail /></ProtectedRoute>} />
|
||||
|
||||
<Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
|
||||
|
||||
<Route path="/my-dashboard" element={<ProtectedRoute role="client"><ClientDashboard /></ProtectedRoute>} />
|
||||
<Route path="/my-company" element={<ProtectedRoute role="client"><MyCompany /></ProtectedRoute>} />
|
||||
<Route path="/my-requests" element={<ProtectedRoute role="client"><MyRequests /></ProtectedRoute>} />
|
||||
<Route path="/my-requests/:id" element={<ProtectedRoute role="client"><RequestDetail /></ProtectedRoute>} />
|
||||
<Route path="/my-projects" element={<ProtectedRoute role="client"><MyProjects /></ProtectedRoute>} />
|
||||
<Route path="/my-projects/:id" element={<ProtectedRoute role="client"><MyProjectDetail /></ProtectedRoute>} />
|
||||
<Route path="/my-dashboard" element={<Navigate to="/dashboard" replace />} />
|
||||
<Route path="/my-company" element={<Navigate to="/company" replace />} />
|
||||
<Route path="/my-requests" element={<Navigate to="/requests" replace />} />
|
||||
<Route path="/my-requests/:id" element={<RedirectRequestDetail />} />
|
||||
<Route path="/my-projects" element={<Navigate to="/projects" replace />} />
|
||||
<Route path="/my-projects/:id" element={<RedirectProjectDetail />} />
|
||||
<Route path="/my-invoices" element={<ProtectedRoute role="client"><MyInvoices /></ProtectedRoute>} />
|
||||
<Route path="/new-request" element={<ProtectedRoute role="client"><NewRequest /></ProtectedRoute>} />
|
||||
<Route path="/new-project" element={<ProtectedRoute role="client"><NewProject /></ProtectedRoute>} />
|
||||
@@ -96,6 +125,7 @@ export default function App() {
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</ChunkErrorBoundary>
|
||||
</BrowserRouter>
|
||||
</AuthProvider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user