create-bdpamke-react-scaffold 1.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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/bin/create-bdpamke-react-scaffold.js +101 -0
  4. package/package.json +39 -0
  5. package/template/.env.example +6 -0
  6. package/template/FUNCTIONS_EXAMPLES.md +480 -0
  7. package/template/HOWTOadd a page.md +166 -0
  8. package/template/REACT_PROPS_USEEFFECT.md +210 -0
  9. package/template/REGISTRATION_FLOW.md +268 -0
  10. package/template/USESTATE_EXAMPLES.md +451 -0
  11. package/template/components.json +20 -0
  12. package/template/index.html +13 -0
  13. package/template/jsconfig.json +19 -0
  14. package/template/package-lock.json +5988 -0
  15. package/template/package.json +73 -0
  16. package/template/postcss.config.cjs +6 -0
  17. package/template/public/images/BDPA_edited.png +0 -0
  18. package/template/server/server.js +86 -0
  19. package/template/server/utils/apiClient.js +59 -0
  20. package/template/server/utils/password.js +60 -0
  21. package/template/src/App.jsx +10 -0
  22. package/template/src/components/layout/Container.jsx +7 -0
  23. package/template/src/components/layout/Section.jsx +7 -0
  24. package/template/src/components/ui/accordion.jsx +41 -0
  25. package/template/src/components/ui/alert-dialog.jsx +99 -0
  26. package/template/src/components/ui/alert.jsx +47 -0
  27. package/template/src/components/ui/aspect-ratio.jsx +5 -0
  28. package/template/src/components/ui/avatar.jsx +35 -0
  29. package/template/src/components/ui/badge.jsx +34 -0
  30. package/template/src/components/ui/button.jsx +47 -0
  31. package/template/src/components/ui/calendar.jsx +173 -0
  32. package/template/src/components/ui/card.jsx +50 -0
  33. package/template/src/components/ui/carousel.jsx +194 -0
  34. package/template/src/components/ui/checkbox.jsx +22 -0
  35. package/template/src/components/ui/collapsible.jsx +11 -0
  36. package/template/src/components/ui/command.jsx +116 -0
  37. package/template/src/components/ui/dialog.jsx +94 -0
  38. package/template/src/components/ui/drawer.jsx +92 -0
  39. package/template/src/components/ui/dropdown-menu.jsx +155 -0
  40. package/template/src/components/ui/form.jsx +138 -0
  41. package/template/src/components/ui/hover-card.jsx +25 -0
  42. package/template/src/components/ui/icons.jsx +81 -0
  43. package/template/src/components/ui/input.jsx +19 -0
  44. package/template/src/components/ui/label.jsx +16 -0
  45. package/template/src/components/ui/menubar.jsx +200 -0
  46. package/template/src/components/ui/navigation-menu.jsx +104 -0
  47. package/template/src/components/ui/popover.jsx +25 -0
  48. package/template/src/components/ui/progress.jsx +20 -0
  49. package/template/src/components/ui/radio-group.jsx +29 -0
  50. package/template/src/components/ui/scroll-area.jsx +40 -0
  51. package/template/src/components/ui/select.jsx +120 -0
  52. package/template/src/components/ui/separator.jsx +25 -0
  53. package/template/src/components/ui/sheet.jsx +108 -0
  54. package/template/src/components/ui/skeleton.jsx +10 -0
  55. package/template/src/components/ui/slider.jsx +23 -0
  56. package/template/src/components/ui/sonner.jsx +42 -0
  57. package/template/src/components/ui/switch.jsx +24 -0
  58. package/template/src/components/ui/table.jsx +83 -0
  59. package/template/src/components/ui/tabs.jsx +41 -0
  60. package/template/src/components/ui/textarea.jsx +18 -0
  61. package/template/src/components/ui/toast.jsx +82 -0
  62. package/template/src/components/ui/toaster.jsx +33 -0
  63. package/template/src/components/ui/toggle.jsx +40 -0
  64. package/template/src/components/ui/tooltip.jsx +24 -0
  65. package/template/src/hooks/use-toast.js +155 -0
  66. package/template/src/index.css +61 -0
  67. package/template/src/index.js +6 -0
  68. package/template/src/lib/utils.js +11 -0
  69. package/template/src/main.jsx +15 -0
  70. package/template/src/pages/Home.jsx +26 -0
  71. package/template/tailwind.config.cjs +76 -0
  72. package/template/vite.config.mts +22 -0
