changes
This commit is contained in:
@@ -136,6 +136,75 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative inline-block" id="phoneDirWrapper">
|
||||
<div class="flex items-center gap-1">
|
||||
<button id="phoneDirBtn" class="px-3 py-1.5 text-sm rounded-lg bg-neutral-100 dark:bg-neutral-700 text-neutral-700 dark:text-neutral-200 hover:bg-neutral-200 dark:hover:bg-neutral-600 transition-colors" title="Generate printable phone directory">
|
||||
<i class="fa-solid fa-address-book mr-1"></i>
|
||||
Phone Directory
|
||||
</button>
|
||||
<div class="relative group">
|
||||
<button type="button" class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300 transition-colors" title="Phone Directory Help">
|
||||
<i class="fa-solid fa-circle-question text-sm"></i>
|
||||
</button>
|
||||
<div class="hidden group-hover:block absolute right-0 mt-2 w-80 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg p-3 z-30">
|
||||
<div class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase mb-2">Phone Directory Help</div>
|
||||
<div class="space-y-2 text-xs text-neutral-600 dark:text-neutral-300">
|
||||
<p><strong>Grouping Options:</strong></p>
|
||||
<ul class="list-disc list-inside space-y-1 ml-2">
|
||||
<li><strong>None:</strong> Alphabetical by last name, no sections</li>
|
||||
<li><strong>By Letter:</strong> A-Z sections based on first letter of last name</li>
|
||||
<li><strong>By Group:</strong> Sections by customer group (Client, Attorney, etc.)</li>
|
||||
<li><strong>Group + Letter:</strong> Group sections, then letter subsections within each</li>
|
||||
</ul>
|
||||
<p class="mt-2"><strong>Letter Buckets:</strong> Names starting with numbers or symbols go into the "#" bucket.</p>
|
||||
<p class="mt-2"><strong>Page Breaks:</strong> HTML format can insert page breaks between top-level groups for printing.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="phoneDirPopover" class="hidden absolute right-0 mt-2 w-80 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg p-3 z-20">
|
||||
<div class="text-xs font-semibold text-neutral-500 dark:text-neutral-400 uppercase mb-2">Phone Directory</div>
|
||||
<div class="grid grid-cols-2 gap-3 text-sm">
|
||||
<div class="col-span-2">
|
||||
<label class="block text-xs text-neutral-600 dark:text-neutral-300 mb-1" for="phoneDirMode">Mode</label>
|
||||
<select id="phoneDirMode" class="w-full px-2 py-1.5 rounded border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800">
|
||||
<option value="numbers">Numbers</option>
|
||||
<option value="addresses">Addresses</option>
|
||||
<option value="full">Full</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-neutral-600 dark:text-neutral-300 mb-1" for="phoneDirFormat">Format</label>
|
||||
<select id="phoneDirFormat" class="w-full px-2 py-1.5 rounded border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800">
|
||||
<option value="html">HTML</option>
|
||||
<option value="csv">CSV</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-neutral-600 dark:text-neutral-300 mb-1" for="phoneDirGrouping">Grouping</label>
|
||||
<select id="phoneDirGrouping" class="w-full px-2 py-1.5 rounded border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800">
|
||||
<option value="none">None</option>
|
||||
<option value="letter">By Letter</option>
|
||||
<option value="group">By Group</option>
|
||||
<option value="group_letter">Group + Letter</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="inline-flex items-center gap-2 text-xs">
|
||||
<input type="checkbox" id="phoneDirPageBreak">
|
||||
<span>Page break per top-level group (HTML only)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-xs text-neutral-500 dark:text-neutral-400">Uses current group filters and sort.</div>
|
||||
<div class="mt-3 flex items-center justify-end gap-2">
|
||||
<button id="downloadPhoneDirBtn" class="px-3 py-1.5 text-sm rounded-lg bg-primary-600 text-white hover:bg-primary-700 transition-colors">
|
||||
<i class="fa-solid fa-download mr-1"></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
@@ -396,6 +465,56 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (compactBtn && window.toggleCompactMode) {
|
||||
compactBtn.addEventListener('click', window.toggleCompactMode);
|
||||
}
|
||||
// Support phone directory preconfiguration via URL
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const wantsPhoneDir = params.has('phone_dir') && params.get('phone_dir') !== '0' && params.get('phone_dir') !== 'false';
|
||||
const modeParam = params.get('mode');
|
||||
const formatParam = params.get('format');
|
||||
const groupingParam = params.get('grouping');
|
||||
const pageBreakParam = params.get('page_break');
|
||||
const namePrefixParam = params.get('name_prefix');
|
||||
|
||||
// If any params provided, set UI defaults
|
||||
setTimeout(() => {
|
||||
const fmt = document.getElementById('phoneDirFormat');
|
||||
const grp = document.getElementById('phoneDirGrouping');
|
||||
const pb = document.getElementById('phoneDirPageBreak');
|
||||
const md = document.getElementById('phoneDirMode');
|
||||
if (formatParam && fmt) fmt.value = formatParam;
|
||||
if (groupingParam && grp) grp.value = groupingParam;
|
||||
if (pageBreakParam != null && pb) pb.checked = (pageBreakParam === '1' || pageBreakParam === 'true');
|
||||
if (modeParam && md) md.value = modeParam;
|
||||
// If name_prefix provided and single char, also bind search field so our downloader logic includes it
|
||||
if (typeof namePrefixParam === 'string' && namePrefixParam.length === 1) {
|
||||
const s = document.getElementById('searchInput');
|
||||
if (s) s.value = namePrefixParam;
|
||||
}
|
||||
}, 25);
|
||||
|
||||
// Auto-open popover from hash or when phone_dir=1
|
||||
if (window.location.hash === '#phone-dir' || wantsPhoneDir) {
|
||||
setTimeout(() => {
|
||||
const btn = document.getElementById('phoneDirBtn');
|
||||
if (btn) btn.click();
|
||||
// If routing from hash without explicit params, set sensible defaults
|
||||
if (!formatParam || !groupingParam) {
|
||||
const fmt = document.getElementById('phoneDirFormat');
|
||||
const grp = document.getElementById('phoneDirGrouping');
|
||||
const pb = document.getElementById('phoneDirPageBreak');
|
||||
if (fmt && !formatParam) fmt.value = 'html';
|
||||
if (grp && !groupingParam) grp.value = 'letter';
|
||||
if (pb && !pageBreakParam) pb.checked = true;
|
||||
}
|
||||
// Auto-trigger download when phone_dir=1
|
||||
if (wantsPhoneDir) {
|
||||
const dl = document.getElementById('downloadPhoneDirBtn');
|
||||
if (dl) dl.click();
|
||||
}
|
||||
}, 60);
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// Initialize page size selector value
|
||||
const sizeSel = document.getElementById('pageSizeSelect');
|
||||
if (sizeSel) { sizeSel.value = String(window.customerPageSize); }
|
||||
@@ -531,6 +650,51 @@ function setupEventListeners() {
|
||||
e.stopPropagation();
|
||||
columnsPopover.classList.toggle('hidden');
|
||||
});
|
||||
// Phone directory popover toggle
|
||||
const phoneDirBtn = document.getElementById('phoneDirBtn');
|
||||
const phoneDirPopover = document.getElementById('phoneDirPopover');
|
||||
if (phoneDirBtn && phoneDirPopover) {
|
||||
phoneDirBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
phoneDirPopover.classList.toggle('hidden');
|
||||
});
|
||||
// Download action
|
||||
const downloadBtn = document.getElementById('downloadPhoneDirBtn');
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
const mode = (document.getElementById('phoneDirMode')?.value || 'numbers');
|
||||
const format = (document.getElementById('phoneDirFormat')?.value || 'html');
|
||||
const grouping = (document.getElementById('phoneDirGrouping')?.value || 'letter');
|
||||
const pageBreak = !!(document.getElementById('phoneDirPageBreak')?.checked);
|
||||
const u = new URL(window.location.origin + '/api/customers/phone-book');
|
||||
const p = u.searchParams;
|
||||
p.set('mode', mode);
|
||||
p.set('format', format);
|
||||
p.set('grouping', grouping);
|
||||
if (pageBreak) p.set('page_break', '1');
|
||||
// Include filters and sort
|
||||
const by = window.currentSortBy || 'name';
|
||||
const dir = window.currentSortDir || 'asc';
|
||||
p.set('sort_by', by);
|
||||
p.set('sort_dir', dir);
|
||||
(Array.isArray(window.currentGroupFilters) ? window.currentGroupFilters : []).forEach(v => p.append('groups', v));
|
||||
// Optional name prefix: if user typed single letter quickly, offer faster slicing
|
||||
const q = (document.getElementById('searchInput')?.value || '').trim();
|
||||
if (q && q.length === 1) {
|
||||
p.set('name_prefix', q);
|
||||
}
|
||||
// Trigger download
|
||||
window.location.href = u.toString();
|
||||
phoneDirPopover.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
// Clicking outside closes both popovers
|
||||
document.addEventListener('click', function() {
|
||||
phoneDirPopover.classList.add('hidden');
|
||||
});
|
||||
phoneDirPopover.addEventListener('click', function(e) { e.stopPropagation(); });
|
||||
}
|
||||
document.addEventListener('click', function() {
|
||||
columnsPopover.classList.add('hidden');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user