(Feat): Initial Commit

This commit is contained in:
2025-11-27 22:50:08 +00:00
commit 00f9ed128b
79 changed files with 17413 additions and 0 deletions

207
src/services/api.ts Normal file
View File

@@ -0,0 +1,207 @@
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api';
class ApiService {
private baseURL: string;
constructor(baseURL: string) {
this.baseURL = baseURL;
}
private getToken(): string | null {
return localStorage.getItem('token');
}
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const token = this.getToken();
const headers: HeadersInit = {
'Content-Type': 'application/json',
...options.headers,
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(`${this.baseURL}${endpoint}`, {
...options,
headers,
});
if (response.status === 401) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/';
throw new Error('Unauthorized');
}
if (!response.ok) {
const error = await response.json().catch(() => ({ error: 'Request failed' }));
throw new Error(error.error || 'Request failed');
}
return response.json();
}
// Auth
async login(username: string, password: string) {
return this.request<{ token: string; user: any }>('/auth/login', {
method: 'POST',
body: JSON.stringify({ username, password }),
});
}
async getMe() {
return this.request<any>('/auth/me');
}
async changePassword(currentPassword: string, newPassword: string) {
return this.request<{ message: string }>('/auth/change-password', {
method: 'POST',
body: JSON.stringify({ currentPassword, newPassword }),
});
}
// Users
async getUsers(params?: { role?: string; departmentId?: number }) {
const query = new URLSearchParams(params as any).toString();
return this.request<any[]>(`/users${query ? `?${query}` : ''}`);
}
async getUser(id: number) {
return this.request<any>(`/users/${id}`);
}
async createUser(data: any) {
return this.request<any>('/users', {
method: 'POST',
body: JSON.stringify(data),
});
}
async updateUser(id: number, data: any) {
return this.request<any>(`/users/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async deleteUser(id: number) {
return this.request<{ message: string }>(`/users/${id}`, {
method: 'DELETE',
});
}
// Departments
async getDepartments() {
return this.request<any[]>('/departments');
}
async getDepartment(id: number) {
return this.request<any>(`/departments/${id}`);
}
async getSubDepartments(departmentId: number) {
return this.request<any[]>(`/departments/${departmentId}/sub-departments`);
}
async createDepartment(name: string) {
return this.request<any>('/departments', {
method: 'POST',
body: JSON.stringify({ name }),
});
}
// Work Allocations
async getWorkAllocations(params?: { employeeId?: number; status?: string; departmentId?: number }) {
const query = new URLSearchParams(params as any).toString();
return this.request<any[]>(`/work-allocations${query ? `?${query}` : ''}`);
}
async getWorkAllocation(id: number) {
return this.request<any>(`/work-allocations/${id}`);
}
async createWorkAllocation(data: any) {
return this.request<any>('/work-allocations', {
method: 'POST',
body: JSON.stringify(data),
});
}
async updateWorkAllocationStatus(id: number, status: string, completionDate?: string) {
return this.request<any>(`/work-allocations/${id}/status`, {
method: 'PUT',
body: JSON.stringify({ status, completionDate }),
});
}
async deleteWorkAllocation(id: number) {
return this.request<{ message: string }>(`/work-allocations/${id}`, {
method: 'DELETE',
});
}
// Attendance
async getAttendance(params?: { employeeId?: number; startDate?: string; endDate?: string; status?: string }) {
const query = new URLSearchParams(params as any).toString();
return this.request<any[]>(`/attendance${query ? `?${query}` : ''}`);
}
async checkIn(employeeId: number, workDate: string) {
return this.request<any>('/attendance/check-in', {
method: 'POST',
body: JSON.stringify({ employeeId, workDate }),
});
}
async checkOut(employeeId: number, workDate: string) {
return this.request<any>('/attendance/check-out', {
method: 'POST',
body: JSON.stringify({ employeeId, workDate }),
});
}
async getAttendanceSummary(params?: { startDate?: string; endDate?: string; departmentId?: number }) {
const query = new URLSearchParams(params as any).toString();
return this.request<any[]>(`/attendance/summary/stats${query ? `?${query}` : ''}`);
}
// Contractor Rates
async getContractorRates(params?: { contractorId?: number; subDepartmentId?: number }) {
const query = params ? new URLSearchParams(params as any).toString() : '';
return this.request<any[]>(`/contractor-rates${query ? `?${query}` : ''}`);
}
async getCurrentRate(contractorId: number, subDepartmentId?: number) {
const query = subDepartmentId ? `?subDepartmentId=${subDepartmentId}` : '';
return this.request<any>(`/contractor-rates/contractor/${contractorId}/current${query}`);
}
async setContractorRate(data: {
contractorId: number;
subDepartmentId?: number;
activity?: string;
rate: number;
effectiveDate: string
}) {
return this.request<any>('/contractor-rates', {
method: 'POST',
body: JSON.stringify(data),
});
}
async updateContractorRate(id: number, data: { rate?: number; activity?: string; effectiveDate?: string }) {
return this.request<any>(`/contractor-rates/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async deleteContractorRate(id: number) {
return this.request<{ message: string }>(`/contractor-rates/${id}`, {
method: 'DELETE',
});
}
}
export const api = new ApiService(API_BASE_URL);