267 lines
7.9 KiB
JavaScript
267 lines
7.9 KiB
JavaScript
let teamMemberModal, notificationModal, confirmationModal;
|
|
let currentMemberId = null;
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
teamMemberModal = new bootstrap.Modal(
|
|
document.getElementById("teamMemberModal")
|
|
);
|
|
notificationModal = new bootstrap.Modal(
|
|
document.getElementById("notificationModal")
|
|
);
|
|
confirmationModal = new bootstrap.Modal(
|
|
document.getElementById("confirmationModal")
|
|
);
|
|
|
|
checkAuth().then((authenticated) => {
|
|
if (authenticated) {
|
|
loadTeamMembers();
|
|
}
|
|
});
|
|
|
|
// Image preview on URL change
|
|
document.getElementById("memberImage").addEventListener("input", function () {
|
|
updateImagePreview(this.value);
|
|
});
|
|
});
|
|
|
|
// Load all team members
|
|
async function loadTeamMembers() {
|
|
try {
|
|
const response = await fetch("/api/admin/team-members");
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.teamMembers) {
|
|
displayTeamMembers(data.teamMembers);
|
|
} else {
|
|
showNotification("Failed to load team members", "error");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error loading team members:", error);
|
|
showNotification("Error loading team members", "error");
|
|
}
|
|
}
|
|
|
|
// Display team members in grid
|
|
function displayTeamMembers(members) {
|
|
const container = document.getElementById("teamMembersContainer");
|
|
|
|
if (members.length === 0) {
|
|
container.innerHTML = `
|
|
<div class="col-12 text-center py-5">
|
|
<i class="bi bi-people" style="font-size: 4rem; color: #cbd5e0;"></i>
|
|
<p class="mt-3 text-muted">No team members yet. Add your first team member!</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = members
|
|
.map(
|
|
(member) => `
|
|
<div class="col-md-6 col-lg-4 mb-4">
|
|
<div class="team-preview-card">
|
|
<div class="team-preview-image">
|
|
${
|
|
member.image_url
|
|
? `<img src="${member.image_url}" alt="${member.name}" />`
|
|
: `<i class="bi bi-person-circle"></i>`
|
|
}
|
|
</div>
|
|
<div class="team-preview-name">${escapeHtml(member.name)}</div>
|
|
<div class="team-preview-position">${escapeHtml(member.position)}</div>
|
|
<div class="team-preview-bio">${
|
|
member.bio ? escapeHtml(member.bio) : ""
|
|
}</div>
|
|
<div class="mt-3 d-flex justify-content-center gap-2">
|
|
<button class="btn btn-sm btn-outline-primary" onclick="editTeamMember('${
|
|
member.id
|
|
}')">
|
|
<i class="bi bi-pencil"></i> Edit
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-danger" onclick="confirmDelete('${
|
|
member.id
|
|
}', '${escapeHtml(member.name)}')">
|
|
<i class="bi bi-trash"></i> Delete
|
|
</button>
|
|
</div>
|
|
<div class="mt-2">
|
|
<small class="text-muted">Order: ${member.display_order}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
// Show add modal
|
|
function showAddModal() {
|
|
currentMemberId = null;
|
|
document.getElementById("modalTitle").textContent = "Add Team Member";
|
|
document.getElementById("teamMemberForm").reset();
|
|
document.getElementById("memberId").value = "";
|
|
document.getElementById("imagePreview").innerHTML = "";
|
|
teamMemberModal.show();
|
|
}
|
|
|
|
// Edit team member
|
|
async function editTeamMember(id) {
|
|
try {
|
|
const response = await fetch(`/api/admin/team-members/${id}`);
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.teamMember) {
|
|
currentMemberId = id;
|
|
const member = data.teamMember;
|
|
|
|
document.getElementById("modalTitle").textContent = "Edit Team Member";
|
|
document.getElementById("memberId").value = member.id;
|
|
document.getElementById("memberName").value = member.name;
|
|
document.getElementById("memberPosition").value = member.position;
|
|
document.getElementById("memberBio").value = member.bio || "";
|
|
document.getElementById("memberImage").value = member.image_url || "";
|
|
document.getElementById("displayOrder").value = member.display_order || 0;
|
|
|
|
updateImagePreview(member.image_url);
|
|
teamMemberModal.show();
|
|
} else {
|
|
showNotification("Failed to load team member details", "error");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error loading team member:", error);
|
|
showNotification("Error loading team member", "error");
|
|
}
|
|
}
|
|
|
|
// Save team member (create or update)
|
|
async function saveTeamMember() {
|
|
const id = document.getElementById("memberId").value;
|
|
const name = document.getElementById("memberName").value.trim();
|
|
const position = document.getElementById("memberPosition").value.trim();
|
|
const bio = document.getElementById("memberBio").value.trim();
|
|
const image_url = document.getElementById("memberImage").value.trim();
|
|
const display_order =
|
|
parseInt(document.getElementById("displayOrder").value) || 0;
|
|
|
|
if (!name || !position) {
|
|
showNotification("Name and position are required", "error");
|
|
return;
|
|
}
|
|
|
|
const payload = {
|
|
name,
|
|
position,
|
|
bio,
|
|
image_url,
|
|
display_order,
|
|
};
|
|
|
|
try {
|
|
const url = id
|
|
? `/api/admin/team-members/${id}`
|
|
: "/api/admin/team-members";
|
|
const method = id ? "PUT" : "POST";
|
|
|
|
const response = await fetch(url, {
|
|
method,
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showNotification(
|
|
data.message || "Team member saved successfully",
|
|
"success"
|
|
);
|
|
teamMemberModal.hide();
|
|
loadTeamMembers();
|
|
} else {
|
|
showNotification(data.message || "Failed to save team member", "error");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error saving team member:", error);
|
|
showNotification("Error saving team member", "error");
|
|
}
|
|
}
|
|
|
|
// Confirm delete
|
|
function confirmDelete(id, name) {
|
|
currentMemberId = id;
|
|
document.getElementById(
|
|
"confirmationMessage"
|
|
).textContent = `Are you sure you want to delete "${name}"? This action cannot be undone.`;
|
|
|
|
const confirmBtn = document.getElementById("confirmButton");
|
|
confirmBtn.onclick = () => deleteTeamMember(id);
|
|
|
|
confirmationModal.show();
|
|
}
|
|
|
|
// Delete team member
|
|
async function deleteTeamMember(id) {
|
|
try {
|
|
const response = await fetch(`/api/admin/team-members/${id}`, {
|
|
method: "DELETE",
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showNotification("Team member deleted successfully", "success");
|
|
confirmationModal.hide();
|
|
loadTeamMembers();
|
|
} else {
|
|
showNotification("Failed to delete team member", "error");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error deleting team member:", error);
|
|
showNotification("Error deleting team member", "error");
|
|
}
|
|
}
|
|
|
|
// Update image preview
|
|
function updateImagePreview(url) {
|
|
const preview = document.getElementById("imagePreview");
|
|
if (url) {
|
|
preview.innerHTML = `
|
|
<img src="${url}" alt="Preview" style="max-width: 150px; max-height: 150px; border-radius: 50%; border: 3px solid #667eea;" />
|
|
`;
|
|
} else {
|
|
preview.innerHTML = "";
|
|
}
|
|
}
|
|
|
|
// Open media library (placeholder for future integration)
|
|
function openMediaLibrary() {
|
|
// For now, redirect to media library in a new window
|
|
window.open("/admin/media-library.html", "_blank");
|
|
showNotification(
|
|
"Select an image from the media library and copy its URL back here",
|
|
"success"
|
|
);
|
|
}
|
|
|
|
// Show notification
|
|
function showNotification(message, type = "success") {
|
|
const modal = document.getElementById("notificationModal");
|
|
const header = modal.querySelector(".modal-header");
|
|
const messageEl = document.getElementById("notificationMessage");
|
|
const title = document.getElementById("notificationTitle");
|
|
|
|
header.className = "modal-header " + type;
|
|
title.textContent = type === "success" ? "Success" : "Error";
|
|
messageEl.textContent = message;
|
|
|
|
notificationModal.show();
|
|
}
|
|
|
|
// Escape HTML
|
|
function escapeHtml(text) {
|
|
if (!text) return "";
|
|
const div = document.createElement("div");
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|