feat: add user authentication with separate login and register pages

- Custom User model with email as unique identifier (AUTH_USER_MODEL)

- POST /api/auth/register/ with email validation, password min 8 chars, duplicate rejection

- POST /api/auth/login/ returning JWT (access + refresh) tokens

- Passwords hashed via Django's make_password

- React LoginPage and RegisterPage with form validation

- AuthContext with useReducer for auth state management

- Axios API client with JWT token injection

- TypeScript conversion of frontend scaffold
This commit is contained in:
Marko (Hermes Implementer)
2026-05-26 00:54:27 +00:00
parent b91b7c364e
commit 6867a91b67
28 changed files with 3313 additions and 55 deletions
+55
View File
@@ -0,0 +1,55 @@
import axios from "axios";
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_URL || "http://localhost:8000",
headers: {
"Content-Type": "application/json",
},
});
// Attach access token to every request if present
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem("access_token");
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export interface RegisterPayload {
email: string;
password: string;
password_confirm: string;
first_name?: string;
last_name?: string;
}
export interface LoginPayload {
email: string;
password: string;
}
export interface UserProfile {
id: number;
email: string;
first_name: string;
last_name: string;
}
export interface LoginResponse {
user: UserProfile;
access: string;
refresh: string;
}
export function registerUser(payload: RegisterPayload): Promise<UserProfile> {
return apiClient
.post<UserProfile>("/api/auth/register/", payload)
.then((res) => res.data);
}
export function loginUser(payload: LoginPayload): Promise<LoginResponse> {
return apiClient
.post<LoginResponse>("/api/auth/login/", payload)
.then((res) => res.data);
}