312 lines
8.5 KiB
JavaScript
312 lines
8.5 KiB
JavaScript
/**
|
|
* 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 = `
|
|
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
`;
|
|
|
|
$(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';
|
|
}
|
|
});
|