From 583f1c9d32edc20d4783b9a0306976636b30a72e Mon Sep 17 00:00:00 2001 From: Kobe Date: Tue, 10 Jun 2025 12:39:46 +0200 Subject: [PATCH] Update instance_detail.html --- templates/main/instance_detail.html | 655 ++++++++++++++++++++++++++-- 1 file changed, 612 insertions(+), 43 deletions(-) diff --git a/templates/main/instance_detail.html b/templates/main/instance_detail.html index 06252c9..0d00c08 100644 --- a/templates/main/instance_detail.html +++ b/templates/main/instance_detail.html @@ -88,6 +88,11 @@ Company Information +
@@ -98,45 +103,205 @@
Company Details
- -

Loading...

+
+
Company Name:
+
Loading...
+
- -

Loading...

+
+
Industry:
+
Loading...
+
- -

Loading...

+
+
Description:
+
Loading...
+
Contact Information
- -

Loading...

+
+
Email:
+
Loading...
+
- -

Loading...

+
+
Phone:
+
Loading...
+
- -

Loading...

+
+
Website:
+
Loading...
+
- -

Loading...

+
+
Address:
+
Loading...
+
+ + +
+
+
Contact List
+ +
+ + +
+ + + + + + + + + + + + + + + + + +
NameEmailPhoneCompanyPositionStatusActions
Loading contacts...
+
+
+ + + + + + + + + {% endblock %} {% block extra_js %} @@ -148,7 +313,7 @@ console.log('Script block loaded'); function testElements() { console.log('Testing DOM elements...'); const elements = [ - 'company-name', + 'company-name-value', 'company-industry', 'company-description', 'company-email', @@ -277,10 +442,35 @@ async function fetchCompanyInfo() { const data = await response.json(); console.log('Settings data received:', data); + // Update company name separately with debugging + const companyNameElement = document.getElementById('company-name-value'); + const companyNameLabel = document.getElementById('company-name-label'); + console.log('Before update - Label:', companyNameLabel?.textContent); + console.log('Before update - Value:', companyNameElement?.textContent); + + if (companyNameElement) { + companyNameElement.textContent = data.company_name || 'Not set'; + } + + // Ensure label text is set + if (companyNameLabel && !companyNameLabel.textContent) { + companyNameLabel.textContent = 'Company Name:'; + } + + console.log('After update - Label:', companyNameLabel?.textContent); + console.log('After update - Value:', companyNameElement?.textContent); + // Update company details - document.getElementById('company-name').textContent = data.company_name || 'Not set'; - document.getElementById('company-industry').textContent = data.company_industry || 'Not set'; - document.getElementById('company-description').textContent = data.company_description || 'Not set'; + const updateElement = (id, value) => { + const element = document.getElementById(id); + if (element && element.classList.contains('company-value')) { + element.textContent = value || 'Not set'; + } + }; + + // Update other company details + updateElement('company-industry', data.company_industry); + updateElement('company-description', data.company_description); // Update contact information const emailElement = document.getElementById('company-email'); @@ -288,35 +478,41 @@ async function fetchCompanyInfo() { const websiteElement = document.getElementById('company-website'); // Update email with mailto link - if (data.company_email && data.company_email !== 'Not set') { - emailElement.innerHTML = ` - ${data.company_email} - `; - } else { - emailElement.textContent = 'Not set'; + if (emailElement && emailElement.classList.contains('company-value')) { + if (data.company_email && data.company_email !== 'Not set') { + emailElement.innerHTML = ` + ${data.company_email} + `; + } else { + emailElement.textContent = 'Not set'; + } } // Update phone with tel link - if (data.company_phone && data.company_phone !== 'Not set') { - phoneElement.innerHTML = ` - ${data.company_phone} - `; - } else { - phoneElement.textContent = 'Not set'; + if (phoneElement && phoneElement.classList.contains('company-value')) { + if (data.company_phone && data.company_phone !== 'Not set') { + phoneElement.innerHTML = ` + ${data.company_phone} + `; + } else { + phoneElement.textContent = 'Not set'; + } } // Update website with external link - if (data.company_website && data.company_website !== 'Not set') { - // Ensure website has http/https prefix - let websiteUrl = data.company_website; - if (!websiteUrl.startsWith('http://') && !websiteUrl.startsWith('https://')) { - websiteUrl = 'https://' + websiteUrl; + if (websiteElement && websiteElement.classList.contains('company-value')) { + if (data.company_website && data.company_website !== 'Not set') { + // Ensure website has http/https prefix + let websiteUrl = data.company_website; + if (!websiteUrl.startsWith('http://') && !websiteUrl.startsWith('https://')) { + websiteUrl = 'https://' + websiteUrl; + } + websiteElement.innerHTML = ` + ${data.company_website} + `; + } else { + websiteElement.textContent = 'Not set'; } - websiteElement.innerHTML = ` - ${data.company_website} - `; - } else { - websiteElement.textContent = 'Not set'; } // Format address @@ -327,16 +523,19 @@ async function fetchCompanyInfo() { data.company_zip, data.company_country ].filter(Boolean); - document.getElementById('company-address').textContent = addressParts.length ? addressParts.join(', ') : 'Not set'; + updateElement('company-address', addressParts.length ? addressParts.join(', ') : 'Not set'); console.log('Company info update complete'); } catch (error) { console.error('Error in fetchCompanyInfo:', error); // Show error state in all fields - const fields = ['company-name', 'company-industry', 'company-description', + const fields = ['company-name-value', 'company-industry', 'company-description', 'company-email', 'company-phone', 'company-website', 'company-address']; fields.forEach(field => { - document.getElementById(field).textContent = 'Error loading data'; + const element = document.getElementById(field); + if (element && element.classList.contains('company-value')) { + element.textContent = 'Error loading data'; + } }); } } @@ -374,5 +573,375 @@ window.addEventListener('beforeunload', function() { clearInterval(statusUpdateInterval); } }); + +// Contacts Management Functions +async function fetchContacts() { + try { + // First get JWT token + console.log('Getting management token for contacts...'); + const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, { + method: 'POST', + headers: { + 'X-API-Key': '{{ instance.connection_token }}', + 'Accept': 'application/json' + } + }); + + if (!tokenResponse.ok) { + throw new Error('Failed to get management token'); + } + + const tokenData = await tokenResponse.json(); + if (!tokenData.token) { + throw new Error('No token received'); + } + + // Then fetch contacts using the JWT token + const response = await fetch(`{{ instance.main_url }}/api/admin/contacts`, { + headers: { + 'Accept': 'application/json', + 'Authorization': `Bearer ${tokenData.token}` + } + }); + + if (!response.ok) { + throw new Error('Failed to fetch contacts'); + } + + const contacts = await response.json(); + const contactsList = document.getElementById('contactsTableBody'); + contactsList.innerHTML = ''; + + if (contacts.length === 0) { + contactsList.innerHTML = ` +
+ +

No contacts found

+
+ `; + return; + } + + contacts.forEach(contact => { + const row = document.createElement('tr'); + row.innerHTML = ` + ${contact.username} + ${contact.email || 'Not set'} + ${contact.phone || 'Not set'} + ${contact.company || 'Not set'} + ${contact.position || 'Not set'} + + + ${contact.is_active ? 'Active' : 'Inactive'} + + + +
+ + +
+ + `; + contactsList.appendChild(row); + }); + } catch (error) { + console.error('Error fetching contacts:', error); + const contactsList = document.getElementById('contactsTableBody'); + contactsList.innerHTML = ` +
+ +

Error loading contacts

+
+ `; + } +} + +async function addContact(event) { + event.preventDefault(); + try { + // First get JWT token + const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, { + method: 'POST', + headers: { + 'X-API-Key': '{{ instance.connection_token }}', + 'Accept': 'application/json' + } + }); + + if (!tokenResponse.ok) { + throw new Error('Failed to get management token'); + } + + const tokenData = await tokenResponse.json(); + if (!tokenData.token) { + throw new Error('No token received'); + } + + const formData = new FormData(event.target); + const response = await fetch(`{{ instance.main_url }}/api/admin/contacts`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${tokenData.token}` + }, + body: JSON.stringify({ + username: formData.get('name'), + email: formData.get('email'), + phone: formData.get('phone'), + company: formData.get('company'), + position: formData.get('position'), + status: formData.get('status') + }) + }); + + if (!response.ok) { + throw new Error('Failed to add contact'); + } + + // Close modal and refresh list + const modal = bootstrap.Modal.getInstance(document.getElementById('addContactModal')); + modal.hide(); + fetchContacts(); + + // Show success message + showToast('Contact added successfully', 'success'); + } catch (error) { + console.error('Error adding contact:', error); + showToast('Error adding contact', 'error'); + } +} + +async function editContact(id) { + try { + // First get JWT token + const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, { + method: 'POST', + headers: { + 'X-API-Key': '{{ instance.connection_token }}', + 'Accept': 'application/json' + } + }); + + if (!tokenResponse.ok) { + throw new Error('Failed to get management token'); + } + + const tokenData = await tokenResponse.json(); + if (!tokenData.token) { + throw new Error('No token received'); + } + + const response = await fetch(`{{ instance.main_url }}/api/admin/contacts/${id}`, { + headers: { + 'Accept': 'application/json', + 'Authorization': `Bearer ${tokenData.token}` + } + }); + + if (!response.ok) { + throw new Error('Failed to fetch contact details'); + } + + const contact = await response.json(); + + // Populate form + document.getElementById('edit-contact-id').value = contact.id; + document.getElementById('edit-name').value = contact.username; + document.getElementById('edit-email').value = contact.email || ''; + document.getElementById('edit-phone').value = contact.phone || ''; + document.getElementById('edit-company').value = contact.company || ''; + document.getElementById('edit-position').value = contact.position || ''; + document.getElementById('edit-status').value = contact.is_active ? 'active' : 'inactive'; + + // Show modal + const modal = new bootstrap.Modal(document.getElementById('editContactModal')); + modal.show(); + } catch (error) { + console.error('Error fetching contact details:', error); + showToast('Error loading contact details', 'error'); + } +} + +async function updateContact(event) { + event.preventDefault(); + try { + // First get JWT token + const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, { + method: 'POST', + headers: { + 'X-API-Key': '{{ instance.connection_token }}', + 'Accept': 'application/json' + } + }); + + if (!tokenResponse.ok) { + throw new Error('Failed to get management token'); + } + + const tokenData = await tokenResponse.json(); + if (!tokenData.token) { + throw new Error('No token received'); + } + + const formData = new FormData(event.target); + const id = formData.get('id'); + + const response = await fetch(`{{ instance.main_url }}/api/admin/contacts/${id}`, { + method: 'PUT', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${tokenData.token}` + }, + body: JSON.stringify({ + username: formData.get('name'), + email: formData.get('email'), + phone: formData.get('phone'), + company: formData.get('company'), + position: formData.get('position'), + status: formData.get('status') === 'active' + }) + }); + + if (!response.ok) { + throw new Error('Failed to update contact'); + } + + // Close modal and refresh list + const modal = bootstrap.Modal.getInstance(document.getElementById('editContactModal')); + modal.hide(); + fetchContacts(); + + // Show success message + showToast('Contact updated successfully', 'success'); + } catch (error) { + console.error('Error updating contact:', error); + showToast('Error updating contact', 'error'); + } +} + +async function deleteContact(id) { + // Store the contact ID for the delete confirmation + const deleteModal = new bootstrap.Modal(document.getElementById('deleteContactModal')); + document.getElementById('confirmDelete').onclick = async () => { + try { + // First get JWT token + const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, { + method: 'POST', + headers: { + 'X-API-Key': '{{ instance.connection_token }}', + 'Accept': 'application/json' + } + }); + + if (!tokenResponse.ok) { + throw new Error('Failed to get management token'); + } + + const tokenData = await tokenResponse.json(); + if (!tokenData.token) { + throw new Error('No token received'); + } + + const response = await fetch(`{{ instance.main_url }}/api/admin/contacts/${id}`, { + method: 'DELETE', + headers: { + 'Accept': 'application/json', + 'Authorization': `Bearer ${tokenData.token}` + } + }); + + if (!response.ok) { + throw new Error('Failed to delete contact'); + } + + // Close modal and refresh list + deleteModal.hide(); + fetchContacts(); + + // Show success message + showToast('Contact deleted successfully', 'success'); + } catch (error) { + console.error('Error deleting contact:', error); + showToast('Error deleting contact', 'error'); + } + }; + + // Show the delete confirmation modal + deleteModal.show(); +} + +// Helper function to show toast messages +function showToast(title, message, type = 'info') { + const toast = document.createElement('div'); + toast.className = `toast align-items-center text-white bg-${type} border-0`; + toast.setAttribute('role', 'alert'); + toast.setAttribute('aria-live', 'assertive'); + toast.setAttribute('aria-atomic', 'true'); + + toast.innerHTML = ` +
+
+ ${title}
+ ${message} +
+ +
+ `; + + const toastContainer = document.getElementById('toastContainer') || (() => { + const container = document.createElement('div'); + container.id = 'toastContainer'; + container.className = 'toast-container position-fixed bottom-0 end-0 p-3'; + document.body.appendChild(container); + return container; + })(); + + toastContainer.appendChild(toast); + const bsToast = new bootstrap.Toast(toast); + bsToast.show(); + + toast.addEventListener('hidden.bs.toast', () => { + toast.remove(); + }); +} + +// Event Listeners +document.addEventListener('DOMContentLoaded', function() { + // ... existing event listeners ... + + // Fetch contacts when contacts tab is shown + document.getElementById('contacts-tab').addEventListener('shown.bs.tab', fetchContacts); + + // Debug the company name label + const label = document.getElementById('company-name-label'); + if (label) { + console.log('Company name label found:', label); + + // Create a MutationObserver to watch for changes + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + console.log('Label changed:', mutation); + console.log('Old value:', mutation.oldValue); + console.log('New value:', label.textContent); + }); + }); + + // Start observing + observer.observe(label, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }); + } else { + console.log('Company name label not found'); + } +}); {% endblock %} \ No newline at end of file