feat: Initialize frontend and backend structure with essential configurations
- Added TypeScript build info for frontend. - Created Vite configuration for React application. - Implemented pre-commit hook to run checks before commits. - Set up PostgreSQL Dockerfile with PostGIS support and initialization scripts. - Added database creation script for PostgreSQL with necessary extensions. - Established Python project configuration with dependencies and development tools. - Developed pre-commit script to enforce code quality checks for backend and frontend. - Created PowerShell script to set up Git hooks path.
This commit is contained in:
84
frontend/src/services/api.ts
Normal file
84
frontend/src/services/api.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import type { AuthResponse, LoginPayload, RegisterPayload } from '../types/auth';
|
||||
import type { Station, Track, Train } from '../types/domain';
|
||||
|
||||
export class ApiError extends Error {
|
||||
readonly status: number;
|
||||
|
||||
constructor(message: string, status: number) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
export interface NetworkSnapshot {
|
||||
readonly stations: Station[];
|
||||
readonly tracks: Track[];
|
||||
readonly trains: Train[];
|
||||
}
|
||||
|
||||
const JSON_HEADERS = {
|
||||
accept: 'application/json',
|
||||
'content-type': 'application/json',
|
||||
};
|
||||
|
||||
export async function login(credentials: LoginPayload): Promise<AuthResponse> {
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify(credentials),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new ApiError('Invalid username or password', response.status);
|
||||
}
|
||||
|
||||
return (await response.json()) as AuthResponse;
|
||||
}
|
||||
|
||||
export async function register(credentials: RegisterPayload): Promise<AuthResponse> {
|
||||
const response = await fetch('/api/auth/register', {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify(credentials),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
response.status === 409
|
||||
? 'Username already exists'
|
||||
: 'Registration failed. Please try again.';
|
||||
throw new ApiError(message, response.status);
|
||||
}
|
||||
|
||||
return (await response.json()) as AuthResponse;
|
||||
}
|
||||
|
||||
export async function fetchNetworkSnapshot(
|
||||
token: string,
|
||||
signal?: AbortSignal
|
||||
): Promise<NetworkSnapshot> {
|
||||
const response = await fetch('/api/network', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
response.status === 401
|
||||
? 'Authorization required. Please sign in again.'
|
||||
: `Failed to fetch network snapshot (status ${response.status})`;
|
||||
throw new ApiError(message, response.status);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as NetworkSnapshot;
|
||||
return {
|
||||
stations: data.stations ?? [],
|
||||
tracks: data.tracks ?? [],
|
||||
trains: data.trains ?? [],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user