progress on customer data
This commit is contained in:
426
static/js/customers-modern.js
Normal file
426
static/js/customers-modern.js
Normal file
@@ -0,0 +1,426 @@
|
||||
// Modern helper functions for customer details modal
|
||||
|
||||
function formatCustomerPhonesModern(phones) {
|
||||
if (!phones || phones.length === 0) {
|
||||
return `
|
||||
<div class="flex items-center space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-neutral-100 dark:bg-neutral-600 rounded-lg flex items-center justify-center">
|
||||
<i class="fa-solid fa-phone text-neutral-400 text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-1">Phone Numbers</p>
|
||||
<span class="text-neutral-400 font-medium">Not provided</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return phones.map(phone => `
|
||||
<div class="flex items-start space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-green-100 dark:bg-green-900/50 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5">
|
||||
<i class="fa-solid fa-phone text-green-600 dark:text-green-400 text-sm"></i>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-1">${phone.location || 'Phone'}</p>
|
||||
<p class="font-mono text-neutral-900 dark:text-neutral-100 font-medium">${escapeHtml(phone.phone)}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function formatCustomerAddressModern(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-center space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-neutral-100 dark:bg-neutral-600 rounded-lg flex items-center justify-center">
|
||||
<i class="fa-solid fa-map-marker-alt text-neutral-400 text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-1">Address</p>
|
||||
<span class="text-neutral-400 font-medium">Not provided</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="space-y-2">
|
||||
${addressParts.map(part => `
|
||||
<div class="flex items-start space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-emerald-100 dark:bg-emerald-900/50 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5">
|
||||
<i class="fa-solid fa-location-dot text-emerald-600 dark:text-emerald-400 text-sm"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-neutral-700 dark:text-neutral-300 font-medium leading-relaxed">${part}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function formatCustomerPersonalInfo(customer) {
|
||||
const hasPersonalInfo = customer.dob || customer.legal_status || customer.ss_number || customer.prefix || customer.middle || customer.suffix;
|
||||
|
||||
if (!hasPersonalInfo) {
|
||||
return `
|
||||
<div class="flex items-center space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-neutral-100 dark:bg-neutral-600 rounded-lg flex items-center justify-center">
|
||||
<i class="fa-solid fa-user text-neutral-400 text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-1">Personal Information</p>
|
||||
<span class="text-neutral-400 font-medium">Not provided</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const personalItems = [];
|
||||
|
||||
if (customer.dob) {
|
||||
personalItems.push({
|
||||
icon: 'fa-calendar',
|
||||
label: 'Date of Birth',
|
||||
value: customer.dob,
|
||||
color: 'purple'
|
||||
});
|
||||
}
|
||||
|
||||
if (customer.ss_number) {
|
||||
personalItems.push({
|
||||
icon: 'fa-id-card',
|
||||
label: 'SSN',
|
||||
value: customer.ss_number,
|
||||
color: 'purple',
|
||||
mono: true
|
||||
});
|
||||
}
|
||||
|
||||
if (customer.legal_status) {
|
||||
personalItems.push({
|
||||
icon: 'fa-gavel',
|
||||
label: 'Legal Status',
|
||||
value: customer.legal_status,
|
||||
color: 'purple'
|
||||
});
|
||||
}
|
||||
|
||||
if (customer.prefix) {
|
||||
personalItems.push({
|
||||
icon: 'fa-tag',
|
||||
label: 'Prefix',
|
||||
value: customer.prefix,
|
||||
color: 'purple'
|
||||
});
|
||||
}
|
||||
|
||||
if (customer.middle) {
|
||||
personalItems.push({
|
||||
icon: 'fa-user',
|
||||
label: 'Middle Name',
|
||||
value: customer.middle,
|
||||
color: 'purple'
|
||||
});
|
||||
}
|
||||
|
||||
if (customer.suffix) {
|
||||
personalItems.push({
|
||||
icon: 'fa-tag',
|
||||
label: 'Suffix',
|
||||
value: customer.suffix,
|
||||
color: 'purple'
|
||||
});
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="space-y-3">
|
||||
${personalItems.map(item => `
|
||||
<div class="flex items-start space-x-3 p-3 bg-neutral-50 dark:bg-neutral-700/50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-purple-100 dark:bg-purple-900/50 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5">
|
||||
<i class="fa-solid ${item.icon} text-purple-600 dark:text-purple-400 text-sm"></i>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-1">${item.label}</p>
|
||||
<p class="${item.mono ? 'font-mono' : ''} text-neutral-900 dark:text-neutral-100 font-medium break-all">${escapeHtml(item.value)}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Updated showCustomerDetailsModal function - Legacy-style compact 2-column layout with larger text
|
||||
function showCustomerDetailsModal(customer) {
|
||||
// Create modal content matching the legacy system layout exactly
|
||||
const modalContent = `
|
||||
<div class="fixed inset-0 bg-black/60 z-50 overflow-y-auto" id="customerDetailsModal">
|
||||
<div class="flex min-h-full items-center justify-center p-4">
|
||||
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow-2xl w-full max-w-4xl border-4 border-neutral-600 dark:border-neutral-400 my-8">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b-2 border-neutral-300 dark:border-neutral-600 bg-gradient-to-r from-neutral-100 to-neutral-50 dark:from-neutral-700 dark:to-neutral-800">
|
||||
<h2 class="text-lg font-bold text-neutral-900 dark:text-neutral-100">Customer Details</h2>
|
||||
<button onclick="closeCustomerDetailsModal()" class="text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200 transition-colors p-1">
|
||||
<i class="fa-solid fa-xmark text-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Content - Legacy Layout -->
|
||||
<div class="px-6 py-5 space-y-5">
|
||||
<!-- Top Line: ID (Center Bold) -->
|
||||
<div class="text-center">
|
||||
<span class="text-xl font-bold text-neutral-900 dark:text-neutral-100 bg-neutral-200 dark:bg-neutral-700 px-6 py-2 rounded-lg border-2 border-neutral-400 dark:border-neutral-500 font-mono shadow-sm">${escapeHtml(customer.id || '')}</span>
|
||||
</div>
|
||||
|
||||
<!-- Second Line: Name Information (Left) | Phone with Location (Right) -->
|
||||
<div class="grid grid-cols-2 gap-8 border-2 border-neutral-400 dark:border-neutral-500 rounded-lg p-5 bg-neutral-50 dark:bg-neutral-800/50">
|
||||
<!-- Left: Name Information -->
|
||||
<div class="space-y-3">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-3 border-b border-neutral-300 dark:border-neutral-600 pb-2">Name Information</div>
|
||||
${customer.prefix ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Prefix:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.prefix)}</span></div>` : ''}
|
||||
${customer.first ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">First:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.first)}</span></div>` : ''}
|
||||
${customer.middle ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Middle:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.middle)}</span></div>` : ''}
|
||||
${customer.last ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Last:</span><span class="text-sm text-neutral-900 dark:text-neutral-100 font-bold">${escapeHtml(customer.last)}</span></div>` : ''}
|
||||
${customer.suffix ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Suffix:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.suffix)}</span></div>` : ''}
|
||||
</div>
|
||||
|
||||
<!-- Right: Phone with Location -->
|
||||
<div class="space-y-3">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-3 border-b border-neutral-300 dark:border-neutral-600 pb-2">Phone Numbers</div>
|
||||
${formatCustomerPhonesLegacyLarger(customer.phone_numbers || [])}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Third Line: Group, Title, Address (Left) | Email, DOB, SS, Legal Status (Right) -->
|
||||
<div class="grid grid-cols-2 gap-8 border-2 border-neutral-400 dark:border-neutral-500 rounded-lg p-5 bg-neutral-50 dark:bg-neutral-800/50">
|
||||
<!-- Left: Group, Title, Address -->
|
||||
<div class="space-y-3">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-3 border-b border-neutral-300 dark:border-neutral-600 pb-2">General Information</div>
|
||||
${customer.group ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Group:</span><span class="text-sm text-blue-700 dark:text-blue-300 font-bold">${escapeHtml(customer.group)}</span></div>` : ''}
|
||||
${customer.title ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Title:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.title)}</span></div>` : ''}
|
||||
<div class="pt-2">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-2">Address</div>
|
||||
${formatCustomerAddressLegacyLarger(customer)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Email, DOB, SS, Legal Status -->
|
||||
<div class="space-y-3">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-3 border-b border-neutral-300 dark:border-neutral-600 pb-2">Personal Details</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-neutral-600 dark:text-neutral-400">Email:</span>
|
||||
${customer.email ? `<a href="mailto:${encodeURIComponent(customer.email)}" class="text-sm text-blue-600 dark:text-blue-400 hover:underline break-all max-w-xs">${escapeHtml(customer.email)}</a>` : '<span class="text-sm text-neutral-400">-</span>'}
|
||||
</div>
|
||||
${customer.dob ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">DOB:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.dob)}</span></div>` : ''}
|
||||
${customer.ss_number ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">SSN:</span><span class="text-sm font-mono text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.ss_number)}</span></div>` : ''}
|
||||
${customer.legal_status ? `<div class="flex justify-between"><span class="text-sm text-neutral-600 dark:text-neutral-400">Legal Status:</span><span class="text-sm text-neutral-900 dark:text-neutral-100">${escapeHtml(customer.legal_status)}</span></div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fourth Line: Full Single Column with Memo Information (ALWAYS SHOW) -->
|
||||
<div class="border-2 border-neutral-400 dark:border-neutral-500 rounded-lg p-5 bg-neutral-50 dark:bg-neutral-800/50">
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 font-bold mb-3 border-b border-neutral-300 dark:border-neutral-600 pb-1">Memo</div>
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 leading-relaxed whitespace-pre-wrap bg-white dark:bg-neutral-800 p-3 rounded border border-neutral-300 dark:border-neutral-600 min-h-[60px] max-h-32 overflow-y-auto">
|
||||
${customer.memo ? escapeHtml(customer.memo) : 'No memo information available'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="flex items-center justify-end gap-3 px-6 py-4 border-t-2 border-neutral-300 dark:border-neutral-600 bg-gradient-to-r from-neutral-100 to-neutral-50 dark:from-neutral-700 dark:to-neutral-800">
|
||||
<button onclick="closeCustomerDetailsModal()" class="px-4 py-2 bg-neutral-300 dark:bg-neutral-600 text-neutral-800 dark:text-white hover:bg-neutral-400 dark:hover:bg-neutral-500 rounded-lg transition-colors text-sm font-medium border border-neutral-400 dark:border-neutral-500">
|
||||
Close
|
||||
</button>
|
||||
<button onclick="closeCustomerDetailsModal(); editCustomer('${escapeHtml(customer.id)}');" style="background-color: #dc2626; color: white; padding: 8px 16px; border-radius: 6px; border: none; font-weight: 500; font-size: 14px;">
|
||||
<i class="fa-solid fa-pencil" style="margin-right: 4px;"></i>Edit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add modal to body
|
||||
document.body.insertAdjacentHTML('beforeend', modalContent);
|
||||
}
|
||||
|
||||
// Compact formatting functions for cleaner display
|
||||
function formatCustomerPhonesCompact(phones) {
|
||||
if (!phones || phones.length === 0) {
|
||||
return `
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-neutral-600 dark:text-neutral-400">Phone:</span>
|
||||
<span class="text-sm text-neutral-400">-</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return phones.map(phone => `
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-neutral-600 dark:text-neutral-400">${phone.location || 'Phone'}:</span>
|
||||
<span class="text-sm text-neutral-900 dark:text-neutral-100 font-mono">${escapeHtml(phone.phone)}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function formatCustomerAddressCompact(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-2">
|
||||
<span class="text-sm">No address provided</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 leading-relaxed">
|
||||
${addressParts.map(part => `<div>${part}</div>`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Ultra-compact formatting functions for minimal space usage
|
||||
function formatCustomerPhonesUltraCompact(phones) {
|
||||
if (!phones || phones.length === 0) {
|
||||
return `
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs text-neutral-600 dark:text-neutral-400">Phone:</span>
|
||||
<span class="text-xs text-neutral-400">-</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return phones.map(phone => `
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs text-neutral-600 dark:text-neutral-400">${phone.location || 'Phone'}:</span>
|
||||
<span class="text-xs text-neutral-900 dark:text-neutral-100 font-mono">${escapeHtml(phone.phone)}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function formatCustomerAddressUltraCompact(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-1">
|
||||
<span class="text-xs">No address provided</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-xs text-neutral-700 dark:text-neutral-300 leading-tight">
|
||||
${addressParts.map(part => `<div>${part}</div>`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Legacy formatting functions to match the old system layout
|
||||
function formatCustomerPhonesLegacy(phones) {
|
||||
if (!phones || phones.length === 0) {
|
||||
return `<div class="text-xs text-neutral-400">No phone numbers</div>`;
|
||||
}
|
||||
|
||||
return phones.map(phone => `
|
||||
<div class="flex justify-between">
|
||||
<span class="text-xs text-neutral-600 dark:text-neutral-400">${phone.location || 'Phone'}:</span>
|
||||
<span class="text-xs text-neutral-900 dark:text-neutral-100 font-mono">${escapeHtml(phone.phone)}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function formatCustomerAddressLegacy(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-xs text-neutral-400">No address provided</div>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-xs text-neutral-700 dark:text-neutral-300 leading-tight space-y-0.5">
|
||||
${addressParts.map(part => `<div>${part}</div>`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Legacy formatting functions with larger text
|
||||
function formatCustomerPhonesLegacyLarger(phones) {
|
||||
if (!phones || phones.length === 0) {
|
||||
return `<div class="text-sm text-neutral-400">No phone numbers</div>`;
|
||||
}
|
||||
|
||||
return phones.map(phone => `
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-neutral-600 dark:text-neutral-400">${phone.location || 'Phone'}:</span>
|
||||
<span class="text-sm text-neutral-900 dark:text-neutral-100 font-mono font-medium">${escapeHtml(phone.phone)}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function formatCustomerAddressLegacyLarger(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-sm text-neutral-400">No address provided</div>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-300 leading-relaxed space-y-1">
|
||||
${addressParts.map(part => `<div>${part}</div>`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Make functions globally available
|
||||
window.formatCustomerPhonesModern = formatCustomerPhonesModern;
|
||||
window.formatCustomerAddressModern = formatCustomerAddressModern;
|
||||
window.formatCustomerPersonalInfo = formatCustomerPersonalInfo;
|
||||
window.formatCustomerPhonesCompact = formatCustomerPhonesCompact;
|
||||
window.formatCustomerAddressCompact = formatCustomerAddressCompact;
|
||||
window.formatCustomerPhonesUltraCompact = formatCustomerPhonesUltraCompact;
|
||||
window.formatCustomerAddressUltraCompact = formatCustomerAddressUltraCompact;
|
||||
window.formatCustomerPhonesLegacy = formatCustomerPhonesLegacy;
|
||||
window.formatCustomerAddressLegacy = formatCustomerAddressLegacy;
|
||||
window.formatCustomerPhonesLegacyLarger = formatCustomerPhonesLegacyLarger;
|
||||
window.formatCustomerAddressLegacyLarger = formatCustomerAddressLegacyLarger;
|
||||
window.showCustomerDetailsModal = showCustomerDetailsModal;
|
||||
@@ -61,8 +61,8 @@ function displayCustomers(customers) {
|
||||
<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>
|
||||
<button class="edit-customer-btn" style="display: inline-flex; align-items: center; background-color: #dc2626; color: white; padding: 8px 12px; border-radius: 6px; border: none; font-weight: 600; font-size: 14px;">
|
||||
<i class="fa-solid fa-pencil" style="margin-right: 8px;"></i>
|
||||
Edit
|
||||
</button>
|
||||
</div>
|
||||
@@ -524,6 +524,23 @@ async function saveCustomer() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Double confirm for edits
|
||||
if (isEditing) {
|
||||
const confirmMessage = `Are you sure you want to update customer "${customerData.last}"? This will permanently modify the customer record.`;
|
||||
const firstConfirm = confirm(confirmMessage);
|
||||
|
||||
if (!firstConfirm) {
|
||||
return; // User cancelled
|
||||
}
|
||||
|
||||
// Second confirmation
|
||||
const secondConfirm = confirm('Please confirm again: Do you really want to save these changes? This action cannot be undone.');
|
||||
|
||||
if (!secondConfirm) {
|
||||
return; // User cancelled on second confirmation
|
||||
}
|
||||
}
|
||||
|
||||
let response;
|
||||
if (isEditing) {
|
||||
// Update existing customer
|
||||
|
||||
@@ -278,6 +278,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/static/js/customers-tailwind.js?v=12"></script>
|
||||
<script src="/static/js/customers-modern.js?v=1"></script>
|
||||
|
||||
<script>
|
||||
// Initialize on page load
|
||||
@@ -437,33 +438,68 @@ function displayPhoneSearchResults(results) {
|
||||
|
||||
results.forEach(result => {
|
||||
const row = document.createElement('tr');
|
||||
row.className = 'hover:bg-neutral-50 dark:hover:bg-neutral-800/50 transition-colors duration-150';
|
||||
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 cursor-pointer';
|
||||
|
||||
// Store customer ID as data attribute to avoid escaping issues
|
||||
row.dataset.customerId = result.customer.id;
|
||||
|
||||
row.innerHTML = `
|
||||
<td class=\"px-3 py-2 whitespace-nowrap\">
|
||||
<div class=\"text-sm font-mono text-neutral-900 dark:text-neutral-100 truncate\" title=\"${result.customer.id}\">${result.customer.id}</div>
|
||||
<td class=\"px-4 py-4 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\" title=\"${result.customer.id}\">${result.customer.id}</div>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap\">
|
||||
<div class=\"text-sm font-medium text-neutral-900 dark:text-neutral-100 truncate\" title=\"${result.customer.name}\">${result.customer.name}</div>
|
||||
<td class=\"px-4 py-4 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\" title=\"${result.customer.name}\">${result.customer.name}</div>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap\">
|
||||
<span class="text-neutral-400 dark:text-neutral-500">-</span>
|
||||
<td class=\"px-4 py-4 customer-cell\">
|
||||
<span class="text-neutral-400 dark:text-neutral-500 text-sm font-medium">-</span>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap text-sm text-neutral-900 dark:text-neutral-100 truncate\" title=\"${result.customer.city}, ${result.customer.state}\">
|
||||
<td class=\"px-4 py-4 customer-cell\">
|
||||
<div class=\"text-sm font-medium text-neutral-900 dark:text-neutral-100\" title=\"${result.customer.city}, ${result.customer.state}\">
|
||||
${result.customer.city}, ${result.customer.state}
|
||||
</div>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap text-sm text-neutral-900 dark:text-neutral-100 truncate\" title=\"${result.location}: ${result.phone}\">
|
||||
<td class=\"px-4 py-4 customer-cell\">
|
||||
<div class=\"text-sm font-mono font-medium text-neutral-900 dark:text-neutral-100\" title=\"${result.location}: ${result.phone}\">
|
||||
<div class="font-semibold text-warning-600 dark:text-warning-400">${result.location}: ${result.phone}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap\">
|
||||
<span class="text-neutral-400 dark:text-neutral-500">-</span>
|
||||
<td class=\"px-4 py-4 customer-cell\">
|
||||
<span class="text-neutral-400 dark:text-neutral-500 text-sm font-medium">-</span>
|
||||
</td>
|
||||
<td class=\"px-3 py-2 whitespace-nowrap text-right text-sm font-medium\">
|
||||
<button onclick="editCustomer('${result.customer.id}')" class="inline-flex items-center gap-1 px-3 py-1.5 bg-primary-600 text-white hover:bg-primary-700 rounded-lg transition-colors duration-200 text-xs">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
<span>Edit</span>
|
||||
<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-phone-result-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-phone-result-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 for clickable row (same as main customer table)
|
||||
const customerCells = row.querySelectorAll('.customer-cell');
|
||||
customerCells.forEach(cell => {
|
||||
cell.addEventListener('click', () => viewCustomer(result.customer.id));
|
||||
});
|
||||
|
||||
// Add event listener for the view button
|
||||
const viewBtn = row.querySelector('.view-phone-result-btn');
|
||||
viewBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
viewCustomer(result.customer.id);
|
||||
});
|
||||
|
||||
// Add event listener for the edit button to avoid backslash escaping issues
|
||||
const editBtn = row.querySelector('.edit-phone-result-btn');
|
||||
editBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
editCustomer(result.customer.id);
|
||||
});
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user