forked from izu/student-web-if-development-kit
fix(c4a): fix 'SOP tidak ditemukan' visibility logic on page load
This commit is contained in:
+51
-21
@@ -12,6 +12,20 @@ function t(key, fallback) {
|
|||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper untuk melokalisasi teks dari objek bilingual {id, en} atau string biasa.
|
||||||
|
* @param {string|Object} field - Data teks (bisa string biasa atau objek {id, en})
|
||||||
|
* @returns {string} Teks terlokalisasi
|
||||||
|
*/
|
||||||
|
function loc(field) {
|
||||||
|
if (!field) return '';
|
||||||
|
if (typeof field === 'object') {
|
||||||
|
const lang = (window.getLang && typeof window.getLang === 'function') ? window.getLang() : 'id';
|
||||||
|
return field[lang] || field['id'] || '';
|
||||||
|
}
|
||||||
|
return String(field);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalisasi nomor telepon ke format standard e.g. 628...
|
* Normalisasi nomor telepon ke format standard e.g. 628...
|
||||||
* @param {string} phone - Nomor telepon mentah
|
* @param {string} phone - Nomor telepon mentah
|
||||||
@@ -100,12 +114,12 @@ export function renderStaffCards(staffs) {
|
|||||||
|
|
||||||
const scheduleHTML = schedule.map(sched =>
|
const scheduleHTML = schedule.map(sched =>
|
||||||
`<div class="schedule-item">` +
|
`<div class="schedule-item">` +
|
||||||
`<span class="s-day">${sched.day}</span>` +
|
`<span class="s-day">${loc(sched.day)}</span>` +
|
||||||
`<span class="s-time">${sched.time} <span class="s-break">| ${sched.break}</span></span>` +
|
`<span class="s-time">${loc(sched.time)} <span class="s-break">| ${loc(sched.break)}</span></span>` +
|
||||||
`</div>`
|
`</div>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
const tasksHTML = tasks.map(task => `<li>${task}</li>`).join('');
|
const tasksHTML = tasks.map(task => `<li>${loc(task)}</li>`).join('');
|
||||||
const isPhoneValid = isValidWhatsAppNumber(phone);
|
const isPhoneValid = isValidWhatsAppNumber(phone);
|
||||||
const encodedPhone = isPhoneValid ? encodePhone(phone) : '';
|
const encodedPhone = isPhoneValid ? encodePhone(phone) : '';
|
||||||
const displayPhone = isPhoneValid ? formatPhoneForDisplay(phone) : '-';
|
const displayPhone = isPhoneValid ? formatPhoneForDisplay(phone) : '-';
|
||||||
@@ -123,13 +137,13 @@ export function renderStaffCards(staffs) {
|
|||||||
<img src="${image}" alt="${name}" onerror="this.style.display='none'"/>
|
<img src="${image}" alt="${name}" onerror="this.style.display='none'"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="staff-name">${name}</div>
|
<div class="staff-name">${loc(name)}</div>
|
||||||
<div class="staff-role">${role}</div>
|
<div class="staff-role">${loc(role)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="staff-card-body">
|
<div class="staff-card-body">
|
||||||
<div class="staff-info-grid">
|
<div class="staff-info-grid">
|
||||||
<div class="staff-info-item"><span class="icon">📍</span><div><span class="label">${t('grp_c4a_label_location', 'Lokasi')}</span><span class="val">${location}</span></div></div>
|
<div class="staff-info-item"><span class="icon">📍</span><div><span class="label">${t('grp_c4a_label_location', 'Lokasi')}</span><span class="val">${loc(location)}</span></div></div>
|
||||||
<div class="staff-info-item">
|
<div class="staff-info-item">
|
||||||
<span class="icon">🕒</span>
|
<span class="icon">🕒</span>
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
@@ -202,27 +216,29 @@ function buildSopCard(sop) {
|
|||||||
|
|
||||||
const catLabel = getCatLabel(category);
|
const catLabel = getCatLabel(category);
|
||||||
const catClass = CATEGORY_COLORS[category] || '';
|
const catClass = CATEGORY_COLORS[category] || '';
|
||||||
|
const titleText = loc(title);
|
||||||
|
const descText = loc(description);
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<article class="sop-grid-card reveal" data-tab-id="${tabId}" data-category="${category}" data-title="${title.toLowerCase()}">
|
<article class="sop-grid-card reveal" data-tab-id="${tabId}" data-category="${category}" data-title="${titleText.toLowerCase()}">
|
||||||
<div class="sgc-header">
|
<div class="sgc-header">
|
||||||
<div class="sgc-icon-wrap">
|
<div class="sgc-icon-wrap">
|
||||||
<i class="fas ${icon}"></i>
|
<i class="fas ${icon}"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="sgc-meta">
|
<div class="sgc-meta">
|
||||||
<h3 class="sgc-title">${title}</h3>
|
<h3 class="sgc-title">${titleText}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sgc-category-row">
|
<div class="sgc-category-row">
|
||||||
<span class="sgc-category ${catClass}">${catLabel}</span>
|
<span class="sgc-category ${catClass}">${catLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="sgc-desc">${description}</p>
|
<p class="sgc-desc">${descText}</p>
|
||||||
<div class="sgc-footer">
|
<div class="sgc-footer">
|
||||||
<div class="sgc-steps">
|
<div class="sgc-steps">
|
||||||
<i class="fas fa-list-ol"></i>
|
<i class="fas fa-list-ol"></i>
|
||||||
<span>${procedures.length} ${t('grp_c4a_label_steps', 'Langkah')}</span>
|
<span>${procedures.length} ${t('grp_c4a_label_steps', 'Langkah')}</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="sgc-detail-btn" data-tab-id="${tabId}" aria-label="${t('grp_c4a_label_view_detail', 'Lihat Detail')} ${title}">
|
<button class="sgc-detail-btn" data-tab-id="${tabId}" aria-label="${t('grp_c4a_label_view_detail', 'Lihat Detail')} ${titleText}">
|
||||||
${t('grp_c4a_label_view_detail', 'Lihat Detail')} <i class="fas fa-arrow-right"></i>
|
${t('grp_c4a_label_view_detail', 'Lihat Detail')} <i class="fas fa-arrow-right"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,13 +266,18 @@ function buildSopModalContent(sop) {
|
|||||||
const catLabel = getCatLabel(category);
|
const catLabel = getCatLabel(category);
|
||||||
const catClass = CATEGORY_COLORS[category] || '';
|
const catClass = CATEGORY_COLORS[category] || '';
|
||||||
|
|
||||||
const reqsHTML = requirements.map(req => `<li>${req}</li>`).join('');
|
const titleText = loc(title);
|
||||||
const procsHTML = procedures.map(proc => `<li>${proc}</li>`).join('');
|
const descText = loc(description);
|
||||||
|
const purposeText = loc(purpose);
|
||||||
|
const additionalInfoText = loc(additionalInfo);
|
||||||
|
|
||||||
|
const reqsHTML = requirements.map(req => `<li>${loc(req)}</li>`).join('');
|
||||||
|
const procsHTML = procedures.map(proc => `<li>${loc(proc)}</li>`).join('');
|
||||||
|
|
||||||
// staffResponsible bersifat opsional — sembunyikan blok jika tidak ada
|
// staffResponsible bersifat opsional — sembunyikan blok jika tidak ada
|
||||||
const hasStaff = Array.isArray(staffResponsible) && staffResponsible.length > 0;
|
const hasStaff = Array.isArray(staffResponsible) && staffResponsible.length > 0;
|
||||||
const staffHTML = hasStaff
|
const staffHTML = hasStaff
|
||||||
? staffResponsible.map(staffName => `<span class="sop-staff-pill">${staffName}</span>`).join('')
|
? staffResponsible.map(staffName => `<span class="sop-staff-pill">${loc(staffName)}</span>`).join('')
|
||||||
: '';
|
: '';
|
||||||
const staffBlockHTML = hasStaff
|
const staffBlockHTML = hasStaff
|
||||||
? `<div class="sop-staff-block">
|
? `<div class="sop-staff-block">
|
||||||
@@ -266,10 +287,10 @@ function buildSopModalContent(sop) {
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
// additionalInfo bersifat opsional — sembunyikan blok jika tidak ada
|
// additionalInfo bersifat opsional — sembunyikan blok jika tidak ada
|
||||||
const additionalInfoHTML = additionalInfo
|
const additionalInfoHTML = additionalInfoText
|
||||||
? `<div class="sop-info-box">
|
? `<div class="sop-info-box">
|
||||||
<span class="iico">ℹ️</span>
|
<span class="iico">ℹ️</span>
|
||||||
<p class="sop-info-box-text"><strong>${t('grp_c4a_label_additional_info', 'Informasi Tambahan (Bersifat Opsional):')}</strong> ${additionalInfo}</p>
|
<p class="sop-info-box-text"><strong>${t('grp_c4a_label_additional_info', 'Informasi Tambahan (Bersifat Opsional):')}</strong> ${additionalInfoText}</p>
|
||||||
</div>`
|
</div>`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
@@ -283,15 +304,15 @@ function buildSopModalContent(sop) {
|
|||||||
<div class="sop-modal-badges">
|
<div class="sop-modal-badges">
|
||||||
<span class="sgc-category ${catClass}">${catLabel}</span>
|
<span class="sgc-category ${catClass}">${catLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="sop-modal-title" id="sop-modal-title">${title}</h2>
|
<h2 class="sop-modal-title" id="sop-modal-title">${titleText}</h2>
|
||||||
<p class="sop-modal-desc">${description}</p>
|
<p class="sop-modal-desc">${descText}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sop-modal-body">
|
<div class="sop-modal-body">
|
||||||
<div class="sop-block">
|
<div class="sop-block">
|
||||||
<div class="sop-block-label">${t('grp_c4a_label_purpose', 'Tujuan')}</div>
|
<div class="sop-block-label">${t('grp_c4a_label_purpose', 'Tujuan')}</div>
|
||||||
<p class="sop-block-text">${purpose}</p>
|
<p class="sop-block-text">${purposeText}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="sop-two-col">
|
<div class="sop-two-col">
|
||||||
<div>
|
<div>
|
||||||
@@ -319,15 +340,19 @@ export function renderSopCards(sops) {
|
|||||||
// simpan data global di element agar bisa diakses filter/search
|
// simpan data global di element agar bisa diakses filter/search
|
||||||
container._sopData = sops;
|
container._sopData = sops;
|
||||||
|
|
||||||
|
const emptyState = document.getElementById('sop-empty-state');
|
||||||
|
|
||||||
// Tampilkan pesan jika data SOP kosong atau gagal dimuat
|
// Tampilkan pesan jika data SOP kosong atau gagal dimuat
|
||||||
if (!sops || sops.length === 0) {
|
if (!sops || sops.length === 0) {
|
||||||
container.innerHTML = `<p class="empty-state-msg">${t('grp_c4a_empty_sop', 'Data SOP tidak tersedia saat ini.')}</p>`;
|
container.innerHTML = `<p class="empty-state-msg">${t('grp_c4a_empty_sop', 'Data SOP tidak tersedia saat ini.')}</p>`;
|
||||||
updateResultInfo(0, 0);
|
updateResultInfo(0, 0);
|
||||||
|
if (emptyState) emptyState.style.display = 'none';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = sops.map(buildSopCard).join('');
|
container.innerHTML = sops.map(buildSopCard).join('');
|
||||||
updateResultInfo(sops.length, sops.length);
|
updateResultInfo(sops.length, sops.length);
|
||||||
|
if (emptyState) emptyState.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update teks info jumlah hasil */
|
/** Update teks info jumlah hasil */
|
||||||
@@ -371,7 +396,12 @@ export function applySopFilter() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emptyState = document.getElementById('sop-empty-state');
|
const emptyState = document.getElementById('sop-empty-state');
|
||||||
if (emptyState) emptyState.style.display = visibleCount === 0 ? 'flex' : 'none';
|
if (emptyState) {
|
||||||
|
// Tampilkan "SOP tidak ditemukan" HANYA jika memang ada data SOP tetapi hasil filter 0.
|
||||||
|
// Jika data SOP memang kosong (tidak ada card sama sekali di data source), sembunyikan.
|
||||||
|
const hasData = container._sopData && container._sopData.length > 0;
|
||||||
|
emptyState.style.display = (hasData && visibleCount === 0) ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
updateResultInfo(visibleCount, cards.length);
|
updateResultInfo(visibleCount, cards.length);
|
||||||
}
|
}
|
||||||
@@ -626,11 +656,11 @@ export function renderFaqSection(faqs) {
|
|||||||
return `
|
return `
|
||||||
<div class="faq-item reveal ${delayClass}">
|
<div class="faq-item reveal ${delayClass}">
|
||||||
<div class="faq-question">
|
<div class="faq-question">
|
||||||
<span class="faq-question-text">${faq.question}</span>
|
<span class="faq-question-text">${loc(faq.question)}</span>
|
||||||
<div class="faq-icon">+</div>
|
<div class="faq-icon">+</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="faq-answer">
|
<div class="faq-answer">
|
||||||
<div class="faq-answer-inner">${faq.answer}</div>
|
<div class="faq-answer-inner">${loc(faq.answer)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|||||||
Reference in New Issue
Block a user