diff options
Diffstat (limited to 'frontend/src/lib')
-rw-r--r-- | frontend/src/lib/api.ts | 123 | ||||
-rw-r--r-- | frontend/src/lib/utils.ts | 6 |
2 files changed, 129 insertions, 0 deletions
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts new file mode 100644 index 0000000..35ef8d6 --- /dev/null +++ b/frontend/src/lib/api.ts @@ -0,0 +1,123 @@ +// API base URL +const API_BASE_URL = 'http://localhost:8080/api/v1'; + +// Helper function for fetching data with authorization +async function fetchWithAuth(url: string, options: RequestInit = {}) { + // Get token from local storage + const token = localStorage.getItem('token'); + + // Set up headers with authorization + const headers = { + 'Content-Type': 'application/json', + ...(token ? { 'Authorization': `Bearer ${token}` } : {}), + ...options.headers + }; + + // Perform fetch + const response = await fetch(`${API_BASE_URL}${url}`, { + ...options, + headers + }); + + // Handle unauthorized responses + if (response.status === 401) { + localStorage.removeItem('token'); + window.location.href = '/login'; + throw new Error('Unauthorized'); + } + + // Parse response + if (!response.ok) { + const errorData = await response.json().catch(() => null); + throw new Error(errorData?.error || `API Error: ${response.status}`); + } + + return response.json(); +} + +// Auth API +export const authApi = { + login: async (email: string, password: string) => { + const response = await fetch(`${API_BASE_URL}/auth/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password }) + }); + + if (!response.ok) { + const errorData = await response.json().catch(() => null); + throw new Error(errorData?.error || 'Login failed'); + } + + const data = await response.json(); + localStorage.setItem('token', data.token); + return data; + }, + + signup: async (name: string, email: string, password: string) => { + const response = await fetch(`${API_BASE_URL}/auth/signup`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name, email, password }) + }); + + if (!response.ok) { + const errorData = await response.json().catch(() => null); + throw new Error(errorData?.error || 'Signup failed'); + } + + return response.json(); + }, + + logout: () => { + localStorage.removeItem('token'); + window.location.href = '/login'; + } +}; + +// Loan API +export interface Loan { + ID: number; + CreatedAt: string; + UpdatedAt: string; + DeletedAt: string | null; + UserID: number; + AccountID: number | null; + Name: string; + OriginalAmount: number; + CurrentBalance: number; + InterestRate: number; + StartDate: string; + EndDate: string; +} + +export interface LoanInput { + name: string; + originalAmount: number; + currentBalance: number; + interestRate: number; + startDate: string; + endDate: string; + accountId?: number; +} + +export const loanApi = { + getLoans: () => fetchWithAuth('/loans'), + getLoan: (id: number) => fetchWithAuth(`/loans/${id}`), + createLoan: (loan: LoanInput) => fetchWithAuth('/loans', { + method: 'POST', + body: JSON.stringify(loan) + }), + updateLoan: (id: number, loan: Partial<LoanInput>) => fetchWithAuth(`/loans/${id}`, { + method: 'PUT', + body: JSON.stringify(loan) + }), + deleteLoan: (id: number) => fetchWithAuth(`/loans/${id}`, { + method: 'DELETE' + }) +}; + +// User API +export const userApi = { + getProfile: () => fetchWithAuth('/users/me') +};
\ No newline at end of file diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/frontend/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} |