baraqex 1.0.76 → 2.0.0

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.
Files changed (182) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +268 -315
  3. package/bin/baraqex.js +150 -12
  4. package/dist/browser.d.ts +1 -1
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +2319 -205
  7. package/dist/browser.js.map +4 -4
  8. package/dist/core/batch.d.ts +10 -0
  9. package/dist/core/batch.d.ts.map +1 -0
  10. package/dist/core/component.d.ts +69 -0
  11. package/dist/core/component.d.ts.map +1 -0
  12. package/dist/core/context.d.ts +22 -0
  13. package/dist/core/context.d.ts.map +1 -0
  14. package/dist/core/errors.d.ts +125 -0
  15. package/dist/core/errors.d.ts.map +1 -0
  16. package/dist/core/event-bus.d.ts +29 -0
  17. package/dist/core/event-bus.d.ts.map +1 -0
  18. package/dist/core/forms.d.ts +128 -0
  19. package/dist/core/forms.d.ts.map +1 -0
  20. package/dist/core/hooks.d.ts +84 -0
  21. package/dist/core/hooks.d.ts.map +1 -0
  22. package/dist/core/index.d.ts +23 -0
  23. package/dist/core/index.d.ts.map +1 -0
  24. package/dist/core/jsx-runtime.d.ts +45 -0
  25. package/dist/core/jsx-runtime.d.ts.map +1 -0
  26. package/dist/core/lifecycle-events.d.ts +71 -0
  27. package/dist/core/lifecycle-events.d.ts.map +1 -0
  28. package/dist/core/renderer.d.ts +39 -0
  29. package/dist/core/renderer.d.ts.map +1 -0
  30. package/dist/core/router.d.ts +108 -0
  31. package/dist/core/router.d.ts.map +1 -0
  32. package/dist/core/server-renderer.d.ts +26 -0
  33. package/dist/core/server-renderer.d.ts.map +1 -0
  34. package/dist/core/store.d.ts +102 -0
  35. package/dist/core/store.d.ts.map +1 -0
  36. package/dist/core/types.d.ts +66 -0
  37. package/dist/core/types.d.ts.map +1 -0
  38. package/dist/core/utils.d.ts +153 -0
  39. package/dist/core/utils.d.ts.map +1 -0
  40. package/dist/core/vdom.d.ts +29 -0
  41. package/dist/core/vdom.d.ts.map +1 -0
  42. package/dist/index.d.ts +39 -35
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2592 -508
  45. package/dist/index.js.map +4 -4
  46. package/dist/server/auth.d.ts +8 -3
  47. package/dist/server/auth.d.ts.map +1 -1
  48. package/dist/server/index.d.ts +2 -2
  49. package/dist/server/index.d.ts.map +1 -1
  50. package/dist/server/index.js +173 -112
  51. package/dist/server/index.js.map +4 -4
  52. package/dist/server/middleware.d.ts +10 -1
  53. package/dist/server/middleware.d.ts.map +1 -1
  54. package/package.json +224 -124
  55. package/templates/basic-app/src/main.jsx +336 -0
  56. package/templates/complete-app/api/hello.js +0 -0
  57. package/templates/complete-app/client.js +58 -0
  58. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  59. package/templates/complete-app/package.json +18 -0
  60. package/templates/complete-app/pages/about.js +119 -0
  61. package/templates/complete-app/pages/about.jsx +0 -0
  62. package/templates/complete-app/pages/index.js +157 -0
  63. package/templates/complete-app/pages/index.jsx +0 -0
  64. package/templates/complete-app/pages/wasm-demo.js +290 -0
  65. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  66. package/templates/complete-app/public/client.js +89 -0
  67. package/templates/complete-app/public/index.html +118 -0
  68. package/templates/complete-app/public/styles.css +76 -0
  69. package/templates/complete-app/readme.md +188 -0
  70. package/templates/complete-app/server.js +226 -0
  71. package/templates/complete-app/server.ts +275 -0
  72. package/templates/complete-app/src/App.tsx +59 -0
  73. package/templates/complete-app/src/client.ts +61 -0
  74. package/templates/complete-app/src/client.tsx +18 -0
  75. package/templates/complete-app/src/pages/index.tsx +51 -0
  76. package/templates/complete-app/src/server.ts +218 -0
  77. package/templates/complete-app/tsconfig.json +22 -0
  78. package/templates/complete-app/tsconfig.server.json +19 -0
  79. package/templates/complete-app/vite.config.js +57 -0
  80. package/templates/complete-app/vite.config.ts +30 -0
  81. package/templates/complete-app/wasm/build.bat +0 -0
  82. package/templates/complete-app/wasm/build.sh +0 -0
  83. package/templates/complete-app/wasm/example.go +0 -0
  84. package/templates/fullstack-app/README.md +37 -0
  85. package/templates/fullstack-app/api/hello.js +11 -0
  86. package/templates/fullstack-app/api/hello.ts +18 -0
  87. package/templates/fullstack-app/api/users/[id].ts +73 -0
  88. package/templates/fullstack-app/api/users/index.ts +32 -0
  89. package/templates/fullstack-app/build/main.css +874 -0
  90. package/templates/fullstack-app/build/main.css.map +7 -0
  91. package/templates/fullstack-app/build/main.js +967 -0
  92. package/templates/fullstack-app/build/main.js.map +7 -0
  93. package/templates/fullstack-app/build.ts +210 -0
  94. package/templates/fullstack-app/index.html +36 -0
  95. package/templates/fullstack-app/package.json +35 -0
  96. package/templates/fullstack-app/postcss.config.js +6 -0
  97. package/templates/fullstack-app/process-tailwind.js +45 -0
  98. package/templates/fullstack-app/public/_redirects +1 -0
  99. package/templates/fullstack-app/public/route-handler.js +47 -0
  100. package/templates/fullstack-app/public/spa-fix.html +17 -0
  101. package/templates/fullstack-app/public/styles.css +975 -0
  102. package/templates/fullstack-app/public/tailwind.css +15 -0
  103. package/templates/fullstack-app/server.js +267 -0
  104. package/templates/fullstack-app/server.ts +474 -0
  105. package/templates/fullstack-app/src/README.md +55 -0
  106. package/templates/fullstack-app/src/client.js +87 -0
  107. package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
  108. package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
  109. package/templates/fullstack-app/src/components/Layout.tsx +42 -0
  110. package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
  111. package/templates/fullstack-app/src/components/UserList.tsx +44 -0
  112. package/templates/fullstack-app/src/config.ts +42 -0
  113. package/templates/fullstack-app/src/data/api.ts +206 -0
  114. package/templates/fullstack-app/src/main.tsx +155 -0
  115. package/templates/fullstack-app/src/middleware.ts +28 -0
  116. package/templates/fullstack-app/src/pages/404.tsx +28 -0
  117. package/templates/fullstack-app/src/pages/[id].tsx +0 -0
  118. package/templates/fullstack-app/src/pages/_app.tsx +11 -0
  119. package/templates/fullstack-app/src/pages/_document.tsx +25 -0
  120. package/templates/fullstack-app/src/pages/_error.tsx +45 -0
  121. package/templates/fullstack-app/src/pages/about/index.tsx +67 -0
  122. package/templates/fullstack-app/src/pages/about.tsx +71 -0
  123. package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
  124. package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
  125. package/templates/fullstack-app/src/pages/index.tsx +110 -0
  126. package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
  127. package/templates/fullstack-app/src/pages/users.tsx +60 -0
  128. package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
  129. package/templates/fullstack-app/src/router.ts +255 -0
  130. package/templates/fullstack-app/src/styles.css +5 -0
  131. package/templates/fullstack-app/tailwind.config.js +11 -0
  132. package/templates/fullstack-app/tsconfig.json +18 -0
  133. package/templates/fullstack-app/vite.config.js +87 -0
  134. package/templates/go/build.bat +36 -0
  135. package/templates/go/build.sh +43 -0
  136. package/templates/go/example.go +205 -0
  137. package/templates/go-wasm-app/README.md +38 -0
  138. package/templates/go-wasm-app/babel.config.js +21 -0
  139. package/templates/go-wasm-app/build-client.js +49 -0
  140. package/templates/go-wasm-app/build-wasm.js +237 -0
  141. package/templates/go-wasm-app/build.config.js +62 -0
  142. package/templates/go-wasm-app/build.js +218 -0
  143. package/templates/go-wasm-app/package.json +32 -0
  144. package/templates/go-wasm-app/public/index.html +128 -0
  145. package/templates/go-wasm-app/public/styles.css +197 -0
  146. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  147. package/templates/go-wasm-app/public/wasm/wasm_exec.js +561 -0
  148. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +39 -0
  149. package/templates/go-wasm-app/server.js +70 -0
  150. package/templates/go-wasm-app/src/App.jsx +38 -0
  151. package/templates/go-wasm-app/src/app.js +173 -0
  152. package/templates/go-wasm-app/src/client.js +57 -0
  153. package/templates/go-wasm-app/src/components/Footer.jsx +13 -0
  154. package/templates/go-wasm-app/src/components/Header.jsx +19 -0
  155. package/templates/go-wasm-app/src/components/WasmDemo.jsx +120 -0
  156. package/templates/go-wasm-app/src/main.jsx +12 -0
  157. package/templates/go-wasm-app/src/wasm/example.go +75 -0
  158. package/templates/go-wasm-app/tsconfig.server.json +18 -0
  159. package/templates/go-wasm-app/vite.config.js +45 -0
  160. package/dist/forms/index.d.ts +0 -2
  161. package/dist/forms/index.d.ts.map +0 -1
  162. package/dist/forms/types.d.ts +0 -2
  163. package/dist/forms/types.d.ts.map +0 -1
  164. package/dist/frontend/components/WasmLoader.d.ts +0 -2
  165. package/dist/frontend/components/WasmLoader.d.ts.map +0 -1
  166. package/dist/frontend/hooks/useWasm.d.ts +0 -2
  167. package/dist/frontend/hooks/useWasm.d.ts.map +0 -1
  168. package/dist/frontend/index.d.ts +0 -2
  169. package/dist/frontend/index.d.ts.map +0 -1
  170. package/dist/router/index.d.ts +0 -2
  171. package/dist/router/index.d.ts.map +0 -1
  172. package/dist/router/types.d.ts +0 -2
  173. package/dist/router/types.d.ts.map +0 -1
  174. package/dist/store/index.d.ts +0 -2
  175. package/dist/store/index.d.ts.map +0 -1
  176. package/dist/store/types.d.ts +0 -2
  177. package/dist/store/types.d.ts.map +0 -1
  178. package/templates/basic-app/package-lock.json +0 -7173
  179. package/templates/fullstack-template/package-lock.json +0 -3558
  180. package/templates/ssr-template/package-lock.json +0 -5380
  181. package/templates/wasm/package-lock.json +0 -5347
  182. package/templates/wasm/public/example.wasm +0 -0
