CCCPaste

7b5177126e48d

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];
  }
}