| const rawRows = Array.isArray(window.DATA) ? window.DATA : []; |
|
|
| const selectors = { |
| total: document.getElementById("totalCount"), |
| researchers: document.getElementById("researcherCount"), |
| inspectors: document.getElementById("inspectorCount"), |
| tabs: document.querySelectorAll(".modeTab"), |
| panels: document.querySelectorAll(".searchPanel"), |
| researcherInput: document.getElementById("researcherInput"), |
| researcherSelect: document.getElementById("researcherSelect"), |
| inspectorGrid: document.getElementById("inspectorGrid"), |
| inspectorResearcherSelect: document.getElementById("inspectorResearcherSelect"), |
| resultEyebrow: document.getElementById("resultEyebrow"), |
| resultTitle: document.getElementById("resultTitle"), |
| resultCount: document.getElementById("resultCount"), |
| results: document.getElementById("results"), |
| }; |
|
|
| let selectedInspector = ""; |
|
|
| function clean(value) { |
| return String(value ?? "").trim(); |
| } |
|
|
| function normalizeArabic(value) { |
| return clean(value) |
| .toLowerCase() |
| .replace(/[\u064B-\u065F\u0670\u06D6-\u06ED]/g, "") |
| .replace(/\u0640/g, "") |
| .replace(/[إأآٱ]/g, "ا") |
| .replace(/ى/g, "ي") |
| .replace(/ة/g, "ه") |
| .replace(/\s+/g, " "); |
| } |
|
|
| function valueOf(row, keys, index) { |
| if (Array.isArray(row)) return clean(row[index]); |
| for (const key of keys) { |
| if (row && Object.prototype.hasOwnProperty.call(row, key)) return clean(row[key]); |
| } |
| return ""; |
| } |
|
|
| function mapRow(row) { |
| return { |
| establishment: valueOf(row, ["establishment", "name", "sample", "اسم المنشأة", "إسم المنشأة"], 0), |
| statusMain: valueOf(row, ["statusMain", "status_b", "b", "حالة العينة في المسح", "حالة العينة في المسح "], 1), |
| statusOther: valueOf(row, ["statusOther", "status_c", "c", "حالة العينة في مسح اخر", "حالة العينة في مسح آخر"], 2), |
| survey: valueOf(row, ["survey", "surveyName", "اسم المسح"], 3), |
| researcher: valueOf(row, ["researcher", "researcherName", "اسم الباحث الحالي", "اسم الباحث"], 4), |
| inspector: valueOf(row, ["inspector", "inspectorName", "المفتش", "اسم المفتش"], 5), |
| }; |
| } |
|
|
| function unique(values) { |
| return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b, "ar")); |
| } |
|
|
| function escapeHtml(value) { |
| return clean(value) |
| .replaceAll("&", "&") |
| .replaceAll("<", "<") |
| .replaceAll(">", ">") |
| .replaceAll('"', """) |
| .replaceAll("'", "'"); |
| } |
|
|
| function optionHtml(value) { |
| return `<option value="${escapeHtml(value)}">${escapeHtml(value)}</option>`; |
| } |
|
|
| const rows = rawRows |
| .map(mapRow) |
| .filter((row) => normalizeArabic(row.statusMain) !== normalizeArabic(row.statusOther)); |
|
|
| const researchers = unique(rows.map((row) => row.researcher)); |
| const inspectors = unique(rows.map((row) => row.inspector)); |
|
|
| selectors.total.textContent = rows.length; |
| selectors.researchers.textContent = researchers.length; |
| selectors.inspectors.textContent = inspectors.length; |
|
|
| function setMode(mode) { |
| selectors.tabs.forEach((tab) => { |
| const active = tab.dataset.mode === mode; |
| tab.classList.toggle("active", active); |
| tab.setAttribute("aria-selected", String(active)); |
| }); |
| selectors.panels.forEach((panel) => panel.classList.toggle("active", panel.id === `${mode}Panel`)); |
| if (mode === "researcher") selectors.researcherInput.focus(); |
| } |
|
|
| function byResearcher(query, sourceRows = rows) { |
| const tokens = normalizeArabic(query).split(" ").filter(Boolean); |
| if (!tokens.length) return []; |
| return sourceRows.filter((row) => { |
| const name = normalizeArabic(row.researcher); |
| return tokens.every((token) => name.includes(token)); |
| }); |
| } |
|
|
| function byInspector(name) { |
| const target = normalizeArabic(name); |
| return rows.filter((row) => normalizeArabic(row.inspector) === target); |
| } |
|
|
| function renderControls() { |
| selectors.researcherSelect.innerHTML = `<option value="">اختر اسم الباحث</option>${researchers.map(optionHtml).join("")}`; |
|
|
| selectors.inspectorGrid.innerHTML = inspectors.map((name) => ( |
| `<button class="inspectorChip" type="button" data-inspector="${escapeHtml(name)}">${escapeHtml(name)}</button>` |
| )).join(""); |
| } |
|
|
| function renderInspectorResearchers(inspectorName) { |
| const list = byInspector(inspectorName); |
| const names = unique(list.map((row) => row.researcher)); |
| selectors.inspectorResearcherSelect.disabled = names.length === 0; |
| selectors.inspectorResearcherSelect.innerHTML = `<option value="">كل الباحثين للمفتش</option>${names.map(optionHtml).join("")}`; |
| } |
|
|
| function renderResults(list, title, eyebrow = "النتائج") { |
| selectors.resultEyebrow.textContent = eyebrow; |
| selectors.resultTitle.textContent = title; |
| selectors.resultCount.textContent = list.length; |
|
|
| if (!list.length) { |
| selectors.results.innerHTML = `<div class="emptyState">لا توجد عينات مختلفة حسب الخيار الحالي</div>`; |
| return; |
| } |
|
|
| selectors.results.innerHTML = list.map((row) => ` |
| <article class="sampleCard"> |
| <h3 class="sampleName">${escapeHtml(row.establishment || "بدون اسم منشأة")}</h3> |
| <div class="metaLine"> |
| <span>الباحث: ${escapeHtml(row.researcher || "-")}</span> |
| </div> |
| <div class="statusGrid"> |
| <div class="statusBox"> |
| <strong>حالة العينة في المسح</strong> |
| <p>${escapeHtml(row.statusMain || "-")}</p> |
| </div> |
| <div class="statusBox"> |
| <strong>حالة العينة في مسح آخر</strong> |
| <p>${escapeHtml(row.statusOther || "-")}</p> |
| <em>${escapeHtml(row.survey || "بدون اسم مسح")}</em> |
| </div> |
| </div> |
| </article> |
| `).join(""); |
| } |
|
|
| function resetInspectorResearcherSelect() { |
| selectedInspector = ""; |
| selectors.inspectorResearcherSelect.disabled = true; |
| selectors.inspectorResearcherSelect.innerHTML = `<option value="">اختر المفتش أولاً</option>`; |
| } |
|
|
| function showResearcher(name) { |
| selectors.researcherInput.value = name; |
| selectors.researcherSelect.value = name; |
| renderResults(byResearcher(name), `نتائج الباحث: ${name}`, "بحث الباحث"); |
| } |
|
|
| selectors.tabs.forEach((tab) => { |
| tab.addEventListener("click", () => setMode(tab.dataset.mode)); |
| }); |
|
|
| selectors.researcherInput.addEventListener("input", () => { |
| const query = selectors.researcherInput.value; |
| selectors.researcherSelect.value = researchers.includes(query) ? query : ""; |
| if (!query.trim()) { |
| renderResults([], "اكتب اسم الباحث أو اختر اسم المفتش"); |
| return; |
| } |
| renderResults(byResearcher(query), `نتائج الباحث: ${query}`, "بحث الباحث"); |
| }); |
|
|
| selectors.researcherSelect.addEventListener("change", () => { |
| const name = selectors.researcherSelect.value; |
| if (!name) { |
| selectors.researcherInput.value = ""; |
| renderResults([], "اكتب اسم الباحث أو اختر اسم المفتش"); |
| return; |
| } |
| showResearcher(name); |
| }); |
|
|
| selectors.inspectorGrid.addEventListener("click", (event) => { |
| const chip = event.target.closest("[data-inspector]"); |
| if (!chip) return; |
| selectedInspector = chip.dataset.inspector; |
| document.querySelectorAll(".inspectorChip").forEach((button) => { |
| button.classList.toggle("selected", button.dataset.inspector === selectedInspector); |
| }); |
| renderInspectorResearchers(selectedInspector); |
| renderResults(byInspector(selectedInspector), `مفتش: ${selectedInspector}`, "بحث المفتش"); |
| }); |
|
|
| selectors.inspectorResearcherSelect.addEventListener("change", () => { |
| if (!selectedInspector) return; |
| const inspectorRows = byInspector(selectedInspector); |
| const researcherName = selectors.inspectorResearcherSelect.value; |
| if (!researcherName) { |
| renderResults(inspectorRows, `مفتش: ${selectedInspector}`, "كل باحثي المفتش"); |
| return; |
| } |
| renderResults(byResearcher(researcherName, inspectorRows), `الباحث: ${researcherName}`, `مفتش: ${selectedInspector}`); |
| }); |
|
|
| renderControls(); |
| resetInspectorResearcherSelect(); |
| renderResults([], "اكتب اسم الباحث أو اختر اسم المفتش"); |
|
|