/* settings.js — Halaman pengaturan: perusahaan, HR, status, data */ (function () { 'use strict'; var $ = function (s, r) { return (r || document).querySelector(s); }; function esc(v) { return UI.escape(v); } function init() { Store.init(); loadSettings(); renderStatuses(); renderInfo(); bind(); } function loadSettings() { var s = Store.get().settings; $('#s-perusahaan').value = s.perusahaan || ''; $('#s-hr').value = s.hr || ''; $('#s-jabatan').value = s.jabatanHr || ''; } function renderStatuses() { var list = Store.sortedStatuses(); $('#statusBody').innerHTML = list.map(function (s) { return '' + '' + s.urutan + '' + '' + esc(s.nama) + '' + '' + esc(s.warna) + '' + '' + (s.isFinal ? 'Ya' : '-') + '' + '
' + '' + '' + '
' + ''; }).join(''); } function renderInfo() { Store.fileCount().then(function (n) { $('#dataInfo').textContent = 'Jumlah pelamar: ' + Store.get().candidates.length + ' • Template: ' + Store.get().templates.length + ' • Berkas tersimpan: ' + n; }).catch(function () { $('#dataInfo').textContent = 'Jumlah pelamar: ' + Store.get().candidates.length + ' • Template: ' + Store.get().templates.length; }); } function openStatusForm(id) { var s = id ? Store.statusById(id) : null; var body = '
' + '
' + '
' + '
' + '
' + '
'; var footer = '' + ''; UI.openModal({ title: id ? 'Edit Status' : 'Tambah Status', body: body, footer: footer, onMount: function (el) { el.querySelector('[data-close]').addEventListener('click', UI.closeModal); el.querySelector('#saveStatus').addEventListener('click', function () { var nama = el.querySelector('#st-nama').value.trim(); if (!nama) { UI.toast('Nama status wajib diisi.', 'err'); return; } var urutanVal = el.querySelector('#st-urutan').value; Store.saveStatus({ id: id || undefined, nama: nama, warna: el.querySelector('#st-warna').value, urutan: urutanVal ? parseInt(urutanVal, 10) : undefined, isFinal: el.querySelector('#st-final').value === '1' }); UI.toast('Status disimpan.', 'ok'); UI.closeModal(); renderStatuses(); }); } }); } function download(filename, text) { var blob = new Blob([text], { type: 'application/json' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); setTimeout(function () { URL.revokeObjectURL(url); }, 500); } function doExport() { Store.exportData().then(function (data) { var text = JSON.stringify(data); var stamp = new Date().toISOString().slice(0, 10).replace(/-/g, ''); download('e-recruitment-backup-' + stamp + '.json', text); UI.toast('Backup berhasil diunduh.', 'ok'); }).catch(function (err) { UI.toast('Gagal export: ' + err.message, 'err'); }); } function doImport(file) { var reader = new FileReader(); reader.onload = function () { var data; try { data = JSON.parse(reader.result); } catch (e) { UI.toast('File JSON tidak valid.', 'err'); return; } if (!UI.confirmDialog('Import akan MENGGANTI seluruh data saat ini. Lanjutkan?')) return; Store.importData(data).then(function () { UI.toast('Data berhasil diimport.', 'ok'); loadSettings(); renderStatuses(); renderInfo(); }).catch(function (err) { UI.toast('Gagal import: ' + err.message, 'err'); }); }; reader.readAsText(file); } function doExportExcel() { var list = Store.get().candidates; if (!list.length) { UI.toast('Belum ada data pelamar untuk diexport.', 'err'); return; } try { Excel.exportCandidates(list, Store.get().statuses); UI.toast('File Excel diunduh.', 'ok'); } catch (err) { UI.toast('Gagal export Excel: ' + err.message, 'err'); } } function doImportExcel(file) { UI.toast('Membaca file Excel...'); Excel.readRows(file).then(function (json) { var mapped = Excel.mapRows(json, Store.get().statuses); var valid = [], invalid = 0; mapped.forEach(function (row) { var norm = Phone.normalize(row.phoneRaw || ''); if (!row.nama || !Phone.isValid(norm)) { invalid++; return; } row.phoneNorm = norm; valid.push(row); }); if (!valid.length) { UI.toast('Tidak ada baris valid. Kolom "Nama" dan "No WhatsApp" wajib terisi.', 'err'); return; } var pesan = 'Ditemukan ' + valid.length + ' baris valid' + (invalid ? ' dan ' + invalid + ' baris dilewati' : '') + '.\n\nTambahkan baris valid ke daftar pelamar?'; if (!UI.confirmDialog(pesan)) return; valid.forEach(function (row) { Store.addCandidate(row); }); UI.toast(valid.length + ' pelamar ditambahkan.', 'ok'); renderInfo(); }).catch(function (err) { UI.toast('Gagal import Excel: ' + err.message, 'err'); }); } function bind() { $('#saveSettings').addEventListener('click', function () { Store.setSettings({ perusahaan: $('#s-perusahaan').value.trim(), hr: $('#s-hr').value.trim(), jabatanHr: $('#s-jabatan').value.trim() }); UI.toast('Pengaturan disimpan.', 'ok'); }); $('#btnAddStatus').addEventListener('click', function () { openStatusForm(null); }); $('#btnExport').addEventListener('click', doExport); $('#btnImport').addEventListener('click', function () { $('#importFile').click(); }); $('#importFile').addEventListener('change', function (e) { if (e.target.files && e.target.files[0]) doImport(e.target.files[0]); e.target.value = ''; }); $('#btnExportExcel').addEventListener('click', doExportExcel); $('#btnImportExcel').addEventListener('click', function () { $('#importExcelFile').click(); }); $('#btnTemplateExcel').addEventListener('click', function () { try { Excel.exportTemplate(); UI.toast('Template Excel diunduh.', 'ok'); } catch (err) { UI.toast('Gagal mengunduh template: ' + err.message, 'err'); } }); $('#importExcelFile').addEventListener('change', function (e) { if (e.target.files && e.target.files[0]) doImportExcel(e.target.files[0]); e.target.value = ''; }); $('#btnReset').addEventListener('click', function () { if (!UI.confirmDialog('Reset akan menghapus SEMUA data pelamar, template, dan berkas. Lanjutkan?')) return; Store.reset().then(function () { UI.toast('Data telah direset.', 'ok'); loadSettings(); renderStatuses(); renderInfo(); }); }); document.addEventListener('click', function (e) { var edit = e.target.closest('[data-st-edit]'); if (edit) { openStatusForm(edit.getAttribute('data-st-edit')); return; } var del = e.target.closest('[data-st-del]'); if (del) { var s = Store.statusById(del.getAttribute('data-st-del')); if (s && UI.confirmDialog('Hapus status "' + s.nama + '"?')) { try { Store.deleteStatus(s.id); UI.toast('Status dihapus.', 'ok'); renderStatuses(); } catch (err) { UI.toast(err.message, 'err'); } } } }); } document.addEventListener('DOMContentLoaded', init); })();