renderer.js
unknown
javascript
9 months ago
38 kB
20
Indexable
document.addEventListener('DOMContentLoaded', () => {
loadContent('dashboard');
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
document.querySelectorAll('.nav-link').forEach(n => n.classList.remove('active'));
e.target.classList.add('active');
loadContent(e.target.dataset.page);
});
});
});
async function loadContent(page) {
const container = document.getElementById('main-content');
const title = document.getElementById('page-title');
showLoading();
try {
title.textContent = page.charAt(0).toUpperCase() + page.slice(1);
// Updated path construction
const pagePath = `./src/pages/${page}.html`;
const response = await fetch(pagePath);
if (!response.ok) {
throw new Error(`Failed to load page: ${response.status} ${response.statusText}`);
}
container.innerHTML = await response.text();
if (typeof window[`init${page.charAt(0).toUpperCase() + page.slice(1)}`] === 'function') {
await window[`init${page.charAt(0).toUpperCase() + page.slice(1)}`]();
}
} catch (error) {
showError(error);
} finally {
hideLoading();
}
}
// ==================== DASHBOARD ====================
window.initDashboard = async () => {
try {
const stats = await window.electron.queryDB(`
SELECT
(SELECT COUNT(*) FROM veterinarians) AS vets,
(SELECT COUNT(*) FROM clients) AS clients,
(SELECT COUNT(*) FROM pets) AS pets,
(SELECT COUNT(*) FROM appointments) AS appointments
`);
const upcomingAppointments = await window.electron.queryDB(`
SELECT a.*, p.name AS pet_name, v.name AS vet_name
FROM appointments a
JOIN pets p ON a.pet_id = p.id
JOIN veterinarians v ON a.vet_id = v.id
WHERE a.date > NOW()
ORDER BY a.date ASC
LIMIT 5
`);
// Display stats
document.getElementById('main-content').innerHTML = `
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-body">
<h5 class="card-title">Veterinarians</h5>
<p class="card-text display-4">${stats[0].vets}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-body">
<h5 class="card-title">Clients</h5>
<p class="card-text display-4">${stats[0].clients}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-body">
<h5 class="card-title">Pets</h5>
<p class="card-text display-4">${stats[0].pets}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-body">
<h5 class="card-title">Appointments</h5>
<p class="card-text display-4">${stats[0].appointments}</p>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Upcoming Appointments</h5>
</div>
<div class="card-body">
${upcomingAppointments.length === 0 ?
'<div class="text-muted">No upcoming appointments</div>' :
`<div class="list-group">
${upcomingAppointments.map(app => `
<div class="list-group-item">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">${app.pet_name} - ${app.type}</h6>
<small>${new Date(app.date).toLocaleString()}</small>
</div>
<p class="mb-1">With ${app.vet_name}</p>
<small class="text-muted">Status: ${app.status}</small>
</div>
`).join('')}
</div>`
}
</div>
</div>
`;
} catch (error) {
showError(error);
}
};
// ==================== UTILITY FUNCTIONS ====================
function showLoading() {
document.getElementById('loading').style.display = 'flex';
}
function hideLoading() {
document.getElementById('loading').style.display = 'none';
}
function showError(error) {
const container = document.getElementById('main-content');
container.innerHTML = `
<div class="alert alert-danger">
<h5>Error loading content</h5>
<pre>${error.message}</pre>
</div>
`;
}
// ==================== CLIENTS ====================
window.initClients = async () => {
try {
const clients = await window.electron.queryDB(`
SELECT c.*, COUNT(p.id) AS pet_count
FROM clients c
LEFT JOIN pets p ON c.id = p.owner_id
GROUP BY c.id
`);
const tbody = document.getElementById('clients-list');
if (!tbody) return;
tbody.innerHTML = clients.length === 0 ?
'<tr><td colspan="5" class="text-center">No clients found.</td></tr>' :
clients.map(client => `
<tr>
<td>${client.name}</td>
<td>
${client.email ? `${client.email}<br>` : ''}
${client.phone || ''}
</td>
<td>${client.address ? client.address.replace(/\n/g, '<br>') : ''}</td>
<td>${client.pet_count}</td>
<td>
<button class="btn btn-sm btn-outline-primary me-2" onclick="loadClientData(${client.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteClient(${client.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('');
// Add form handler
const addForm = document.getElementById('addClientForm');
if (addForm) {
addForm.addEventListener('submit', handleAddClient);
}
// Edit form handler
const editForm = document.getElementById('editClientForm');
if (editForm) {
editForm.addEventListener('submit', handleEditClient);
}
} catch (error) {
showError(error);
}
};
async function handleAddClient(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const clientData = Object.fromEntries(formData.entries());
try {
await window.electron.queryDB(
'INSERT INTO clients (name, email, phone, address) VALUES (?, ?, ?, ?)',
[clientData.name, clientData.email, clientData.phone, clientData.address]
);
const modalEl = document.getElementById('addClientModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
form.reset();
await initClients();
showToast('Client added successfully', 'success');
} catch (error) {
showError(error);
}
}
async function handleEditClient(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const clientId = formData.get('id');
try {
await window.electron.queryDB(
'UPDATE clients SET name = ?, email = ?, phone = ?, address = ? WHERE id = ?',
[formData.get('name'), formData.get('email'), formData.get('phone'), formData.get('address'), clientId]
);
const modalEl = document.getElementById('editClientModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
await initClients();
showToast('Client updated successfully', 'success');
} catch (error) {
showError(error);
}
}
async function loadClientData(id) {
try {
const [client] = await window.electron.queryDB(
'SELECT * FROM clients WHERE id = ?',
[id]
);
if (client) {
const form = document.getElementById('editClientForm');
if (!form) return;
form.elements['id'].value = client.id;
form.elements['name'].value = client.name;
form.elements['email'].value = client.email || '';
form.elements['phone'].value = client.phone || '';
form.elements['address'].value = client.address || '';
const modal = new bootstrap.Modal(document.getElementById('editClientModal'));
modal.show();
}
} catch (error) {
showError(error);
}
}
async function deleteClient(id) {
if (!confirm('Are you sure you want to delete this client?')) {
return;
}
try {
await window.electron.queryDB(
'DELETE FROM clients WHERE id = ?',
[id]
);
await initClients();
showToast('Client deleted successfully', 'success');
} catch (error) {
showError(error);
}
}
// ==================== PETS ====================
let currentPetId = null;
async function handleAddPet(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const petData = Object.fromEntries(formData.entries());
// Convert empty string to null for optional fields
if (!petData.age) petData.age = null;
if (!petData.species) petData.species = null;
if (!petData.breed) petData.breed = null;
try {
await window.electron.queryDB(
'INSERT INTO pets (name, species, breed, age, owner_id) VALUES (?, ?, ?, ?, ?)',
[petData.name, petData.species, petData.breed, petData.age, petData.owner_id]
);
const modalEl = document.getElementById('addPetModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
form.reset();
await initPets();
showToast('Pet added successfully', 'success');
} catch (error) {
showError(error);
}
}
async function handleEditPet(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const petId = formData.get('id');
const petData = Object.fromEntries(formData.entries());
// Convert empty string to null for optional fields
if (!petData.age) petData.age = null;
if (!petData.species) petData.species = null;
if (!petData.breed) petData.breed = null;
try {
await window.electron.queryDB(
'UPDATE pets SET name = ?, species = ?, breed = ?, age = ?, owner_id = ? WHERE id = ?',
[petData.name, petData.species, petData.breed, petData.age, petData.owner_id, petId]
);
const modalEl = document.getElementById('editPetModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
await initPets();
showToast('Pet updated successfully', 'success');
} catch (error) {
showError(error);
}
}
async function loadPetData(id) {
try {
const [pet] = await window.electron.queryDB(
'SELECT * FROM pets WHERE id = ?',
[id]
);
if (pet) {
const form = document.getElementById('editPetForm');
if (!form) return;
form.elements['id'].value = pet.id;
form.elements['name'].value = pet.name;
form.elements['species'].value = pet.species || '';
form.elements['breed'].value = pet.breed || '';
form.elements['age'].value = pet.age || '';
form.elements['owner_id'].value = pet.owner_id;
const modal = new bootstrap.Modal(document.getElementById('editPetModal'));
modal.show();
}
} catch (error) {
showError(error);
}
}
async function deletePet(id) {
if (!confirm('Are you sure you want to delete this pet? This will also delete all associated appointments.')) {
return;
}
try {
// First delete related appointments
await window.electron.queryDB(
'DELETE FROM appointments WHERE pet_id = ?',
[id]
);
// Then delete the pet
await window.electron.queryDB(
'DELETE FROM pets WHERE id = ?',
[id]
);
await initPets();
showToast('Pet deleted successfully', 'success');
} catch (error) {
showError(error);
}
}
async function openMedicalRecords(petId) {
currentPetId = petId;
await Promise.all([loadMedications(petId), loadAttachments(petId)]);
const modal = new bootstrap.Modal(document.getElementById('medicalRecordsModal'));
modal.show();
}
async function loadMedications(petId) {
try {
const medications = await window.electron.queryDB(`
SELECT m.*, v.name as vet_name
FROM pet_medical_records m
LEFT JOIN veterinarians v ON m.vet_id = v.id
WHERE m.pet_id = ?
ORDER BY m.date DESC
`, [petId]);
const tbody = document.getElementById('medicationsList');
if (!tbody) return;
tbody.innerHTML = medications.length === 0 ?
'<tr><td colspan="6" class="text-center">No medication records found</td></tr>' :
medications.map(med => `
<tr>
<td>${new Date(med.date).toLocaleDateString()}</td>
<td>${med.medication_name}</td>
<td>${med.dosage}</td>
<td>${med.notes || '-'}</td>
<td>${med.next_appointment_date ? new Date(med.next_appointment_date).toLocaleDateString() : '-'}</td>
<td>${med.vet_name || 'Unknown'}</td>
</tr>
`).join('');
} catch (error) {
showError(error);
}
}
async function loadAttachments(petId) {
try {
const attachments = await window.electron.queryDB(`
SELECT a.*, v.name as vet_name
FROM pet_attachments a
LEFT JOIN veterinarians v ON a.uploaded_by = v.id
WHERE a.pet_id = ?
ORDER BY a.upload_date DESC
`, [petId]);
const tbody = document.getElementById('attachmentsList');
if (!tbody) return;
tbody.innerHTML = attachments.length === 0 ?
'<tr><td colspan="5" class="text-center">No attachments found</td></tr>' :
attachments.map(att => `
<tr>
<td>${new Date(att.upload_date).toLocaleDateString()}</td>
<td>${att.file_name}</td>
<td>${att.description || '-'}</td>
<td>${att.vet_name || 'Unknown'}</td>
<td>
<button class="btn btn-sm btn-outline-primary me-2" onclick="viewAttachment('${att.file_path}')">
<i class="bi bi-eye"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteAttachment(${att.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('');
} catch (error) {
showError(error);
}
}
async function deleteAttachment(id) {
if (!confirm('Are you sure you want to delete this attachment?')) {
return;
}
try {
const [attachment] = await window.electron.queryDB(
'SELECT file_path FROM pet_attachments WHERE id = ?',
[id]
);
if (attachment) {
// Delete file from filesystem
await window.electron.deleteFile(attachment.file_path);
// Delete record from database
await window.electron.queryDB(
'DELETE FROM pet_attachments WHERE id = ?',
[id]
);
await loadAttachments(currentPetId);
showToast('Attachment deleted successfully', 'success');
}
} catch (error) {
showError(error);
}
}
async function viewAttachment(filePath) {
try {
await window.electron.openFile(filePath);
} catch (error) {
showError(error);
}
}
async function handleAddMedication(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
try {
const [vet] = await window.electron.queryDB('SELECT id FROM veterinarians LIMIT 1');
await window.electron.queryDB(`
INSERT INTO pet_medical_records
(pet_id, vet_id, date, medication_name, dosage, notes, next_appointment_date)
VALUES (?, ?, NOW(), ?, ?, ?, ?)
`, [
currentPetId,
vet.id,
formData.get('medication_name'),
formData.get('dosage'),
formData.get('notes') || null,
formData.get('next_appointment_date') || null
]);
const modal = bootstrap.Modal.getInstance(document.getElementById('addMedicationModal'));
modal.hide();
form.reset();
await loadMedications(currentPetId);
showToast('Medication record added successfully', 'success');
} catch (error) {
showError(error);
}
}
async function handleUploadAttachment(e) {
e.preventDefault();
const form = e.target;
const fileInput = document.getElementById('attachmentFile');
const description = document.getElementById('attachmentDescription').value;
if (!fileInput.files?.length) {
showToast('Please select a file', 'error');
return;
}
try {
const file = fileInput.files[0];
const [vet] = await window.electron.queryDB('SELECT id FROM veterinarians LIMIT 1');
const uploadResult = await window.electron.uploadFile(file);
if (uploadResult.success) {
await window.electron.queryDB(`
INSERT INTO pet_attachments
(pet_id, file_name, file_path, file_type, upload_date, uploaded_by, description)
VALUES (?, ?, ?, ?, NOW(), ?, ?)
`, [
currentPetId,
file.name,
uploadResult.filePath,
file.type,
vet.id,
description || null
]);
form.reset();
await loadAttachments(currentPetId);
showToast('Attachment uploaded successfully', 'success');
}
} catch (error) {
showError(error);
}
}
window.initPets = async () => {
try {
const [pets, clients] = await Promise.all([
window.electron.queryDB(`
SELECT p.*, c.name AS owner_name
FROM pets p
JOIN clients c ON p.owner_id = c.id
ORDER BY p.name
`),
window.electron.queryDB('SELECT id, name FROM clients ORDER BY name')
]);
// Populate owner select dropdowns in both forms
const ownerSelects = document.querySelectorAll('select[name="owner_id"]');
ownerSelects.forEach(select => {
select.innerHTML = `
<option value="">Select an owner</option>
${clients.map(c => `<option value="${c.id}">${c.name}</option>`).join('')}
`;
});
// Render pets table
const tbody = document.getElementById('pets-list');
if (!tbody) return;
tbody.innerHTML = pets.length === 0 ?
'<tr><td colspan="5" class="text-center">No pets found.</td></tr>' :
pets.map(pet => `
<tr>
<td>${pet.name}</td>
<td>${pet.species || 'Unknown'} / ${pet.breed || 'Mixed'}</td>
<td>${pet.age ? `${pet.age} years` : '-'}</td>
<td>${pet.owner_name}</td>
<td>
<button class="btn btn-sm btn-outline-primary me-2" onclick="loadPetData(${pet.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deletePet(${pet.id})">
<i class="bi bi-trash"></i>
</button>
<button class="btn btn-sm btn-outline-info me-2" onclick="openMedicalRecords(${pet.id})">
<i class="bi bi-journal-medical"></i>
</button>
</td>
</tr>
`).join('');
// Add form handler
const addForm = document.getElementById('addPetForm');
if (addForm) {
addForm.addEventListener('submit', handleAddPet);
}
// Edit form handler
const editForm = document.getElementById('editPetForm');
if (editForm) {
editForm.addEventListener('submit', handleEditPet);
}
// Medical record handlers
document.getElementById('addMedicationForm')?.addEventListener('submit', handleAddMedication);
document.getElementById('uploadAttachmentForm')?.addEventListener('submit', handleUploadAttachment);
} catch (error) {
showError(error);
}
};
// ==================== APPOINTMENTS ====================
window.initAppointments = async () => {
try {
const [appointments, pets, vets] = await Promise.all([
window.electron.queryDB(`
SELECT
a.*,
p.name AS pet_name,
c.name AS owner_name,
v.name AS vet_name
FROM appointments a
JOIN pets p ON a.pet_id = p.id
JOIN clients c ON p.owner_id = c.id
JOIN veterinarians v ON a.vet_id = v.id
ORDER BY a.date DESC
`),
window.electron.queryDB('SELECT id, name FROM pets ORDER BY name'),
window.electron.queryDB('SELECT id, name FROM veterinarians ORDER BY name')
]);
// Populate select dropdowns in both forms
const petSelects = document.querySelectorAll('select[name="pet_id"]');
const vetSelects = document.querySelectorAll('select[name="vet_id"]');
petSelects.forEach(select => {
select.innerHTML = `
<option value="">Select a pet</option>
${pets.map(p => `<option value="${p.id}">${p.name}</option>`).join('')}
`;
});
vetSelects.forEach(select => {
select.innerHTML = `
<option value="">Select a veterinarian</option>
${vets.map(v => `<option value="${v.id}">${v.name}</option>`).join('')}
`;
});
// Render appointments table
const tbody = document.getElementById('appointments-list');
tbody.innerHTML = appointments.length === 0 ?
'<tr><td colspan="7" class="text-center">No appointments found</td></tr>' :
appointments.map(app => `
<tr>
<td>${new Date(app.date).toLocaleString()}</td>
<td>${app.pet_name}</td>
<td>${app.owner_name}</td>
<td>${app.vet_name}</td>
<td><span class="badge bg-primary">${app.type}</span></td>
<td><span class="badge ${getStatusBadge(app.status)}">${app.status}</span></td>
<td>
<button class="btn btn-sm btn-outline-primary me-2" onclick="loadAppointmentData(${app.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteAppointment(${app.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('');
// Add form handler
const addForm = document.getElementById('addAppointmentForm');
if (addForm) {
addForm.addEventListener('submit', handleAddAppointment);
}
// Edit form handler
const editForm = document.getElementById('editAppointmentForm');
if (editForm) {
editForm.addEventListener('submit', handleEditAppointment);
}
} catch (error) {
showError(error);
}
};
async function handleAddAppointment(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const appointmentData = Object.fromEntries(formData.entries());
try {
// Validate date is not in the past
if (new Date(appointmentData.date) < new Date()) {
throw new Error('Appointment date cannot be in the past');
}
await window.electron.queryDB(
'INSERT INTO appointments (pet_id, vet_id, date, type, notes, status) VALUES (?, ?, ?, ?, ?, ?)',
[
appointmentData.pet_id,
appointmentData.vet_id,
appointmentData.date,
appointmentData.type,
appointmentData.notes || null,
'scheduled'
]
);
const modalEl = document.getElementById('addAppointmentModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
form.reset();
await initAppointments();
showToast('Appointment added successfully', 'success');
} catch (error) {
showError(error);
}
}
async function handleEditAppointment(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const appointmentId = formData.get('id');
const appointmentData = Object.fromEntries(formData.entries());
try {
// Validate date is not in the past if status is not completed or canceled
if (appointmentData.status !== 'completed' && appointmentData.status !== 'canceled') {
if (new Date(appointmentData.date) < new Date()) {
throw new Error('Appointment date cannot be in the past for active appointments');
}
}
await window.electron.queryDB(
'UPDATE appointments SET pet_id = ?, vet_id = ?, date = ?, type = ?, notes = ?, status = ? WHERE id = ?',
[
appointmentData.pet_id,
appointmentData.vet_id,
appointmentData.date,
appointmentData.type,
appointmentData.notes || null,
appointmentData.status,
appointmentId
]
);
const modalEl = document.getElementById('editAppointmentModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
await initAppointments();
showToast('Appointment updated successfully', 'success');
} catch (error) {
showError(error);
}
}
async function loadAppointmentData(id) {
try {
const [appointment] = await window.electron.queryDB(
'SELECT * FROM appointments WHERE id = ?',
[id]
);
if (appointment) {
const form = document.getElementById('editAppointmentForm');
if (!form) return;
form.elements['id'].value = appointment.id;
form.elements['pet_id'].value = appointment.pet_id;
form.elements['vet_id'].value = appointment.vet_id;
form.elements['date'].value = new Date(appointment.date).toISOString().slice(0, 16);
form.elements['type'].value = appointment.type;
form.elements['status'].value = appointment.status;
form.elements['notes'].value = appointment.notes || '';
const modal = new bootstrap.Modal(document.getElementById('editAppointmentModal'));
modal.show();
}
} catch (error) {
showError(error);
}
}
async function deleteAppointment(id) {
if (!confirm('Are you sure you want to delete this appointment?')) {
return;
}
try {
await window.electron.queryDB(
'DELETE FROM appointments WHERE id = ?',
[id]
);
await initAppointments();
showToast('Appointment deleted successfully', 'success');
} catch (error) {
showError(error);
}
}
function getStatusBadge(status) {
const badges = {
'scheduled': 'bg-primary',
'completed': 'bg-success',
'canceled': 'bg-danger'
};
return badges[status] || 'bg-secondary';
}
function showToast(message, type = 'success') {
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
toastContainer.className = 'position-fixed bottom-0 end-0 p-3';
document.body.appendChild(toastContainer);
}
const toast = document.createElement('div');
toast.className = `toast align-items-center text-white bg-${type} border-0`;
toast.setAttribute('role', 'alert');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
toastContainer.appendChild(toast);
const bsToast = new bootstrap.Toast(toast, { autohide: true, delay: 3000 });
bsToast.show();
toast.addEventListener('hidden.bs.toast', () => toast.remove());
}
function showError(error) {
console.error('Error:', error);
showToast(error.message || 'An error occurred', 'danger');
}
// ==================== VETERINARIANS ====================
window.initVeterinarians = async () => {
try {
const veterinarians = await window.electron.queryDB(
`SELECT id, name, email, phone, specialization FROM veterinarians`
);
const veterinariansList = document.getElementById('veterinarians-list');
if (!veterinariansList) return;
veterinariansList.innerHTML = veterinarians.length === 0 ?
'<tr><td colspan="5" class="text-center">No veterinarians found.</td></tr>' :
veterinarians.map(vet => `
<tr>
<td>${vet.name}</td>
<td>${vet.email || ''}</td>
<td>${vet.phone || ''}</td>
<td>${vet.specialization || ''}</td>
<td>
<button class="btn btn-sm btn-outline-primary me-2" onclick="loadVetData(${vet.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteVeterinarian(${vet.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('');
// Add form handler
const addForm = document.getElementById('addVeterinarianForm');
if (addForm) {
addForm.addEventListener('submit', handleAddVeterinarian);
}
// Edit form handler
const editForm = document.getElementById('editVeterinarianForm');
if (editForm) {
editForm.addEventListener('submit', handleEditVeterinarian);
}
} catch (error) {
showError(error);
}
};
async function handleAddVeterinarian(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const vetData = Object.fromEntries(formData.entries());
try {
await window.electron.queryDB(
'INSERT INTO veterinarians (name, email, phone, specialization) VALUES (?, ?, ?, ?)',
[vetData.name, vetData.email, vetData.phone, vetData.specialization]
);
// Get the modal element and create a Bootstrap modal instance
const modalEl = document.getElementById('addVeterinarianModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
form.reset();
await initVeterinarians();
showToast('Veterinarian added successfully', 'success');
} catch (error) {
showError(error);
}
}
async function handleEditVeterinarian(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const vetId = formData.get('id');
try {
await window.electron.queryDB(
'UPDATE veterinarians SET name = ?, email = ?, phone = ?, specialization = ? WHERE id = ?',
[formData.get('name'), formData.get('email'), formData.get('phone'), formData.get('specialization'), vetId]
);
const modalEl = document.getElementById('editVeterinarianModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
} else {
modalEl.style.display = 'none';
modalEl.classList.remove('show');
document.body.classList.remove('modal-open');
const modalBackdrop = document.querySelector('.modal-backdrop');
if (modalBackdrop) {
modalBackdrop.remove();
}
}
await initVeterinarians();
showToast('Veterinarian updated successfully', 'success');
} catch (error) {
showError(error);
}
}
async function loadVetData(id) {
try {
const [vet] = await window.electron.queryDB(
'SELECT * FROM veterinarians WHERE id = ?',
[id]
);
if (vet) {
const form = document.getElementById('editVeterinarianForm');
if (!form) return;
form.elements['id'].value = vet.id;
form.elements['name'].value = vet.name;
form.elements['email'].value = vet.email || '';
form.elements['phone'].value = vet.phone || '';
form.elements['specialization'].value = vet.specialization || '';
const modal = new bootstrap.Modal(document.getElementById('editVeterinarianModal'));
modal.show();
}
} catch (error) {
showError(error);
}
}
async function deleteVeterinarian(id) {
if (!confirm('Are you sure you want to delete this veterinarian?')) {
return;
}
try {
await window.electron.queryDB(
'DELETE FROM veterinarians WHERE id = ?',
[id]
);
await initVeterinarians();
showToast('Veterinarian deleted successfully', 'success');
} catch (error) {
showError(error);
}
}Editor is loading...
Leave a Comment