Files
delphi-database/static/js/customers-tailwind.js
2025-08-11 21:58:25 -05:00

699 lines
34 KiB
JavaScript

// Customer management functionality - Tailwind version
let currentPage = 0;
let currentSearch = '';
let isEditing = false;
let editingCustomerId = null;
// Enhanced table display function
function displayCustomers(customers) {
const tbody = document.getElementById('customersTableBody');
const emptyState = document.getElementById('emptyState');
tbody.innerHTML = '';
if (!customers || customers.length === 0) {
emptyState.classList.remove('hidden');
return;
}
emptyState.classList.add('hidden');
customers.forEach(customer => {
const row = document.createElement('tr');
row.className = 'group border-b border-neutral-100 dark:border-neutral-700/50 hover:bg-gradient-to-r hover:from-blue-50/30 hover:to-indigo-50/30 dark:hover:from-blue-900/10 dark:hover:to-indigo-900/10 transition-all duration-200';
// Store customer ID as data attribute to avoid escaping issues in onclick
row.dataset.customerId = customer.id;
// Build clean, simple row structure with clickable rows (no inline onclick to avoid backslash issues)
row.innerHTML = `
<td class="px-4 py-4 cursor-pointer customer-cell">
<div class="text-sm font-mono font-semibold text-neutral-900 dark:text-neutral-100 bg-gradient-to-br from-neutral-50 to-neutral-100 dark:from-neutral-800 dark:to-neutral-700 px-3 py-2 rounded-lg shadow-sm border border-neutral-200/50 dark:border-neutral-600/50 group-hover:shadow-md transition-shadow">
${escapeHtml(customer.id || '')}
</div>
</td>
<td class="px-4 py-4 cursor-pointer customer-cell">
<div class="text-sm font-semibold text-neutral-900 dark:text-neutral-100 group-hover:text-blue-700 dark:group-hover:text-blue-300 transition-colors">
${escapeHtml(formatFullName(customer))}
</div>
${customer.title ? `<div class="text-xs text-neutral-500 dark:text-neutral-400 mt-1 font-medium">${escapeHtml(customer.title)}</div>` : ''}
</td>
<td class="px-4 py-4 cursor-pointer customer-cell">
${customer.group ? `<span class="inline-flex items-center px-3 py-1.5 rounded-lg text-xs font-bold bg-gradient-to-r from-blue-50 to-blue-100 dark:from-blue-900/40 dark:to-blue-800/40 text-blue-800 dark:text-blue-200 border border-blue-200/70 dark:border-blue-700/70 shadow-sm">${escapeHtml(customer.group)}</span>` : '<span class="text-neutral-400 text-sm font-medium">-</span>'}
</td>
<td class="px-4 py-4 cursor-pointer customer-cell">
<div class="text-sm font-medium text-neutral-900 dark:text-neutral-100">
${escapeHtml(formatCityState(customer))}
</div>
${customer.a1 ? `<div class="text-xs text-neutral-500 dark:text-neutral-400 mt-1 truncate max-w-xs font-medium">${escapeHtml(customer.a1)}</div>` : ''}
</td>
<td class="px-4 py-4 cursor-pointer customer-cell">
<div class="text-sm font-mono font-medium text-neutral-900 dark:text-neutral-100">
${formatPrimaryPhone(customer.phone_numbers || [])}
</div>
</td>
<td class="px-4 py-4 cursor-pointer customer-cell">
${customer.email ? `<a href="mailto:${encodeURIComponent(customer.email)}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-200 text-sm font-medium transition-colors underline decoration-blue-300/50 hover:decoration-blue-500" onclick="event.stopPropagation()">${escapeHtml(customer.email)}</a>` : '<span class="text-neutral-400 text-sm font-medium">-</span>'}
</td>
<td class="px-4 py-4 text-right">
<div class="flex items-center justify-end space-x-2 opacity-70 group-hover:opacity-100 transition-opacity">
<button class="view-customer-btn inline-flex items-center px-3 py-2 bg-gradient-to-r from-slate-100 to-slate-200 dark:from-slate-700 dark:to-slate-600 text-slate-700 dark:text-slate-200 hover:from-slate-200 hover:to-slate-300 dark:hover:from-slate-600 dark:hover:to-slate-500 rounded-lg text-sm font-semibold transition-all duration-200 shadow-sm hover:shadow-md border border-slate-300/50 dark:border-slate-500/50">
<i class="fa-solid fa-eye mr-2"></i>
View
</button>
<button class="edit-customer-btn inline-flex items-center px-3 py-2 bg-gradient-to-r from-blue-600 to-blue-700 dark:from-blue-700 dark:to-blue-800 text-white hover:from-blue-700 hover:to-blue-800 dark:hover:from-blue-600 dark:hover:to-blue-700 rounded-lg text-sm font-semibold transition-all duration-200 shadow-sm hover:shadow-md">
<i class="fa-solid fa-pencil mr-2"></i>
Edit
</button>
</div>
</td>
`;
// Add event listeners using the stored customer ID (no escaping issues)
const customerCells = row.querySelectorAll('.customer-cell');
customerCells.forEach(cell => {
cell.addEventListener('click', () => viewCustomer(customer.id));
});
const viewBtn = row.querySelector('.view-customer-btn');
const editBtn = row.querySelector('.edit-customer-btn');
viewBtn.addEventListener('click', (e) => {
e.stopPropagation();
viewCustomer(customer.id);
});
editBtn.addEventListener('click', (e) => {
e.stopPropagation();
editCustomer(customer.id);
});
tbody.appendChild(row);
});
}
// Helper functions
function getInitials(customer) {
const first = (customer.first || '').trim();
const last = (customer.last || '').trim();
if (first && last) {
return (first.charAt(0) + last.charAt(0)).toUpperCase();
} else if (last) {
return last.charAt(0).toUpperCase();
} else if (first) {
return first.charAt(0).toUpperCase();
} else {
return '?';
}
}
function formatFullName(customer) {
const parts = [];
if (customer.prefix) parts.push(customer.prefix.trim());
if (customer.first) parts.push(customer.first.trim());
if (customer.middle) parts.push(customer.middle.trim());
if (customer.last) parts.push(customer.last.trim());
if (customer.suffix) parts.push(customer.suffix.trim());
return parts.join(' ') || 'Unknown';
}
function formatCityState(customer) {
const parts = [];
if (customer.city) parts.push(customer.city.trim());
if (customer.abrev) parts.push(customer.abrev.trim());
return parts.join(', ') || '-';
}
function formatPrimaryPhone(phones) {
if (!phones || phones.length === 0) {
return '<span class="text-neutral-400">-</span>';
}
const primary = phones[0];
const count = phones.length;
if (count === 1) {
return escapeHtml(primary.phone || '');
} else {
return escapeHtml(primary.phone || '') + ` <span class="text-xs text-neutral-500">(+${count - 1} more)</span>`;
}
}
function escapeHtml(str) {
if (!str && str !== 0) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
// Enhanced alert function
function showAlert(message, type = 'info') {
if (window.alerts && typeof window.alerts.show === 'function') {
window.alerts.show(message, type);
return;
}
// Fallback
alert(String(message));
}
// Modal management functions
function showAddCustomerModal() {
isEditing = false;
editingCustomerId = null;
document.getElementById('customerModalLabel').textContent = 'Add New Customer';
document.getElementById('deleteCustomerBtn').classList.add('hidden');
clearCustomerForm();
document.getElementById('customerModal').classList.remove('hidden');
}
function closeCustomerModal() {
document.getElementById('customerModal').classList.add('hidden');
}
function showEditCustomerModal() {
document.getElementById('customerModalLabel').textContent = 'Edit Customer';
document.getElementById('deleteCustomerBtn').classList.remove('hidden');
document.getElementById('customerModal').classList.remove('hidden');
}
// Customer detail functions
async function viewCustomer(customerId) {
try {
// URL encode the customer ID to handle special characters like backslashes and spaces
const encodedCustomerId = encodeURIComponent(customerId);
const response = await window.http.wrappedFetch(`/api/customers/${encodedCustomerId}`);
if (!response.ok) throw new Error('Failed to load customer details');
const customer = await response.json();
showCustomerDetailsModal(customer);
} catch (error) {
console.error('Error loading customer:', error);
showAlert(`Error loading customer: ${error.message}`, 'danger');
}
}
function showCustomerDetailsModal(customer) {
// Create modal content
const modalContent = `
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4" id="customerDetailsModal">
<div class="bg-white dark:bg-neutral-800 rounded-xl shadow-xl max-w-5xl w-full max-h-[85vh] overflow-hidden">
<div class="flex items-center justify-between px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<h2 class="text-xl font-semibold text-neutral-900 dark:text-neutral-100">Customer Details</h2>
<button onclick="closeCustomerDetailsModal()" class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300 transition-colors">
<i class="fa-solid fa-xmark text-xl"></i>
</button>
</div>
<div class="px-8 py-6 max-h-[70vh] overflow-y-auto">
<!-- Customer Header -->
<div class="mb-8 pb-6 border-b border-neutral-200 dark:border-neutral-700">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-neutral-900 dark:text-neutral-100 mb-2">${escapeHtml(formatFullName(customer))}</h1>
<div class="flex items-center space-x-4">
<span class="inline-flex items-center px-3 py-1 rounded-lg text-sm font-mono bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 border">${escapeHtml(customer.id || '')}</span>
${customer.group ? `<span class="inline-flex items-center px-3 py-1 rounded-lg text-sm font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200 border border-blue-200 dark:border-blue-700">${escapeHtml(customer.group)}</span>` : ''}
${customer.title ? `<span class="text-neutral-600 dark:text-neutral-400">${escapeHtml(customer.title)}</span>` : ''}
</div>
</div>
</div>
</div>
<!-- Main Content Grid -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Contact Information (Left Column) -->
<div class="lg:col-span-1">
<div class="bg-neutral-50 dark:bg-neutral-800/50 rounded-lg p-6 border border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-neutral-100 mb-4 flex items-center">
<i class="fa-solid fa-address-card mr-2 text-blue-600 dark:text-blue-400"></i>
Contact Details
</h3>
<div class="space-y-4">
${customer.email ? `
<div class="flex items-center space-x-3">
<i class="fa-solid fa-envelope text-neutral-500 w-4"></i>
<a href="mailto:${encodeURIComponent(customer.email)}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline break-all">${escapeHtml(customer.email)}</a>
</div>
` : `
<div class="flex items-center space-x-3">
<i class="fa-solid fa-envelope text-neutral-400 w-4"></i>
<span class="text-neutral-400">No email provided</span>
</div>
`}
${formatCustomerPhonesCard(customer.phone_numbers || [])}
</div>
</div>
</div>
<!-- Address Information (Middle Column) -->
<div class="lg:col-span-1">
<div class="bg-neutral-50 dark:bg-neutral-800/50 rounded-lg p-6 border border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-neutral-100 mb-4 flex items-center">
<i class="fa-solid fa-map-marker-alt mr-2 text-green-600 dark:text-green-400"></i>
Address
</h3>
${formatCustomerAddressCard(customer)}
</div>
</div>
<!-- Additional Information (Right Column) -->
<div class="lg:col-span-1">
<div class="bg-neutral-50 dark:bg-neutral-800/50 rounded-lg p-6 border border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-neutral-100 mb-4 flex items-center">
<i class="fa-solid fa-info-circle mr-2 text-purple-600 dark:text-purple-400"></i>
Additional Info
</h3>
<div class="space-y-3">
${customer.dob ? `
<div class="flex justify-between">
<span class="text-neutral-600 dark:text-neutral-400">Date of Birth:</span>
<span class="text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.dob)}</span>
</div>
` : ''}
${customer.legal_status ? `
<div class="flex justify-between">
<span class="text-neutral-600 dark:text-neutral-400">Legal Status:</span>
<span class="text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.legal_status)}</span>
</div>
` : ''}
${customer.ss_number ? `
<div class="flex justify-between">
<span class="text-neutral-600 dark:text-neutral-400">SSN:</span>
<span class="font-mono text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.ss_number)}</span>
</div>
` : ''}
${!customer.dob && !customer.legal_status && !customer.ss_number ? `
<div class="text-center text-neutral-400 py-4">
<i class="fa-solid fa-info-circle mb-2 text-lg"></i>
<p>No additional information available</p>
</div>
` : ''}
</div>
</div>
</div>
</div>
<!-- Notes Section (Full Width) -->
${customer.memo ? `
<div class="mt-8">
<div class="bg-neutral-50 dark:bg-neutral-800/50 rounded-lg p-6 border border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-neutral-100 mb-4 flex items-center">
<i class="fa-solid fa-sticky-note mr-2 text-orange-600 dark:text-orange-400"></i>
Notes
</h3>
<div class="text-neutral-700 dark:text-neutral-300 leading-relaxed whitespace-pre-wrap bg-white dark:bg-neutral-800 p-4 rounded border border-neutral-200 dark:border-neutral-600">${escapeHtml(customer.memo)}</div>
</div>
</div>
` : ''}
</div>
<div class="flex items-center justify-end gap-4 px-8 py-6 border-t border-neutral-200 dark:border-neutral-700 bg-neutral-50 dark:bg-neutral-800/50">
<button onclick="closeCustomerDetailsModal()" class="px-6 py-3 bg-neutral-200 dark:bg-neutral-700 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-300 dark:hover:bg-neutral-600 rounded-lg transition-colors duration-200 font-medium">
Close
</button>
<button onclick="closeCustomerDetailsModal(); editCustomer('${escapeHtml(customer.id)}')" class="px-6 py-3 bg-blue-600 text-white hover:bg-blue-700 rounded-lg transition-colors duration-200 font-medium shadow-sm">
<i class="fa-solid fa-pencil mr-2"></i>Edit Customer
</button>
</div>
</div>
</div>
`;
// Add modal to body
document.body.insertAdjacentHTML('beforeend', modalContent);
}
function closeCustomerDetailsModal() {
const modal = document.getElementById('customerDetailsModal');
if (modal) {
modal.remove();
}
}
function formatCustomerAddress(customer) {
const parts = [];
if (customer.a1) parts.push(`<div>${escapeHtml(customer.a1)}</div>`);
if (customer.a2) parts.push(`<div>${escapeHtml(customer.a2)}</div>`);
if (customer.a3) parts.push(`<div>${escapeHtml(customer.a3)}</div>`);
const cityState = formatCityState(customer);
if (cityState !== '-') {
parts.push(`<div>${escapeHtml(cityState)}</div>`);
}
if (customer.zip) {
parts.push(`<div>${escapeHtml(customer.zip)}</div>`);
}
return parts.length > 0 ? `<div class="mb-2"><span class="font-medium">Address:</span><div class="ml-4">${parts.join('')}</div></div>` : '';
}
function formatCustomerPhones(phones) {
if (!phones || phones.length === 0) {
return '<div><span class="font-medium">Phone:</span> <span class="text-neutral-400">None</span></div>';
}
const phoneList = phones.map(phone =>
`<div class="ml-4">${phone.location ? `<span class="text-xs text-neutral-500">${escapeHtml(phone.location)}:</span> ` : ''}${escapeHtml(phone.phone)}</div>`
).join('');
return `<div class="mb-2"><span class="font-medium">Phone${phones.length > 1 ? 's' : ''}:</span>${phoneList}</div>`;
}
function formatCustomerAddressLarge(customer) {
const addressParts = [];
if (customer.a1) addressParts.push(escapeHtml(customer.a1));
if (customer.a2) addressParts.push(escapeHtml(customer.a2));
if (customer.a3) addressParts.push(escapeHtml(customer.a3));
const cityState = formatCityState(customer);
if (cityState !== '-') addressParts.push(escapeHtml(cityState));
if (customer.zip) addressParts.push(escapeHtml(customer.zip));
if (addressParts.length === 0) {
return '<div class="flex items-start"><span class="font-semibold text-neutral-700 dark:text-neutral-300 w-20 flex-shrink-0">Address:</span> <span class="text-neutral-400">Not provided</span></div>';
}
return `<div class="flex items-start"><span class="font-semibold text-neutral-700 dark:text-neutral-300 w-20 flex-shrink-0">Address:</span> <div class="space-y-1">${addressParts.map(part => `<div>${part}</div>`).join('')}</div></div>`;
}
function formatCustomerPhonesLarge(phones) {
if (!phones || phones.length === 0) {
return '<div class="flex items-start"><span class="font-semibold text-neutral-700 dark:text-neutral-300 w-20 flex-shrink-0">Phone:</span> <span class="text-neutral-400">None</span></div>';
}
const phoneList = phones.map(phone =>
`<div class="flex items-center space-x-2">
<span class="font-mono bg-neutral-100 dark:bg-neutral-700 px-2 py-1 rounded text-sm">${escapeHtml(phone.phone)}</span>
${phone.location ? `<span class="text-xs px-2 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded">${escapeHtml(phone.location)}</span>` : ''}
</div>`
).join('');
return `<div class="flex items-start"><span class="font-semibold text-neutral-700 dark:text-neutral-300 w-20 flex-shrink-0">Phone${phones.length > 1 ? 's' : ''}:</span> <div class="space-y-2">${phoneList}</div></div>`;
}
function formatCustomerPhonesCard(phones) {
if (!phones || phones.length === 0) {
return `
<div class="flex items-center space-x-3">
<i class="fa-solid fa-phone text-neutral-400 w-4"></i>
<span class="text-neutral-400">No phone numbers</span>
</div>
`;
}
return phones.map(phone => `
<div class="flex items-center space-x-3">
<i class="fa-solid fa-phone text-neutral-500 w-4"></i>
<div class="flex items-center space-x-2">
<span class="font-mono text-neutral-900 dark:text-neutral-100">${escapeHtml(phone.phone)}</span>
${phone.location ? `<span class="text-xs px-2 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full">${escapeHtml(phone.location)}</span>` : ''}
</div>
</div>
`).join('');
}
function formatCustomerAddressCard(customer) {
const addressParts = [];
if (customer.a1) addressParts.push(escapeHtml(customer.a1));
if (customer.a2) addressParts.push(escapeHtml(customer.a2));
if (customer.a3) addressParts.push(escapeHtml(customer.a3));
const cityState = formatCityState(customer);
if (cityState !== '-') addressParts.push(escapeHtml(cityState));
if (customer.zip) addressParts.push(escapeHtml(customer.zip));
if (addressParts.length === 0) {
return `
<div class="text-center text-neutral-400 py-4">
<i class="fa-solid fa-map-marker-alt mb-2 text-lg"></i>
<p>No address provided</p>
</div>
`;
}
return `
<div class="space-y-2">
${addressParts.map(part => `<div class="text-neutral-700 dark:text-neutral-300">${part}</div>`).join('')}
</div>
`;
}
async function editCustomer(customerId) {
try {
// URL encode the customer ID to handle special characters like backslashes and spaces
const encodedCustomerId = encodeURIComponent(customerId);
const response = await window.http.wrappedFetch(`/api/customers/${encodedCustomerId}`);
if (!response.ok) throw new Error('Failed to load customer details');
const customer = await response.json();
populateEditForm(customer);
showEditCustomerModal();
} catch (error) {
console.error('Error loading customer for edit:', error);
showAlert(`Error loading customer: ${error.message}`, 'danger');
}
}
function populateEditForm(customer) {
isEditing = true;
editingCustomerId = customer.id;
// Populate form fields
document.getElementById('customerId').value = customer.id || '';
document.getElementById('last').value = customer.last || '';
document.getElementById('first').value = customer.first || '';
document.getElementById('middle').value = customer.middle || '';
document.getElementById('prefix').value = customer.prefix || '';
document.getElementById('suffix').value = customer.suffix || '';
document.getElementById('title').value = customer.title || '';
document.getElementById('group').value = customer.group || '';
document.getElementById('a1').value = customer.a1 || '';
document.getElementById('a2').value = customer.a2 || '';
document.getElementById('a3').value = customer.a3 || '';
document.getElementById('city').value = customer.city || '';
document.getElementById('abrev').value = customer.abrev || '';
document.getElementById('zip').value = customer.zip || '';
document.getElementById('email').value = customer.email || '';
document.getElementById('dob').value = customer.dob || '';
document.getElementById('ss_number').value = customer.ss_number || '';
document.getElementById('legal_status').value = customer.legal_status || '';
document.getElementById('memo').value = customer.memo || '';
// Populate phone numbers
populatePhoneNumbers(customer.phone_numbers || []);
// Make customer ID readonly for editing
document.getElementById('customerId').readOnly = true;
}
async function saveCustomer() {
try {
// Gather form data
const customerData = {
last: document.getElementById('last').value,
first: document.getElementById('first').value || null,
middle: document.getElementById('middle').value || null,
prefix: document.getElementById('prefix').value || null,
suffix: document.getElementById('suffix').value || null,
title: document.getElementById('title').value || null,
group: document.getElementById('group').value || null,
a1: document.getElementById('a1').value || null,
a2: document.getElementById('a2').value || null,
a3: document.getElementById('a3').value || null,
city: document.getElementById('city').value || null,
abrev: document.getElementById('abrev').value || null,
zip: document.getElementById('zip').value || null,
email: document.getElementById('email').value || null,
dob: document.getElementById('dob').value || null,
ss_number: document.getElementById('ss_number').value || null,
legal_status: document.getElementById('legal_status').value || null,
memo: document.getElementById('memo').value || null
};
// Validate required fields
if (!customerData.last) {
showAlert('Last name/Company is required', 'danger');
return;
}
let response;
if (isEditing) {
// Update existing customer
const encodedCustomerId = encodeURIComponent(editingCustomerId);
response = await window.http.wrappedFetch(`/api/customers/${encodedCustomerId}`, {
method: 'PUT',
body: JSON.stringify(customerData)
});
} else {
// Create new customer
customerData.id = document.getElementById('customerId').value;
if (!customerData.id) {
showAlert('Customer ID is required', 'danger');
return;
}
response = await window.http.wrappedFetch('/api/customers/', {
method: 'POST',
body: JSON.stringify(customerData)
});
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to save customer');
}
showAlert(isEditing ? 'Customer updated successfully!' : 'Customer created successfully!', 'success');
closeCustomerModal();
loadCustomers(); // Refresh the customer list
} catch (error) {
console.error('Error saving customer:', error);
showAlert(`Error saving customer: ${error.message}`, 'danger');
}
}
function deleteCustomer() {
showAlert('Delete customer feature coming soon...', 'info');
}
function validateCustomerId() {
// Placeholder
}
function populatePhoneNumbers(phones) {
const phoneList = document.getElementById('phoneList');
phoneList.innerHTML = '';
phones.forEach((phone, index) => {
const phoneDiv = document.createElement('div');
phoneDiv.className = 'flex items-center space-x-2';
phoneDiv.innerHTML = `
<div class="flex-1">
<input type="text"
value="${escapeHtml(phone.location || '')}"
placeholder="Location (e.g., Home, Office)"
class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 text-sm"
data-phone-index="${index}"
data-phone-field="location">
</div>
<div class="flex-1">
<input type="text"
value="${escapeHtml(phone.phone || '')}"
placeholder="Phone number"
class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 text-sm"
data-phone-index="${index}"
data-phone-field="phone">
</div>
<button type="button" onclick="removePhoneNumber(${index})" class="px-2 py-2 bg-danger-600 text-white hover:bg-danger-700 rounded-lg text-sm transition-colors">
<i class="fa-solid fa-trash"></i>
</button>
`;
phoneList.appendChild(phoneDiv);
});
}
function clearCustomerForm() {
isEditing = false;
editingCustomerId = null;
// Clear all form fields
document.getElementById('customerId').value = '';
document.getElementById('customerId').readOnly = false;
document.getElementById('last').value = '';
document.getElementById('first').value = '';
document.getElementById('middle').value = '';
document.getElementById('prefix').value = '';
document.getElementById('suffix').value = '';
document.getElementById('title').value = '';
document.getElementById('group').value = '';
document.getElementById('a1').value = '';
document.getElementById('a2').value = '';
document.getElementById('a3').value = '';
document.getElementById('city').value = '';
document.getElementById('abrev').value = '';
document.getElementById('zip').value = '';
document.getElementById('email').value = '';
document.getElementById('dob').value = '';
document.getElementById('ss_number').value = '';
document.getElementById('legal_status').value = '';
document.getElementById('memo').value = '';
// Clear phone numbers
document.getElementById('phoneList').innerHTML = '';
}
function removePhoneNumber(index) {
const phoneList = document.getElementById('phoneList');
const phoneInputs = phoneList.children;
if (phoneInputs[index]) {
phoneInputs[index].remove();
// Re-index remaining phone inputs
Array.from(phoneInputs).forEach((phoneDiv, newIndex) => {
const inputs = phoneDiv.querySelectorAll('input');
inputs.forEach(input => {
input.setAttribute('data-phone-index', newIndex);
});
const button = phoneDiv.querySelector('button');
if (button) {
button.setAttribute('onclick', `removePhoneNumber(${newIndex})`);
}
});
}
}
function addPhoneNumber() {
const phoneList = document.getElementById('phoneList');
const currentCount = phoneList.children.length;
const phoneDiv = document.createElement('div');
phoneDiv.className = 'flex items-center space-x-2';
phoneDiv.innerHTML = `
<div class="flex-1">
<input type="text"
value=""
placeholder="Location (e.g., Home, Office)"
class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 text-sm"
data-phone-index="${currentCount}"
data-phone-field="location">
</div>
<div class="flex-1">
<input type="text"
value=""
placeholder="Phone number"
class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 text-sm"
data-phone-index="${currentCount}"
data-phone-field="phone">
</div>
<button type="button" onclick="removePhoneNumber(${currentCount})" class="px-2 py-2 bg-danger-600 text-white hover:bg-danger-700 rounded-lg text-sm transition-colors">
<i class="fa-solid fa-trash"></i>
</button>
`;
phoneList.appendChild(phoneDiv);
}
// Make functions globally available
window.showAddCustomerModal = showAddCustomerModal;
window.closeCustomerModal = closeCustomerModal;
window.showEditCustomerModal = showEditCustomerModal;
window.displayCustomers = displayCustomers;
window.showAlert = showAlert;
window.editCustomer = editCustomer;
window.viewCustomer = viewCustomer;
window.saveCustomer = saveCustomer;
window.deleteCustomer = deleteCustomer;
window.validateCustomerId = validateCustomerId;
window.closeCustomerDetailsModal = closeCustomerDetailsModal;
window.populateEditForm = populateEditForm;
window.populatePhoneNumbers = populatePhoneNumbers;
window.clearCustomerForm = clearCustomerForm;
window.addPhoneNumber = addPhoneNumber;
window.removePhoneNumber = removePhoneNumber;