baraqex 1.0.67 → 1.0.69
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/dist/index.js +17 -3
- package/dist/index.js.map +2 -2
- package/dist/server/api-router.d.ts +3 -1
- package/dist/server/api-router.d.ts.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +17 -3
- package/dist/server/index.js.map +2 -2
- package/package.json +1 -1
- package/templates/fullstack-template/.env.example +16 -29
- package/templates/fullstack-template/README.md +9 -45
- package/templates/fullstack-template/package-lock.json +1504 -6211
- package/templates/fullstack-template/package.json +16 -46
- package/templates/fullstack-template/server.js +52 -25
- package/templates/fullstack-template/src/App.tsx +178 -1
- package/templates/fullstack-template/src/api/hello.js +19 -0
- package/templates/fullstack-template/src/api/users.js +39 -0
- package/templates/fullstack-template/src/pages/index.tsx +200 -0
- package/templates/fullstack-template/src/server.ts +162 -98
- package/templates/fullstack-template/tsconfig.json +30 -0
|
@@ -1,66 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fullstack-baraqex-app",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "A fullstack application built with Baraqex",
|
|
6
4
|
"type": "module",
|
|
5
|
+
"description": "A fullstack application built with Baraqex framework",
|
|
6
|
+
"main": "server.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"dev": "
|
|
9
|
-
"
|
|
10
|
-
"build
|
|
11
|
-
"build:
|
|
12
|
-
"
|
|
13
|
-
"test": "jest",
|
|
14
|
-
"lint": "eslint src --ext .ts,.tsx,.js,.jsx",
|
|
15
|
-
"format": "prettier --write src/**/*.{ts,tsx,js,jsx,json,css,md}",
|
|
16
|
-
"db:migrate": "node scripts/migrate.js",
|
|
17
|
-
"db:seed": "node scripts/seed.js"
|
|
8
|
+
"dev": "tsx src/server.ts",
|
|
9
|
+
"start": "tsx src/server.ts",
|
|
10
|
+
"build": "tsc && echo 'Build complete'",
|
|
11
|
+
"build:start": "npm run build && node dist/server.js",
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
13
|
},
|
|
19
14
|
"dependencies": {
|
|
20
|
-
"baraqex": "^1.0.
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"cors": "^2.8.5",
|
|
24
|
-
"dotenv": "^16.3.1",
|
|
25
|
-
"express": "^4.18.2",
|
|
26
|
-
"express-rate-limit": "^6.10.0",
|
|
27
|
-
"frontend-hamroun": "latest",
|
|
28
|
-
"helmet": "^7.0.0",
|
|
29
|
-
"jsonwebtoken": "^9.0.2",
|
|
30
|
-
"morgan": "^1.10.0",
|
|
31
|
-
"multer": "latest"
|
|
15
|
+
"baraqex": "^1.0.68",
|
|
16
|
+
"dotenv": "^16.0.0",
|
|
17
|
+
"express": "^4.21.2"
|
|
32
18
|
},
|
|
33
19
|
"devDependencies": {
|
|
34
|
-
"@types/
|
|
35
|
-
"@types/
|
|
36
|
-
"
|
|
37
|
-
"@types/express": "^4.17.17",
|
|
38
|
-
"@types/jest": "^29.5.4",
|
|
39
|
-
"@types/jsonwebtoken": "^9.0.2",
|
|
40
|
-
"@types/morgan": "^1.9.4",
|
|
41
|
-
"@types/multer": "^1.4.7",
|
|
42
|
-
"@types/node": "^20.5.0",
|
|
43
|
-
"esbuild": "^0.19.0",
|
|
44
|
-
"eslint": "^8.47.0",
|
|
45
|
-
"jest": "^29.6.0",
|
|
46
|
-
"nodemon": "^3.0.1",
|
|
47
|
-
"prettier": "^3.0.0",
|
|
20
|
+
"@types/express": "^4.17.0",
|
|
21
|
+
"@types/node": "^20.0.0",
|
|
22
|
+
"tsx": "^4.0.0",
|
|
48
23
|
"typescript": "^5.0.0"
|
|
49
24
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"mysql2": "^3.6.0",
|
|
53
|
-
"pg": "^8.11.3"
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=16.0.0"
|
|
54
27
|
},
|
|
55
28
|
"keywords": [
|
|
56
29
|
"baraqex",
|
|
57
30
|
"fullstack",
|
|
58
|
-
"react",
|
|
59
31
|
"typescript",
|
|
60
32
|
"express",
|
|
61
|
-
"
|
|
62
|
-
"authentication"
|
|
33
|
+
"ssr"
|
|
63
34
|
],
|
|
64
|
-
"author": "",
|
|
65
35
|
"license": "MIT"
|
|
66
36
|
}
|
|
@@ -1,35 +1,62 @@
|
|
|
1
1
|
import { createServer } from 'baraqex';
|
|
2
|
-
import dotenv from 'dotenv';
|
|
3
2
|
|
|
4
|
-
//
|
|
5
|
-
dotenv.config();
|
|
6
|
-
|
|
7
|
-
// Create development server
|
|
3
|
+
// Create a fullstack server with basic configuration
|
|
8
4
|
const server = createServer({
|
|
9
|
-
port:
|
|
5
|
+
port: process.env.PORT || 3000,
|
|
10
6
|
apiDir: './src/api',
|
|
11
|
-
pagesDir: './src/pages',
|
|
7
|
+
pagesDir: './src/pages',
|
|
12
8
|
staticDir: './public',
|
|
13
9
|
enableCors: true,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
// Uncomment and configure database if needed
|
|
11
|
+
// db: {
|
|
12
|
+
// url: process.env.DATABASE_URL || 'mongodb://localhost:27017/baraqex-app',
|
|
13
|
+
// type: 'mongodb'
|
|
14
|
+
// },
|
|
15
|
+
// Uncomment and configure authentication if needed
|
|
16
|
+
// auth: {
|
|
17
|
+
// secret: process.env.JWT_SECRET || 'your-secret-key',
|
|
18
|
+
// expiresIn: '7d'
|
|
19
|
+
// }
|
|
18
20
|
});
|
|
19
21
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
// Add graceful shutdown handling
|
|
23
|
+
process.on('SIGTERM', async () => {
|
|
24
|
+
console.log('SIGTERM received, shutting down gracefully');
|
|
25
|
+
await server.stop();
|
|
26
|
+
process.exit(0);
|
|
27
|
+
});
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
console.log('
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log('📋 API Docs: http://localhost:3000/api-docs');
|
|
31
|
-
console.log('💚 Health: http://localhost:3000/health');
|
|
32
|
-
}).catch(error => {
|
|
33
|
-
console.error('❌ Failed to start server:', error);
|
|
34
|
-
process.exit(1);
|
|
29
|
+
process.on('SIGINT', async () => {
|
|
30
|
+
console.log('SIGINT received, shutting down gracefully');
|
|
31
|
+
await server.stop();
|
|
32
|
+
process.exit(0);
|
|
35
33
|
});
|
|
34
|
+
|
|
35
|
+
// Start the server
|
|
36
|
+
async function startServer() {
|
|
37
|
+
try {
|
|
38
|
+
console.log('🚀 Starting Baraqex Fullstack Server...');
|
|
39
|
+
await server.start();
|
|
40
|
+
|
|
41
|
+
console.log('✅ Server started successfully!');
|
|
42
|
+
console.log(`🌐 Server running at http://localhost:${server.config?.port || 3000}`);
|
|
43
|
+
console.log('📚 API endpoints available at /api/*');
|
|
44
|
+
console.log('📊 API documentation at /api-docs');
|
|
45
|
+
console.log('\n💡 Quick start:');
|
|
46
|
+
console.log(' - Add API routes in ./src/api/');
|
|
47
|
+
console.log(' - Add pages in ./src/pages/');
|
|
48
|
+
console.log(' - Static files go in ./public/');
|
|
49
|
+
console.log(' - Press Ctrl+C to stop the server');
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('❌ Failed to start server:', error.message);
|
|
52
|
+
|
|
53
|
+
if (error.message.includes('Express not installed')) {
|
|
54
|
+
console.log('\n💡 To fix this, run:');
|
|
55
|
+
console.log(' npm install express @types/express');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
startServer();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { jsx, useState, useEffect } from 'frontend-hamroun';
|
|
2
1
|
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
3
2
|
import { ApiProvider } from './contexts/ApiContext';
|
|
4
3
|
import { Header } from './components/Header';
|
|
@@ -8,6 +7,13 @@ import { TodoList } from './components/TodoList';
|
|
|
8
7
|
import { UserProfile } from './components/UserProfile';
|
|
9
8
|
import { LoadingSpinner } from './components/LoadingSpinner';
|
|
10
9
|
import './styles/App.css';
|
|
10
|
+
import { useState, useEffect } from 'baraqex';
|
|
11
|
+
|
|
12
|
+
interface User {
|
|
13
|
+
id: number;
|
|
14
|
+
name: string;
|
|
15
|
+
email: string;
|
|
16
|
+
}
|
|
11
17
|
|
|
12
18
|
type View = 'dashboard' | 'todos' | 'profile' | 'login';
|
|
13
19
|
|
|
@@ -15,6 +21,9 @@ function AppContent() {
|
|
|
15
21
|
const { user, loading: authLoading } = useAuth();
|
|
16
22
|
const [currentView, setCurrentView] = useState<View>('dashboard');
|
|
17
23
|
const [loading, setLoading] = useState(true);
|
|
24
|
+
const [users, setUsers] = useState<User[]>([]);
|
|
25
|
+
const [newUser, setNewUser] = useState({ name: '', email: '' });
|
|
26
|
+
const [userLoading, setUserLoading] = useState(false);
|
|
18
27
|
|
|
19
28
|
useEffect(() => {
|
|
20
29
|
// Simulate app initialization
|
|
@@ -25,6 +34,51 @@ function AppContent() {
|
|
|
25
34
|
return () => clearTimeout(timer);
|
|
26
35
|
}, []);
|
|
27
36
|
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
fetchUsers();
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
const fetchUsers = async () => {
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch('/api/users');
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
if (data.success) {
|
|
46
|
+
setUsers(data.users);
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error fetching users:', error);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
setUserLoading(true);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch('/api/users', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(newUser),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
|
|
68
|
+
if (data.success) {
|
|
69
|
+
setUsers([...users, data.user]);
|
|
70
|
+
setNewUser({ name: '', email: '' });
|
|
71
|
+
} else {
|
|
72
|
+
alert('Error: ' + data.error);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Error creating user:', error);
|
|
76
|
+
alert('Error creating user');
|
|
77
|
+
} finally {
|
|
78
|
+
setUserLoading(false);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
28
82
|
if (loading || authLoading) {
|
|
29
83
|
return <LoadingSpinner message="Loading application..." />;
|
|
30
84
|
}
|
|
@@ -70,6 +124,125 @@ function AppContent() {
|
|
|
70
124
|
<footer className="app-footer">
|
|
71
125
|
<p>© 2024 Fullstack Baraqex App. Built with ❤️ using Baraqex Framework.</p>
|
|
72
126
|
</footer>
|
|
127
|
+
|
|
128
|
+
{/* Add User Form */}
|
|
129
|
+
<div style={{
|
|
130
|
+
background: '#f5f5f5',
|
|
131
|
+
padding: '20px',
|
|
132
|
+
borderRadius: '8px',
|
|
133
|
+
marginBottom: '30px'
|
|
134
|
+
}}>
|
|
135
|
+
<h2 style={{ marginTop: '0', color: '#333' }}>Add New User</h2>
|
|
136
|
+
<form onSubmit={handleSubmit}>
|
|
137
|
+
<div style={{ marginBottom: '15px' }}>
|
|
138
|
+
<input
|
|
139
|
+
type="text"
|
|
140
|
+
placeholder="Name"
|
|
141
|
+
value={newUser.name}
|
|
142
|
+
onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
|
|
143
|
+
style={{
|
|
144
|
+
width: '100%',
|
|
145
|
+
padding: '10px',
|
|
146
|
+
border: '1px solid #ddd',
|
|
147
|
+
borderRadius: '4px',
|
|
148
|
+
fontSize: '14px'
|
|
149
|
+
}}
|
|
150
|
+
required
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
<div style={{ marginBottom: '15px' }}>
|
|
154
|
+
<input
|
|
155
|
+
type="email"
|
|
156
|
+
placeholder="Email"
|
|
157
|
+
value={newUser.email}
|
|
158
|
+
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
|
|
159
|
+
style={{
|
|
160
|
+
width: '100%',
|
|
161
|
+
padding: '10px',
|
|
162
|
+
border: '1px solid #ddd',
|
|
163
|
+
borderRadius: '4px',
|
|
164
|
+
fontSize: '14px'
|
|
165
|
+
}}
|
|
166
|
+
required
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
<button
|
|
170
|
+
type="submit"
|
|
171
|
+
disabled={userLoading}
|
|
172
|
+
style={{
|
|
173
|
+
background: userLoading ? '#ccc' : '#007bff',
|
|
174
|
+
color: 'white',
|
|
175
|
+
border: 'none',
|
|
176
|
+
padding: '10px 20px',
|
|
177
|
+
borderRadius: '4px',
|
|
178
|
+
cursor: userLoading ? 'not-allowed' : 'pointer',
|
|
179
|
+
fontSize: '14px'
|
|
180
|
+
}}
|
|
181
|
+
>
|
|
182
|
+
{userLoading ? 'Adding...' : 'Add User'}
|
|
183
|
+
</button>
|
|
184
|
+
</form>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
{/* Users List */}
|
|
188
|
+
<div>
|
|
189
|
+
<h2 style={{ color: '#333' }}>Users ({users.length})</h2>
|
|
190
|
+
{users.length === 0 ? (
|
|
191
|
+
<p style={{ color: '#666', fontStyle: 'italic' }}>
|
|
192
|
+
No users found. Add some users using the form above!
|
|
193
|
+
</p>
|
|
194
|
+
) : (
|
|
195
|
+
<div style={{ display: 'grid', gap: '10px' }}>
|
|
196
|
+
{users.map((user) => (
|
|
197
|
+
<div
|
|
198
|
+
key={user.id}
|
|
199
|
+
style={{
|
|
200
|
+
background: 'white',
|
|
201
|
+
border: '1px solid #ddd',
|
|
202
|
+
borderRadius: '6px',
|
|
203
|
+
padding: '15px',
|
|
204
|
+
display: 'flex',
|
|
205
|
+
justifyContent: 'space-between',
|
|
206
|
+
alignItems: 'center'
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
<div>
|
|
210
|
+
<strong style={{ color: '#333' }}>{user.name}</strong>
|
|
211
|
+
<br />
|
|
212
|
+
<span style={{ color: '#666', fontSize: '14px' }}>{user.email}</span>
|
|
213
|
+
</div>
|
|
214
|
+
<div style={{
|
|
215
|
+
background: '#28a745',
|
|
216
|
+
color: 'white',
|
|
217
|
+
padding: '4px 8px',
|
|
218
|
+
borderRadius: '4px',
|
|
219
|
+
fontSize: '12px'
|
|
220
|
+
}}>
|
|
221
|
+
ID: {user.id}
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
))}
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
{/* API Info */}
|
|
230
|
+
<div style={{
|
|
231
|
+
marginTop: '40px',
|
|
232
|
+
padding: '20px',
|
|
233
|
+
background: '#e7f3ff',
|
|
234
|
+
borderRadius: '8px'
|
|
235
|
+
}}>
|
|
236
|
+
<h3 style={{ marginTop: '0', color: '#0066cc' }}>🔗 API Endpoints</h3>
|
|
237
|
+
<ul style={{ color: '#333' }}>
|
|
238
|
+
<li><code>GET /api/users</code> - Fetch all users</li>
|
|
239
|
+
<li><code>POST /api/users</code> - Create a new user</li>
|
|
240
|
+
<li><code>GET /api/hello</code> - Simple hello endpoint</li>
|
|
241
|
+
</ul>
|
|
242
|
+
<p style={{ color: '#666', fontSize: '14px', marginBottom: '0' }}>
|
|
243
|
+
Try visiting <a href="/api/users" target="_blank">/api/users</a> or <a href="/api/hello" target="_blank">/api/hello</a> to see the API responses.
|
|
244
|
+
</p>
|
|
245
|
+
</div>
|
|
73
246
|
</div>
|
|
74
247
|
);
|
|
75
248
|
}
|
|
@@ -92,3 +265,7 @@ App.getMeta = () => ({
|
|
|
92
265
|
'og:description': 'Complete fullstack solution with Baraqex',
|
|
93
266
|
'og:type': 'website'
|
|
94
267
|
});
|
|
268
|
+
|
|
269
|
+
// Page metadata for SEO
|
|
270
|
+
App.title = 'Baraqex Fullstack Demo';
|
|
271
|
+
App.description = 'A demonstration of Baraqex fullstack capabilities with SSR and API integration';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Example API route: GET /api/hello
|
|
2
|
+
export async function get(req, res) {
|
|
3
|
+
res.json({
|
|
4
|
+
message: 'Hello from Baraqex API!',
|
|
5
|
+
timestamp: new Date().toISOString(),
|
|
6
|
+
method: 'GET'
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// POST /api/hello
|
|
11
|
+
export async function post(req, res) {
|
|
12
|
+
const { name } = req.body;
|
|
13
|
+
res.json({
|
|
14
|
+
message: `Hello ${name || 'World'}!`,
|
|
15
|
+
timestamp: new Date().toISOString(),
|
|
16
|
+
method: 'POST',
|
|
17
|
+
body: req.body
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// In-memory user storage for demo
|
|
2
|
+
let users = [
|
|
3
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com' },
|
|
4
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
|
|
5
|
+
];
|
|
6
|
+
|
|
7
|
+
// GET /api/users
|
|
8
|
+
export async function get(req, res) {
|
|
9
|
+
res.json({
|
|
10
|
+
success: true,
|
|
11
|
+
users,
|
|
12
|
+
count: users.length
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// POST /api/users
|
|
17
|
+
export async function post(req, res) {
|
|
18
|
+
const { name, email } = req.body;
|
|
19
|
+
|
|
20
|
+
if (!name || !email) {
|
|
21
|
+
return res.status(400).json({
|
|
22
|
+
success: false,
|
|
23
|
+
error: 'Name and email are required'
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const newUser = {
|
|
28
|
+
id: users.length + 1,
|
|
29
|
+
name,
|
|
30
|
+
email
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
users.push(newUser);
|
|
34
|
+
|
|
35
|
+
res.status(201).json({
|
|
36
|
+
success: true,
|
|
37
|
+
user: newUser
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { useState, useEffect } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
interface User {
|
|
4
|
+
id: number;
|
|
5
|
+
name: string;
|
|
6
|
+
email: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function HomePage() {
|
|
10
|
+
const [users, setUsers] = useState<User[]>([]);
|
|
11
|
+
const [newUser, setNewUser] = useState({ name: '', email: '' });
|
|
12
|
+
const [loading, setLoading] = useState(false);
|
|
13
|
+
|
|
14
|
+
// Fetch users on component mount
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
fetchUsers();
|
|
17
|
+
}, []);
|
|
18
|
+
|
|
19
|
+
const fetchUsers = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch('/api/users');
|
|
22
|
+
const data = await response.json();
|
|
23
|
+
if (data.success) {
|
|
24
|
+
setUsers(data.users);
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('Error fetching users:', error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
setLoading(true);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch('/api/users', {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify(newUser),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
|
|
46
|
+
if (data.success) {
|
|
47
|
+
setUsers([...users, data.user]);
|
|
48
|
+
setNewUser({ name: '', email: '' });
|
|
49
|
+
} else {
|
|
50
|
+
alert('Error: ' + data.error);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Error creating user:', error);
|
|
54
|
+
alert('Error creating user');
|
|
55
|
+
} finally {
|
|
56
|
+
setLoading(false);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div style={{
|
|
62
|
+
fontFamily: 'system-ui, sans-serif',
|
|
63
|
+
maxWidth: '800px',
|
|
64
|
+
margin: '0 auto',
|
|
65
|
+
padding: '20px'
|
|
66
|
+
}}>
|
|
67
|
+
<h1 style={{ color: '#333', marginBottom: '30px' }}>
|
|
68
|
+
🚀 Baraqex Fullstack Demo
|
|
69
|
+
</h1>
|
|
70
|
+
|
|
71
|
+
<p style={{ color: '#666', marginBottom: '40px' }}>
|
|
72
|
+
This page demonstrates server-side rendering with API integration.
|
|
73
|
+
The page is rendered on the server and then hydrated on the client.
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
{/* Add User Form */}
|
|
77
|
+
<div style={{
|
|
78
|
+
background: '#f5f5f5',
|
|
79
|
+
padding: '20px',
|
|
80
|
+
borderRadius: '8px',
|
|
81
|
+
marginBottom: '30px'
|
|
82
|
+
}}>
|
|
83
|
+
<h2 style={{ marginTop: '0', color: '#333' }}>Add New User</h2>
|
|
84
|
+
<form onSubmit={handleSubmit}>
|
|
85
|
+
<div style={{ marginBottom: '15px' }}>
|
|
86
|
+
<input
|
|
87
|
+
type="text"
|
|
88
|
+
placeholder="Name"
|
|
89
|
+
value={newUser.name}
|
|
90
|
+
onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
|
|
91
|
+
style={{
|
|
92
|
+
width: '100%',
|
|
93
|
+
padding: '10px',
|
|
94
|
+
border: '1px solid #ddd',
|
|
95
|
+
borderRadius: '4px',
|
|
96
|
+
fontSize: '14px'
|
|
97
|
+
}}
|
|
98
|
+
required
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
<div style={{ marginBottom: '15px' }}>
|
|
102
|
+
<input
|
|
103
|
+
type="email"
|
|
104
|
+
placeholder="Email"
|
|
105
|
+
value={newUser.email}
|
|
106
|
+
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
|
|
107
|
+
style={{
|
|
108
|
+
width: '100%',
|
|
109
|
+
padding: '10px',
|
|
110
|
+
border: '1px solid #ddd',
|
|
111
|
+
borderRadius: '4px',
|
|
112
|
+
fontSize: '14px'
|
|
113
|
+
}}
|
|
114
|
+
required
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
<button
|
|
118
|
+
type="submit"
|
|
119
|
+
disabled={loading}
|
|
120
|
+
style={{
|
|
121
|
+
background: loading ? '#ccc' : '#007bff',
|
|
122
|
+
color: 'white',
|
|
123
|
+
border: 'none',
|
|
124
|
+
padding: '10px 20px',
|
|
125
|
+
borderRadius: '4px',
|
|
126
|
+
cursor: loading ? 'not-allowed' : 'pointer',
|
|
127
|
+
fontSize: '14px'
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{loading ? 'Adding...' : 'Add User'}
|
|
131
|
+
</button>
|
|
132
|
+
</form>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{/* Users List */}
|
|
136
|
+
<div>
|
|
137
|
+
<h2 style={{ color: '#333' }}>Users ({users.length})</h2>
|
|
138
|
+
{users.length === 0 ? (
|
|
139
|
+
<p style={{ color: '#666', fontStyle: 'italic' }}>
|
|
140
|
+
No users found. Add some users using the form above!
|
|
141
|
+
</p>
|
|
142
|
+
) : (
|
|
143
|
+
<div style={{ display: 'grid', gap: '10px' }}>
|
|
144
|
+
{users.map((user) => (
|
|
145
|
+
<div
|
|
146
|
+
key={user.id}
|
|
147
|
+
style={{
|
|
148
|
+
background: 'white',
|
|
149
|
+
border: '1px solid #ddd',
|
|
150
|
+
borderRadius: '6px',
|
|
151
|
+
padding: '15px',
|
|
152
|
+
display: 'flex',
|
|
153
|
+
justifyContent: 'space-between',
|
|
154
|
+
alignItems: 'center'
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
<div>
|
|
158
|
+
<strong style={{ color: '#333' }}>{user.name}</strong>
|
|
159
|
+
<br />
|
|
160
|
+
<span style={{ color: '#666', fontSize: '14px' }}>{user.email}</span>
|
|
161
|
+
</div>
|
|
162
|
+
<div style={{
|
|
163
|
+
background: '#28a745',
|
|
164
|
+
color: 'white',
|
|
165
|
+
padding: '4px 8px',
|
|
166
|
+
borderRadius: '4px',
|
|
167
|
+
fontSize: '12px'
|
|
168
|
+
}}>
|
|
169
|
+
ID: {user.id}
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
))}
|
|
173
|
+
</div>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
{/* API Info */}
|
|
178
|
+
<div style={{
|
|
179
|
+
marginTop: '40px',
|
|
180
|
+
padding: '20px',
|
|
181
|
+
background: '#e7f3ff',
|
|
182
|
+
borderRadius: '8px'
|
|
183
|
+
}}>
|
|
184
|
+
<h3 style={{ marginTop: '0', color: '#0066cc' }}>🔗 API Endpoints</h3>
|
|
185
|
+
<ul style={{ color: '#333' }}>
|
|
186
|
+
<li><code>GET /api/users</code> - Fetch all users</li>
|
|
187
|
+
<li><code>POST /api/users</code> - Create a new user</li>
|
|
188
|
+
<li><code>GET /api/hello</code> - Simple hello endpoint</li>
|
|
189
|
+
</ul>
|
|
190
|
+
<p style={{ color: '#666', fontSize: '14px', marginBottom: '0' }}>
|
|
191
|
+
Try visiting <a href="/api/users" target="_blank">/api/users</a> or <a href="/api/hello" target="_blank">/api/hello</a> to see the API responses.
|
|
192
|
+
</p>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Page metadata for SEO
|
|
199
|
+
HomePage.title = 'Baraqex Fullstack Demo';
|
|
200
|
+
HomePage.description = 'A demonstration of Baraqex fullstack capabilities with SSR and API integration';
|