source: chapterx-frontend/src/App.tsx@ b62cefc

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

Added frontend and imporoved AI Suggestions service

  • Property mode set to 100644
File size: 7.4 KB
Line 
1import React, { Suspense, lazy, ReactNode } from 'react'
2import { Routes, Route, Navigate } from 'react-router-dom'
3import { useAuthStore } from './store/authStore'
4import { useUIStore } from './store/uiStore'
5import { UserRole } from './types'
6import { Navbar } from './components/layout/Navbar'
7import { Footer } from './components/layout/Footer'
8import { ToastContainer } from './components/ui/Toast'
9import { DevSwitcher } from './components/DevSwitcher'
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 addToast('Please sign in to access this page.', 'warning')
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 return (
70 <div className="flex flex-col min-h-screen">
71 <Navbar />
72 <main className="flex-1">
73 <Suspense fallback={<SuspenseFallback />}>
74 <Routes>
75 {/* Public */}
76 <Route path="/" element={<LandingPage />} />
77 <Route path="/login" element={<LoginPage />} />
78 <Route path="/register" element={<RegisterPage />} />
79 <Route path="/browse" element={<BrowsePage />} />
80 <Route path="/genres" element={<GenresListPage />} />
81 <Route path="/genres/:genre" element={<GenrePage />} />
82 <Route path="/story/:id" element={<StoryDetailPage />} />
83 <Route path="/story/:storyId/chapter/:chapterId" element={<ChapterReadPage />} />
84 <Route path="/community-lists" element={<CommunityListsPage />} />
85 <Route path="/profile/:username" element={<ProfilePage />} />
86 <Route path="/notifications" element={<NotificationsPage />} />
87
88 {/* Authenticated */}
89 <Route
90 path="/reading-lists"
91 element={
92 <ProtectedRoute>
93 <ReadingListPage />
94 </ProtectedRoute>
95 }
96 />
97
98 {/* Writer routes */}
99 <Route
100 path="/writer"
101 element={
102 <ProtectedRoute requiredRole={['writer', 'admin']}>
103 <WriterDashboard />
104 </ProtectedRoute>
105 }
106 />
107 <Route
108 path="/writer/create-story"
109 element={
110 <ProtectedRoute requiredRole={['writer', 'admin']}>
111 <CreateStoryPage />
112 </ProtectedRoute>
113 }
114 />
115 <Route
116 path="/writer/edit-story/:id"
117 element={
118 <ProtectedRoute requiredRole={['writer', 'admin']}>
119 <EditStoryPage />
120 </ProtectedRoute>
121 }
122 />
123 <Route
124 path="/writer/create-chapter/:storyId"
125 element={
126 <ProtectedRoute requiredRole={['writer', 'admin']}>
127 <CreateChapterPage />
128 </ProtectedRoute>
129 }
130 />
131 <Route
132 path="/writer/edit-chapter/:chapterId"
133 element={
134 <ProtectedRoute requiredRole={['writer', 'admin']}>
135 <EditChapterPage />
136 </ProtectedRoute>
137 }
138 />
139
140 {/* Admin routes */}
141 <Route
142 path="/admin"
143 element={
144 <ProtectedRoute requiredRole="admin">
145 <AdminDashboard />
146 </ProtectedRoute>
147 }
148 />
149 <Route
150 path="/admin/users"
151 element={
152 <ProtectedRoute requiredRole="admin">
153 <AdminUsersPage />
154 </ProtectedRoute>
155 }
156 />
157 <Route
158 path="/admin/content"
159 element={
160 <ProtectedRoute requiredRole="admin">
161 <AdminContentPage />
162 </ProtectedRoute>
163 }
164 />
165 <Route
166 path="/admin/genres"
167 element={
168 <ProtectedRoute requiredRole="admin">
169 <AdminGenresPage />
170 </ProtectedRoute>
171 }
172 />
173
174 {/* 404 */}
175 <Route path="*" element={<Navigate to="/" replace />} />
176 </Routes>
177 </Suspense>
178 </main>
179 <Footer />
180 <ToastContainer />
181 <DevSwitcher />
182 </div>
183 )
184}
185
186export default App
Note: See TracBrowser for help on using the repository browser.