Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,236 changes: 5,236 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-tooltip": "^1.1.6",
"axios": "^1.7.7",
"caniuse-lite": "^1.0.30001639",
"chart.js": "^4.2.1",
"class-variance-authority": "^0.7.1",
Expand Down
12 changes: 0 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 8 additions & 13 deletions src/core/services/authService.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import {AuthenticationResponse, LoginRequest, RegistrationRequest} from "@/core/types/authentication.ts";
import axiosInstance from './httpService.ts';
import fetchClient from "./httpService.ts";

const baseURL = '/auth';

async function signup(payload: RegistrationRequest): Promise<AuthenticationResponse> {
const response = await axiosInstance.post(`${baseURL}/register`, payload);
return response.data;
export async function signup(payload: RegistrationRequest): Promise<AuthenticationResponse> {
return await fetchClient.post(`${baseURL}/register`, payload);
}

async function signin(data: LoginRequest): Promise<AuthenticationResponse> {
const response = await axiosInstance.post(`${baseURL}/login`, data);
return response.data;
export async function signin(data: LoginRequest): Promise<AuthenticationResponse> {
return await fetchClient.post(`${baseURL}/login`, data);
}

async function sendGeneratedPasswordEmail(email: string): Promise<void> {
const response = await axiosInstance.post(`${baseURL}/forget-password`, {email});
return response.data;
}

export {signin, signup, sendGeneratedPasswordEmail}
export async function sendGeneratedPasswordEmail(email: string): Promise<void> {
return await fetchClient.post(`${baseURL}/forget-password`, { email });
}
21 changes: 10 additions & 11 deletions src/core/services/holidayService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axiosInstance from "./httpService";
import fetchClient from "./httpService";
import {
FetchedPublicHoliday,
HolidayOverviewResponse,
Expand All @@ -9,23 +9,22 @@ import {
const baseURL = '/holidays';

export async function getHolidaysOverview(): Promise<HolidayOverviewResponse[]> {
const response = await axiosInstance.get(baseURL)
return response.data;
return await fetchClient.get(baseURL);
}

export async function getHolidays(year: number, countryCode: string): Promise<HolidayResponse[]> {
const response = await axiosInstance.get(`${baseURL}/${countryCode}/${year}`)
return response.data;
return await fetchClient.get(`${baseURL}/${countryCode}/${year}`);
}

export async function fetchHolidays(year: number, countryCode: string): Promise<FetchedPublicHoliday[]> {
const response = await axiosInstance.get(`${baseURL}/fetch`, {
params: {year, countryCode}
})
return response.data;
const queryParams = new URLSearchParams({
year: year.toString(),
countryCode
}).toString();

return await fetchClient.get(`${baseURL}/fetch?${queryParams}`);
}

export async function createHolidays(payload: HolidaysCreateRequest[]): Promise<HolidayResponse> {
const response = await axiosInstance.post(`${baseURL}/batch`, payload);
return response.data;
return await fetchClient.post(`${baseURL}/batch`, payload);
}
114 changes: 83 additions & 31 deletions src/core/services/httpService.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,93 @@
import axios from 'axios';

// Function to get the access token
function getAccessToken(): string | null {
return localStorage.getItem("ACCESS_TOKEN");
}

// Create an Axios instance
const axiosInstance = axios.create({
baseURL: '/api',
headers: {
const BASE_URL = '/api';

function createHeaders(): HeadersInit {
const headers: HeadersInit = {
'Content-Type': 'application/json',
},
});

// Add a request interceptor to include the Authorization header
axiosInstance.interceptors.request.use(
(request) => {
const token = getAccessToken();
if (token) {
request.headers['Authorization'] = `Bearer ${token}`;
};

const token = getAccessToken();
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}

return headers;
}

// Custom fetch function with built-in error handling
async function customFetch(url: string, options: RequestInit = {}): Promise<any> {
const fullUrl = `${BASE_URL}/${url}`;

// Set up request with headers
const requestOptions: RequestInit = {
...options,
headers: {
...createHeaders(),
...options.headers,
},
};

try {
const response = await fetch(fullUrl, requestOptions);

// Handle unauthorized responses
if (response.status === 403) {
const UNAUTHORIZED_PATHS = ['/signin', '/signup'];
if (!UNAUTHORIZED_PATHS.includes(window.location.pathname)) {
localStorage.removeItem('ACCESS_TOKEN');
window.location.href = '/signin';
throw new Error('Unauthorized access');
}
}
return request;
},
(error) => Promise.reject(error)
);

// Add a response interceptor to handle responses and errors globally
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
const UNAUTHORIZED_PATHS = ['/signin', '/signup'];
if (error.response?.status === 403 && !UNAUTHORIZED_PATHS.includes(window.location.pathname)) {
localStorage.removeItem('ACCESS_TOKEN');
window.location.href = '/signin';

// Check if the response is ok (status in the range 200-299)
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

// Check content type to determine parsing method
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
return Promise.reject(error);
}
);
}

// Create HTTP method wrappers
const fetchClient = {
get: (url: string, options: RequestInit = {}) =>
customFetch(url, { ...options, method: 'GET' }),

post: (url: string, data: any, options: RequestInit = {}) =>
customFetch(url, {
...options,
method: 'POST',
body: JSON.stringify(data),
}),

put: (url: string, data: any, options: RequestInit = {}) =>
customFetch(url, {
...options,
method: 'PUT',
body: JSON.stringify(data),
}),

delete: (url: string, options: RequestInit = {}) =>
customFetch(url, { ...options, method: 'DELETE' }),

patch: (url: string, data: any, options: RequestInit = {}) =>
customFetch(url, {
...options,
method: 'PATCH',
body: JSON.stringify(data),
}),
};

export default axiosInstance;
export default fetchClient;
97 changes: 37 additions & 60 deletions src/core/services/leaveService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axiosInstance from "@/core/services/httpService.ts";
import fetchClient from "@/core/services/httpService.ts";
import {
GetLeavesFilter,
LeaveCheckRequest,
Expand All @@ -18,90 +18,67 @@ import {PagedResponse} from "@/core/types/common.ts";

const baseURL = '/leaves';

async function getLeaves(filter: GetLeavesFilter = {}, pageNumber: number = 0): Promise<PagedResponse<LeaveResponse>> {
const response = await axiosInstance.get(baseURL, {
params: {...filter, pageNumber}
});
return response.data;
}
export async function getLeaves(filter: GetLeavesFilter = {}, pageNumber: number = 0): Promise<PagedResponse<LeaveResponse>> {
const queryObject: Record<string, string> = {
pageNumber: pageNumber.toString(),
...(filter.teamId !== undefined ? { teamId: filter.teamId.toString() } : {}),
...(filter.userId !== undefined ? { userId: filter.userId.toString() } : {}),
...(filter.status !== undefined ? { status: filter.status } : {}),
};

const queryParams = new URLSearchParams(queryObject).toString();

async function getLeavesBalance(userId: number | null = null): Promise<UserLeaveBalanceResponse[]> {
const response = await axiosInstance.get(`${baseURL}/${userId ? userId : 'mine'}/balance`);
return response.data;
return await fetchClient.get(`${baseURL}?${queryParams}`);
}

async function updateLeavesStatus(payload: LeaveUpdateRequest, id: number): Promise<LeaveResponse> {
const response = await axiosInstance.put(`${baseURL}/${id}`, payload);
return response.data;
export async function getLeavesBalance(userId: number | null = null): Promise<UserLeaveBalanceResponse[]> {
return await fetchClient.get(`${baseURL}/${userId ? userId : 'mine'}/balance`);
}

async function createLeave(payload: LeaveCreateRequest): Promise<LeaveResponse> {
const response = await axiosInstance.post(baseURL, payload);
return response.data;
export async function updateLeavesStatus(payload: LeaveUpdateRequest, id: number): Promise<LeaveResponse> {
return await fetchClient.put(`${baseURL}/${id}`, payload);
}

async function getLeavesPolicies(): Promise<LeavePolicyResponse[]> {
const response = await axiosInstance.get(`${baseURL}/policies`);
return response.data;
export async function createLeave(payload: LeaveCreateRequest): Promise<LeaveResponse> {
return await fetchClient.post(baseURL, payload);
}

async function getLeavesPolicy(id: number): Promise<LeavePolicyResponse> {
const response = await axiosInstance.get(`${baseURL}/policies/${id}`);
return response.data;
export async function getLeavesPolicies(): Promise<LeavePolicyResponse[]> {
return await fetchClient.get(`${baseURL}/policies`);
}

async function createLeavesPolicy(payload: LeavePolicyCreateRequest): Promise<LeavePolicyResponse> {
const response = await axiosInstance.post(`${baseURL}/policies`, payload);
return response.data;
export async function getLeavesPolicy(id: number): Promise<LeavePolicyResponse> {
return await fetchClient.get(`${baseURL}/policies/${id}`);
}

async function deleteLeavePolicy(id: number) {
const response = await axiosInstance.delete(`${baseURL}/policies/${id}`);
return response.data;
export async function createLeavesPolicy(payload: LeavePolicyCreateRequest): Promise<LeavePolicyResponse> {
return await fetchClient.post(`${baseURL}/policies`, payload);
}

async function updateLeavePolicy(payload: LeavePolicyUpdateRequest, id: number): Promise<LeavePolicyResponse> {
const response = await axiosInstance.put(`${baseURL}/policies/${id}`, payload);
return response.data;
export async function deleteLeavePolicy(id: number) {
return await fetchClient.delete(`${baseURL}/policies/${id}`);
}

async function getLeavesTypes(): Promise<LeaveTypeResponse[]> {
const response = await axiosInstance.get(`${baseURL}/types`);
return response.data;
export async function updateLeavePolicy(payload: LeavePolicyUpdateRequest, id: number): Promise<LeavePolicyResponse> {
return await fetchClient.put(`${baseURL}/policies/${id}`, payload);
}

async function deleteLeaveType(id: number) {
const response = await axiosInstance.delete(`${baseURL}/types/${id}`);
return response.data;
export async function getLeavesTypes(): Promise<LeaveTypeResponse[]> {
return await fetchClient.get(`${baseURL}/types`);
}

async function updateLeaveType(payload: LeaveTypeUpdateRequest, id: number): Promise<LeaveTypeResponse> {
const response = await axiosInstance.put(`${baseURL}/types/${id}`, payload);
return response.data;
export async function deleteLeaveType(id: number) {
return await fetchClient.delete(`${baseURL}/types/${id}`);
}

async function createLeavesType(payload: LeaveTypeCreateRequest): Promise<LeaveTypeResponse> {
const response = await axiosInstance.post(`${baseURL}/types`, payload);
return response.data;
export async function updateLeaveType(payload: LeaveTypeUpdateRequest, id: number): Promise<LeaveTypeResponse> {
return await fetchClient.put(`${baseURL}/types/${id}`, payload);
}

export async function createLeavesCheck(payload: LeaveCheckRequest): Promise<LeaveCheckResponse> {
const response = await axiosInstance.post(`${baseURL}/check`, payload);
return response.data;
export async function createLeavesType(payload: LeaveTypeCreateRequest): Promise<LeaveTypeResponse> {
return await fetchClient.post(`${baseURL}/types`, payload);
}

export {
getLeaves,
updateLeavesStatus,
createLeave,
getLeavesPolicies,
createLeavesPolicy,
updateLeavePolicy,
deleteLeavePolicy,
getLeavesBalance,
getLeavesTypes,
deleteLeaveType,
updateLeaveType,
createLeavesType,
getLeavesPolicy
export async function createLeavesCheck(payload: LeaveCheckRequest): Promise<LeaveCheckResponse> {
return await fetchClient.post(`${baseURL}/check`, payload);
}
Loading