Spaces:
Sleeping
Sleeping
| function showContactDetails(contactId) { | |
| openContactDetailsModal(contactId); | |
| } | |
| // ── OPEN CONTACT DETAILS MODAL/DRAWER ── | |
| function openContactDetailsModal(contactId, isEditMode = false) { | |
| const c = mockContacts.find(x => x.id === contactId); | |
| if (!c) { | |
| alert("Contact not found."); | |
| return; | |
| } | |
| let backdrop = document.getElementById('contact-details-backdrop'); | |
| if (!backdrop) { | |
| backdrop = document.createElement('div'); | |
| backdrop.id = 'contact-details-backdrop'; | |
| backdrop.className = 'sidepanel-backdrop'; | |
| document.body.appendChild(backdrop); | |
| } | |
| let sidepanel = document.getElementById('contact-details-drawer'); | |
| if (!sidepanel) { | |
| sidepanel = document.createElement('div'); | |
| sidepanel.id = 'contact-details-drawer'; | |
| sidepanel.className = 'sidepanel'; | |
| document.body.appendChild(sidepanel); | |
| } | |
| if (isEditMode) { | |
| const companyOptions = mockCompanies.map(comp => `<option value="${comp.id}" ${comp.id === c.company_id ? 'selected' : ''}>${escapeHtml(comp.name)}</option>`).join(''); | |
| sidepanel.innerHTML = ` | |
| <div class="sidepanel-header"> | |
| <h3 class="sidepanel-title">Edit Contact</h3> | |
| </div> | |
| <form id="contact-edit-form" class="h-100 d-flex flex-column m-0"> | |
| <div class="sidepanel-body"> | |
| <div class="mb-3"> | |
| <label class="form-label-sm fw-semibold">Company *</label> | |
| <select class="form-select form-select-sm shadow-none" name="company_id" required> | |
| ${companyOptions} | |
| </select> | |
| </div> | |
| <div class="row g-2"> | |
| <div class="col-6 mb-3"> | |
| <label class="form-label-sm fw-semibold">First Name *</label> | |
| <input type="text" class="form-control form-control-sm shadow-none" name="first_name" value="${escapeHtml(c.first_name)}" required> | |
| </div> | |
| <div class="col-6 mb-3"> | |
| <label class="form-label-sm fw-semibold">Last Name *</label> | |
| <input type="text" class="form-control form-control-sm shadow-none" name="last_name" value="${escapeHtml(c.last_name)}" required> | |
| </div> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label-sm fw-semibold">Title / Position</label> | |
| <input type="text" class="form-control form-control-sm shadow-none" name="title" value="${escapeHtml(c.title || '')}" placeholder="e.g. Purchasing Manager"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label-sm fw-semibold">Email</label> | |
| <input type="email" class="form-control form-control-sm shadow-none" name="email" value="${escapeHtml(c.email || '')}" placeholder="e.g. john.doe@company.com"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label-sm fw-semibold">Phone</label> | |
| <input type="text" class="form-control form-control-sm shadow-none" name="phone" value="${escapeHtml(c.phone || '')}" placeholder="e.g. +1 555-123-4567"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label-sm fw-semibold">LinkedIn Profile URL</label> | |
| <input type="url" class="form-control form-control-sm shadow-none" name="linkedin" value="${escapeHtml(c.linkedin || '')}" placeholder="e.g. https://linkedin.com/in/username"> | |
| </div> | |
| <div class="form-check mb-3"> | |
| <input class="form-check-input shadow-none" type="checkbox" name="is_primary" id="contact-edit-is-primary" ${c.is_primary ? 'checked' : ''}> | |
| <label class="form-check-label small text-muted" for="contact-edit-is-primary" style="cursor: pointer;"> | |
| Mark as Primary Contact for this company | |
| </label> | |
| </div> | |
| </div> | |
| <div class="sidepanel-footer"> | |
| <button type="button" class="btn btn-outline-secondary btn-cancel-custom btn-sm" id="contact-edit-cancel-btn">Cancel</button> | |
| <button type="submit" class="btn btn-dark-custom btn-sm">Save Changes</button> | |
| </div> | |
| </form> | |
| `; | |
| } else { | |
| sidepanel.innerHTML = ` | |
| <div class="sidepanel-header"> | |
| <h3 class="sidepanel-title">Contact Profile</h3> | |
| <div> | |
| <button class="btn btn-outline-secondary btn-sm d-flex align-items-center gap-2" id="contact-details-edit-btn"> | |
| <i class="bi bi-pencil"></i> <span>Edit</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="sidepanel-body"> | |
| <div class="d-flex align-items-center gap-3 mb-4"> | |
| <div class="bg-dark text-white rounded-circle d-flex align-items-center justify-content-center fw-bold" style="width: 56px; height: 56px; font-size: 1.35rem;"> | |
| ${escapeHtml(c.first_name[0] || '')}${escapeHtml(c.last_name[0] || '')} | |
| </div> | |
| <div> | |
| <h4 class="m-0 fw-bold">${escapeHtml(c.first_name)} ${escapeHtml(c.last_name)}</h4> | |
| <p class="text-muted m-0 small">${escapeHtml(c.title || 'No Title')}</p> | |
| </div> | |
| </div> | |
| <div class="sidepanel-section-title">Professional Identity</div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">Associated Company</span> | |
| <strong class="text-dark small">${escapeHtml(c.company || 'No Company')}</strong> | |
| </div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">Role / Title</span> | |
| <span class="text-dark small">${escapeHtml(c.title) || '<span class="text-muted small">No Data</span>'}</span> | |
| </div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">Contact Role Status</span> | |
| ${c.is_primary ? `<span class="badge bg-dark text-white small">Primary Contact</span>` : `<span class="badge bg-light text-dark border small">Standard Contact</span>`} | |
| </div> | |
| <div class="sidepanel-section-title">Contact Details</div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">Email</span> | |
| ${c.email ? `<a href="mailto:${escapeHtml(c.email)}" class="text-dark text-decoration-underline small">${escapeHtml(c.email)}</a>` : '<span class="text-muted small">No Data</span>'} | |
| </div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">Phone</span> | |
| <span class="text-dark small">${escapeHtml(c.phone) || '<span class="text-muted small">No Data</span>'}</span> | |
| </div> | |
| <div class="mb-3"> | |
| <span class="field-label d-block text-uppercase text-muted fw-bold" style="font-size: 0.72rem;">LinkedIn</span> | |
| ${c.linkedin ? `<a href="${escapeHtml(c.linkedin)}" target="_blank" class="text-dark text-decoration-underline small"><i class="bi bi-linkedin me-1 text-muted"></i>${escapeHtml(c.linkedin)}</a>` : '<span class="text-muted small">No Data</span>'} | |
| </div> | |
| </div> | |
| <div class="sidepanel-footer"> | |
| <button type="button" class="btn btn-dark-custom btn-sm" id="contact-details-ok-btn">Close</button> | |
| </div> | |
| `; | |
| } | |
| const closeBtn = document.getElementById('contact-details-close-btn'); | |
| const closeDrawer = () => { | |
| sidepanel.classList.remove('show'); | |
| backdrop.classList.remove('show'); | |
| }; | |
| if (closeBtn) { | |
| closeBtn.addEventListener('click', closeDrawer); | |
| } | |
| backdrop.onclick = closeDrawer; | |
| if (isEditMode) { | |
| const cancelBtn = document.getElementById('contact-edit-cancel-btn'); | |
| const form = document.getElementById('contact-edit-form'); | |
| if (cancelBtn) { | |
| cancelBtn.addEventListener('click', () => { | |
| openContactDetailsModal(contactId, false); | |
| }); | |
| } | |
| if (form) { | |
| form.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const formData = new FormData(form); | |
| const payload = {}; | |
| formData.forEach((val, key) => { | |
| payload[key] = val; | |
| }); | |
| payload.company_id = parseInt(payload.company_id, 10); | |
| payload.is_primary = document.getElementById('contact-edit-is-primary').checked ? 1 : 0; | |
| try { | |
| const response = await fetch(`/api/contacts/${contactId}`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(payload) | |
| }); | |
| const result = await response.json(); | |
| if (response.ok && result.success) { | |
| closeDrawer(); | |
| await loadDataFromDb(); | |
| handleNavigation(); | |
| } else { | |
| alert("Error: " + (result.error || "Could not save contact.")); | |
| } | |
| } catch (err) { | |
| console.error("Error updating contact:", err); | |
| alert("Error sending update request to backend."); | |
| } | |
| }); | |
| } | |
| } else { | |
| const editBtn = document.getElementById('contact-details-edit-btn'); | |
| const okBtn = document.getElementById('contact-details-ok-btn'); | |
| if (editBtn) { | |
| editBtn.addEventListener('click', () => { | |
| openContactDetailsModal(contactId, true); | |
| }); | |
| } | |
| if (okBtn) { | |
| okBtn.addEventListener('click', closeDrawer); | |
| } | |
| } | |
| setTimeout(() => { | |
| sidepanel.classList.add('show'); | |
| backdrop.classList.add('show'); | |
| }, 10); | |
| } | |
| // ── OPEN AGENT SPACE DRAWER/SIDEPANEL ── | |