add basic user management
This commit is contained in:
parent
09150ba3bb
commit
9e7ad622f9
12 changed files with 673 additions and 35 deletions
97
frontend/src/api/apiClient.ts
Normal file
97
frontend/src/api/apiClient.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* A centralized API client that wraps around the native fetch API.
|
||||
* It automatically handles authentication headers, JSON parsing, and error handling.
|
||||
*
|
||||
* This client is used across the app for interacting with backend endpoints.
|
||||
*
|
||||
* @todo modify all endpoints to use api client and remove old utils
|
||||
*/
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE
|
||||
|
||||
/**
|
||||
* Helper: Reads the JWT token from localStorage (if available)
|
||||
*/
|
||||
function getAuthToken(): string | null {
|
||||
try {
|
||||
const sessionData = localStorage.getItem("session");
|
||||
if (!sessionData) return null;
|
||||
|
||||
const parsed = JSON.parse(sessionData);
|
||||
return parsed.token ?? null;
|
||||
} catch (err) {
|
||||
console.error("Failed to parse token from localStorage:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom error class for API responses.
|
||||
*/
|
||||
export class ApiError extends Error {
|
||||
public status: number;
|
||||
public details?: string;
|
||||
|
||||
constructor(message: string, status: number, details?: string) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for making API requests.
|
||||
* Handles JSON encoding/decoding and authorization headers automatically.
|
||||
*
|
||||
* @param endpoint - API endpoint (e.g. "user/me")
|
||||
* @param options - fetch configuration (method, headers, body)
|
||||
* @returns parsed JSON response
|
||||
*/
|
||||
export async function apiRequest<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const token = getAuthToken();
|
||||
|
||||
const headers: HeadersInit = {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? {Authorization: `Bearer ${token}`} : {}),
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
|
||||
// Handle non-OK responses gracefully
|
||||
if (!response.ok) {
|
||||
let details;
|
||||
try {
|
||||
details = await response.json();
|
||||
} catch {
|
||||
details = await response.text();
|
||||
}
|
||||
throw new ApiError(`Request to ${endpoint} failed`, response.status, details);
|
||||
}
|
||||
|
||||
// Handle empty response bodies
|
||||
if (response.status === 204) {
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand helpers for convenience.
|
||||
*/
|
||||
export const apiClient = {
|
||||
get: <T>(endpoint: string) => apiRequest<T>(endpoint, {method: "GET"}),
|
||||
post: <T>(endpoint: string, body: object) =>
|
||||
apiRequest<T>(endpoint, {method: "POST", body: JSON.stringify(body)}),
|
||||
put: <T>(endpoint: string, body: object) =>
|
||||
apiRequest<T>(endpoint, {method: "PUT", body: JSON.stringify(body)}),
|
||||
delete: <T>(endpoint: string) =>
|
||||
apiRequest<T>(endpoint, {method: "DELETE"}),
|
||||
};
|
||||
7
frontend/src/api/dtos/ChangeUserPasswordRequestDto.ts
Normal file
7
frontend/src/api/dtos/ChangeUserPasswordRequestDto.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* DTO for changing user password
|
||||
*/
|
||||
export class ChangeUserPasswordRequestDto {
|
||||
userId?: string;
|
||||
password?: string;
|
||||
}
|
||||
9
frontend/src/api/dtos/CreateUserRequestDto.ts
Normal file
9
frontend/src/api/dtos/CreateUserRequestDto.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { UserDto } from "./UserDto.js";
|
||||
|
||||
/**
|
||||
* DTO used for user creation
|
||||
*/
|
||||
export class CreateUserRequestDto {
|
||||
userData?: UserDto;
|
||||
password?: string;
|
||||
}
|
||||
24
frontend/src/api/points/UserPoint.ts
Normal file
24
frontend/src/api/points/UserPoint.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import {apiClient} from "../apiClient";
|
||||
import type {UserDto} from "../dtos/UserDto";
|
||||
import type {CreateUserRequestDto} from "../dtos/CreateUserRequestDto";
|
||||
import type {ChangeUserPasswordRequestDto} from "../dtos/ChangeUserPasswordRequestDto";
|
||||
|
||||
export async function fetchCurrentUser(): Promise<UserDto> {
|
||||
return apiClient.get("/user/me");
|
||||
}
|
||||
|
||||
export async function fetchAllUsers(): Promise<UserDto[]> {
|
||||
return apiClient.get("/user/list");
|
||||
}
|
||||
|
||||
export async function createUser(dto: CreateUserRequestDto): Promise<UserDto> {
|
||||
return apiClient.post("/user/create", dto);
|
||||
}
|
||||
|
||||
export async function updateUser(dto: UserDto): Promise<UserDto> {
|
||||
return apiClient.post("/user/update", dto);
|
||||
}
|
||||
|
||||
export async function changePassword(dto: ChangeUserPasswordRequestDto) {
|
||||
return apiClient.post("/user/change-password", dto);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue