source: chapterx-frontend/src/App.tsx@ 7fbb91c

main
Last change on this file since 7fbb91c was 7fbb91c, checked in by kikisrbinoska <srbinoskakristina07@…>, 3 months ago

Added functional collaboration between users

  • Property mode set to 100644
File size: 7.6 KB
Line 
1import React, { Suspense, lazy, ReactNode, useEffect } from 'react'
2import { Routes, Route, Navigate } from 'react-router-dom'
3import { useAuthStore } from './store/authStore'
4import { useUIStore } from './store/uiStore'
5import { useStoryStore } from './store/storyStore'
6import { UserRole } from './types'
7import { Navbar } from './components/layout/Navbar'
8import { Footer } from './components/layout/Footer'
9import { ToastContainer } from './components/ui/Toast'
10import { DevSwitcher } from './components/DevSwitcher'
11import { Spinner } from './components/ui/Spinner'
12
13// Lazy imports
14const LandingPage = lazy(() => import('./pages/LandingPage').then(m => ({ default: m.LandingPage })))
15const LoginPage = lazy(() => import('./pages/auth/LoginPage').then(m => ({ default: m.LoginPage })))
16const RegisterPage = lazy(() => import('./pages/auth/RegisterPage').then(m => ({ default: m.RegisterPage })))
17const BrowsePage = lazy(() => import('./pages/browse/BrowsePage').then(m => ({ default: m.BrowsePage })))
18const GenrePage = lazy(() => import('./pages/browse/GenrePage').then(m => ({ default: m.GenrePage })))
19const GenresListPage = lazy(() => import('./pages/browse/GenrePage').then(m => ({ default: m.GenresListPage })))
20const StoryDetailPage = lazy(() => import('./pages/story/StoryDetailPage').then(m => ({ default: m.StoryDetailPage })))
21const ChapterReadPage = lazy(() => import('./pages/story/ChapterReadPage').then(m => ({ default: m.ChapterReadPage })))
22const WriterDashboard = lazy(() => import('./pages/writer/WriterDashboard').then(m => ({ default: m.WriterDashboard })))
23const CreateStoryPage = lazy(() => import('./pages/writer/CreateStoryPage').then(m => ({ default: m.CreateStoryPage })))
24const EditStoryPage = lazy(() => import('./pages/writer/EditStoryPage').then(m => ({ default: m.EditStoryPage })))
25const CreateChapterPage = lazy(() => import('./pages/writer/CreateChapterPage').then(m => ({ default: m.CreateChapterPage })))
26const EditChapterPage = lazy(() => import('./pages/writer/EditChapterPage').then(m => ({ default: m.EditChapterPage })))
27const ReadingListPage = lazy(() => import('./pages/reading-list/ReadingListPage').then(m => ({ default: m.ReadingListPage })))
28const CommunityListsPage = lazy(() => import('./pages/reading-list/CommunityListsPage').then(m => ({ default: m.CommunityListsPage })))
29const ProfilePage = lazy(() => import('./pages/profile/ProfilePage').then(m => ({ default: m.ProfilePage })))
30const AdminDashboard = lazy(() => import('./pages/admin/AdminDashboard').then(m => ({ default: m.AdminDashboard })))
31const AdminUsersPage = lazy(() => import('./pages/admin/AdminUsersPage').then(m => ({ default: m.AdminUsersPage })))
32const AdminContentPage = lazy(() => import('./pages/admin/AdminContentPage').then(m => ({ default: m.AdminContentPage })))
33const AdminGenresPage = lazy(() => import('./pages/admin/AdminGenresPage').then(m => ({ default: m.AdminGenresPage })))
34const NotificationsPage = lazy(() => import('./pages/NotificationsPage').then(m => ({ default: m.NotificationsPage })))
35
36const SuspenseFallback = () => (
37 <div className="flex items-center justify-center min-h-[50vh]">
38 <Spinner size="lg" />
39 </div>
40)
41
42// Protected route component
43const ProtectedRoute = ({
44 children,
45 requiredRole,
46}: {
47 children: ReactNode
48 requiredRole?: UserRole | UserRole[]
49}) => {
50 const { currentUser } = useAuthStore()
51 const { addToast } = useUIStore()
52
53 if (!currentUser) {
54 return <Navigate to="/login" replace />
55 }
56
57 if (requiredRole) {
58 const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole]
59 if (!roles.includes(currentUser.role)) {
60 addToast('You do not have permission to access this page.', 'error')
61 return <Navigate to="/" replace />
62 }
63 }
64
65 return <>{children}</>
66}
67
68function App() {
69 const { fetchStories, fetchChapters, fetchCollaborations, fetchReadingLists } = useStoryStore()
70
71 useEffect(() => {
72 fetchStories()
73 fetchChapters()
74 fetchCollaborations()
75 fetchReadingLists()
76 }, [])
77
78 return (
79 <div className="flex flex-col min-h-screen">
80 <Navbar />
81 <main className="flex-1">
82 <Suspense fallback={<SuspenseFallback />}>
83 <Routes>
84 {/* Public */}
85 <Route path="/" element={<LandingPage />} />
86 <Route path="/login" element={<LoginPage />} />
87 <Route path="/register" element={<RegisterPage />} />
88 <Route path="/browse" element={<BrowsePage />} />
89 <Route path="/genres" element={<GenresListPage />} />
90 <Route path="/genres/:genre" element={<GenrePage />} />
91 <Route path="/story/:id" element={<StoryDetailPage />} />
92 <Route path="/story/:storyId/chapter/:chapterId" element={<ChapterReadPage />} />
93 <Route path="/community-lists" element={<CommunityListsPage />} />
94 <Route path="/profile/:username" element={<ProfilePage />} />
95 <Route path="/notifications" element={<NotificationsPage />} />
96
97 {/* Authenticated */}
98 <Route
99 path="/reading-lists"
100 element={
101 <ProtectedRoute>
102 <ReadingListPage />
103 </ProtectedRoute>
104 }
105 />
106
107 {/* Writer routes */}
108 <Route
109 path="/writer"
110 element={
111 <ProtectedRoute requiredRole={['writer', 'admin']}>
112 <WriterDashboard />
113 </ProtectedRoute>
114 }
115 />
116 <Route
117 path="/writer/create-story"
118 element={
119 <ProtectedRoute requiredRole={['writer', 'admin']}>
120 <CreateStoryPage />
121 </ProtectedRoute>
122 }
123 />
124 <Route
125 path="/writer/edit-story/:id"
126 element={
127 <ProtectedRoute requiredRole={['writer', 'admin']}>
128 <EditStoryPage />
129 </ProtectedRoute>
130 }
131 />
132 <Route
133 path="/writer/create-chapter/:storyId"
134 element={
135 <ProtectedRoute requiredRole={['writer', 'admin']}>
136 <CreateChapterPage />
137 </ProtectedRoute>
138 }
139 />
140 <Route
141 path="/writer/edit-chapter/:chapterId"
142 element={
143 <ProtectedRoute requiredRole={['writer', 'admin']}>
144 <EditChapterPage />
145 </ProtectedRoute>
146 }
147 />
148
149 {/* Admin routes */}
150 <Route
151 path="/admin"
152 element={
153 <ProtectedRoute requiredRole="admin">
154 <AdminDashboard />
155 </ProtectedRoute>
156 }
157 />
158 <Route
159 path="/admin/users"
160 element={
161 <ProtectedRoute requiredRole="admin">
162 <AdminUsersPage />
163 </ProtectedRoute>
164 }
165 />
166 <Route
167 path="/admin/content"
168 element={
169 <ProtectedRoute requiredRole="admin">
170 <AdminContentPage />
171 </ProtectedRoute>
172 }
173 />
174 <Route
175 path="/admin/genres"
176 element={
177 <ProtectedRoute requiredRole="admin">
178 <AdminGenresPage />
179 </ProtectedRoute>
180 }
181 />
182
183 {/* 404 */}
184 <Route path="*" element={<Navigate to="/" replace />} />
185 </Routes>
186 </Suspense>
187 </main>
188 <Footer />
189 <ToastContainer />
190 <DevSwitcher />
191 </div>
192 )
193}
194
195export default App
Note: See TracBrowser for help on using the repository browser.