proje-react-panel 1.4.1 → 1.6.0-test-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules.md +11 -1
- package/.vscode/launch.json +9 -0
- package/AUTH_LAYOUT_EXAMPLE.md +343 -0
- package/AUTH_LAYOUT_GUIDE.md +819 -0
- package/IMPLEMENTATION_GUIDE.md +899 -0
- package/dist/api/ApiConfig.d.ts +11 -0
- package/dist/api/AuthApi.d.ts +2 -5
- package/dist/api/CrudApi.d.ts +11 -12
- package/dist/components/list/CellField.d.ts +2 -2
- package/dist/components/list/cells/BooleanCell.d.ts +5 -2
- package/dist/components/list/cells/DateCell.d.ts +5 -2
- package/dist/components/list/cells/DefaultCell.d.ts +3 -2
- package/dist/components/list/cells/DownloadCell.d.ts +3 -2
- package/dist/components/list/cells/ImageCell.d.ts +3 -2
- package/dist/components/list/cells/LinkCell.d.ts +8 -0
- package/dist/components/list/cells/UUIDCell.d.ts +5 -2
- package/dist/decorators/auth/DefaultLoginForm.d.ts +4 -0
- package/dist/decorators/details/Details.d.ts +1 -1
- package/dist/decorators/list/Cell.d.ts +5 -1
- package/dist/decorators/list/List.d.ts +8 -4
- package/dist/decorators/list/cells/LinkCell.d.ts +13 -0
- package/dist/index.cjs.js +15 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.esm.js +15 -1
- package/dist/types/Login.d.ts +8 -0
- package/package.json +3 -1
- package/src/api/ApiConfig.ts +63 -0
- package/src/api/AuthApi.ts +8 -0
- package/src/api/CrudApi.ts +96 -60
- package/src/assets/icons/svg/down-arrow-backup-2.svg +3 -0
- package/src/components/DetailsPage.tsx +5 -1
- package/src/components/list/CellField.tsx +25 -10
- package/src/components/list/Datagrid.tsx +83 -53
- package/src/components/list/ListPage.tsx +3 -0
- package/src/components/list/cells/BooleanCell.tsx +7 -2
- package/src/components/list/cells/DateCell.tsx +6 -2
- package/src/components/list/cells/DefaultCell.tsx +4 -4
- package/src/components/list/cells/DownloadCell.tsx +4 -2
- package/src/components/list/cells/ImageCell.tsx +5 -2
- package/src/components/list/cells/LinkCell.tsx +31 -0
- package/src/components/list/cells/UUIDCell.tsx +6 -2
- package/src/decorators/auth/DefaultLoginForm.ts +32 -0
- package/src/decorators/details/Details.ts +1 -1
- package/src/decorators/list/Cell.ts +5 -1
- package/src/decorators/list/List.ts +4 -4
- package/src/decorators/list/cells/LinkCell.ts +22 -0
- package/src/index.ts +27 -1
- package/src/services/DataService.ts +14 -10
- package/src/store/store.ts +1 -1
- package/src/styles/components/button.scss +14 -0
- package/src/styles/index.scss +1 -1
- package/src/styles/list.scss +64 -1
- package/src/types/Login.ts +9 -0
- package/src/utils/logout.ts +2 -0
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
# AuthLayout with Sidebar Implementation Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to implement the `AuthLayout` component with a collapsible sidebar in your React application using the `proje-react-panel` library.
|
|
4
|
+
|
|
5
|
+
> **Note**: `AuthLayout` is a **helper component** created for the example application. It is **not part of the core `proje-react-panel` library**. This component demonstrates how to use the library's `Layout` component to create a complete authentication layout with sidebar functionality.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The `AuthLayout` provides a complete authenticated layout with:
|
|
10
|
+
|
|
11
|
+
- Collapsible sidebar navigation
|
|
12
|
+
- User authentication handling
|
|
13
|
+
- Automatic redirect to login for unauthenticated users
|
|
14
|
+
- Logout functionality
|
|
15
|
+
- Responsive design
|
|
16
|
+
- Icon support for menu items
|
|
17
|
+
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
1. [Quick Start](#quick-start)
|
|
21
|
+
2. [Basic Implementation](#basic-implementation)
|
|
22
|
+
3. [Component Structure](#component-structure)
|
|
23
|
+
4. [Menu Configuration](#menu-configuration)
|
|
24
|
+
5. [Icon System](#icon-system)
|
|
25
|
+
6. [Styling](#styling)
|
|
26
|
+
7. [Authentication Setup](#authentication-setup)
|
|
27
|
+
8. [Complete Example](#complete-example)
|
|
28
|
+
9. [Advanced Usage](#advanced-usage)
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
> **Important**: The `AuthLayout` component shown in this guide is a **helper component** that demonstrates how to use the `proje-react-panel` library. You'll need to create this component yourself as it's not included in the library.
|
|
33
|
+
|
|
34
|
+
> **Note**: The helper component uses React Router components like `Outlet`, `BrowserRouter`, `Route`, `Routes`, and `Link` - these are **not part of the `proje-react-panel` library** but are required dependencies for the helper component implementation.
|
|
35
|
+
|
|
36
|
+
To get started with AuthLayout, follow these steps:
|
|
37
|
+
|
|
38
|
+
1. **Install dependencies**:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install proje-react-panel @fortawesome/react-fontawesome @fortawesome/free-solid-svg-icons react-router axios
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> **Important**: Use `react-router` (not `react-router-dom`) for all routing components.
|
|
45
|
+
|
|
46
|
+
2. **Create your AuthLayout component**:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
// AuthLayout.tsx
|
|
50
|
+
import { Outlet } from 'react-router';
|
|
51
|
+
import { Layout, logout } from 'proje-react-panel';
|
|
52
|
+
import { setAuthLogout } from './api/apiConfig';
|
|
53
|
+
|
|
54
|
+
export function AuthLayout() {
|
|
55
|
+
return (
|
|
56
|
+
<Layout
|
|
57
|
+
logout={() => {
|
|
58
|
+
setAuthLogout();
|
|
59
|
+
logout(() => (window.location.href = '/login'));
|
|
60
|
+
}}
|
|
61
|
+
getIcons={getIcons}
|
|
62
|
+
menu={getMenu}
|
|
63
|
+
>
|
|
64
|
+
<Outlet />
|
|
65
|
+
</Layout>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
3. **Set up your routing**:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// App.tsx
|
|
74
|
+
import { Panel } from 'proje-react-panel';
|
|
75
|
+
import { BrowserRouter as Router, Route, Routes } from 'react-router'; // Use react-router, not react-router-dom
|
|
76
|
+
import { AuthLayout } from './AuthLayout';
|
|
77
|
+
|
|
78
|
+
export function App() {
|
|
79
|
+
return (
|
|
80
|
+
<Panel>
|
|
81
|
+
<Router>
|
|
82
|
+
<Routes>
|
|
83
|
+
<Route path="/" element={<AuthLayout />}>
|
|
84
|
+
{/* Your authenticated routes */}
|
|
85
|
+
</Route>
|
|
86
|
+
<Route path="/login" element={<Login />} />
|
|
87
|
+
</Routes>
|
|
88
|
+
</Router>
|
|
89
|
+
</Panel>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> **Important**: Always use `key` props on your route components to prevent rendering issues:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<Route path={"/"} index element={<Dashboard key="dashboard" />} />
|
|
98
|
+
<Route path={"users"}>
|
|
99
|
+
<Route path={""} element={<ListPage key="user-list" model={UserList} />} />
|
|
100
|
+
<Route path={"create"} element={<FormPage key="user-create" model={CreateUserForm} />} />
|
|
101
|
+
</Route>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
4. **Add menu configuration** (see Menu Configuration section below)
|
|
105
|
+
|
|
106
|
+
## Basic Implementation
|
|
107
|
+
|
|
108
|
+
### 1. Import Required Components
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { Outlet } from 'react-router'; // React Router component (not from proje-react-panel)
|
|
112
|
+
import React from 'react';
|
|
113
|
+
import { Layout, logout } from 'proje-react-panel'; // Core library components
|
|
114
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // External dependency
|
|
115
|
+
import { setAuthLogout } from './api/apiConfig'; // Custom helper function
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
> **Important**: Always import from `react-router`, not `react-router-dom`. The library is designed to work with `react-router`.
|
|
119
|
+
|
|
120
|
+
### 2. Create the AuthLayout Component
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
export function AuthLayout() {
|
|
124
|
+
return (
|
|
125
|
+
<Layout
|
|
126
|
+
logout={() => {
|
|
127
|
+
setAuthLogout();
|
|
128
|
+
logout(() => {
|
|
129
|
+
window.location.href = '/login';
|
|
130
|
+
});
|
|
131
|
+
}}
|
|
132
|
+
getIcons={getIcons}
|
|
133
|
+
menu={getMenu}
|
|
134
|
+
>
|
|
135
|
+
<Outlet />
|
|
136
|
+
</Layout>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Component Structure
|
|
142
|
+
|
|
143
|
+
### Layout Component
|
|
144
|
+
|
|
145
|
+
The `Layout` component from `proje-react-panel` provides the main structure. This is the **core component from the library** that you'll use to build your custom AuthLayout:
|
|
146
|
+
|
|
147
|
+
> **Important**: The `Layout` component automatically redirects unauthenticated users to the login page. If no user is authenticated, it will call the `logout` function with `'redirect'` parameter.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<Layout
|
|
151
|
+
logout={logoutFunction} // Function to handle logout
|
|
152
|
+
getIcons={getIcons} // Function to render icons
|
|
153
|
+
menu={getMenu} // Function that returns menu items
|
|
154
|
+
>
|
|
155
|
+
<Outlet /> // Child routes content
|
|
156
|
+
</Layout>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Component Hierarchy
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
App
|
|
163
|
+
├── Panel (from proje-react-panel)
|
|
164
|
+
│ └── Router
|
|
165
|
+
│ └── Routes
|
|
166
|
+
│ ├── AuthLayout (authenticated routes)
|
|
167
|
+
│ │ ├── Layout (from proje-react-panel)
|
|
168
|
+
│ │ │ ├── SideBar
|
|
169
|
+
│ │ │ │ ├── Toggle Button
|
|
170
|
+
│ │ │ │ ├── Navigation Links
|
|
171
|
+
│ │ │ │ └── Logout Button
|
|
172
|
+
│ │ │ └── Main Content
|
|
173
|
+
│ │ │ └── <Outlet /> (child routes)
|
|
174
|
+
│ │ └── Child Routes (Dashboard, Admins, etc.)
|
|
175
|
+
│ └── Login Route
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Data Flow
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
AuthLayout
|
|
182
|
+
├── getMenu() → Menu Items Array
|
|
183
|
+
├── getIcons() → Icon Components
|
|
184
|
+
├── logout() → Authentication Cleanup
|
|
185
|
+
└── <Outlet /> → Rendered Child Components
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Props Interface
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
interface LayoutProps<IconType> {
|
|
192
|
+
children?: React.ReactNode;
|
|
193
|
+
menu?: () => { name: string; path: string; iconType: IconType }[];
|
|
194
|
+
getIcons?: (iconType: IconType) => React.ReactNode;
|
|
195
|
+
logout?: (type: 'redirect' | 'logout') => void;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Menu Configuration
|
|
200
|
+
|
|
201
|
+
### 1. Define Icon Types
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
export type IconType =
|
|
205
|
+
| 'dashboard'
|
|
206
|
+
| 'admin'
|
|
207
|
+
| 'user'
|
|
208
|
+
| 'message'
|
|
209
|
+
| 'thread'
|
|
210
|
+
| 'assets'
|
|
211
|
+
| 'localization'
|
|
212
|
+
| 'language';
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 2. Create Menu Function
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
function getMenu(): {
|
|
219
|
+
name: string;
|
|
220
|
+
path: string;
|
|
221
|
+
iconType: IconType;
|
|
222
|
+
}[] {
|
|
223
|
+
return [
|
|
224
|
+
{ name: 'Dashboard', path: '/', iconType: 'dashboard' },
|
|
225
|
+
{ name: 'Admins', path: '/admins', iconType: 'admin' },
|
|
226
|
+
{ name: 'Users', path: 'users', iconType: 'user' },
|
|
227
|
+
{ name: 'Threads', path: 'threads', iconType: 'thread' },
|
|
228
|
+
{ name: 'Messages', path: 'messages', iconType: 'message' },
|
|
229
|
+
{ name: 'Assets', path: 'assets', iconType: 'assets' },
|
|
230
|
+
{ name: 'Localization', path: 'localization?language=tr', iconType: 'localization' },
|
|
231
|
+
{ name: 'Languages', path: 'languages', iconType: 'language' },
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Menu Item Properties
|
|
237
|
+
|
|
238
|
+
- `name`: Display text for the menu item
|
|
239
|
+
- `path`: Route path (can include query parameters)
|
|
240
|
+
- `iconType`: Type identifier for the icon
|
|
241
|
+
|
|
242
|
+
## Icon System
|
|
243
|
+
|
|
244
|
+
### 1. Import Icons
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import {
|
|
248
|
+
faDashboard,
|
|
249
|
+
faEnvelope,
|
|
250
|
+
faGlobe,
|
|
251
|
+
faImage,
|
|
252
|
+
faLanguage,
|
|
253
|
+
faMessage,
|
|
254
|
+
faUserAlt,
|
|
255
|
+
faUserCircle,
|
|
256
|
+
} from '@fortawesome/free-solid-svg-icons';
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 2. Create Icon Function
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
function getIcons(iconType: IconType) {
|
|
263
|
+
switch (iconType) {
|
|
264
|
+
case 'dashboard':
|
|
265
|
+
return <FontAwesomeIcon icon={faDashboard} />;
|
|
266
|
+
case 'admin':
|
|
267
|
+
return <FontAwesomeIcon icon={faUserAlt} />;
|
|
268
|
+
case 'user':
|
|
269
|
+
return <FontAwesomeIcon icon={faUserCircle} />;
|
|
270
|
+
case 'message':
|
|
271
|
+
return <FontAwesomeIcon icon={faEnvelope} />;
|
|
272
|
+
case 'thread':
|
|
273
|
+
return <FontAwesomeIcon icon={faMessage} />;
|
|
274
|
+
case 'assets':
|
|
275
|
+
return <FontAwesomeIcon icon={faImage} />;
|
|
276
|
+
case 'localization':
|
|
277
|
+
return <FontAwesomeIcon icon={faLanguage} />;
|
|
278
|
+
case 'language':
|
|
279
|
+
return <FontAwesomeIcon icon={faGlobe} />;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Custom Icon Implementation
|
|
285
|
+
|
|
286
|
+
You can use any React component as an icon:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
function getIcons(iconType: IconType) {
|
|
290
|
+
switch (iconType) {
|
|
291
|
+
case 'dashboard':
|
|
292
|
+
return <YourCustomIcon />;
|
|
293
|
+
case 'admin':
|
|
294
|
+
return <span>👤</span>; // Emoji icons
|
|
295
|
+
// ... other cases
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Styling
|
|
301
|
+
|
|
302
|
+
### Layout Styles
|
|
303
|
+
|
|
304
|
+
The layout uses CSS classes that are automatically included with the library:
|
|
305
|
+
|
|
306
|
+
```scss
|
|
307
|
+
.layout {
|
|
308
|
+
.content {
|
|
309
|
+
flex: 1;
|
|
310
|
+
padding: 0 0 0 1rem;
|
|
311
|
+
overflow-y: auto;
|
|
312
|
+
transition: margin-left 0.3s ease;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Sidebar Styles
|
|
318
|
+
|
|
319
|
+
The sidebar includes responsive behavior and animations:
|
|
320
|
+
|
|
321
|
+
```scss
|
|
322
|
+
.sidebar {
|
|
323
|
+
position: relative;
|
|
324
|
+
background-color: #343a40;
|
|
325
|
+
height: 100vh;
|
|
326
|
+
transition: width 0.3s ease;
|
|
327
|
+
border-right: 1px solid #454d55;
|
|
328
|
+
|
|
329
|
+
&.open {
|
|
330
|
+
width: 250px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
&.closed {
|
|
334
|
+
width: 60px;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Custom Styling
|
|
340
|
+
|
|
341
|
+
You can override styles by targeting the CSS classes:
|
|
342
|
+
|
|
343
|
+
```scss
|
|
344
|
+
// Custom sidebar background
|
|
345
|
+
.sidebar {
|
|
346
|
+
background-color: #your-color;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Custom navigation link styles
|
|
350
|
+
.nav-links a {
|
|
351
|
+
color: #your-text-color;
|
|
352
|
+
|
|
353
|
+
&:hover {
|
|
354
|
+
background-color: #your-hover-color;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
&.active {
|
|
358
|
+
background-color: #your-active-color;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Authentication Setup
|
|
364
|
+
|
|
365
|
+
### Authentication Flow
|
|
366
|
+
|
|
367
|
+
The `Layout` component from `proje-react-panel` automatically handles authentication:
|
|
368
|
+
|
|
369
|
+
```tsx
|
|
370
|
+
// The Layout component checks user authentication automatically
|
|
371
|
+
<Layout
|
|
372
|
+
logout={() => {
|
|
373
|
+
setAuthLogout();
|
|
374
|
+
logout(() => {
|
|
375
|
+
window.location.href = '/login';
|
|
376
|
+
});
|
|
377
|
+
}}
|
|
378
|
+
getIcons={getIcons}
|
|
379
|
+
menu={getMenu}
|
|
380
|
+
>
|
|
381
|
+
<Outlet />
|
|
382
|
+
</Layout>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Authentication Behavior:**
|
|
386
|
+
|
|
387
|
+
- ✅ **Authenticated users**: See the layout with sidebar
|
|
388
|
+
- ❌ **Unauthenticated users**: Automatically redirected to `/login`
|
|
389
|
+
- 🔄 **Logout**: Clears tokens and redirects to `/login`
|
|
390
|
+
- 🔄 **401 errors**: Automatically handled by API interceptors
|
|
391
|
+
|
|
392
|
+
### 1. API Configuration
|
|
393
|
+
|
|
394
|
+
```tsx
|
|
395
|
+
// api/apiConfig.ts
|
|
396
|
+
import axios, { AxiosInstance } from 'axios';
|
|
397
|
+
|
|
398
|
+
let axiosInstance: AxiosInstance;
|
|
399
|
+
|
|
400
|
+
export function initApi(config: { baseUrl: string }) {
|
|
401
|
+
axiosInstance = axios.create({
|
|
402
|
+
baseURL: config.baseUrl,
|
|
403
|
+
headers: {
|
|
404
|
+
'Content-Type': 'application/json',
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Handle 401 responses
|
|
409
|
+
axiosInstance.interceptors.response.use(
|
|
410
|
+
response => response,
|
|
411
|
+
error => {
|
|
412
|
+
if (error.response && error.response.status === 401) {
|
|
413
|
+
setAuthLogout();
|
|
414
|
+
window.location.href = '/login';
|
|
415
|
+
}
|
|
416
|
+
return Promise.reject(error);
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function setAuthLogout(): void {
|
|
422
|
+
if (!axiosInstance) {
|
|
423
|
+
throw new Error('API not initialized. Call initApi first.');
|
|
424
|
+
}
|
|
425
|
+
axiosInstance.defaults.headers.common['Authorization'] = null;
|
|
426
|
+
localStorage.removeItem('token');
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### 2. Initialize API
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
// In your main App component
|
|
434
|
+
import { initApi, initAuthToken, setAuthToken } from './api/apiConfig';
|
|
435
|
+
|
|
436
|
+
initApi({
|
|
437
|
+
baseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080',
|
|
438
|
+
});
|
|
439
|
+
initAuthToken();
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Complete Example
|
|
443
|
+
|
|
444
|
+
### App.tsx
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
import React from 'react';
|
|
448
|
+
import { Login, Panel, ListPage, FormPage, DetailsPage } from 'proje-react-panel';
|
|
449
|
+
import { BrowserRouter as Router, Route, Routes } from 'react-router';
|
|
450
|
+
import { AuthLayout } from './AuthLayout';
|
|
451
|
+
import { initApi, initAuthToken, setAuthToken } from './api/apiConfig';
|
|
452
|
+
|
|
453
|
+
// Initialize API
|
|
454
|
+
initApi({
|
|
455
|
+
baseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080',
|
|
456
|
+
});
|
|
457
|
+
initAuthToken();
|
|
458
|
+
|
|
459
|
+
export function App() {
|
|
460
|
+
return (
|
|
461
|
+
<Panel
|
|
462
|
+
onInit={appData => {
|
|
463
|
+
if (appData.token) {
|
|
464
|
+
setAuthToken(appData.token);
|
|
465
|
+
}
|
|
466
|
+
}}
|
|
467
|
+
>
|
|
468
|
+
<Router>
|
|
469
|
+
<Routes>
|
|
470
|
+
<Route path="/" element={<AuthLayout />}>
|
|
471
|
+
{/* Your authenticated routes here */}
|
|
472
|
+
<Route path={'/'} index element={<Dashboard />} />
|
|
473
|
+
<Route path={'admins'}>
|
|
474
|
+
<Route path={''} element={<ListPage model={AdminList} />} />
|
|
475
|
+
<Route path={'create'} element={<FormPage model={CreateAdminForm} />} />
|
|
476
|
+
<Route path={'edit/:id'} element={<FormPage model={EditAdminForm} />} />
|
|
477
|
+
<Route path={':id'} element={<DetailsPage model={AdminDetails} />} />
|
|
478
|
+
</Route>
|
|
479
|
+
{/* Add more routes as needed */}
|
|
480
|
+
</Route>
|
|
481
|
+
<Route path="/login" element={<Login model={LoginForm} />} />
|
|
482
|
+
</Routes>
|
|
483
|
+
</Router>
|
|
484
|
+
</Panel>
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### AuthLayout.tsx
|
|
490
|
+
|
|
491
|
+
```tsx
|
|
492
|
+
import { Outlet } from 'react-router';
|
|
493
|
+
import React from 'react';
|
|
494
|
+
import { Layout, logout } from 'proje-react-panel';
|
|
495
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
496
|
+
import {
|
|
497
|
+
faDashboard,
|
|
498
|
+
faEnvelope,
|
|
499
|
+
faGlobe,
|
|
500
|
+
faImage,
|
|
501
|
+
faLanguage,
|
|
502
|
+
faMessage,
|
|
503
|
+
faUserAlt,
|
|
504
|
+
faUserCircle,
|
|
505
|
+
} from '@fortawesome/free-solid-svg-icons';
|
|
506
|
+
import { setAuthLogout } from './api/apiConfig';
|
|
507
|
+
|
|
508
|
+
export type IconType =
|
|
509
|
+
| 'dashboard'
|
|
510
|
+
| 'admin'
|
|
511
|
+
| 'user'
|
|
512
|
+
| 'message'
|
|
513
|
+
| 'thread'
|
|
514
|
+
| 'assets'
|
|
515
|
+
| 'localization'
|
|
516
|
+
| 'language';
|
|
517
|
+
|
|
518
|
+
function getIcons(iconType: IconType) {
|
|
519
|
+
switch (iconType) {
|
|
520
|
+
case 'dashboard':
|
|
521
|
+
return <FontAwesomeIcon icon={faDashboard} />;
|
|
522
|
+
case 'admin':
|
|
523
|
+
return <FontAwesomeIcon icon={faUserAlt} />;
|
|
524
|
+
case 'user':
|
|
525
|
+
return <FontAwesomeIcon icon={faUserCircle} />;
|
|
526
|
+
case 'message':
|
|
527
|
+
return <FontAwesomeIcon icon={faEnvelope} />;
|
|
528
|
+
case 'thread':
|
|
529
|
+
return <FontAwesomeIcon icon={faMessage} />;
|
|
530
|
+
case 'assets':
|
|
531
|
+
return <FontAwesomeIcon icon={faImage} />;
|
|
532
|
+
case 'localization':
|
|
533
|
+
return <FontAwesomeIcon icon={faLanguage} />;
|
|
534
|
+
case 'language':
|
|
535
|
+
return <FontAwesomeIcon icon={faGlobe} />;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function getMenu(): {
|
|
540
|
+
name: string;
|
|
541
|
+
path: string;
|
|
542
|
+
iconType: IconType;
|
|
543
|
+
}[] {
|
|
544
|
+
return [
|
|
545
|
+
{ name: 'Dashboard', path: '/', iconType: 'dashboard' },
|
|
546
|
+
{ name: 'Admins', path: '/admins', iconType: 'admin' },
|
|
547
|
+
{ name: 'Users', path: 'users', iconType: 'user' },
|
|
548
|
+
{ name: 'Threads', path: 'threads', iconType: 'thread' },
|
|
549
|
+
{ name: 'Messages', path: 'messages', iconType: 'message' },
|
|
550
|
+
{ name: 'Assets', path: 'assets', iconType: 'assets' },
|
|
551
|
+
{ name: 'Localization', path: 'localization?language=tr', iconType: 'localization' },
|
|
552
|
+
{ name: 'Languages', path: 'languages', iconType: 'language' },
|
|
553
|
+
];
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function AuthLayout() {
|
|
557
|
+
return (
|
|
558
|
+
<Layout
|
|
559
|
+
logout={() => {
|
|
560
|
+
setAuthLogout();
|
|
561
|
+
logout(() => {
|
|
562
|
+
window.location.href = '/login';
|
|
563
|
+
});
|
|
564
|
+
}}
|
|
565
|
+
getIcons={getIcons}
|
|
566
|
+
menu={getMenu}
|
|
567
|
+
>
|
|
568
|
+
<Outlet />
|
|
569
|
+
</Layout>
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## Features
|
|
575
|
+
|
|
576
|
+
### Sidebar Functionality
|
|
577
|
+
|
|
578
|
+
- **Collapsible**: Click the toggle button to expand/collapse
|
|
579
|
+
- **Active State**: Current route is highlighted
|
|
580
|
+
- **Responsive**: Adapts to different screen sizes
|
|
581
|
+
- **Smooth Animations**: CSS transitions for better UX
|
|
582
|
+
|
|
583
|
+
### Authentication Features
|
|
584
|
+
|
|
585
|
+
- **Auto-redirect**: Redirects to login on 401 errors and for unauthenticated users
|
|
586
|
+
- **Token Management**: Handles JWT tokens automatically
|
|
587
|
+
- **Logout**: Clears tokens and redirects to login
|
|
588
|
+
- **Route Protection**: Automatically protects authenticated routes
|
|
589
|
+
|
|
590
|
+
### Navigation Features
|
|
591
|
+
|
|
592
|
+
- **Active Link Detection**: Automatically highlights current page
|
|
593
|
+
- **Icon Support**: FontAwesome or custom icons
|
|
594
|
+
- **Flexible Menu**: Easy to customize menu items
|
|
595
|
+
|
|
596
|
+
## Troubleshooting
|
|
597
|
+
|
|
598
|
+
### Common Issues
|
|
599
|
+
|
|
600
|
+
1. **Icons not showing**: Ensure FontAwesome is properly installed and imported
|
|
601
|
+
2. **Styling issues**: Check that CSS files are imported in your main stylesheet
|
|
602
|
+
3. **Authentication problems**: Verify API configuration and token handling
|
|
603
|
+
4. **Routing issues**: Ensure React Router is properly configured
|
|
604
|
+
5. **Rendering issues**: Always use `key` props on route components to prevent React rendering problems
|
|
605
|
+
|
|
606
|
+
### Debug Tips
|
|
607
|
+
|
|
608
|
+
- Check browser console for errors
|
|
609
|
+
- Verify API endpoints are accessible
|
|
610
|
+
- Ensure all required dependencies are installed
|
|
611
|
+
- Check that CSS classes are not being overridden
|
|
612
|
+
|
|
613
|
+
## Dependencies
|
|
614
|
+
|
|
615
|
+
Required packages:
|
|
616
|
+
|
|
617
|
+
```json
|
|
618
|
+
{
|
|
619
|
+
"proje-react-panel": "^latest",
|
|
620
|
+
"@fortawesome/fontawesome-svg-core": "^latest",
|
|
621
|
+
"@fortawesome/free-solid-svg-icons": "^latest",
|
|
622
|
+
"@fortawesome/react-fontawesome": "^latest",
|
|
623
|
+
"react-router": "^latest",
|
|
624
|
+
"axios": "^latest"
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
> **Note**: Only `proje-react-panel` is the core library. The other packages are dependencies you'll need to install to implement the AuthLayout helper component.
|
|
629
|
+
|
|
630
|
+
### Library vs Helper Component Dependencies
|
|
631
|
+
|
|
632
|
+
**Core Library Components** (from `proje-react-panel`):
|
|
633
|
+
|
|
634
|
+
- `Layout` - Main layout component with sidebar
|
|
635
|
+
- `logout` - Logout utility function
|
|
636
|
+
- `Panel` - Main application wrapper
|
|
637
|
+
- `Login`, `ListPage`, `FormPage`, `DetailsPage` - UI components
|
|
638
|
+
|
|
639
|
+
**Helper Component Dependencies** (external packages):
|
|
640
|
+
|
|
641
|
+
- `react-router` - For routing (`Outlet`, `BrowserRouter`, `Route`, `Routes`, `Link`)
|
|
642
|
+
- `@fortawesome/*` - For icons
|
|
643
|
+
- `axios` - For API calls
|
|
644
|
+
- `react` - React framework
|
|
645
|
+
|
|
646
|
+
### What's from the Library vs External Dependencies
|
|
647
|
+
|
|
648
|
+
**From `proje-react-panel` library:**
|
|
649
|
+
|
|
650
|
+
- `Layout` - Main layout with sidebar
|
|
651
|
+
- `Panel` - Application wrapper
|
|
652
|
+
- `Login`, `ListPage`, `FormPage`, `DetailsPage` - UI components
|
|
653
|
+
- `logout` - Utility function
|
|
654
|
+
|
|
655
|
+
**External dependencies (not from library):**
|
|
656
|
+
|
|
657
|
+
- `react-router` - Routing components (`Outlet`, `BrowserRouter`, `Route`, `Routes`, `Link`) - **Use `react-router`, NOT `react-router-dom`**
|
|
658
|
+
- `@fortawesome/*` - Icons
|
|
659
|
+
- `axios` - HTTP client
|
|
660
|
+
- `react` - React framework
|
|
661
|
+
|
|
662
|
+
## Advanced Usage
|
|
663
|
+
|
|
664
|
+
### Important: Use react-router (Not react-router-dom)
|
|
665
|
+
|
|
666
|
+
**Critical Requirement**: The `proje-react-panel` library is designed to work with `react-router`, not `react-router-dom`.
|
|
667
|
+
|
|
668
|
+
```tsx
|
|
669
|
+
// ✅ Correct - Use react-router
|
|
670
|
+
import { BrowserRouter as Router, Route, Routes, Outlet, Link } from 'react-router';
|
|
671
|
+
|
|
672
|
+
// ❌ Wrong - Don't use react-router-dom
|
|
673
|
+
import { BrowserRouter as Router, Route, Routes, Outlet, Link } from 'react-router-dom';
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
**Why react-router is required:**
|
|
677
|
+
|
|
678
|
+
- The library's components are built specifically for `react-router`
|
|
679
|
+
- `react-router-dom` has different APIs and behavior
|
|
680
|
+
- Using the wrong package will cause compatibility issues
|
|
681
|
+
- The library expects `react-router`'s specific component structure
|
|
682
|
+
|
|
683
|
+
### Important: Using Key Props
|
|
684
|
+
|
|
685
|
+
**Always use `key` props on your route components** to prevent React rendering issues:
|
|
686
|
+
|
|
687
|
+
```tsx
|
|
688
|
+
// ✅ Good - with key props
|
|
689
|
+
<Route path={"/"} index element={<Dashboard key="dashboard" />} />
|
|
690
|
+
<Route path={"users"}>
|
|
691
|
+
<Route path={""} element={<ListPage key="user-list" model={UserList} />} />
|
|
692
|
+
<Route path={"create"} element={<FormPage key="user-create" model={CreateUserForm} />} />
|
|
693
|
+
<Route path={"edit/:id"} element={<FormPage key="user-edit" model={EditUserForm} />} />
|
|
694
|
+
<Route path={":id"} element={<DetailsPage key="user-details" model={UserDetails} />} />
|
|
695
|
+
</Route>
|
|
696
|
+
|
|
697
|
+
// ❌ Bad - without key props (can cause rendering issues)
|
|
698
|
+
<Route path={"/"} index element={<Dashboard />} />
|
|
699
|
+
<Route path={"users"}>
|
|
700
|
+
<Route path={""} element={<ListPage model={UserList} />} />
|
|
701
|
+
</Route>
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**Why key props are important:**
|
|
705
|
+
|
|
706
|
+
- Prevents React from reusing components incorrectly
|
|
707
|
+
- Ensures proper component lifecycle management
|
|
708
|
+
- Avoids state persistence issues between route changes
|
|
709
|
+
- Improves performance by helping React identify components
|
|
710
|
+
|
|
711
|
+
### Custom Sidebar Behavior
|
|
712
|
+
|
|
713
|
+
You can customize the sidebar behavior by extending the Layout component:
|
|
714
|
+
|
|
715
|
+
```tsx
|
|
716
|
+
// CustomLayout.tsx
|
|
717
|
+
import { Layout } from 'proje-react-panel';
|
|
718
|
+
import { useState } from 'react';
|
|
719
|
+
|
|
720
|
+
export function CustomLayout({ children, ...props }) {
|
|
721
|
+
const [sidebarOpen, setSidebarOpen] = useState(true);
|
|
722
|
+
|
|
723
|
+
return (
|
|
724
|
+
<div className="custom-layout">
|
|
725
|
+
<Layout {...props}>{children}</Layout>
|
|
726
|
+
</div>
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Dynamic Menu Items
|
|
732
|
+
|
|
733
|
+
Create dynamic menu items based on user permissions:
|
|
734
|
+
|
|
735
|
+
```tsx
|
|
736
|
+
function getMenu(userRole: string) {
|
|
737
|
+
const baseMenu = [{ name: 'Dashboard', path: '/', iconType: 'dashboard' }];
|
|
738
|
+
|
|
739
|
+
if (userRole === 'admin') {
|
|
740
|
+
return [
|
|
741
|
+
...baseMenu,
|
|
742
|
+
{ name: 'Admins', path: '/admins', iconType: 'admin' },
|
|
743
|
+
{ name: 'Settings', path: '/settings', iconType: 'settings' },
|
|
744
|
+
];
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return baseMenu;
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
### Custom Styling with CSS Variables
|
|
752
|
+
|
|
753
|
+
Use CSS variables for easy theming:
|
|
754
|
+
|
|
755
|
+
```scss
|
|
756
|
+
:root {
|
|
757
|
+
--sidebar-bg: #343a40;
|
|
758
|
+
--sidebar-width-open: 250px;
|
|
759
|
+
--sidebar-width-closed: 60px;
|
|
760
|
+
--sidebar-text-color: #e9ecef;
|
|
761
|
+
--sidebar-active-color: #fff;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.sidebar {
|
|
765
|
+
background-color: var(--sidebar-bg);
|
|
766
|
+
width: var(--sidebar-width-open);
|
|
767
|
+
|
|
768
|
+
&.closed {
|
|
769
|
+
width: var(--sidebar-width-closed);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
### Integration with State Management
|
|
775
|
+
|
|
776
|
+
Integrate with Redux or Zustand for global state:
|
|
777
|
+
|
|
778
|
+
```tsx
|
|
779
|
+
// With Zustand
|
|
780
|
+
import { useAppStore } from './store/store';
|
|
781
|
+
|
|
782
|
+
export function AuthLayout() {
|
|
783
|
+
const { user, logout } = useAppStore();
|
|
784
|
+
|
|
785
|
+
return (
|
|
786
|
+
<Layout
|
|
787
|
+
logout={() => {
|
|
788
|
+
logout();
|
|
789
|
+
window.location.href = '/login';
|
|
790
|
+
}}
|
|
791
|
+
getIcons={getIcons}
|
|
792
|
+
menu={() => getMenu(user?.role)}
|
|
793
|
+
>
|
|
794
|
+
<Outlet />
|
|
795
|
+
</Layout>
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
### Performance Optimization
|
|
801
|
+
|
|
802
|
+
For better performance with large menus:
|
|
803
|
+
|
|
804
|
+
```tsx
|
|
805
|
+
import { useMemo } from 'react';
|
|
806
|
+
|
|
807
|
+
export function AuthLayout() {
|
|
808
|
+
const menuItems = useMemo(() => getMenu(), []);
|
|
809
|
+
const iconFunction = useMemo(() => getIcons, []);
|
|
810
|
+
|
|
811
|
+
return (
|
|
812
|
+
<Layout menu={() => menuItems} getIcons={iconFunction} logout={handleLogout}>
|
|
813
|
+
<Outlet />
|
|
814
|
+
</Layout>
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
This guide provides everything you need to implement a complete AuthLayout with sidebar functionality in your React application.
|