Skip to content

Commit 10a817f

Browse files
Merge pull request #1 from ConnorHall938/copilot/implement-react-frontend
Implement React frontend with Vite and TypeScript
2 parents 402b68d + f5eb304 commit 10a817f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3863
-117
lines changed

README.md

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PwrProgram
22

3-
A comprehensive fitness program management API built with TypeScript, Node.js, and PostgreSQL. Manage workout programs, cycles, blocks, sessions, exercises, and sets with a hierarchical structure designed for coaches and athletes.
3+
A comprehensive fitness program management application built with TypeScript, React, Node.js, and PostgreSQL. Manage workout programs, cycles, blocks, sessions, exercises, and sets with a hierarchical structure designed for coaches and athletes.
44

55
## 🚀 Features
66

@@ -11,6 +11,14 @@ A comprehensive fitness program management API built with TypeScript, Node.js, a
1111
- **Pagination**: Efficient data retrieval with configurable page sizes
1212
- **HATEOAS**: Discoverable REST API with hypermedia links
1313

14+
### Frontend (React + Vite)
15+
- **Modern Stack**: React 19, TypeScript, Vite
16+
- **Routing**: React Router v7 with protected routes
17+
- **Authentication**: Context-based auth with session management
18+
- **Component Library**: Reusable UI components (Button, Input, Card)
19+
- **CSS Modules**: Scoped styling for maintainability
20+
- **API Integration**: Type-safe API client with error handling
21+
1422
### Security
1523
-**Password Hashing**: Bcrypt with configurable rounds
1624
-**Session Management**: Database-backed sessions (TypeORM store, scalable to Redis)
@@ -142,26 +150,32 @@ All configuration is done through environment variables. Copy `.env.example` to
142150

143151
### Development
144152
```bash
145-
# Start dev server with hot reload
146-
pnpm --filter @pwrprogram/api dev
153+
# Start API server with hot reload
154+
pnpm dev:api
147155

148-
# Run tests
149-
pnpm --filter @pwrprogram/api test
156+
# Start frontend dev server
157+
pnpm dev:web
158+
159+
# Run API tests
160+
pnpm test:api
150161

151162
# Run tests with coverage
152-
pnpm --filter @pwrprogram/api test:coverage
163+
pnpm test:api:coverage
153164

154-
# Lint code
155-
pnpm --filter @pwrprogram/api lint
165+
# Lint frontend code
166+
pnpm lint:web
156167
```
157168

158169
### Production
159170
```bash
160-
# Build the application
171+
# Build the API
161172
pnpm --filter @pwrprogram/api build
162173

163-
# Start production server
164-
pnpm --filter @pwrprogram/api start
174+
# Build the frontend
175+
pnpm build:web
176+
177+
# Start production API server
178+
pnpm start:api
165179
```
166180

