source: chapterx-frontend/src/App.tsx@ 0b502c2

main
Last change on this file since 0b502c2 was 0b502c2, checked in by kikisrbinoska <srbinoskakristina07@…>, 12 days ago

Fixed user profile and reading lists

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