$(document).ready(function(){const config=window.memberDashboardConfig||{};const routes=config.routes||{};const initialWidgets=config.initialWidgets||{};const polling=config.polling||{};const chartRegistry={};const dataTableRegistry={};const widgetStatusMap={loading:{label:'Memuat',className:'member-status-pill--loading'},ready:{label:'Siap',className:'member-status-pill--ready'},empty:{label:'Kosong',className:'member-status-pill--empty'},pending_integration:{label:'Menunggu Integrasi',className:'member-status-pill--pending'},error:{label:'Error',className:'member-status-pill--error'}};function formatTimestamp(value){if(!value){return''}
return new Intl.DateTimeFormat('id-ID',{dateStyle:'medium',timeStyle:'short'}).format(new Date(value))}
function setHtml(selector,html){$(selector).html(html)}
function formatMetric(value){if(typeof value==='number'&&Number.isFinite(value)){return new Intl.NumberFormat('id-ID').format(value)}
return value??'-'}
function escapeHtml(value){return String(value??'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,''')}
function statusPill(status){const state=widgetStatusMap[status]||widgetStatusMap.error;return `${state.label}`}
function renderPlaceholder(selector,status,message){const state=widgetStatusMap[status]||widgetStatusMap.error;setHtml(selector,`${statusPill(status)}
${message || state.label}
`)}
function destroyChart(id){if(chartRegistry[id]){chartRegistry[id].destroy()}}
function renderChart(id,type,data,options={}){const canvas=document.getElementById(id);if(!canvas||typeof Chart==='undefined'){return}
destroyChart(id);chartRegistry[id]=new Chart(canvas.getContext('2d'),{type,data,options:Object.assign({maintainAspectRatio:!1,responsive:!0,plugins:{legend:{position:'bottom'}}},options)})}
function initOrRefreshTable(selector,rows,columns){const table=$(selector);const tbody=table.find('tbody');tbody.html(rows.map((row,index)=>{const cells=columns.map((column)=>{if(typeof column.render==='function'){return `${column.render(row, index)} | `}
return `${row[column.key] ?? ''} | `}).join('');return `${cells}
`}).join(''));if(!$.fn.DataTable){return}
if(dataTableRegistry[selector]){dataTableRegistry[selector].destroy();dataTableRegistry[selector]=null}
dataTableRegistry[selector]=table.DataTable({paging:rows.length>5,searching:rows.length>5,info:!1,pageLength:5,order:[],language:typeof datatable_indonesia_language_url!=='undefined'?{url:datatable_indonesia_language_url}:{}})}
async function fetchWidget(url){const response=await fetch(url,{headers:{'X-Requested-With':'XMLHttpRequest','Accept':'application/json'}});if(!response.ok){throw new Error(`Request failed: ${response.status}`)}
return response.json()}
function renderSummary(widget){const data=widget.data||{};setHtml('#memberDashboardSummaryUpdated',`Diperbarui ${formatTimestamp(widget.last_updated)}`);if(Array.isArray(data.summary_cards)&&data.summary_cards.length){setHtml('#memberDashboardSummaryCards',data.summary_cards.map((card)=>`
${card.label}
${formatMetric(card.value)}
${card.description}
`).join(''))}
initOrRefreshTable('#memberDashboardKkTable',data.nomor_kk_rows||[],[{render:(_row,index)=>index+1},{key:'label'},{render:(row)=>row.search?`${row.value}`:row.value}]);initOrRefreshTable('#memberDashboardVillageTable',data.village_rows||[],[{render:(_row,index)=>index+1},{key:'label'},{key:'district'},{key:'value'}]);renderChart('memberDashboardDistrictChart','bar',data.district_chart||{labels:[],datasets:[]},{scales:{y:{beginAtZero:!0}}});renderPlaceholder('#memberDashboardDistrictState',widget.status,'Distribusi kecamatan dimuat dari backend.')}
function renderDetailRows(selector,rows,emptyMessage){if(!Array.isArray(rows)||!rows.length){setHtml(selector,`
Status
${escapeHtml(emptyMessage || 'Belum ada data')}
`);return}
setHtml(selector,rows.map((row)=>`
${escapeHtml(row.label)}
${escapeHtml(row.value)}
`).join(''))}
function renderQuickLinks(selector,links){if(!Array.isArray(links)||!links.length){setHtml(selector,'');return}
setHtml(selector,links.map((link)=>`
${escapeHtml(link.label)}
`).join(''))}
function renderChips(selector,rows,emptyMessage){if(!Array.isArray(rows)||!rows.length){setHtml(selector,`${escapeHtml(emptyMessage || 'Belum ada data')}`);return}
setHtml(selector,rows.map((row)=>`
${escapeHtml(row.label)}
`).join(''))}
function renderQuickStats(selector,rows){if(!Array.isArray(rows)||!rows.length){setHtml(selector,'');return}
setHtml(selector,rows.map((row)=>`
${escapeHtml(row.label)}
${formatMetric(row.value)}
`).join(''))}
function renderCitizen(widget){const data=widget.data||{};setHtml('#memberDashboardCitizenCards',(data.identity_cards||[]).map((card)=>`
${escapeHtml(card.label)}
${escapeHtml(formatMetric(card.value))}
${escapeHtml(card.description)}
`).join(''));renderDetailRows('#memberDashboardCitizenProfileRows',data.profile_rows||[],'Belum ada profil warga yang tertaut ke akun ini.');renderQuickLinks('#memberDashboardCitizenQuickLinks',data.quick_links||[]);renderPlaceholder('#memberDashboardCitizenProfileState',data.profile_status||widget.status||'empty',widget.meta?.message||'Snapshot profil member dimuat dari data penduduk.');renderDetailRows('#memberDashboardCitizenHousingRows',data.housing_rows||[],'Belum ada rumah utama yang tertaut ke profil ini.');renderChips('#memberDashboardCitizenAssistanceRows',data.assistance_rows||[],'Belum ada program bantuan sosial yang tercatat.');renderPlaceholder('#memberDashboardCitizenHousingState',data.housing_status||'empty',(data.housing_rows||[]).length?'Rumah utama warga sudah terbaca dari modul perumahan.':'Data rumah warga belum tersedia atau belum ditautkan.');renderQuickStats('#memberDashboardCitizenComplaintSummary',data.complaint_summary||[]);initOrRefreshTable('#memberDashboardCitizenComplaintTable',data.complaint_rows||[],[{key:'ticket'},{render:(row)=>{const title=escapeHtml(row.title);const service=escapeHtml(row.service||'Aduan umum');if(row.tracking_url){return `${title}${service}
`}
return `${title}${service}
`}},{key:'status'},{render:(row)=>row.reported_at?formatTimestamp(row.reported_at):'-'}]);renderPlaceholder('#memberDashboardCitizenComplaintState',data.complaint_status||'empty',(data.complaint_rows||[]).length?'Daftar aduan terbaru yang terkait dengan akun ini.':'Belum ada aduan yang tercatat untuk akun atau profil ini.');renderQuickStats('#memberDashboardCitizenAppointmentSummary',data.appointment_summary||[]);initOrRefreshTable('#memberDashboardCitizenAppointmentTable',data.appointment_rows||[],[{key:'booking_code'},{render:(row)=>{const title=escapeHtml(row.service||'Layanan publik');const queueNumber=escapeHtml(row.queue_number||'-');if(row.tracking_url){return `${title}${queueNumber}
`}
return `${title}${queueNumber}
`}},{key:'status'},{render:(row)=>row.scheduled_for?formatTimestamp(row.scheduled_for):'-'}]);renderPlaceholder('#memberDashboardCitizenAppointmentState',data.appointment_status||'empty',(data.appointment_rows||[]).length?'Daftar booking dan antrian terbaru yang terkait dengan akun ini.':'Belum ada booking atau nomor antrian yang tercatat untuk akun ini.')}
function renderDemografi(widget){const data=widget.data||{};renderChart('memberDashboardBirthChart','line',data.birth_chart||{labels:[],datasets:[]},{scales:{y:{beginAtZero:!0}}});renderChart('memberDashboardDeathChart','line',data.death_chart||{labels:[],datasets:[]},{scales:{y:{beginAtZero:!0}}});renderChart('memberDashboardGenderChart','doughnut',data.gender_chart||{labels:[],datasets:[]});renderChart('memberDashboardPyramidChart','bar',data.population_pyramid||{labels:[],datasets:[]},{scales:{y:{beginAtZero:!0}}});renderPlaceholder('#memberDashboardBirthState',widget.status,`Diperbarui ${formatTimestamp(widget.last_updated)}`);renderPlaceholder('#memberDashboardDeathState',widget.status,'Menggunakan tanggal meninggal yang tersimpan.');renderPlaceholder('#memberDashboardGenderState',widget.status,'Komposisi gender aktif.');renderPlaceholder('#memberDashboardPyramidState',widget.status,'Struktur umur aktif.')}
function renderEkonomi(widget){const data=widget.data||{};renderPlaceholder('#memberDashboardSembakoState',data.sembako?.status||'pending_integration',data.sembako?.message);if((data.pendapatan_proxy?.chart?.labels||[]).length){renderChart('memberDashboardIncomeChart','bar',data.pendapatan_proxy.chart,{scales:{y:{beginAtZero:!0}}})}else{destroyChart('memberDashboardIncomeChart')}
renderPlaceholder('#memberDashboardIncomeState',data.pendapatan_proxy?.status||'empty',data.pendapatan_proxy?.message);if((data.bansos?.chart?.labels||[]).length){renderChart('memberDashboardBansosChart','pie',data.bansos.chart);initOrRefreshTable('#memberDashboardBansosTable',data.bansos.rows||[],[{key:'label'},{key:'value'}])}else{destroyChart('memberDashboardBansosChart');initOrRefreshTable('#memberDashboardBansosTable',[],[{key:'label'},{key:'value'}])}
renderPlaceholder('#memberDashboardBansosState',data.bansos?.status||'empty',data.bansos?.message);renderPlaceholder('#memberDashboardRetribusiState',data.retribusi?.status||'pending_integration',data.retribusi?.message)}
function renderPerumahan(widget){const data=widget.data||{};setHtml('#memberDashboardHousingSummary',(data.summary_cards||[]).map((card)=>`
${card.label}
${formatMetric(card.value)}
Blok perumahan existing yang sekarang membaca data rumah nyata.
`).join(''));if((data.housing_chart?.labels||[]).length){renderChart('memberDashboardHousingChart','bar',data.housing_chart,{scales:{y:{beginAtZero:!0}}})}else{destroyChart('memberDashboardHousingChart')}
if((data.ownership_chart?.labels||[]).length){renderChart('memberDashboardOwnershipChart','doughnut',data.ownership_chart)}else{destroyChart('memberDashboardOwnershipChart')}
renderPlaceholder('#memberDashboardHousingState',widget.status,widget.meta?.message||'Ringkasan rumah dimuat dari modul perumahan.');renderPlaceholder('#memberDashboardOwnershipState',widget.status,'Status kepemilikan rumah aktif.')}
function renderPendidikan(widget){const data=widget.data||{};if((data.education_chart?.labels||[]).length){renderChart('memberDashboardEducationChart','polarArea',data.education_chart)}else{destroyChart('memberDashboardEducationChart')}
if((data.occupation_chart?.labels||[]).length){renderChart('memberDashboardOccupationChart','bar',data.occupation_chart,{scales:{y:{beginAtZero:!0}}})}else{destroyChart('memberDashboardOccupationChart')}
initOrRefreshTable('#memberDashboardEducationTable',data.education_rows||[],[{key:'label'},{key:'value'},{key:'top_instansi'}]);renderPlaceholder('#memberDashboardEducationState',widget.status,'Distribusi pendidikan dimuat dari riwayat pendidikan.');renderPlaceholder('#memberDashboardOccupationState',widget.status,'Pekerjaan dibaca dari profesi pada master penduduk.')}
function renderKesehatan(widget){const data=widget.data||{};setHtml('#memberDashboardHealthCoverage',(data.coverage_cards||[]).map((card)=>`
${card.label}
${formatMetric(card.value)}
${card.description}
`).join(''));setHtml('#memberDashboardHealthWidgets',(data.widgets||[]).map((item)=>`
${statusPill(item.status === 'pending_integration' ? 'pending_integration' : item.status)}
${item.title}
${item.message}
`).join(''))}
async function loadAndRender(name,renderer){try{const response=await fetchWidget(routes[name]);renderer(response.widget)}catch(error){console.error(`member dashboard widget ${name} error`,error);renderer({status:'error',data:{},meta:{},last_updated:null})}}
if(initialWidgets.summary){renderSummary(initialWidgets.summary)}
if(initialWidgets.citizen){renderCitizen(initialWidgets.citizen)}
renderPlaceholder('#memberDashboardCitizenProfileState','loading','Memuat profil dan keluarga aktif...');renderPlaceholder('#memberDashboardCitizenHousingState','loading','Memuat rumah dan bantuan sosial...');renderPlaceholder('#memberDashboardCitizenComplaintState','loading','Memuat pelacakan aduan...');renderPlaceholder('#memberDashboardCitizenAppointmentState','loading','Memuat booking dan nomor antrian...');renderPlaceholder('#memberDashboardBirthState','loading','Memuat data kelahiran...');renderPlaceholder('#memberDashboardDeathState','loading','Memuat data kematian...');renderPlaceholder('#memberDashboardGenderState','loading','Memuat komposisi gender...');renderPlaceholder('#memberDashboardPyramidState','loading','Memuat struktur umur...');renderPlaceholder('#memberDashboardSembakoState','loading','Memeriksa integrasi komoditas...');renderPlaceholder('#memberDashboardIncomeState','loading','Memuat proxy ekonomi...');renderPlaceholder('#memberDashboardBansosState','loading','Memuat distribusi bantuan sosial...');renderPlaceholder('#memberDashboardRetribusiState','loading','Memeriksa integrasi retribusi...');renderPlaceholder('#memberDashboardHousingState','loading','Memuat ringkasan perumahan...');renderPlaceholder('#memberDashboardOwnershipState','loading','Memuat status kepemilikan...');renderPlaceholder('#memberDashboardEducationState','loading','Memuat distribusi pendidikan...');renderPlaceholder('#memberDashboardOccupationState','loading','Memuat distribusi pekerjaan...');setHtml('#memberDashboardHealthWidgets',`
${statusPill('loading')}
Memuat widget kesehatan
Payload transisi kesehatan sedang diminta dari backend.
`);loadAndRender('citizen',renderCitizen);loadAndRender('demografi',renderDemografi);loadAndRender('ekonomi',renderEkonomi);loadAndRender('perumahan',renderPerumahan);loadAndRender('pendidikan',renderPendidikan);loadAndRender('kesehatan',renderKesehatan);if(polling.summary&&routes.summary){setInterval(()=>loadAndRender('summary',renderSummary),polling.summary)}
if(polling.heavy){['citizen','demografi','ekonomi','perumahan','pendidikan','kesehatan'].forEach((widgetName)=>{if(!routes[widgetName]){return}
setInterval(()=>loadAndRender(widgetName,{citizen:renderCitizen,demografi:renderDemografi,ekonomi:renderEkonomi,perumahan:renderPerumahan,pendidikan:renderPendidikan,kesehatan:renderKesehatan}[widgetName]),polling.heavy)})}})