/** * AJAX Helper for AbsensiKu Application * This file contains helper functions for making AJAX requests to the API */ class AjaxHelper { constructor() { this.baseUrl = '/api'; this.token = localStorage.getItem('auth_token'); this.setupDefaults(); } setupDefaults() { // Setup CSRF token and default headers $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), 'Authorization': this.token ? `Bearer ${this.token}` : '', 'Accept': 'application/json', 'Content-Type': 'application/json' } }); } updateToken(token) { this.token = token; localStorage.setItem('auth_token', token); this.setupDefaults(); } clearToken() { this.token = null; localStorage.removeItem('auth_token'); localStorage.removeItem('user_data'); } // Generic AJAX request method async request(method, endpoint, data = null, options = {}) { const config = { url: `${this.baseUrl}${endpoint}`, type: method, ...options }; if (data) { if (method === 'GET') { config.data = data; } else { config.data = JSON.stringify(data); } } try { const response = await $.ajax(config); return { success: true, data: response }; } catch (xhr) { const error = xhr.responseJSON || { message: 'Network error occurred' }; // Handle unauthorized access if (xhr.status === 401) { this.clearToken(); window.location.href = '/login'; return; } return { success: false, error: error, status: xhr.status }; } } // Convenience methods async get(endpoint, params = null) { return this.request('GET', endpoint, params); } async post(endpoint, data) { return this.request('POST', endpoint, data); } async put(endpoint, data) { return this.request('PUT', endpoint, data); } async delete(endpoint) { return this.request('DELETE', endpoint); } // File upload method async uploadFile(endpoint, formData) { const config = { headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), 'Authorization': this.token ? `Bearer ${this.token}` : '', }, processData: false, contentType: false }; return this.request('POST', endpoint, formData, config); } // Authentication methods async login(credentials) { const result = await this.request('POST', '/login', credentials); if (result.success && result.data.data?.token) { this.updateToken(result.data.data.token); localStorage.setItem('user_data', JSON.stringify(result.data.data)); } return result; } async logout() { const result = await this.request('POST', '/logout'); this.clearToken(); return result; } async getProfile() { return this.get('/profile'); } // Admin API methods async getUsers(params = {}) { return this.get('/admin/users', params); } async createUser(userData) { return this.post('/admin/users', userData); } async updateUser(id, userData) { return this.put(`/admin/users/${id}`, userData); } async deleteUser(id) { return this.delete(`/admin/users/${id}`); } async getAttendances(params = {}) { return this.get('/admin/attendances', params); } async approveAttendance(id) { return this.put(`/admin/attendances/${id}/approve`); } async getPermissions(params = {}) { return this.get('/admin/permissions', params); } async approvePermission(id) { return this.put(`/admin/permissions/${id}/approve`); } async getLocations(params = {}) { return this.get('/admin/locations', params); } async createLocation(locationData) { return this.post('/admin/locations', locationData); } async updateLocation(id, locationData) { return this.put(`/admin/locations/${id}`, locationData); } async deleteLocation(id) { return this.delete(`/admin/locations/${id}`); } async getAttendanceReport(params = {}) { return this.get('/admin/reports/attendance', params); } async getPermissionReport(params = {}) { return this.get('/admin/reports/permission', params); } async getDashboardStats() { return this.get('/admin/reports/dashboard'); } // Employee API methods async submitAttendance(attendanceData) { return this.post('/employee/attendance', attendanceData); } async getAttendanceHistory(params = {}) { return this.get('/employee/attendance/history', params); } async getTodayAttendanceStatus() { return this.get('/employee/attendance/today-status'); } async submitPermission(permissionData) { return this.post('/employee/permission', permissionData); } async getPermissionHistory(params = {}) { return this.get('/employee/permission/history', params); } async cancelPermission(id) { return this.put(`/employee/permission/${id}/cancel`); } async updateProfile(profileData) { return this.put('/employee/profile', profileData); } async changePassword(passwordData) { return this.put('/employee/password', passwordData); } async uploadProfilePhoto(formData) { return this.uploadFile('/employee/profile/photo', formData); } } // Utility functions for UI interactions class UIHelper { static showAlert(container, type, message, autoHide = true) { const alertHtml = ` `; $(container).html(alertHtml); if (autoHide) { setTimeout(() => { $('.alert').fadeOut('slow'); }, 5000); } } static showValidationErrors(errors, formSelector = '') { Object.keys(errors).forEach(field => { const input = $(`${formSelector} [name="${field}"]`); const errorContainer = input.siblings('.invalid-feedback'); input.addClass('is-invalid'); errorContainer.text(errors[field][0]).show(); }); } static clearErrors(formSelector = '') { $(`${formSelector} .form-control`).removeClass('is-invalid'); $(`${formSelector} .invalid-feedback`).hide().text(''); } static setButtonLoading(button, loading = true, loadingText = 'Loading...') { const btn = $(button); const spinner = btn.find('.spinner-border'); const btnText = btn.find('.btn-text'); if (loading) { btn.prop('disabled', true); spinner.removeClass('d-none'); btnText.text(loadingText); } else { btn.prop('disabled', false); spinner.addClass('d-none'); btnText.text(btn.data('original-text') || 'Submit'); } } static formatDate(dateString) { return new Date(dateString).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' }); } static formatDateTime(dateString) { return new Date(dateString).toLocaleString('id-ID', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } } // Initialize global instances const api = new AjaxHelper(); const ui = UIHelper; // Check authentication on page load $(document).ready(function() { const token = localStorage.getItem('auth_token'); const currentPath = window.location.pathname; // Redirect to login if no token and not already on login page if (!token && currentPath !== '/login') { window.location.href = '/login'; } // Redirect to dashboard if token exists and on login page if (token && currentPath === '/login') { window.location.href = '/dashboard'; } });