const API_URL = "https://raw.githubusercontent.com/sweko/uacs-internet-programming-exams/main/dry-run-mid-term-2024/data/authors.json";
let authors = [];
let currentSort = { key: null, direction: 'asc' };
document.addEventListener("DOMContentLoaded", async () => {
await fetchAuthors();
initFilters();
renderTable(authors);
});
async function fetchAuthors() {
try {
const res = await fetch(API_URL);
authors = await res.json();
console.log(authors);
console.log(authors);
} catch (err) {
console.error("Error fetching authors:", err);
}
}
function initFilters() {
const nationalitySet = new Set(authors.map(a => a.nationality));
const select = document.getElementById("nationality-search");
nationalitySet.forEach(n => {
const opt = document.createElement("option");
opt.value = n;
opt.textContent = n;
select.appendChild(opt);
});
document.querySelectorAll("#name-search, #nationality-search, #alive-search, #year-search")
.forEach(el => el.addEventListener("input", applyFilters));
document.getElementById("clearFilters").addEventListener("click", () => {
document.getElementById("name-search").value = "";
document.getElementById("nationality-search").value = "";
document.getElementById("alive-search").checked = false;
document.getElementById("year-search").value = "";
renderTable(authors);
});
document.querySelectorAll("th[data-sort]").forEach(th => {
th.addEventListener("click", () => sortTable(th.dataset.sort));
});
document.getElementById("close-modal").onclick = () => {
document.getElementById("booksModal").style.display = "none";
};
}
function applyFilters() {
let filtered = [...authors];
const name = document.getElementById("name-search").value.toLowerCase();
const nationality = document.getElementById("nationality-search").value;
const alive = document.getElementById("alive-search").checked;
const year = parseInt(document.getElementById("year-search").value);
filtered = filtered.filter(a => {
const isAlive = !a.death_date;
const { start, end } = getYearsActive(a);
return (!name || a.name.toLowerCase().includes(name)) &&
(!nationality || a.nationality === nationality) &&
(!alive || isAlive) &&
(!year || (start <= year && year <= end));
});
renderTable(filtered);
}
function renderTable(data) {
const tbody = document.querySelector("#authorsTable tbody");
tbody.innerHTML = "";
data.forEach(a => {
const row = document.createElement("tr");
const isAlive = !a.death_date;
const age = calculateAge(a);
const { start, end } = getYearsActive(a);
const yearsActive = `${start} - ${end}`;
const books = a.bibliography || [];
const bibliographyCount = books.length;
const summary = getBibliographySummary(books);
row.innerHTML = `
| ${a.id} |
${a.name} |
${a.birth_date} |
|
${age} |
${a.nationality} |
${bibliographyCount} |
${summary} |
${yearsActive} |
`;
tbody.appendChild(row);
});
}
function calculateAge(a) {
const birth = new Date(a.birth_date);
const end = a.death_date ? new Date(a.death_date) : new Date();
return end.getFullYear() - birth.getFullYear();
}
function getBibliographySummary(books) {
const countByType = {};
books.forEach(b => countByType[b.type] = (countByType[b.type] || 0) + 1);
const parts = Object.entries(countByType).map(([type, count]) =>
`${count} ${type}${count > 1 ? "s" : ""}`
);
return parts.join(", ");
}
function getYearsActive(a) {
if (!a.bibliography || a.bibliography.length === 0)
return { start: "-", end: "-" };
const years = a.bibliography.map(b => b.year);
const start = Math.min(...years);
let end = Math.max(...years);
const currentYear = new Date().getFullYear();
const isAlive = !a.death_date;
if (!isAlive) end = new Date(a.death_date).getFullYear();
else if (currentYear - end <= 2) end = "present";
return { start, end };
}
function openBooksModal(booksStr) {
const books = JSON.parse(booksStr);
const tbody = document.querySelector("#booksTable tbody");
tbody.innerHTML = "";
books.sort((a, b) => b.year - a.year)
.forEach(b => {
const tr = document.createElement("tr");
tr.innerHTML = `${b.name} | ${b.year} | ${b.type} | `;
tbody.appendChild(tr);
});
document.getElementById("booksModal").style.display = "flex";
}
function sortTable(key) {
const dir = (currentSort.key === key && currentSort.direction === "asc") ? "desc" : "asc";
currentSort = { key, direction: dir };
const sorted = [...authors].sort((a, b) => compareAuthors(a, b, key, dir));
document.querySelectorAll("th[data-sort]").forEach(th => th.classList.remove("sort-asc", "sort-desc"));
document.querySelector(`th[data-sort="${key}"]`).classList.add(dir === "asc" ? "sort-asc" : "sort-desc");
renderTable(sorted);
}
function compareAuthors(a, b, key, dir) {
const factor = dir === "asc" ? 1 : -1;
const valA = getComparableValue(a, key);
const valB = getComparableValue(b, key);
return (valA > valB ? 1 : valA < valB ? -1 : 0) * factor;
}
function getComparableValue(a, key) {
switch (key) {
case "age": return calculateAge(a);
case "alive": return a.death_date ? 0 : 1;
case "bibliographyCount": return a.bibliography.length;
case "yearsActive":
const { start, end } = getYearsActive(a);
return start * 10000 + (end === "present" ? new Date().getFullYear() : end);
default: return a[key];
}
}