aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/lib/api.ts
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-27 23:02:42 +0530
committerLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-27 23:02:42 +0530
commit538d933baef56d7ee76f78617b553d63713efa24 (patch)
tree3fcbc4208849dfa0e5dc8fe5761e103a3591c283 /frontend/src/lib/api.ts
parent3941d80ff120238b973451325b834ebd8377281e (diff)
downloadfinance-master.tar.gz
finance-master.tar.bz2
finance-master.zip
finance: feat: added the goal page with some improvements of uiHEADmaster
Diffstat (limited to 'frontend/src/lib/api.ts')
-rw-r--r--frontend/src/lib/api.ts304
1 files changed, 135 insertions, 169 deletions
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index 11cee62..67ea975 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -1,72 +1,52 @@
+import axios from 'axios';
+
// 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 = {
+// Create axios instance with defaults
+export const api = axios.create({
+ baseURL: API_BASE_URL,
+ 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}`);
+ },
+});
+
+// Add auth interceptor
+api.interceptors.request.use(
+ (config) => {
+ const token = localStorage.getItem('token');
+ if (token) {
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+ return config;
+ },
+ (error) => Promise.reject(error)
+);
+
+// Handle auth errors
+api.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (error.response && error.response.status === 401 && typeof window !== 'undefined') {
+ localStorage.removeItem('token');
+ window.location.href = '/login';
+ }
+ return Promise.reject(error);
}
-
- 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;
+ const response = await api.post('/auth/login', { email, password });
+ const { token } = response.data;
+ localStorage.setItem('token', token);
+ return response.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();
+ const response = await api.post('/auth/signup', { name, email, password });
+ return response.data;
},
logout: () => {
@@ -77,14 +57,14 @@ export const authApi = {
// Account API
export interface Account {
- ID: number;
- CreatedAt: string;
- UpdatedAt: string;
- DeletedAt: string | null;
- UserID: number;
- Name: string;
- Type: string;
- Balance: number;
+ id: number;
+ createdAt: string;
+ updatedAt: string;
+ deletedAt: string | null;
+ userID: number;
+ name: string;
+ type: string;
+ balance: number;
}
export interface AccountInput {
@@ -94,34 +74,26 @@ export interface AccountInput {
}
export const accountApi = {
- getAccounts: () => fetchWithAuth('/accounts'),
- getAccount: (id: number) => fetchWithAuth(`/accounts/${id}`),
- createAccount: (account: AccountInput) => fetchWithAuth('/accounts', {
- method: 'POST',
- body: JSON.stringify(account)
- }),
- updateAccount: (id: number, account: Partial<AccountInput>) => fetchWithAuth(`/accounts/${id}`, {
- method: 'PUT',
- body: JSON.stringify(account)
- }),
- deleteAccount: (id: number) => fetchWithAuth(`/accounts/${id}`, {
- method: 'DELETE'
- })
+ getAccounts: () => api.get('/accounts').then(res => res.data),
+ getAccount: (id: number) => api.get(`/accounts/${id}`).then(res => res.data),
+ createAccount: (account: AccountInput) => api.post('/accounts', account).then(res => res.data),
+ updateAccount: (id: number, account: Partial<AccountInput>) => api.put(`/accounts/${id}`, account).then(res => res.data),
+ deleteAccount: (id: number) => api.delete(`/accounts/${id}`).then(res => res.data)
};
// Transaction API
export interface Transaction {
- ID: number;
- CreatedAt: string;
- UpdatedAt: string;
- DeletedAt: string | null;
- UserID: number;
- AccountID: number | null;
- Description: string;
- Amount: number;
- Type: "Income" | "Expense";
- Date: string;
- Category: string;
+ id: number;
+ createdAt: string;
+ updatedAt: string;
+ deletedAt: string | null;
+ userID: number;
+ accountID: number | null;
+ description: string;
+ amount: number;
+ type: "Income" | "Expense";
+ date: string;
+ category: string;
}
export interface TransactionInput {
@@ -139,55 +111,54 @@ export interface TransactionFilters {
category?: string;
startDate?: string; // YYYY-MM-DD format
endDate?: string; // YYYY-MM-DD format
+ goalId?: number;
}
export const transactionApi = {
getTransactions: (filters?: TransactionFilters) => {
- let queryParams = '';
-
+ const params: Record<string, string | number | undefined> = {};
if (filters) {
- const params = new URLSearchParams();
- if (filters.type) params.append('type', filters.type);
- if (filters.accountId) params.append('account_id', filters.accountId.toString());
- if (filters.category) params.append('category', filters.category);
- if (filters.startDate) params.append('start_date', filters.startDate);
- if (filters.endDate) params.append('end_date', filters.endDate);
-
- queryParams = `?${params.toString()}`;
+ if (filters.type) params.type = filters.type;
+ if (filters.accountId) params.account_id = filters.accountId;
+ if (filters.category) params.category = filters.category;
+ if (filters.startDate) params.start_date = filters.startDate;
+ if (filters.endDate) params.end_date = filters.endDate;
+ if (filters.goalId) params.goal_id = filters.goalId;
}
-
- return fetchWithAuth(`/transactions${queryParams}`);
+ return api.get('/transactions', { params }).then(res => res.data);
},
- getTransaction: (id: number) => fetchWithAuth(`/transactions/${id}`),
+ getTransaction: (id: number) => api.get(`/transactions/${id}`).then(res => res.data),
- createTransaction: (transaction: TransactionInput) => fetchWithAuth('/transactions', {
- method: 'POST',
- body: JSON.stringify(transaction)
- }),
+ createTransaction: (transaction: TransactionInput) => api.post('/transactions', transaction).then(res => res.data),
- updateTransaction: (id: number, transaction: Partial<TransactionInput>) => fetchWithAuth(`/transactions/${id}`, {
- method: 'PUT',
- body: JSON.stringify(transaction)
- }),
+ updateTransaction: (id: number, transaction: Partial<TransactionInput>) => api.put(`/transactions/${id}`, transaction).then(res => res.data),
- deleteTransaction: (id: number) => fetchWithAuth(`/transactions/${id}`, {
- method: 'DELETE'
- })
+ deleteTransaction: (id: number) => api.delete(`/transactions/${id}`).then(res => res.data)
};
// Goal API
export interface Goal {
- ID: number;
- CreatedAt: string;
- UpdatedAt: string;
- DeletedAt: string | null;
- UserID: number;
- Name: string;
- TargetAmount: number;
- CurrentAmount: number;
- TargetDate: string | null;
- Status: "Active" | "Achieved" | "Cancelled";
+ id: number;
+ createdAt: string;
+ updatedAt: string;
+ deletedAt: string | null;
+ userID: number;
+ name: string;
+ targetAmount: number;
+ currentAmount: number;
+ targetDate: string | null;
+ status: "Active" | "Paused" | "Achieved" | "Cancelled";
+}
+
+export interface GoalProgress {
+ goal: Goal;
+ percentComplete: number;
+ amountRemaining: number;
+ daysRemaining: number;
+ requiredPerDay: number;
+ requiredPerMonth: number;
+ onTrack: boolean;
}
export interface GoalInput {
@@ -195,51 +166,54 @@ export interface GoalInput {
targetAmount: number;
currentAmount?: number;
targetDate?: string; // YYYY-MM-DD format
- status?: "Active" | "Achieved" | "Cancelled";
+ status?: "Active" | "Paused" | "Achieved" | "Cancelled";
}
export const goalApi = {
- getGoals: (status?: "Active" | "Achieved" | "Cancelled") => {
- const queryParams = status ? `?status=${status}` : '';
- return fetchWithAuth(`/goals${queryParams}`);
+ getGoals: (status?: "Active" | "Paused" | "Achieved" | "Cancelled") => {
+ const params = status ? { status } : {};
+ return api.get('/goals', { params }).then(res => res.data);
},
- getGoal: (id: number) => fetchWithAuth(`/goals/${id}`),
+ getGoal: (id: number) => api.get(`/goals/${id}`).then(res => res.data),
+
+ createGoal: (goal: GoalInput) => api.post('/goals', goal).then(res => res.data),
- createGoal: (goal: GoalInput) => fetchWithAuth('/goals', {
- method: 'POST',
- body: JSON.stringify(goal)
- }),
+ updateGoal: (id: number, goal: Partial<GoalInput>) => api.put(`/goals/${id}`, goal).then(res => res.data),
- updateGoal: (id: number, goal: Partial<GoalInput>) => fetchWithAuth(`/goals/${id}`, {
- method: 'PUT',
- body: JSON.stringify(goal)
- }),
+ updateGoalProgress: (id: number, currentAmount: number) =>
+ api.patch(`/goals/${id}/progress`, { currentAmount }).then(res => res.data),
- updateGoalProgress: (id: number, currentAmount: number) => fetchWithAuth(`/goals/${id}/progress`, {
- method: 'PATCH',
- body: JSON.stringify({ currentAmount })
- }),
+ deleteGoal: (id: number) => api.delete(`/goals/${id}`).then(res => res.data),
- deleteGoal: (id: number) => fetchWithAuth(`/goals/${id}`, {
- method: 'DELETE'
- })
+ // New goal progress tracking endpoints
+ getGoalProgress: (id: number) => api.get(`/goals/${id}/progress`).then(res => res.data),
+
+ getAllGoalsProgress: (status?: string) => {
+ const params = status ? { status } : {};
+ return api.get('/goals/progress/all', { params }).then(res => res.data);
+ },
+
+ linkTransactionToGoal: (goalId: number, transactionId: number) =>
+ api.post(`/goals/${goalId}/link-transaction`, { transactionId }).then(res => res.data),
+
+ recalculateGoalProgress: (id: number) => api.post(`/goals/${id}/recalculate`).then(res => res.data)
};
// 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;
+ 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 {
@@ -253,22 +227,14 @@ export interface LoanInput {
}
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'
- })
+ getLoans: () => api.get('/loans').then(res => res.data),
+ getLoan: (id: number) => api.get(`/loans/${id}`).then(res => res.data),
+ createLoan: (loan: LoanInput) => api.post('/loans', loan).then(res => res.data),
+ updateLoan: (id: number, loan: Partial<LoanInput>) => api.put(`/loans/${id}`, loan).then(res => res.data),
+ deleteLoan: (id: number) => api.delete(`/loans/${id}`).then(res => res.data)
};
// User API
export const userApi = {
- getProfile: () => fetchWithAuth('/users/me')
+ getProfile: () => api.get('/users/me').then(res => res.data)
}; \ No newline at end of file