Files
job-tracker/web/src/pages/HomePage.tsx
T
Marko (Hermes Implementer) 48db53c95d 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)
2026-05-26 19:07:02 +00:00

140 lines
3.5 KiB
TypeScript

import { type ReactNode } from "react";
import { useNavigate, Link } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Grid from "@mui/material/Grid";
import Alert from "@mui/material/Alert";
import AddIcon from "@mui/icons-material/Add";
import UpdateCard from "../components/UpdateCard";
import MetricsPanel from "../components/MetricsPanel";
import LoadingSkeleton from "../components/LoadingSkeleton";
import { useDashboardData } from "../hooks/useDashboardData";
function LandingView(): ReactNode {
return (
<Box
sx={{
minHeight: "60vh",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
}}
>
<Typography variant="h3" component="h1" gutterBottom sx={{ fontWeight: 700 }}>
Job Tracker
</Typography>
<Typography variant="h6" color="text.secondary" sx={{ mb: 4, maxWidth: 500 }}>
Track your job applications, interviews, and offers all in one place.
</Typography>
<Box sx={{ display: "flex", gap: 2 }}>
<Button
variant="contained"
size="large"
component={Link}
to="/login"
>
Sign In
</Button>
<Button
variant="outlined"
size="large"
component={Link}
to="/register"
>
Register
</Button>
</Box>
</Box>
);
}
function DashboardView(): ReactNode {
const navigate = useNavigate();
const { data, loading, error } = useDashboardData();
if (loading) {
return <LoadingSkeleton />;
}
return (
<Box>
<Typography
variant="h4"
component="h2"
gutterBottom
sx={{ fontWeight: 600 }}
>
Dashboard
</Typography>
{error && (
<Alert severity="error" sx={{ mb: 3 }}>
Failed to load dashboard data: {error}
</Alert>
)}
{data && (
<>
<Box sx={{ mb: 4 }}>
<MetricsPanel metrics={data.metrics} />
</Box>
<Box
sx={{ mb: 3, display: "flex", justifyContent: "flex-end" }}
>
<Button
variant="contained"
size="large"
startIcon={<AddIcon />}
onClick={() => navigate("/applications/new")}
>
Create New Job Application
</Button>
</Box>
<Typography
variant="h5"
component="h3"
gutterBottom
sx={{ fontWeight: 600 }}
>
Recent Updates
</Typography>
<Grid container spacing={3}>
{data.updates.map((update) => (
<Grid key={update.id} size={{ xs: 12, sm: 6, md: 4 }}>
<UpdateCard update={update} />
</Grid>
))}
</Grid>
{data.updates.length === 0 && (
<Typography
variant="body1"
color="text.secondary"
sx={{ mt: 2 }}
>
No updates yet. Create your first job application to get started.
</Typography>
)}
</>
)}
</Box>
);
}
export default function HomePage(): ReactNode {
const { state } = useAuth();
if (!state.isAuthenticated) {
return <LandingView />;
}
return <DashboardView />;
}