167181
### Docker
@@ -430,18 +444,34 @@ docker run -d \
430444
```
431445
PwrProgram/
432446
├── apps/
433-
│ └── pwrprogram/ # Main API application
447+
│ ├── pwrprogram/ # Main API application
448+
│ │ ├── src/
449+
│ │ │ ├── entity/ # TypeORM entities
450+
│ │ │ ├── routes/ # Express route handlers
451+
│ │ │ ├── middleware/ # Custom middleware
452+
│ │ │ ├── mappers/ # Entity to DTO mappers
453+
│ │ │ ├── utils/ # Utility functions
454+
│ │ │ ├── openapi/ # OpenAPI spec
455+
│ │ │ ├── testing/ # Test files
456+
│ │ │ ├── data-source.ts # TypeORM configuration
457+
│ │ │ └── index.ts # Application entry point
458+
│ │ ├── .env # Environment variables (gitignored)
459+
│ │ └── package.json
460+
│ └── web/ # React frontend application
434461
│ ├── src/
435-
│ │ ├── entity/ # TypeORM entities
436-
│ │ ├── routes/ # Express route handlers
437-
│ │ ├── middleware/ # Custom middleware
438-
│ │ ├── mappers/ # Entity to DTO mappers
439-
│ │ ├── utils/ # Utility functions
440-
│ │ ├── openapi/ # OpenAPI spec
441-
│ │ ├── testing/ # Test files
442-
│ │ ├── data-source.ts # TypeORM configuration
443-
│ │ └── index.ts # Application entry point
444-
│ ├── .env # Environment variables (gitignored)
462+
│ │ ├── components/ # React components
463+
│ │ │ ├── auth/ # Auth-related components
464+
│ │ │ ├── layout/ # Layout components
465+
│ │ │ ├── programs/ # Program management
466+
│ │ │ └── ui/ # Reusable UI components
467+
│ │ ├── context/ # React contexts (Auth)
468+
│ │ ├── hooks/ # Custom React hooks
469+
│ │ ├── lib/ # Utilities and API client
470+
│ │ ├── pages/ # Page components
471+
│ │ ├── types/ # TypeScript types
472+
│ │ ├── App.tsx # App with routing
473+
│ │ └── main.tsx # Entry point
474+
│ ├── vite.config.ts # Vite configuration
445475
│ └── package.json
446476
├── packages/
447477
│ └── shared/ # Shared DTOs and types
@@ -546,7 +576,5 @@ PwrProgram/
546576
- [Express.js](https://expressjs.com/)
547577
- [PostgreSQL](https://www.postgresql.org/)
548578
- [TypeScript](https://www.typescriptlang.org/)
549-
550-
---
551-
552-
**Note**: This is a backend API. Frontend coming soon!
579+
- [React](https://react.dev/)
580+
- [Vite](https://vitejs.dev/)

apps/web/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

apps/web/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## React Compiler
11+
12+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13+
14+
## Expanding the ESLint configuration
15+
16+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17+
18+
```js
19+
export default defineConfig([
20+
globalIgnores(['dist']),
21+
{
22+
files: ['**/*.{ts,tsx}'],
23+
extends: [
24+
// Other configs...
25+
26+
// Remove tseslint.configs.recommended and replace with this
27+
tseslint.configs.recommendedTypeChecked,
28+
// Alternatively, use this for stricter rules
29+
tseslint.configs.strictTypeChecked,
30+
// Optionally, add this for stylistic rules
31+
tseslint.configs.stylisticTypeChecked,
32+
33+
// Other configs...
34+
],
35+
languageOptions: {
36+
parserOptions: {
37+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
38+
tsconfigRootDir: import.meta.dirname,
39+
},
40+
// other options...
41+
},
42+
},
43+
])
44+
```
45+
46+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47+
48+
```js
49+
// eslint.config.js
50+
import reactX from 'eslint-plugin-react-x'
51+
import reactDom from 'eslint-plugin-react-dom'
52+
53+
export default defineConfig([
54+
globalIgnores(['dist']),
55+
{
56+
files: ['**/*.{ts,tsx}'],
57+
extends: [
58+
// Other configs...
59+
// Enable lint rules for React
60+
reactX.configs['recommended-typescript'],
61+
// Enable lint rules for React DOM
62+
reactDom.configs.recommended,
63+
],
64+
languageOptions: {
65+
parserOptions: {
66+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
67+
tsconfigRootDir: import.meta.dirname,
68+
},
69+
// other options...
70+
},
71+
},
72+
])
73+
```

apps/web/eslint.config.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
import { defineConfig, globalIgnores } from 'eslint/config'
7+
8+
export default defineConfig([
9+
globalIgnores(['dist']),
10+
{
11+
files: ['**/*.{ts,tsx}'],
12+
extends: [
13+
js.configs.recommended,
14+
tseslint.configs.recommended,
15+
reactHooks.configs.flat.recommended,
16+
reactRefresh.configs.vite,
17+
],
18+
languageOptions: {
19+
ecmaVersion: 2020,
20+
globals: globals.browser,
21+
},
22+
rules: {
23+
'react-refresh/only-export-components': [
24+
'warn',
25+
{ allowExportNames: ['AuthContext', 'AuthContextType'] },
26+
],
27+
},
28+
},
29+
])

apps/web/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>PwrProgram - Fitness Program Management</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

apps/web/package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "@pwrprogram/web",
3+
"private": true,
4+
"version": "1.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview",
11+
"typecheck": "tsc --noEmit"
12+
},
13+
"dependencies": {
14+
"@pwrprogram/shared": "workspace:*",
15+
"react": "^19.2.0",
16+
"react-dom": "^19.2.0",
17+
"react-router-dom": "^7.6.1"
18+
},
19+
"devDependencies": {
20+
"@eslint/js": "^9.39.1",
21+
"@types/node": "^24.10.1",
22+
"@types/react": "^19.2.5",
23+
"@types/react-dom": "^19.2.3",
24+
"@vitejs/plugin-react": "^5.1.1",
25+
"eslint": "^9.39.1",
26+
"eslint-plugin-react-hooks": "^7.0.1",
27+
"eslint-plugin-react-refresh": "^0.4.24",
28+
"globals": "^16.5.0",
29+
"typescript": "~5.9.3",
30+
"typescript-eslint": "^8.46.4",
31+
"vite": "^7.2.4"
32+
}
33+
}

apps/web/public/vite.svg

Lines changed: 1 addition & 0 deletions
Loading

apps/web/src/App.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Global App Styles */
2+
* {
3+
box-sizing: border-box;
4+
}
5+
6+
#root {
7+
min-height: 100vh;
8+
}
9+
10+
a {
11+
text-decoration: none;
12+
color: inherit;
13+
}
14+
15+
/* Links styled by components */
16+
a:focus-visible {
17+
outline: 2px solid #3b82f6;
18+
outline-offset: 2px;
19+
}
20+

apps/web/src/App.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
2+
import { AuthProvider } from '@/context';
3+
import { MainLayout } from '@/components/layout';
4+
import { ProtectedRoute } from '@/components/auth';
5+
import {
6+
HomePage,
7+
LoginPage,
8+
RegisterPage,
9+
DashboardPage,
10+
ProgramsPage,
11+
ProgramDetailPage,
12+
} from '@/pages';
13+
import './App.css';
14+
15+
function App() {
16+
return (
17+
<AuthProvider>
18+
<BrowserRouter>
19+
<Routes>
20+
<Route element={<MainLayout />}>
21+
{/* Public routes */}
22+
<Route path="/" element={<HomePage />} />
23+
<Route path="/login" element={<LoginPage />} />
24+
<Route path="/register" element={<RegisterPage />} />
25+
26+
{/* Protected routes */}
27+
<Route
28+
path="/dashboard"
29+
element={
30+
<ProtectedRoute>
31+
<DashboardPage />
32+
</ProtectedRoute>
33+
}
34+
/>
35+
<Route
36+
path="/programs"
37+
element={
38+
<ProtectedRoute>
39+
<ProgramsPage />
40+
</ProtectedRoute>
41+
}
42+
/>
43+
<Route
44+
path="/programs/:id"
45+
element={
46+
<ProtectedRoute>
47+
<ProgramDetailPage />
48+
</ProtectedRoute>
49+
}
50+
/>
51+
</Route>
52+
</Routes>
53+
</BrowserRouter>
54+
</AuthProvider>
55+
);
56+
}
57+
58+
export default App;

apps/web/src/assets/react.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)