@@ -0,0 +1,28 @@
1
+ import { jsx } from 'frontend-hamroun';
2
+
3
+ export default function NotFound({ initialState }) {
4
+ return (
5
+ <div className="not-found-container max-w-4xl mx-auto p-6">
6
+ <div className="bg-gray-50 border border-gray-200 rounded-lg p-8 shadow-sm">
7
+ <h1 className="text-3xl font-bold text-gray-700 mb-4">Page Not Found</h1>
8
+
9
+ <p className="text-lg text-gray-600 mb-4">
10
+ The page you are looking for does not exist or has been moved.
11
+ </p>
12
+
13
+ <p className="text-gray-600 mb-6">
14
+ Path: <code className="bg-gray-100 px-2 py-1 rounded">{initialState?.route || 'unknown'}</code>
15
+ </p>
16
+
17
+ <div className="mt-6">
18
+ <a
19
+ href="/"
20
+ className="inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
21
+ >
22
+ Back to Home
23
+ </a>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import { jsx } from 'frontend-hamroun';
2
+ import Layout from '../components/Layout';
3
+
4
+ // This is the main App wrapper component similar to Next.js _app.js
5
+ export default function App({ Component, pageProps, initialState }) {
6
+ return (
7
+ <Layout>
8
+ <Component {...pageProps} initialState={initialState} />
9
+ </Layout>
10
+ );
11
+ }
@@ -0,0 +1,25 @@
1
+ import { jsx } from 'frontend-hamroun';
2
+
3
+ export default function Document({
4
+ title = 'Frontend Hamroun App',
5
+ headContent,
6
+ bodyContent,
7
+ scripts
8
+ }) {
9
+ return (
10
+ <html lang="en">
11
+ <head>
12
+ <meta charSet="UTF-8" />
13
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
14
+ <title>{title}</title>
15
+ <link rel="stylesheet" href="/styles.css" />
16
+ {headContent}
17
+ </head>
18
+ <body>
19
+ <div id="root">{bodyContent}</div>
20
+ <script src="/build/main.js" type="module"></script>
21
+ {scripts}
22
+ </body>
23
+ </html>
24
+ );
25
+ }
@@ -0,0 +1,45 @@
1
+ import { jsx, useState, useEffect } from 'frontend-hamroun';
2
+
3
+ export default function ErrorPage({ initialState }) {
4
+ const { error } = initialState || {};
5
+ const [showDetails, setShowDetails] = useState(false);
6
+ const isDev = process.env.NODE_ENV !== 'production';
7
+
8
+ return (
9
+ <div className="error-page-container max-w-4xl mx-auto p-6">
10
+ <div className="bg-red-50 border border-red-200 rounded-lg p-8 shadow-sm">
11
+ <h1 className="text-3xl font-bold text-red-700 mb-4">Something went wrong</h1>
12
+
13
+ <p className="text-lg text-red-600 mb-4">
14
+ {error?.message || "An unexpected error occurred"}
15
+ </p>
16
+
17
+ {isDev && error?.stack && (
18
+ <div className="mt-6">
19
+ <button
20
+ className="text-blue-600 underline mb-2"
21
+ onClick={() => setShowDetails(!showDetails)}
22
+ >
23
+ {showDetails ? "Hide" : "Show"} technical details
24
+ </button>
25
+
26
+ {showDetails && (
27
+ <pre className="bg-gray-100 p-4 rounded-md text-sm overflow-auto max-h-96 text-gray-800">
28
+ {error.stack}
29
+ </pre>
30
+ )}
31
+ </div>
32
+ )}
33
+
34
+ <div className="mt-6">
35
+ <a
36
+ href="/"
37
+ className="inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
38
+ >
39
+ Back to Home
40
+ </a>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ );
45
+ }
@@ -0,0 +1,67 @@
1
+ import { jsx } from 'frontend-hamroun';
2
+ import Layout from '../../components/Layout';
3
+
4
+ const AboutPage = ({ initialState }) => {
5
+ return (
6
+ <Layout title="About This App">
7
+ <div className="max-w-4xl mx-auto bg-white shadow-lg rounded-lg overflow-hidden">
8
+ <div className="p-8">
9
+ <p className="text-lg text-gray-700 mb-6">
10
+ This is a frontend application built with Frontend Hamroun framework and styled with Tailwind CSS.
11
+ </p>
12
+ <p className="text-gray-600 mb-8">
13
+ It features server-side rendering, client-side navigation, and websocket-based live reloading during development.
14
+ </p>
15
+
16
+ <div className="bg-gray-50 p-6 rounded-lg border border-gray-200 mb-8">
17
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">Key Features</h2>
18
+ <ul className="space-y-2 text-gray-700">
19
+ <li className="flex items-center">
20
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
21
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
22
+ </svg>
23
+ Server-side rendering
24
+ </li>
25
+ <li className="flex items-center">
26
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
27
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
28
+ </svg>
29
+ Client-side navigation
30
+ </li>
31
+ <li className="flex items-center">
32
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
33
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
34
+ </svg>
35
+ Component-based architecture
36
+ </li>
37
+ <li className="flex items-center">
38
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
39
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
40
+ </svg>
41
+ Integrated API backend
42
+ </li>
43
+ <li className="flex items-center">
44
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
45
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
46
+ </svg>
47
+ Live reload during development
48
+ </li>
49
+ <li className="flex items-center">
50
+ <svg className="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
51
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
52
+ </svg>
53
+ Tailwind CSS for styling
54
+ </li>
55
+ </ul>
56
+ </div>
57
+
58
+ <a href="/" className="inline-block px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors">
59
+ Back to Home
60
+ </a>
61
+ </div>
62
+ </div>
63
+ </Layout>
64
+ );
65
+ };
66
+
67
+ export default AboutPage;
@@ -0,0 +1,71 @@
1
+ import { jsx } from 'frontend-hamroun';
2
+ import Layout from '../components/Layout';
3
+
4
+ export default function AboutPage({ initialState }) {
5
+ return (
6
+ <Layout title="About - Frontend Hamroun">
7
+ <div className="max-w-4xl mx-auto">
8
+ <h1 className="text-3xl font-bold text-blue-600 mb-6">
9
+ About Frontend Hamroun
10
+ </h1>
11
+
12
+ <div className="bg-white shadow-lg rounded-lg p-8 mb-8">
13
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">What is Frontend Hamroun?</h2>
14
+ <p className="text-gray-600 mb-4">
15
+ Frontend Hamroun is a lightweight JavaScript framework for building modern web applications.
16
+ It provides a familiar component-based architecture with hooks, JSX support, and
17
+ server-side rendering capabilities.
18
+ </p>
19
+ <p className="text-gray-600 mb-4">
20
+ This framework is designed to be simple yet powerful, offering the essential features
21
+ needed for web application development without the complexity of larger frameworks.
22
+ </p>
23
+
24
+ <h3 className="text-lg font-medium text-gray-700 mt-6 mb-2">Key Features:</h3>
25
+ <ul className="list-disc pl-6 text-gray-600 space-y-2">
26
+ <li>Component-based architecture</li>
27
+ <li>JSX support</li>
28
+ <li>Hooks for state and effects</li>
29
+ <li>Server-side rendering</li>
30
+ <li>Minimal API surface</li>
31
+ <li>File-based routing</li>
32
+ <li>Built-in API routes</li>
33
+ </ul>
34
+ </div>
35
+
36
+ <div className="bg-white shadow-lg rounded-lg p-8">
37
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">Getting Started</h2>
38
+ <p className="text-gray-600 mb-4">
39
+ This application was created using the Frontend Hamroun fullstack template,
40
+ which provides a complete setup for building applications with server-side rendering,
41
+ API routes, and client-side navigation.
42
+ </p>
43
+
44
+ <div className="bg-gray-50 p-4 rounded-md mt-4">
45
+ <h3 className="text-md font-medium text-gray-700 mb-2">Quick Start:</h3>
46
+ <pre className="bg-gray-800 text-gray-100 p-4 rounded overflow-x-auto">
47
+ <code>{`# Create a new application
48
+ npx frontend-hamroun create my-app
49
+
50
+ # Change directory
51
+ cd my-app
52
+
53
+ # Start the development server
54
+ npm run dev`}</code>
55
+ </pre>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </Layout>
60
+ );
61
+ }
62
+
63
+ // Server-side data fetching
64
+ export async function getServerSideProps() {
65
+ return {
66
+ props: {
67
+ pageTitle: 'About Frontend Hamroun',
68
+ description: 'Learn more about the Frontend Hamroun framework'
69
+ }
70
+ };
71
+ }
@@ -0,0 +1,73 @@
1
+ // Dynamic API Route for individual user operations
2
+ import { Request, Response } from 'express';
3
+
4
+ // Sample data store
5
+ const users = [
6
+ { id: 1, name: 'User 1', email: 'user1@example.com' },
7
+ { id: 2, name: 'User 2', email: 'user2@example.com' },
8
+ { id: 3, name: 'User 3', email: 'user3@example.com' }
9
+ ];
10
+
11
+ // Utility to find user by ID
12
+ const findUser = (id: number) => users.find(user => user.id === id);
13
+
14
+ // GET handler for retrieving a specific user
15
+ export async function get(req: Request, res: Response) {
16
+ const userId = parseInt(req.params.id);
17
+
18
+ if (isNaN(userId)) {
19
+ return res.status(400).json({ error: 'Invalid user ID' });
20
+ }
21
+
22
+ const user = findUser(userId);
23
+
24
+ if (!user) {
25
+ return res.status(404).json({ error: 'User not found' });
26
+ }
27
+
28
+ res.json(user);
29
+ }
30
+
31
+ // PUT handler for updating a user
32
+ export async function put(req: Request, res: Response) {
33
+ const userId = parseInt(req.params.id);
34
+
35
+ if (isNaN(userId)) {
36
+ return res.status(400).json({ error: 'Invalid user ID' });
37
+ }
38
+
39
+ const userIndex = users.findIndex(user => user.id === userId);
40
+
41
+ if (userIndex === -1) {
42
+ return res.status(404).json({ error: 'User not found' });
43
+ }
44
+
45
+ // Update user, but preserve the ID
46
+ const updatedUser = { ...req.body, id: userId };
47
+ users[userIndex] = updatedUser;
48
+
49
+ res.json(updatedUser);
50
+ }
51
+
52
+ // DELETE handler for removing a user
53
+ export async function del(req: Request, res: Response) {
54
+ const userId = parseInt(req.params.id);
55
+
56
+ if (isNaN(userId)) {
57
+ return res.status(400).json({ error: 'Invalid user ID' });
58
+ }
59
+
60
+ const userIndex = users.findIndex(user => user.id === userId);
61
+
62
+ if (userIndex === -1) {
63
+ return res.status(404).json({ error: 'User not found' });
64
+ }
65
+
66
+ // Remove the user
67
+ users.splice(userIndex, 1);
68
+
69
+ res.status(204).end();
70
+ }
71
+
72
+ // Use delete handler for DELETE method since 'delete' is a reserved word
73
+ export const DELETE = del;
@@ -0,0 +1,43 @@
1
+ // Next.js-like API Route for Users
2
+ import { Request, Response } from 'express';
3
+
4
+ // Sample data store
5
+ const users = [
6
+ { id: 1, name: 'User 1', email: 'user1@example.com' },
7
+ { id: 2, name: 'User 2', email: 'user2@example.com' },
8
+ { id: 3, name: 'User 3', email: 'user3@example.com' }
9
+ ];
10
+
11
+ // GET handler for retrieving all users
12
+ export async function get(req: Request, res: Response) {
13
+ // Option to simulate delay for testing loading states
14
+ const delay = req.query.delay ? parseInt(req.query.delay as string) : 0;
15
+
16
+ if (delay) {
17
+ await new Promise(resolve => setTimeout(resolve, delay));
18
+ }
19
+
20
+ res.json(users);
21
+ }
22
+
23
+ // POST handler for creating a new user
24
+ export async function post(req: Request, res: Response) {
25
+ try {
26
+ const newUser = req.body;
27
+
28
+ // Validation
29
+ if (!newUser.name || !newUser.email) {
30
+ return res.status(400).json({ error: 'Name and email are required' });
31
+ }
32
+
33
+ // Generate new ID
34
+ const newId = Math.max(0, ...users.map(u => u.id)) + 1;
35
+ const createdUser = { ...newUser, id: newId };
36
+
37
+ users.push(createdUser);
38
+
39
+ res.status(201).json(createdUser);
40
+ } catch (error) {
41
+ res.status(500).json({ error: 'Failed to create user' });
42
+ }
43
+ }
@@ -0,0 +1,110 @@
1
+ import { jsx, useState, useEffect, batchUpdates } from 'frontend-hamroun';
2
+ import UserList from '../components/UserList';
3
+ import StateDemo from '../components/StateDemo';
4
+ import { ErrorBoundary } from '../components/ErrorBoundary';
5
+ import { UserApi } from '../data/api';
6
+
7
+ // Home Page Component with Server Side Props
8
+ export default function HomePage({ users, posts, initialState }) {
9
+ const [state, setState] = useState(initialState || {});
10
+ const [refreshTrigger, setRefreshTrigger] = useState(0);
11
+
12
+ // Fetch data when refresh is triggered
13
+ useEffect(() => {
14
+ if (refreshTrigger === 0) return; // Skip initial render
15
+
16
+ async function fetchData() {
17
+ try {
18
+ const [users, posts] = await Promise.all([
19
+ UserApi.getAll(),
20
+ UserApi.getPosts()
21
+ ]);
22
+
23
+ // Use batch updates for efficiency
24
+ batchUpdates(() => {
25
+ setState(prev => ({
26
+ ...prev,
27
+ data: {
28
+ ...prev.data,
29
+ users,
30
+ posts
31
+ },
32
+ lastUpdate: new Date().toISOString()
33
+ }));
34
+ });
35
+ } catch (error) {
36
+ console.error('Error fetching data:', error);
37
+ }
38
+ }
39
+
40
+ fetchData();
41
+ }, [refreshTrigger]);
42
+
43
+ const handleRefresh = () => {
44
+ setRefreshTrigger(t => t + 1);
45
+ };
46
+
47
+ return (
48
+ <div className="max-w-4xl mx-auto py-8">
49
+ <h1 className="text-3xl font-bold text-blue-600 mb-6">
50
+ Welcome to your Next-style Frontend Hamroun application!
51
+ </h1>
52
+
53
+ <div className="mb-8">
54
+ <button
55
+ className="mb-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
56
+ onClick={handleRefresh}
57
+ >
58
+ Refresh Data
59
+ </button>
60
+
61
+ <div className="bg-blue-50 p-4 rounded-lg border border-blue-100 mb-6">
62
+ <p className="text-blue-700">
63
+ Last updated: {state.lastUpdate || 'Never'}
64
+ </p>
65
+ </div>
66
+ </div>
67
+
68
+ <ErrorBoundary>
69
+ <div className="bg-white shadow-lg rounded-lg p-6 mb-8">
70
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">User List</h2>
71
+ <UserList users={users || state.data?.users || []} />
72
+ </div>
73
+ </ErrorBoundary>
74
+
75
+ <ErrorBoundary>
76
+ <StateDemo />
77
+ </ErrorBoundary>
78
+
79
+ <div className="bg-gray-50 rounded-lg p-6 border border-gray-200 mt-8">
80
+ <h3 className="text-lg font-medium text-gray-700 mb-3">Application State</h3>
81
+ <pre className="overflow-auto p-4 bg-gray-100 rounded-md text-sm text-gray-800">
82
+ {JSON.stringify({ users, posts, ...state }, null, 2)}
83
+ </pre>
84
+ </div>
85
+ </div>
86
+ );
87
+ }
88
+
89
+ // Server-side data fetching (Next.js style)
90
+ export async function getServerSideProps() {
91
+ try {
92
+ const users = await UserApi.getAll();
93
+ const posts = await UserApi.getPosts();
94
+
95
+ return {
96
+ props: {
97
+ users,
98
+ posts
99
+ }
100
+ };
101
+ } catch (error) {
102
+ console.error('Error fetching initial data:', error);
103
+ return {
104
+ props: {
105
+ users: [],
106
+ posts: []
107
+ }
108
+ };
109
+ }
110
+ }
@@ -0,0 +1,153 @@
1
+ import { jsx, useState, useEffect } from 'frontend-hamroun';
2
+ import { UserApi } from '../../data/api';
3
+
4
+ export default function UserDetail({ user, posts, initialState }) {
5
+ // State for client-side data fetching when needed
6
+ const [userData, setUserData] = useState(user);
7
+ const [userPosts, setUserPosts] = useState(posts || []);
8
+ const [loading, setLoading] = useState(false);
9
+ const [error, setError] = useState(null);
10
+
11
+ // Get user ID from route params
12
+ const { id } = initialState?.params || {};
13
+
14
+ // Fetch user data if not provided from server
15
+ useEffect(() => {
16
+ if (!userData && id) {
17
+ setLoading(true);
18
+
19
+ Promise.all([
20
+ UserApi.getById(id),
21
+ UserApi.getPosts(id)
22
+ ])
23
+ .then(([userData, postsData]) => {
24
+ setUserData(userData);
25
+ setUserPosts(postsData);
26
+ setLoading(false);
27
+ })
28
+ .catch(err => {
29
+ console.error('Error fetching user data:', err);
30
+ setError(err.message || 'Failed to load user data');
31
+ setLoading(false);
32
+ });
33
+ }
34
+ }, [userData, id]);
35
+
36
+ if (loading) {
37
+ return (
38
+ <div className="max-w-4xl mx-auto p-4">
39
+ <div className="animate-pulse rounded-md bg-gray-100 p-8">
40
+ <div className="h-8 bg-gray-200 rounded w-1/4 mb-4"></div>
41
+ <div className="h-4 bg-gray-200 rounded w-1/2 mb-2"></div>
42
+ <div className="h-4 bg-gray-200 rounded w-3/4 mb-4"></div>
43
+ <div className="h-40 bg-gray-200 rounded mb-4"></div>
44
+ </div>
45
+ </div>
46
+ );
47
+ }
48
+
49
+ if (error) {
50
+ return (
51
+ <div className="max-w-4xl mx-auto p-4">
52
+ <div className="rounded-md bg-red-50 p-4 border border-red-200">
53
+ <h2 className="text-lg font-bold text-red-700">Error Loading User</h2>
54
+ <p className="text-red-600">{error}</p>
55
+ </div>
56
+ </div>
57
+ );
58
+ }
59
+
60
+ if (!userData) {
61
+ return (
62
+ <div className="max-w-4xl mx-auto p-4">
63
+ <div className="rounded-md bg-yellow-50 p-4 border border-yellow-200">
64
+ <h2 className="text-lg font-bold text-yellow-700">User Not Found</h2>
65
+ <p className="text-yellow-600">Could not find user with ID: {id}</p>
66
+ <a href="/users" className="text-blue-600 hover:underline mt-2 block">
67
+ Back to Users List
68
+ </a>
69
+ </div>
70
+ </div>
71
+ );
72
+ }
73
+
74
+ return (
75
+ <div className="max-w-4xl mx-auto p-4">
76
+ <div className="bg-white shadow-lg rounded-lg p-6 mb-6">
77
+ <h1 className="text-2xl font-bold text-gray-800 mb-4">{userData.name}</h1>
78
+ <div className="user-info mb-6">
79
+ <p className="text-gray-600">
80
+ <span className="font-bold">ID:</span> {userData.id}
81
+ </p>
82
+ <p className="text-gray-600">
83
+ <span className="font-bold">Email:</span> {userData.email}
84
+ </p>
85
+ </div>
86
+
87
+ <a href="/users" className="text-blue-600 hover:underline">
88
+ Back to Users List
89
+ </a>
90
+ </div>
91
+
92
+ {userPosts && userPosts.length > 0 ? (
93
+ <div className="bg-white shadow-lg rounded-lg p-6">
94
+ <h2 className="text-xl font-bold text-gray-800 mb-4">Posts by {userData.name}</h2>
95
+ <div className="space-y-4">
96
+ {userPosts.map(post => (
97
+ <div key={post.id} className="border-b pb-4">
98
+ <h3 className="text-lg font-semibold">{post.title}</h3>
99
+ <p className="text-gray-600">{post.content}</p>
100
+ </div>
101
+ ))}
102
+ </div>
103
+ </div>
104
+ ) : (
105
+ <div className="bg-white shadow-lg rounded-lg p-6">
106
+ <h2 className="text-xl font-bold text-gray-800 mb-4">Posts by {userData.name}</h2>
107
+ <p className="text-gray-500 italic">No posts found for this user.</p>
108
+ </div>
109
+ )}
110
+ </div>
111
+ );
112
+ }
113
+
114
+ // Next.js style server-side data fetching
115
+ export async function getServerSideProps({ params }) {
116
+ try {
117
+ const userId = params.id;
118
+
119
+ // Parallel data fetching
120
+ const [user, posts] = await Promise.all([
121
+ UserApi.getById(parseInt(userId)),
122
+ UserApi.getPosts(parseInt(userId))
123
+ ]);
124
+
125
+ // Handle user not found
126
+ if (!user) {
127
+ return {
128
+ notFound: true
129
+ };
130
+ }
131
+
132
+ return {
133
+ props: {
134
+ user,
135
+ posts
136
+ }
137
+ };
138
+ } catch (error) {
139
+ console.error(`Error fetching user ${params.id}:`, error);
140
+
141
+ // Pass the error for client-side handling
142
+ return {
143
+ props: {
144
+ error: {
145
+ message: error.message,
146
+ status: error.status || 500
147
+ },
148
+ user: null,
149
+ posts: []
150
+ }
151
+ };
152
+ }
153
+ }