@seip/blue-bird 0.3.8 → 0.4.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.
- package/backend/routes/frontend.js +3 -20
- package/core/cli/react.js +187 -135
- package/core/cli/scaffolding-auth.js +27 -11
- package/core/template.js +195 -4
- package/frontend/index.html +4 -7
- package/frontend/resources/css/tailwind.css +2 -0
- package/frontend/resources/js/App.jsx +16 -9
- package/frontend/resources/js/Main.jsx +12 -11
- package/frontend/resources/js/blue-bird/components/Card.jsx +3 -2
- package/frontend/resources/js/blue-bird/components/Skeleton.jsx +45 -0
- package/frontend/resources/js/blue-bird/contexts/LanguageContext.jsx +12 -1
- package/frontend/resources/js/blue-bird/locales/en.json +18 -0
- package/frontend/resources/js/blue-bird/locales/es.json +18 -0
- package/frontend/resources/js/components/Header.jsx +53 -0
- package/frontend/resources/js/pages/About.jsx +21 -23
- package/frontend/resources/js/pages/Home.jsx +47 -58
- package/package.json +3 -1
- package/vite.config.js +3 -2
|
@@ -3,37 +3,20 @@ import Template from "@seip/blue-bird/core/template.js"
|
|
|
3
3
|
|
|
4
4
|
const routerFrontendExample = new Router();
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
routerFrontendExample.seo([
|
|
7
7
|
{
|
|
8
8
|
path: "/",
|
|
9
9
|
component: "Home",
|
|
10
10
|
meta: { titleMeta: "Home - Blue Bird", descriptionMeta: "Welcome to Blue Bird" },
|
|
11
11
|
props: { id: 1, name: "Name" }
|
|
12
|
-
|
|
13
12
|
},
|
|
14
13
|
{
|
|
15
14
|
path: "/about",
|
|
16
15
|
component: "About",
|
|
17
|
-
meta: { titleMeta: "
|
|
16
|
+
meta: { titleMeta: "Aboutt - Blue Bird", descriptionMeta: "About blue bird", keywordsMeta: "Blue Bird, About Blue Bird" },
|
|
18
17
|
props: { id: 2, name: "Name 2" }
|
|
19
18
|
},
|
|
20
|
-
|
|
21
|
-
];
|
|
22
|
-
routesFrontend.forEach(route_ => {
|
|
23
|
-
routerFrontendExample.get(route_.path, (req, res) => {
|
|
24
|
-
const dynamicProps = {
|
|
25
|
-
props: {
|
|
26
|
-
params: req.params,
|
|
27
|
-
query: req.query,
|
|
28
|
-
...route_.props ?? {}
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
return Template.renderReact(res, route_.component, dynamicProps, {
|
|
33
|
-
metaTags: route_.meta,
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
|
19
|
+
])
|
|
37
20
|
|
|
38
21
|
|
|
39
22
|
routerFrontendExample.get("*", (req, res) => {
|
package/core/cli/react.js
CHANGED
|
@@ -30,6 +30,7 @@ class ReactScaffold {
|
|
|
30
30
|
this.createViteConfig();
|
|
31
31
|
this.createAppjs();
|
|
32
32
|
this.createMainJs();
|
|
33
|
+
this.createHeaderJs();
|
|
33
34
|
this.createPagesJs();
|
|
34
35
|
this.updateGitIgnore();
|
|
35
36
|
this.npmInstall();
|
|
@@ -49,7 +50,8 @@ class ReactScaffold {
|
|
|
49
50
|
*/
|
|
50
51
|
createStructure() {
|
|
51
52
|
const dirs = [
|
|
52
|
-
'frontend/resources/js/pages'
|
|
53
|
+
'frontend/resources/js/pages',
|
|
54
|
+
'frontend/resources/js/components'
|
|
53
55
|
];
|
|
54
56
|
|
|
55
57
|
dirs.forEach(dir => {
|
|
@@ -86,6 +88,8 @@ class ReactScaffold {
|
|
|
86
88
|
pkg.dependencies["react"] = "^19.2.4";
|
|
87
89
|
pkg.dependencies["react-dom"] = "^19.2.4";
|
|
88
90
|
pkg.dependencies["react-router-dom"] = "^7.2.0";
|
|
91
|
+
pkg.dependencies["@tailwindcss/vite"] = "^4.2.2";
|
|
92
|
+
pkg.dependencies["tailwindcss"] = "^4.2.2";
|
|
89
93
|
|
|
90
94
|
|
|
91
95
|
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2));
|
|
@@ -108,9 +112,10 @@ class ReactScaffold {
|
|
|
108
112
|
const content = `import { defineConfig } from 'vite';
|
|
109
113
|
import react from '@vitejs/plugin-react';
|
|
110
114
|
import path from 'path';
|
|
115
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
111
116
|
|
|
112
117
|
export default defineConfig({
|
|
113
|
-
plugins: [react()],
|
|
118
|
+
plugins: [react(), tailwindcss()],
|
|
114
119
|
root: path.resolve(__dirname, 'frontend/resources/js'),
|
|
115
120
|
base: '/build/',
|
|
116
121
|
build: {
|
|
@@ -138,99 +143,89 @@ export default defineConfig({
|
|
|
138
143
|
return;
|
|
139
144
|
}
|
|
140
145
|
|
|
141
|
-
const content = `import React, { useEffect } from 'react';
|
|
142
|
-
import
|
|
143
|
-
import
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
<a
|
|
200
|
-
href="https://seip25.github.io/Blue-bird/"
|
|
201
|
-
target="_blank"
|
|
202
|
-
rel="noopener noreferrer"
|
|
203
|
-
className='bg-blue-50 text-blue-500 px-4 py-2 rounded-lg font-semibold transition-colors hover:bg-blue-100 '
|
|
204
|
-
>
|
|
205
|
-
Documentación (Esp)
|
|
206
|
-
|
|
207
|
-
</a>
|
|
208
|
-
</div>
|
|
209
|
-
</Card>
|
|
210
|
-
|
|
211
|
-
<Card className='mt-8 border-none shadow-none'>
|
|
212
|
-
<div className='mt-8 grid grid-cols-1 md:grid-cols-3 gap-4 max-w-1000px mx-auto'>
|
|
213
|
-
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
214
|
-
<h3 className='text-blue-500 font-semibold text-xl mb-4'>Lightweight</h3>
|
|
215
|
-
<p>Built with performance and simplicity in mind.</p>
|
|
216
|
-
</div>
|
|
217
|
-
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
218
|
-
<h3 className='text-blue-500 font-semibold text-xl mb-4'>React Powered</h3>
|
|
219
|
-
<p>Full React + Vite integration .</p>
|
|
146
|
+
const content = ` import React, { useEffect } from 'react';
|
|
147
|
+
import Card from '../blue-bird/components/Card';
|
|
148
|
+
import Header from '../components/Header';
|
|
149
|
+
import { useLanguage } from '../blue-bird/contexts/LanguageContext';
|
|
150
|
+
import Typography from '../blue-bird/components/Typography';
|
|
151
|
+
|
|
152
|
+
export default function Home() {
|
|
153
|
+
const { t } = useLanguage();
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
// Example API call to the backend
|
|
156
|
+
fetch("http://localhost:3000/login", {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: {
|
|
159
|
+
"Content-Type": "application/json",
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify({
|
|
162
|
+
email: "example@example.com",
|
|
163
|
+
password: "myPassword123"
|
|
164
|
+
}),
|
|
165
|
+
})
|
|
166
|
+
.then((response) => response.json())
|
|
167
|
+
.then((data) => console.log('Backend response:', data))
|
|
168
|
+
.catch((error) => console.error('Error fetching from backend:', error));
|
|
169
|
+
}, []);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div
|
|
173
|
+
className="bg-white dark:bg-slate-900 text-gray-900 dark:text-gray-100 min-h-screen"
|
|
174
|
+
>
|
|
175
|
+
<Header />
|
|
176
|
+
<main className='max-w-7xl mx-auto'>
|
|
177
|
+
<div className='text-center p-4'>
|
|
178
|
+
<header className='mb-8 mt-8'>
|
|
179
|
+
<Typography variant='h1' className='text-4xl font-extrabold tracking-tight lg:text-5xl text-slate-900 dark:text-slate-100 mb-4'>
|
|
180
|
+
{t("home_page.title")}
|
|
181
|
+
</Typography>
|
|
182
|
+
<Typography className='text-xl text-slate-500 dark:text-slate-400 max-w-[600px] mx-auto'>
|
|
183
|
+
{t("home_page.description")}
|
|
184
|
+
</Typography>
|
|
185
|
+
</header>
|
|
186
|
+
|
|
187
|
+
<div className='flex gap-4 justify-center mb-12'>
|
|
188
|
+
<a
|
|
189
|
+
href="https://seip25.github.io/Blue-bird/en.html"
|
|
190
|
+
target="_blank"
|
|
191
|
+
rel="noopener noreferrer"
|
|
192
|
+
className='inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-slate-900 dark:bg-slate-100 text-slate-50 dark:text-slate-900 hover:bg-slate-900/90 dark:hover:bg-slate-100/90 h-10 px-4 py-2'
|
|
193
|
+
>
|
|
194
|
+
Documentation (Eng)
|
|
195
|
+
</a>
|
|
196
|
+
<a
|
|
197
|
+
href="https://seip25.github.io/Blue-bird/"
|
|
198
|
+
target="_blank"
|
|
199
|
+
rel="noopener noreferrer"
|
|
200
|
+
className='inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800 h-10 px-4 py-2'
|
|
201
|
+
>
|
|
202
|
+
Documentación (Esp)
|
|
203
|
+
</a>
|
|
220
204
|
</div>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
<
|
|
205
|
+
|
|
206
|
+
<div className='mt-8 grid grid-cols-1 md:grid-cols-3 gap-6 max-w-[1000px] mx-auto text-left'>
|
|
207
|
+
<Card title={t("home_page.lightweight")}>
|
|
208
|
+
<Typography className="text-sm text-slate-500 dark:text-slate-400">
|
|
209
|
+
{t("home_page.lightweightDescription")}
|
|
210
|
+
</Typography>
|
|
211
|
+
</Card>
|
|
212
|
+
<Card title={t("home_page.reactPowered")}>
|
|
213
|
+
<Typography className="text-sm text-slate-500 dark:text-slate-400">
|
|
214
|
+
{t("home_page.reactPoweredDescription")}
|
|
215
|
+
</Typography>
|
|
216
|
+
</Card>
|
|
217
|
+
<Card title={t("home_page.expressBackend")}>
|
|
218
|
+
<Typography className="text-sm text-slate-500 dark:text-slate-400">
|
|
219
|
+
{t("home_page.expressBackendDescription")}
|
|
220
|
+
</Typography>
|
|
221
|
+
</Card>
|
|
224
222
|
</div>
|
|
225
223
|
</div>
|
|
226
|
-
</
|
|
227
|
-
|
|
224
|
+
</main>
|
|
228
225
|
</div>
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
234
229
|
|
|
235
230
|
`;
|
|
236
231
|
fs.writeFileSync(file, content);
|
|
@@ -243,39 +238,37 @@ export default function Home() {
|
|
|
243
238
|
}
|
|
244
239
|
|
|
245
240
|
const content2 = `import React from 'react';
|
|
246
|
-
import
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
</
|
|
241
|
+
import Header from '../components/Header';
|
|
242
|
+
import { useLanguage } from '../blue-bird/contexts/LanguageContext';
|
|
243
|
+
|
|
244
|
+
import Card from '../blue-bird/components/Card';
|
|
245
|
+
import Typography from '../blue-bird/components/Typography'
|
|
246
|
+
|
|
247
|
+
export default function About() {
|
|
248
|
+
const { t } = useLanguage();
|
|
249
|
+
return (
|
|
250
|
+
<div
|
|
251
|
+
className="bg-white dark:bg-slate-900 text-gray-900 dark:text-gray-100 min-h-screen"
|
|
252
|
+
>
|
|
253
|
+
<Header />
|
|
254
|
+
<main className='max-w-3xl mx-auto mt-8 p-4'>
|
|
255
|
+
<Card>
|
|
256
|
+
<Typography variant='h1' className='text-3xl font-bold tracking-tight text-slate-900 dark:text-slate-100 mb-4'>
|
|
257
|
+
{t("about_page.title")}
|
|
258
|
+
</Typography>
|
|
259
|
+
<Typography className='text-slate-500 dark:text-slate-400 leading-7'>
|
|
260
|
+
{t("about_page.description")}
|
|
261
|
+
</Typography>
|
|
262
|
+
<div className='mt-8 pt-4 border-t border-slate-200 dark:border-slate-800'>
|
|
263
|
+
<Typography className='text-sm text-red-500 font-medium'>
|
|
264
|
+
{t("about_page.check_your_console")}
|
|
265
|
+
</Typography>
|
|
266
|
+
</div>
|
|
267
|
+
</Card>
|
|
268
|
+
</main>
|
|
274
269
|
</div>
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
);
|
|
278
|
-
}`;
|
|
270
|
+
);
|
|
271
|
+
}`;
|
|
279
272
|
fs.writeFileSync(file2, content2);
|
|
280
273
|
console.log(chalk.gray("Created frontend/resources/js/pages/About.jsx"));
|
|
281
274
|
}
|
|
@@ -290,10 +283,14 @@ export default function About() {
|
|
|
290
283
|
return;
|
|
291
284
|
}
|
|
292
285
|
|
|
293
|
-
const content = `import React from 'react';
|
|
286
|
+
const content = `import React, { lazy, Suspense } from 'react';
|
|
294
287
|
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
|
295
|
-
import
|
|
296
|
-
import
|
|
288
|
+
import { ThemeProvider } from './blue-bird/contexts/ThemeContext.jsx';
|
|
289
|
+
import Skeleton from './blue-bird/components/Skeleton.jsx';
|
|
290
|
+
import { LanguageProvider } from './blue-bird/contexts/LanguageContext.jsx';
|
|
291
|
+
|
|
292
|
+
const Home = lazy(() => import('./pages/Home'));
|
|
293
|
+
const About = lazy(() => import('./pages/About'));
|
|
297
294
|
|
|
298
295
|
export default function App(_props) {
|
|
299
296
|
const {
|
|
@@ -306,16 +303,20 @@ export default function App(_props) {
|
|
|
306
303
|
console.log(props)
|
|
307
304
|
|
|
308
305
|
return (
|
|
309
|
-
<
|
|
310
|
-
<
|
|
311
|
-
<
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
306
|
+
<ThemeProvider>
|
|
307
|
+
<LanguageProvider>
|
|
308
|
+
<Router>
|
|
309
|
+
<Suspense fallback={<Skeleton />}>
|
|
310
|
+
<Routes>
|
|
311
|
+
<Route path="/" element={<Home />} />
|
|
312
|
+
<Route path="/about" element={<About />} />
|
|
313
|
+
</Routes>
|
|
314
|
+
</Suspense>
|
|
315
|
+
</Router>
|
|
316
|
+
</LanguageProvider>
|
|
317
|
+
</ThemeProvider>
|
|
315
318
|
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
`;
|
|
319
|
+
}`;
|
|
319
320
|
fs.writeFileSync(file, content);
|
|
320
321
|
console.log(chalk.gray("Created frontend/resources/js/App.jsx"));
|
|
321
322
|
}
|
|
@@ -348,6 +349,57 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
348
349
|
console.log(chalk.gray("Created frontend/resources/js/Main.jsx"));
|
|
349
350
|
}
|
|
350
351
|
|
|
352
|
+
createHeaderJs() {
|
|
353
|
+
const file = path.join(this.appDir, 'frontend/resources/js/components/Header.jsx');
|
|
354
|
+
if (fs.existsSync(file)) {
|
|
355
|
+
console.warn(chalk.yellow("Header.jsx already exists. Skipping."));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const content = `import { Link } from "react-router-dom";
|
|
360
|
+
import { useState } from "react";
|
|
361
|
+
import Button from "../blue-bird/components/Button";
|
|
362
|
+
import { useLanguage } from "../blue-bird/contexts/LanguageContext";
|
|
363
|
+
import { useTheme } from "../blue-bird/contexts/ThemeContext";
|
|
364
|
+
|
|
365
|
+
export default function Header() {
|
|
366
|
+
const { t, setLang } = useLanguage();
|
|
367
|
+
const { changeTheme } = useTheme();
|
|
368
|
+
const [emojiTheme, setEmojiTheme] = useState("🌞");
|
|
369
|
+
|
|
370
|
+
const changeThemeEmoji = () => {
|
|
371
|
+
if (emojiTheme === "🌞") {
|
|
372
|
+
setEmojiTheme("🌙");
|
|
373
|
+
changeTheme("dark");
|
|
374
|
+
} else {
|
|
375
|
+
setEmojiTheme("🌞");
|
|
376
|
+
changeTheme("light");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return (
|
|
381
|
+
<header>
|
|
382
|
+
<nav className='bg-white dark:bg-slate-900 text-gray-900 dark:text-gray-100 border-b border-gray-200 dark:border-slate-800 px-4 py-4 flex justify-between items-center gap-4 sticky top-0 z-10'>
|
|
383
|
+
<div className='font-bold text-xl text-slate-900 dark:text-slate-100'>Blue Bird</div>
|
|
384
|
+
<div className='flex justify-between items-center gap-4'>
|
|
385
|
+
<div className="flex justify-between items-center gap-4">
|
|
386
|
+
<Button variant="outline" size="sm" onClick={() => setLang("es")}>ES</Button>
|
|
387
|
+
<Button variant="outline" size="sm" onClick={() => setLang("en")}>EN</Button>
|
|
388
|
+
<Button variant="ghost" size="icon" onClick={changeThemeEmoji}>{emojiTheme}</Button>
|
|
389
|
+
</div>
|
|
390
|
+
<div className="flex justify-between items-center gap-4">
|
|
391
|
+
<Link to="/" className='text-sm font-medium text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 transition-colors'>{t("home")}</Link>
|
|
392
|
+
<Link to="/about" className='text-sm font-medium text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 transition-colors'>{t("about")}</Link>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
</nav>
|
|
396
|
+
</header>
|
|
397
|
+
);
|
|
398
|
+
}`;
|
|
399
|
+
fs.writeFileSync(file, content);
|
|
400
|
+
console.log(chalk.gray("Created frontend/resources/js/components/Header.jsx"));
|
|
401
|
+
}
|
|
402
|
+
|
|
351
403
|
|
|
352
404
|
|
|
353
405
|
/**
|
|
@@ -523,7 +523,7 @@ routerAuth.post("/register", new Validator({ password_confirmation: { required:
|
|
|
523
523
|
const deletedAccount = await AuthService.findUserByEmail(email, 0);
|
|
524
524
|
if (deletedAccount) return res.status(400).json({ message: "Error, your account is deleted", deleted_account_error: true });
|
|
525
525
|
const user = await AuthService.createUser(name, email, password);
|
|
526
|
-
const secure =
|
|
526
|
+
const secure = props.debug == false ? true : false;
|
|
527
527
|
const token = Auth.generateToken({ id: user.id_public, email: user.email });
|
|
528
528
|
res.cookie("token", token, { httpOnly: true, secure: secure, sameSite: "strict", maxAge: 24 * 60 * 60 * 1000 });
|
|
529
529
|
return res.json({ message: "Registered", user: { id: user.id_public, email: user.email } });
|
|
@@ -715,9 +715,12 @@ export default function Register() {
|
|
|
715
715
|
const [password, setPassword] = useState('');
|
|
716
716
|
const [password_confirmation, setPasswordConfirmation] = useState('');
|
|
717
717
|
const [error, setError] = useState(null);
|
|
718
|
+
const [message, setMessage] = useState(null);
|
|
718
719
|
|
|
719
720
|
const handleSubmit = async (e) => {
|
|
720
721
|
e.preventDefault();
|
|
722
|
+
setError(null);
|
|
723
|
+
setMessage(null);
|
|
721
724
|
const lang = localStorage.getItem("blue_bird_lang") ?? "en";
|
|
722
725
|
try {
|
|
723
726
|
const res = await fetch('/auth/register', {
|
|
@@ -732,7 +735,16 @@ export default function Register() {
|
|
|
732
735
|
if (data.error_email_register) throw new Error(t('error_email_register'));
|
|
733
736
|
throw new Error(data.message || t('error_general'));
|
|
734
737
|
}
|
|
735
|
-
|
|
738
|
+
else{
|
|
739
|
+
setMessage(t('register_success') || 'Register success');
|
|
740
|
+
setEmail('');
|
|
741
|
+
setName('');
|
|
742
|
+
setPassword('');
|
|
743
|
+
setPasswordConfirmation('');
|
|
744
|
+
setTimeout(() => {
|
|
745
|
+
window.location.href = '/login';
|
|
746
|
+
}, 4000);
|
|
747
|
+
}
|
|
736
748
|
} catch (err) {
|
|
737
749
|
setError(err.message);
|
|
738
750
|
}
|
|
@@ -744,6 +756,7 @@ export default function Register() {
|
|
|
744
756
|
<div className="mb-6 text-center">
|
|
745
757
|
<Typography variant="h3">{t('register')}</Typography>
|
|
746
758
|
</div>
|
|
759
|
+
{message && <div className="bg-green-100 text-green-700 p-3 mb-4 rounded-md text-sm">{message}</div>}
|
|
747
760
|
{error && <div className="bg-red-100 text-red-700 p-3 mb-4 rounded-md text-sm">{error}</div>}
|
|
748
761
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
749
762
|
<Input label={t('name')} type="text" value={name} onChange={(e) => setName(e.target.value)} required />
|
|
@@ -856,8 +869,6 @@ export default function ResetPassword() {
|
|
|
856
869
|
body: JSON.stringify({ token })
|
|
857
870
|
});
|
|
858
871
|
if (!res.ok) return window.location.href = '/login';
|
|
859
|
-
const data = await res.json();
|
|
860
|
-
setUser(data.user);
|
|
861
872
|
};
|
|
862
873
|
fetchUser();
|
|
863
874
|
}
|
|
@@ -974,12 +985,17 @@ export default function ResetPassword() {
|
|
|
974
985
|
let backendIndex = fs.readFileSync(backendIndexFile, "utf-8");
|
|
975
986
|
if (!backendIndex.includes("routerAuth")) {
|
|
976
987
|
backendIndex = backendIndex.replace(
|
|
977
|
-
|
|
988
|
+
/import\s+routerFrontendExample\s+from\s+["']\.\/routes\/frontend\.js["'];?/,
|
|
978
989
|
'import routerFrontendExample from "./routes/frontend.js";\nimport routerAuth from "./routes/auth.js";\nimport routerAuthenticated from "./routes/authenticated.js";'
|
|
979
990
|
);
|
|
980
991
|
backendIndex = backendIndex.replace(
|
|
981
|
-
|
|
982
|
-
|
|
992
|
+
/routes:\s*\[([^\]]+)\]/,
|
|
993
|
+
(match, p1) => {
|
|
994
|
+
if (p1.includes('routerFrontendExample') && !p1.includes('routerAuth')) {
|
|
995
|
+
return `routes: [${p1.replace('routerFrontendExample', 'routerAuth, routerAuthenticated, routerFrontendExample')}]`;
|
|
996
|
+
}
|
|
997
|
+
return match;
|
|
998
|
+
}
|
|
983
999
|
);
|
|
984
1000
|
fs.writeFileSync(backendIndexFile, backendIndex, "utf-8");
|
|
985
1001
|
console.log(chalk.green("✓ backend/index.js updated to include new routes."));
|
|
@@ -991,19 +1007,19 @@ export default function ResetPassword() {
|
|
|
991
1007
|
let appJsx = fs.readFileSync(appJsxFile, "utf-8");
|
|
992
1008
|
if (!appJsx.includes("LanguageProvider")) {
|
|
993
1009
|
appJsx = appJsx.replace(
|
|
994
|
-
|
|
1010
|
+
/import\s+Home\s+from\s+["']\.\/pages\/Home["'];?/,
|
|
995
1011
|
"import { LanguageProvider } from './blue-bird/contexts/LanguageContext.jsx';\nimport Login from './pages/auth/Login.jsx';\nimport Register from './pages/auth/Register.jsx';\nimport ForgotPassword from './pages/auth/ForgotPassword.jsx';\nimport ResetPassword from './pages/auth/ResetPassword.jsx';\nimport Dashboard from './pages/authenticated/Dashboard.jsx';\nimport Home from './pages/Home';"
|
|
996
1012
|
);
|
|
997
1013
|
appJsx = appJsx.replace(
|
|
998
|
-
|
|
1014
|
+
/<Router>/,
|
|
999
1015
|
"<LanguageProvider>\n <Router>"
|
|
1000
1016
|
);
|
|
1001
1017
|
appJsx = appJsx.replace(
|
|
1002
|
-
|
|
1018
|
+
/<\/Router>/,
|
|
1003
1019
|
"</Router>\n </LanguageProvider>"
|
|
1004
1020
|
);
|
|
1005
1021
|
appJsx = appJsx.replace(
|
|
1006
|
-
|
|
1022
|
+
/<Route\s+path=["']\/about["']\s+element=\{<About\s*\/?>\}\s*\/?>/,
|
|
1007
1023
|
'<Route path="/about" element={<About />} />\n <Route path="/login" element={<Login />} />\n <Route path="/register" element={<Register />} />\n <Route path="/forgot-password" element={<ForgotPassword />} />\n <Route path="/reset-password" element={<ResetPassword />} />\n <Route path="/dashboard" element={<Dashboard />} />'
|
|
1008
1024
|
);
|
|
1009
1025
|
fs.writeFileSync(appJsxFile, appJsx, "utf-8");
|