@@ -0,0 +1,166 @@
1
+ # How-To Guides
2
+
3
+ ## How to Add a New Page
4
+
5
+ 1. **Create the page component** in `src/pages/`:
6
+
7
+ ```jsx
8
+ // src/pages/Dashboard.jsx
9
+ import React from "react";
10
+ import Container from "../components/layout/Container";
11
+ import { Card, CardContent } from "@/components/ui/card";
12
+
13
+ export default function Dashboard() {
14
+ return (
15
+ <Container>
16
+ <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
17
+ <Card>
18
+ <p>Welcome to your dashboard!</p>
19
+ </Card>
20
+ </Container>
21
+ );
22
+ }
23
+ ```
24
+
25
+ 2. **Add the route** in `src/App.jsx`:
26
+
27
+ ```jsx
28
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
29
+ import Dashboard from "./pages/Dashboard";
30
+ // ... other imports
31
+
32
+ function App() {
33
+ return (
34
+ <BrowserRouter>
35
+ <Routes>
36
+ <Route path="/" element={<Home />} />
37
+ <Route path="/dashboard" element={<Dashboard />} />
38
+ {/* Add your new route here */}
39
+ </Routes>
40
+ </BrowserRouter>
41
+ );
42
+ }
43
+ ```
44
+
45
+ 3. **Add navigation link** (optional) in `src/components/ui/Navbar.jsx` or `Sidebar.jsx`:
46
+
47
+ ```jsx
48
+ import { Link } from "react-router-dom";
49
+
50
+ <Link to="/dashboard" className="text-gray-700 hover:text-blue-600">
51
+ Dashboard
52
+ </Link>
53
+ ```
54
+
55
+ ## How to Make a REST API Call
56
+
57
+ The scaffold includes an Axios-based API client in `src/utils/api.js` with built-in CRUD methods.
58
+
59
+ ### Basic API Configuration
60
+
61
+ Set your API base URL in a `.env` file:
62
+
63
+ ```bash
64
+ VITE_API_BASE_URL=https://api.example.com
65
+ ```
66
+
67
+ ### Making API Calls
68
+
69
+ ```jsx
70
+ import { useState, useEffect } from "react";
71
+ import api from "../utils/api";
72
+
73
+ function MyComponent() {
74
+ const [data, setData] = useState([]);
75
+ const [loading, setLoading] = useState(false);
76
+ const [error, setError] = useState(null);
77
+
78
+ // GET request - Fetch all items
79
+ useEffect(() => {
80
+ const fetchData = async () => {
81
+ setLoading(true);
82
+ try {
83
+ const response = await api.getAll("/students");
84
+ setData(response.data);
85
+ } catch (err) {
86
+ setError(err.message);
87
+ } finally {
88
+ setLoading(false);
89
+ }
90
+ };
91
+ fetchData();
92
+ }, []);
93
+
94
+ // GET request - Fetch single item
95
+ const fetchStudent = async (id) => {
96
+ try {
97
+ const response = await api.getById("/students", id);
98
+ console.log(response.data);
99
+ } catch (err) {
100
+ console.error(err);
101
+ }
102
+ };
103
+
104
+ // POST request - Create new item
105
+ const createStudent = async () => {
106
+ try {
107
+ const newStudent = { name: "Ada Lovelace", grade: "A" };
108
+ const response = await api.create("/students", newStudent);
109
+ setData([...data, response.data]);
110
+ } catch (err) {
111
+ setError(err.message);
112
+ }
113
+ };
114
+
115
+ // PUT request - Update item
116
+ const updateStudent = async (id) => {
117
+ try {
118
+ const updates = { name: "Grace Hopper" };
119
+ const response = await api.update(`/students/${id}`, updates);
120
+ setData(data.map(item => item.id === id ? response.data : item));
121
+ } catch (err) {
122
+ setError(err.message);
123
+ }
124
+ };
125
+
126
+ // DELETE request - Remove item
127
+ const deleteStudent = async (id) => {
128
+ try {
129
+ await api.delete(`/students/${id}`);
130
+ setData(data.filter(item => item.id !== id));
131
+ } catch (err) {
132
+ setError(err.message);
133
+ }
134
+ };
135
+
136
+ return (
137
+ <div>
138
+ {loading && <p>Loading...</p>}
139
+ {error && <p className="text-red-500">Error: {error}</p>}
140
+ {/* Render your data here */}
141
+ </div>
142
+ );
143
+ }
144
+ ```
145
+
146
+ ### Available API Methods
147
+
148
+ - `api.getAll(endpoint)` - GET all items
149
+ - `api.getById(endpoint, id)` - GET single item
150
+ - `api.create(endpoint, data)` - POST new item
151
+ - `api.update(endpoint, data)` - PUT update item
152
+ - `api.delete(endpoint)` - DELETE item
153
+ - `api.setToken(token)` - Set authorization token
154
+
155
+ ### Custom API Client
156
+
157
+ Create a custom client for different base URLs:
158
+
159
+ ```js
160
+ import { ApiClient } from "./utils/api";
161
+
162
+ const adminApi = new ApiClient("https://admin.example.com");
163
+ adminApi.setToken("your-jwt-token");
164
+
165
+ const response = await adminApi.getAll("/users");
166
+ ```
@@ -0,0 +1,210 @@
1
+ # React Props and useEffect
2
+
3
+ This guide explains two core React concepts:
4
+
5
+ - `props`
6
+ - `useEffect`
7
+
8
+ ## See also
9
+
10
+ For plain JavaScript function examples, see `FUNCTIONS_EXAMPLES.md`.
11
+
12
+ ## 1. What props are
13
+
14
+ Props are values passed from a parent component to a child component.
15
+
16
+ They let components share data and behavior.
17
+
18
+ ## 2. Basic props example
19
+
20
+ ```jsx
21
+ function WelcomeMessage(props) {
22
+ return <h1>Hello, {props.name}</h1>;
23
+ }
24
+
25
+ export default function App() {
26
+ return <WelcomeMessage name="Ada" />;
27
+ }
28
+ ```
29
+
30
+ Here:
31
+
32
+ - `name` is a prop
33
+ - the parent passes it in
34
+ - the child reads it
35
+
36
+ ## 3. Destructured props example
37
+
38
+ ```jsx
39
+ function WelcomeMessage({ name, role }) {
40
+ return (
41
+ <div>
42
+ <h1>Hello, {name}</h1>
43
+ <p>Role: {role}</p>
44
+ </div>
45
+ );
46
+ }
47
+
48
+ export default function App() {
49
+ return <WelcomeMessage name="Grace" role="Engineer" />;
50
+ }
51
+ ```
52
+
53
+ This is the most common style in React.
54
+
55
+ ## 4. Passing a function as a prop
56
+
57
+ Parents can pass functions to children.
58
+
59
+ ```jsx
60
+ function ChildButton({ onPress }) {
61
+ return <button onClick={onPress}>Click Me</button>;
62
+ }
63
+
64
+ export default function Parent() {
65
+ function handlePress() {
66
+ console.log("Button clicked in child.");
67
+ }
68
+
69
+ return <ChildButton onPress={handlePress} />;
70
+ }
71
+ ```
72
+
73
+ This is useful because child components can trigger logic owned by the parent.
74
+
75
+ ## 5. What useEffect is
76
+
77
+ `useEffect` is a React hook used for side effects.
78
+
79
+ Examples of side effects:
80
+
81
+ - fetching API data
82
+ - setting up timers
83
+ - listening for browser events
84
+ - updating browser state outside the render
85
+
86
+ Basic syntax:
87
+
88
+ ```jsx
89
+ import { useEffect } from "react";
90
+
91
+ useEffect(() => {
92
+ console.log("Effect ran");
93
+ }, []);
94
+ ```
95
+
96
+ The second argument is the dependency array.
97
+
98
+ ## 6. Run once when the component loads
99
+
100
+ ```jsx
101
+ import { useEffect } from "react";
102
+
103
+ export default function Page() {
104
+ useEffect(() => {
105
+ console.log("Component mounted");
106
+ }, []);
107
+
108
+ return <p>Page loaded</p>;
109
+ }
110
+ ```
111
+
112
+ This runs once after the first render.
113
+
114
+ ## 7. Fetch data with useEffect
115
+
116
+ ```jsx
117
+ import { useEffect, useState } from "react";
118
+
119
+ export default function HealthCheck() {
120
+ const [data, setData] = useState(null);
121
+ const [error, setError] = useState("");
122
+
123
+ useEffect(() => {
124
+ const loadHealth = async () => {
125
+ try {
126
+ const response = await fetch("/api/health");
127
+ const result = await response.json();
128
+ setData(result);
129
+ } catch (err) {
130
+ setError("Failed to load health status.");
131
+ }
132
+ };
133
+
134
+ loadHealth();
135
+ }, []);
136
+
137
+ if (error) return <p>{error}</p>;
138
+ if (!data) return <p>Loading...</p>;
139
+
140
+ return <pre>{JSON.stringify(data, null, 2)}</pre>;
141
+ }
142
+ ```
143
+
144
+ This is a common pattern for loading server data when a component appears.
145
+
146
+ ## 8. Run when a value changes
147
+
148
+ ```jsx
149
+ import { useEffect, useState } from "react";
150
+
151
+ export default function SearchExample() {
152
+ const [query, setQuery] = useState("");
153
+
154
+ useEffect(() => {
155
+ if (!query) return;
156
+ console.log("Search query changed:", query);
157
+ }, [query]);
158
+
159
+ return (
160
+ <input
161
+ value={query}
162
+ onChange={(event) => setQuery(event.target.value)}
163
+ placeholder="Search"
164
+ />
165
+ );
166
+ }
167
+ ```
168
+
169
+ This effect runs every time `query` changes.
170
+
171
+ ## 9. Cleanup example
172
+
173
+ ```jsx
174
+ import { useEffect } from "react";
175
+
176
+ export default function TimerExample() {
177
+ useEffect(() => {
178
+ const id = setInterval(() => {
179
+ console.log("Tick");
180
+ }, 1000);
181
+
182
+ return () => {
183
+ clearInterval(id);
184
+ };
185
+ }, []);
186
+
187
+ return <p>Timer running</p>;
188
+ }
189
+ ```
190
+
191
+ The function returned by `useEffect` is cleanup logic.
192
+
193
+ It runs when:
194
+
195
+ - the component is removed
196
+ - or before the effect runs again
197
+
198
+ ## 10. Summary
199
+
200
+ Use `props` when:
201
+
202
+ - a parent needs to pass data to a child
203
+ - a parent needs to pass a function to a child
204
+
205
+ Use `useEffect` when:
206
+
207
+ - code should run after render
208
+ - you need to fetch data
209
+ - you need timers or subscriptions
210
+ - you need cleanup logic
@@ -0,0 +1,268 @@
1
+ # Registration Flow: Send Email and Password to the Server
2
+
3
+ This guide shows how to:
4
+
5
+ 1. Create a registration page in React
6
+ 2. Send `email` and `password` to the server
7
+ 3. Call the server-side encryption function
8
+ 4. Hash the password on the server
9
+ 5. Prove it works by printing the encrypted password in the server console
10
+
11
+ Note: logging password hashes is only for development proof. Do not keep that log in production.
12
+
13
+ ## 1. Use the existing server-side password utility
14
+
15
+ The server already has a password utility in:
16
+
17
+ - `server/utils/password.js`
18
+
19
+ It exports:
20
+
21
+ - `hashPassword(password)`
22
+ - `verifyPassword(password, hash)`
23
+ - `getPasswordStrength(password)`
24
+ - `getPasswordStrengthLabel(password)`
25
+
26
+ That means the registration flow should hash the password on the server, not in React.
27
+
28
+ ## 2. Update the server registration route
29
+
30
+ In `server/server.js`, import `hashPassword` from the server utility.
31
+
32
+ Example:
33
+
34
+ ```js
35
+ "use strict";
36
+ const express = require("express");
37
+ const cors = require("cors");
38
+ const { ApiClient } = require("./utils/apiClient");
39
+ const { hashPassword } = require("./utils/password");
40
+
41
+ const app = express();
42
+ const PORT = 5000;
43
+ ```
44
+
45
+ Then add a registration route like this:
46
+
47
+ ```js
48
+ app.post("/api/register", async (req, res) => {
49
+ const { email, password } = req.body;
50
+
51
+ if (!email || typeof email !== "string") {
52
+ return res.status(400).json({ error: "Email is required." });
53
+ }
54
+
55
+ if (!password || typeof password !== "string") {
56
+ return res.status(400).json({ error: "Password is required." });
57
+ }
58
+
59
+ try {
60
+ const hashedPassword = await hashPassword(password);
61
+
62
+ // Development proof only.
63
+ console.log("Registered email:", email);
64
+ console.log("Encrypted password:", hashedPassword);
65
+
66
+ // In a real app, save email + hashedPassword to the database here.
67
+ return res.status(201).json({
68
+ message: "Registration received.",
69
+ email,
70
+ hashedPassword,
71
+ });
72
+ } catch (error) {
73
+ return res.status(500).json({ error: error.message || "Registration failed." });
74
+ }
75
+ });
76
+ ```
77
+
78
+ ## 3. Create a React registration page
79
+
80
+ Create a page such as `src/pages/Register.jsx`.
81
+
82
+ Example:
83
+
84
+ ```jsx
85
+ import { useState } from "react";
86
+
87
+ export default function Register() {
88
+ const [email, setEmail] = useState("");
89
+ const [password, setPassword] = useState("");
90
+ const [result, setResult] = useState(null);
91
+ const [error, setError] = useState("");
92
+
93
+ const handleSubmit = async (event) => {
94
+ event.preventDefault();
95
+ setError("");
96
+ setResult(null);
97
+
98
+ try {
99
+ const response = await fetch("/api/register", {
100
+ method: "POST",
101
+ headers: {
102
+ "Content-Type": "application/json",
103
+ },
104
+ body: JSON.stringify({ email, password }),
105
+ });
106
+
107
+ const data = await response.json();
108
+
109
+ if (!response.ok) {
110
+ throw new Error(data.error || "Request failed");
111
+ }
112
+
113
+ setResult(data);
114
+ } catch (err) {
115
+ setError(err.message);
116
+ }
117
+ };
118
+
119
+ return (
120
+ <main className="min-h-screen px-6 py-12">
121
+ <div className="mx-auto max-w-md">
122
+ <h1 className="mb-6 text-2xl font-bold">Register</h1>
123
+
124
+ <form onSubmit={handleSubmit} className="space-y-4">
125
+ <div>
126
+ <label htmlFor="email" className="block text-sm font-medium">
127
+ Email
128
+ </label>
129
+ <input
130
+ id="email"
131
+ type="email"
132
+ value={email}
133
+ onChange={(e) => setEmail(e.target.value)}
134
+ className="mt-1 w-full rounded border px-3 py-2"
135
+ required
136
+ />
137
+ </div>
138
+
139
+ <div>
140
+ <label htmlFor="password" className="block text-sm font-medium">
141
+ Password
142
+ </label>
143
+ <input
144
+ id="password"
145
+ type="password"
146
+ value={password}
147
+ onChange={(e) => setPassword(e.target.value)}
148
+ className="mt-1 w-full rounded border px-3 py-2"
149
+ required
150
+ />
151
+ </div>
152
+
153
+ <button
154
+ type="submit"
155
+ className="rounded bg-slate-900 px-4 py-2 text-white"
156
+ >
157
+ Submit Registration
158
+ </button>
159
+ </form>
160
+
161
+ {error ? <p className="mt-4 text-red-600">{error}</p> : null}
162
+
163
+ {result ? (
164
+ <pre className="mt-4 overflow-auto rounded bg-slate-100 p-4 text-sm">
165
+ {JSON.stringify(result, null, 2)}
166
+ </pre>
167
+ ) : null}
168
+ </div>
169
+ </main>
170
+ );
171
+ }
172
+ ```
173
+
174
+ ## 4. Add the route in React
175
+
176
+ In `src/App.jsx`, add the page route.
177
+
178
+ Example:
179
+
180
+ ```jsx
181
+ import { Route, Routes } from "react-router-dom";
182
+ import Home from "./pages/Home.jsx";
183
+ import Register from "./pages/Register.jsx";
184
+
185
+ export default function App() {
186
+ return (
187
+ <Routes>
188
+ <Route path="/" element={<Home />} />
189
+ <Route path="/register" element={<Register />} />
190
+ </Routes>
191
+ );
192
+ }
193
+ ```
194
+
195
+ ## 5. Why the frontend can call `/api/register`
196
+
197
+ This project already proxies `/api` requests from Vite to the Express server.
198
+
199
+ That setup is in:
200
+
201
+ - `vite.config.mts`
202
+
203
+ Because of that, this frontend request works during development:
204
+
205
+ ```js
206
+ fetch("/api/register", {
207
+ method: "POST",
208
+ headers: {
209
+ "Content-Type": "application/json",
210
+ },
211
+ body: JSON.stringify({ email, password }),
212
+ });
213
+ ```
214
+
215
+ It will be forwarded to the Express server running on port `5000`.
216
+
217
+ ## 6. What proves the encryption worked
218
+
219
+ When the form is submitted:
220
+
221
+ 1. React sends the plain-text `email` and `password` to `POST /api/register`
222
+ 2. The server receives them
223
+ 3. The server calls `hashPassword(password)`
224
+ 4. The server logs the hashed value with `console.log`
225
+
226
+ Expected server console output will look similar to this:
227
+
228
+ ```txt
229
+ Registered email: user@example.com
230
+ Encrypted password: $2a$10$w3Pj7x8nK8D2r9M0T6Qv4eM9K5h7sX2mN1aB3cD4eF5gH6iJ7kL8m
231
+ ```
232
+
233
+ The value beginning with `$2a$10$` or `$2b$10$` is a bcrypt hash, which proves the password was encrypted on the server.
234
+
235
+ ## 7. Quick test steps
236
+
237
+ 1. Start the stack:
238
+
239
+ ```bash
240
+ npm run dev:all
241
+ ```
242
+
243
+ 2. Open the app in the browser.
244
+
245
+ 3. Go to `/register`.
246
+
247
+ 4. Enter an email and password.
248
+
249
+ 5. Submit the form.
250
+
251
+ 6. Check the server terminal.
252
+
253
+ You should see the email and encrypted password in the server console.
254
+
255
+ ## 8. Important production note
256
+
257
+ For production, remove this line after testing:
258
+
259
+ ```js
260
+ console.log("Encrypted password:", hashedPassword);
261
+ ```
262
+
263
+ In production, you should:
264
+
265
+ - Hash the password on the server
266
+ - Save only the hash to the database
267
+ - Never log plain-text passwords
268
+ - Usually avoid logging password hashes too