Merge branch 'main' into feature/user-auth
Resolved merge conflicts integrating PR #13 (Home Page with MUI v2): Backend changes: - settings.py: Combined INSTALLED_APPS (accounts + jobs + corsheaders), kept HEAD's REST_FRAMEWORK (AllowAny + throttling) and SIMPLE_JWT, added origin/main's CORS config - urls.py: Combined admin/, api/auth/, api/ routes - pyproject.toml: Combined all dependencies (simplejwt + cors-headers) - uv.lock: Regenerated with updated dependencies Frontend changes: - package.json: Combined all deps (axios + MUI + emotion) - App.tsx: Integrated AuthProvider with MUI AppLayout, all routes - HomePage.tsx: Show landing view when unauthenticated, MUI dashboard when authenticated - main.tsx, tsconfig.json, vite-env.d.ts: Combined both versions - yarn.lock: Kept origin/main's version (regenerated on install)
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# Spec: Home Page with MUI Components
|
||||
|
||||
## Ticket
|
||||
Gitea: crisleo-hermes/job-tracker#2
|
||||
Kanban: t_e6936299
|
||||
|
||||
## Overview
|
||||
Build a home page at route `/` using Material-UI (MUI) components that displays the last three job updates and dashboard metrics, with a button to create a new job application.
|
||||
|
||||
## Pages
|
||||
|
||||
### HomePage (`/`)
|
||||
- AppBar with title "Job Tracker"
|
||||
- Dashboard metrics cards row (total applications, interviews, offers, rejection rate)
|
||||
- Last 3 job updates displayed as cards
|
||||
- "Create New Job Application" button (navigates to creation flow)
|
||||
- Loading skeleton while data fetches
|
||||
- Error snackbar on API failure
|
||||
- Responsive Grid layout
|
||||
|
||||
## API Endpoints Consumed
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/updates/latest/` | 3 most recent JobUpdates with nested job info |
|
||||
| GET | `/api/updates/metrics/` | Dashboard metrics (total, status breakdown, interviews, offers, rejection rate) |
|
||||
|
||||
### Response Shapes
|
||||
|
||||
**GET /api/updates/latest/**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"job_id": 1,
|
||||
"company_name": "Acme Corp",
|
||||
"position_title": "Software Engineer",
|
||||
"from_status": "APPLIED",
|
||||
"to_status": "INTERVIEW",
|
||||
"notes": "Moving to next round",
|
||||
"created_at": "2025-01-15T10:00:00Z",
|
||||
"metrics": {"response_time_days": 5}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**GET /api/updates/metrics/**
|
||||
```json
|
||||
{
|
||||
"total_applications": 12,
|
||||
"status_breakdown": {"APPLIED": 5, "INTERVIEW": 4, "OFFER": 2, "REJECTED": 1},
|
||||
"interviews_count": 6,
|
||||
"offers_count": 2,
|
||||
"rejection_rate": 8.3
|
||||
}
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### `AppLayout`
|
||||
- MUI `AppBar` with `Toolbar`, `Typography` ("Job Tracker")
|
||||
- Wraps child content via `Outlet` from React Router
|
||||
|
||||
### `UpdateCard`
|
||||
- MUI `Card` → `CardContent`
|
||||
- Displays: company name, position title, status change (`from_status` → `to_status`), created date, metrics summary
|
||||
- Props: `JobUpdate`
|
||||
|
||||
### `MetricsPanel`
|
||||
- MUI `Grid` container with metric `Card` items
|
||||
- Each metric: total applications, interviews count, offers count, rejection rate
|
||||
- Props: `DashboardMetrics`
|
||||
|
||||
### `LoadingSkeleton`
|
||||
- MUI `Skeleton` components mimicking the home page layout
|
||||
|
||||
## Data Fetching
|
||||
|
||||
Custom hook `useDashboardData` using React's `useEffect` + `useState`:
|
||||
- Fetches from `/api/updates/latest/` and `/api/updates/metrics/` concurrently (`Promise.all`)
|
||||
- Vite proxy: `/api` → `http://localhost:8000/api`
|
||||
- States: loading, error (with error message), data
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
interface JobUpdate {
|
||||
id: number;
|
||||
job_id: number;
|
||||
company_name: string;
|
||||
position_title: string;
|
||||
from_status: string | null;
|
||||
to_status: string;
|
||||
notes: string;
|
||||
created_at: string;
|
||||
metrics: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface DashboardMetrics {
|
||||
total_applications: number;
|
||||
status_breakdown: Record<string, number>;
|
||||
interviews_count: number;
|
||||
offers_count: number;
|
||||
rejection_rate: number;
|
||||
}
|
||||
```
|
||||
|
||||
## Acceptance Criteria
|
||||
- [x] Home page at route `/`
|
||||
- [x] MUI components exclusively (AppBar, Typography, Card, Grid, Button, Skeleton, Snackbar)
|
||||
- [x] Last 3 job updates: job ID, status, creation date, metrics
|
||||
- [x] "Create New Job Application" button navigates to `/applications/new`
|
||||
- [x] Loading indicators while fetching data (Skeleton components)
|
||||
- [x] Graceful error handling (Snackbar with error message)
|
||||
- [x] Responsive layout (Grid breakpoints)
|
||||
Reference in New Issue
Block a user