// Employee CRUD operations
let currentPage = 1;
let itemsPerPage = 20;
let allEmployees = [];
let employeesCollectionName = 'Employee_Records';
let currentView = localStorage.getItem('employeesView') || 'table'; // 'table' or 'card'
// Common employee field names that we'll display (matching PocketBase schema)
const standardFields = ['First_Name', 'Last_Name', 'Email_Address', 'Phone_Number', 'Voxer_ID', 'Status'];
/**
* Load all employees with optional search filter
*/
async function loadEmployees(page = 1) {
try {
// Show loading state based on current view
if (currentView === 'table') {
const tbody = document.getElementById('employeesTableBody');
if (tbody) {
tbody.innerHTML = '
`;
}).join('');
}
/**
* Display pagination controls
*/
function displayPagination(currentPage, totalPages, totalItems) {
const container = document.getElementById('paginationContainer');
if (!container) return;
if (totalPages <= 1) {
container.innerHTML = '';
return;
}
let html = '
';
// Previous button
if (currentPage > 1) {
html += ``;
}
// Page info
html += `Page ${currentPage} of ${totalPages} (${totalItems} total)`;
// Next button
if (currentPage < totalPages) {
html += ``;
}
html += '
';
container.innerHTML = html;
}
/**
* Load employee for editing
*/
async function loadEmployeeForEdit(employeeId) {
try {
if (!employeeId) {
showMessage('No employee ID provided', 'error');
return null;
}
const employee = await pb.collection(employeesCollectionName).getOne(employeeId);
// Set current employee ID for reports
window.currentEmployeeId = employeeId;
// Update modal header
if (typeof updateEmployeeModalInfo === 'function') {
updateEmployeeModalInfo(employee);
}
// Show reports tab for existing employees - do this after a short delay to ensure DOM is ready
setTimeout(() => {
const reportsTabButton = document.getElementById('tab-reports');
if (reportsTabButton) {
reportsTabButton.classList.remove('hidden');
}
}, 50);
// Populate standard form fields using correct field names
const firstNameField = document.getElementById('First_Name');
if (firstNameField) firstNameField.value = employee.First_Name || '';
const lastNameField = document.getElementById('Last_Name');
if (lastNameField) lastNameField.value = employee.Last_Name || '';
const emailField = document.getElementById('Email_Address');
if (emailField) emailField.value = employee.Email_Address || '';
const phoneField = document.getElementById('Phone_Number');
if (phoneField) phoneField.value = employee.Phone_Number || '';
const voxerField = document.getElementById('Voxer_ID');
if (voxerField) voxerField.value = employee.Voxer_ID || '';
const statusField = document.getElementById('Status');
if (statusField) statusField.value = employee.Status || '';
// Handle additional fields dynamically
const additionalFieldsContainer = document.getElementById('additionalFieldsContainer');
if (additionalFieldsContainer) {
additionalFieldsContainer.innerHTML = '';
// Get all fields from the employee record
const allFields = Object.keys(employee);
const systemFields = new Set(['id', 'created', 'updated', 'collectionId', 'collectionName']);
// Add any fields that aren't in the standard fields
allFields.forEach(field => {
// Skip system fields
if (systemFields.has(field) || field.startsWith('@')) {
return;
}
// Skip standard fields (already handled above)
if (standardFields.includes(field)) {
return;
}
// Create input for this additional field
if (employee[field] !== undefined) {
const fieldLabel = field.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
const fieldId = `field_${field}`;
const fieldDiv = document.createElement('div');
fieldDiv.innerHTML = `
`;
additionalFieldsContainer.appendChild(fieldDiv.firstElementChild);
}
});
}
return employee;
} catch (error) {
console.error('Error loading employee:', error);
showMessage('Error loading employee: ' + (error.message || 'Unknown error'), 'error');
return null;
}
}
/**
* Escape HTML to prevent XSS
*/
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
/**
* Save employee (create or update)
*/
async function saveEmployee() {
try {
const form = document.getElementById('employeeForm');
if (!form) {
showMessage('Form not found', 'error');
return;
}
const formData = new FormData(form);
const employeeId = document.getElementById('employeeId')?.value;
// Build employee object
const employeeData = {};
// Get all form fields from FormData (this includes standard fields)
for (const [key, value] of formData.entries()) {
if (key === 'id') continue;
// Include the value (even if empty for standard fields to allow clearing)
if (value !== null && value !== undefined) {
employeeData[key] = value.trim();
}
}
// Also get additional fields from dynamically created inputs
const additionalFields = document.querySelectorAll('#additionalFieldsContainer input');
additionalFields.forEach(input => {
if (input.name && input.value !== null && input.value !== undefined) {
employeeData[input.name] = input.value.trim();
}
});
if (employeeId) {
// Update existing employee
const updatedEmployee = await pb.collection(employeesCollectionName).update(employeeId, employeeData);
const employeeName = `${updatedEmployee.First_Name || ''} ${updatedEmployee.Last_Name || ''}`.trim() || 'Employee';
showMessage(`${employeeName} updated successfully`, 'success');
} else {
// Create new employee
const newEmployee = await pb.collection(employeesCollectionName).create(employeeData);
const employeeName = `${newEmployee.First_Name || ''} ${newEmployee.Last_Name || ''}`.trim() || 'Employee';
showMessage(`${employeeName} created successfully`, 'success');
}
if (typeof closeEmployeeModal === 'function') {
closeEmployeeModal();
}
loadEmployees(currentPage);
} catch (error) {
console.error('Error saving employee:', error);
const errorMsg = error.message || 'Unknown error';
showMessage('Error saving employee: ' + errorMsg, 'error');
}
}
/**
* Delete employee
*/
async function deleteEmployee(employeeId) {
// Find the employee name for the confirmation message
const employee = allEmployees.find(emp => emp.id === employeeId);
const employeeName = employee
? `${employee.First_Name || ''} ${employee.Last_Name || ''}`.trim() || 'this employee'
: 'this employee';
if (!confirm(`Are you sure you want to delete ${employeeName}? This action cannot be undone.`)) {
return;
}
try {
await pb.collection(employeesCollectionName).delete(employeeId);
showMessage(`Employee ${employeeName} deleted successfully`, 'success');
// Reload employees with current view state
loadEmployees(currentPage);
} catch (error) {
console.error('Error deleting employee:', error);
showMessage('Error deleting employee: ' + (error.message || 'Unknown error'), 'error');
}
}
/**
* Show message to user
*/
function showMessage(message, type = 'success') {
const container = document.getElementById('messageContainer');
if (!container) return;
const bgColor = type === 'success' ? 'bg-green-50 border-green-200 text-green-700' : 'bg-red-50 border-red-200 text-red-700';
container.innerHTML = `
${message}
`;
// Auto-hide after 5 seconds
setTimeout(() => {
container.innerHTML = '';
}, 5000);
}
/**
* Switch between table and card view
*/
function switchView(view) {
currentView = view;
localStorage.setItem('employeesView', view);
updateViewDisplay();
displayEmployees(allEmployees);
}
/**
* Update view display based on current view preference
*/
function updateViewDisplay() {
const tableView = document.getElementById('tableView');
const cardView = document.getElementById('cardView');
const tableViewBtn = document.getElementById('tableViewBtn');
const cardViewBtn = document.getElementById('cardViewBtn');
if (currentView === 'table') {
// Show table, hide card
if (tableView) tableView.classList.remove('hidden');
if (cardView) cardView.classList.add('hidden');
// Table button: active (indigo with shadow)
if (tableViewBtn) {
tableViewBtn.classList.remove('text-gray-700', 'hover:bg-white/40');
tableViewBtn.classList.add('bg-indigo-600/90', 'text-white', 'shadow-lg', 'hover:bg-indigo-700/90');
}
// Card button: inactive (transparent)
if (cardViewBtn) {
cardViewBtn.classList.remove('bg-indigo-600/90', 'text-white', 'shadow-lg', 'hover:bg-indigo-700/90');
cardViewBtn.classList.add('text-gray-700', 'hover:bg-white/40');
}
} else {
// Show card, hide table
if (tableView) tableView.classList.add('hidden');
if (cardView) cardView.classList.remove('hidden');
// Table button: inactive (transparent)
if (tableViewBtn) {
tableViewBtn.classList.remove('bg-indigo-600/90', 'text-white', 'shadow-lg', 'hover:bg-indigo-700/90');
tableViewBtn.classList.add('text-gray-700', 'hover:bg-white/40');
}
// Card button: active (indigo with shadow)
if (cardViewBtn) {
cardViewBtn.classList.remove('text-gray-700', 'hover:bg-white/40');
cardViewBtn.classList.add('bg-indigo-600/90', 'text-white', 'shadow-lg', 'hover:bg-indigo-700/90');
}
}
}
/**
* Switch employee modal tab
*/
function switchEmployeeTab(tabName) {
// Hide all tab contents
document.querySelectorAll('.employee-tab-content').forEach(tab => {
tab.classList.add('hidden');
});
// Remove active state from all tabs
document.querySelectorAll('.employee-tab').forEach(btn => {
btn.classList.remove('border-indigo-500', 'text-indigo-600');
btn.classList.add('border-transparent', 'text-gray-500');
});
// Show selected tab content
const selectedTab = document.getElementById(`employee-tab-${tabName}`);
if (selectedTab) {
selectedTab.classList.remove('hidden');
}
// Activate selected tab button
const selectedButton = document.getElementById(`tab-${tabName}`);
if (selectedButton) {
selectedButton.classList.add('border-indigo-500', 'text-indigo-600');
selectedButton.classList.remove('border-transparent', 'text-gray-500');
}
// Load reports if reports tab is selected
if (tabName === 'reports' && window.currentEmployeeId && typeof loadEmployeeReports === 'function') {
setTimeout(() => {
loadEmployeeReports(window.currentEmployeeId);
}, 100);
}
}
/**
* Update employee modal header info
*/
function updateEmployeeModalInfo(employee) {
const firstName = employee.First_Name || '';
const lastName = employee.Last_Name || '';
const fullName = `${firstName} ${lastName}`.trim() || 'Employee';
document.getElementById('employeeModalTitle').textContent = fullName;
}
// Make functions globally accessible
window.loadEmployees = loadEmployees;
window.loadEmployeeForEdit = loadEmployeeForEdit;
window.saveEmployee = saveEmployee;
window.deleteEmployee = deleteEmployee;
window.switchView = switchView;
window.updateViewDisplay = updateViewDisplay;
window.switchEmployeeTab = switchEmployeeTab;