402 lines
15 KiB
PHP
402 lines
15 KiB
PHP
<style>
|
|
.tpa-mis-dashboard .filter-bar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 12px 20px;
|
|
align-items: flex-end;
|
|
background: #eef5fa;
|
|
border-radius: 10px;
|
|
padding: 10px 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.tpa-mis-dashboard .filter-field {
|
|
flex: 1 1 140px;
|
|
min-width: 120px;
|
|
max-width: 220px;
|
|
}
|
|
.tpa-mis-dashboard .filter-field label {
|
|
display: block;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
margin-bottom: 4px;
|
|
color: #111;
|
|
}
|
|
.tpa-mis-dashboard .filter-field .select2-container {
|
|
width: 100% !important;
|
|
}
|
|
.tpa-mis-dashboard .filter-field .select2-selection--single {
|
|
height: 32px !important;
|
|
min-height: 32px;
|
|
border: 1px solid #d8e2ea !important;
|
|
border-radius: 8px !important;
|
|
font-size: 12px;
|
|
}
|
|
.tpa-mis-dashboard .filter-field .select2-selection__rendered {
|
|
line-height: 30px !important;
|
|
padding-left: 10px !important;
|
|
color: #333;
|
|
}
|
|
.tpa-mis-dashboard .filter-field .select2-selection__arrow {
|
|
height: 30px !important;
|
|
}
|
|
.tpa-mis-dashboard .filter-field .select2-container--disabled .select2-selection--single {
|
|
background-color: #f5f7f9 !important;
|
|
cursor: not-allowed;
|
|
opacity: 0.85;
|
|
}
|
|
.tpa-mis-dashboard .dashboard-status {
|
|
font-size: 12px;
|
|
color: #5c6b7a;
|
|
padding: 4px 0 10px;
|
|
min-height: 20px;
|
|
}
|
|
.tpa-mis-dashboard .dashboard-status.is-error { color: #c0392b; }
|
|
.tpa-mis-dashboard .dashboard-status.is-loading { color: #0a8794; }
|
|
.tpa-mis-dashboard .dashboard-placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 200px;
|
|
color: #7a8a99;
|
|
font-size: 13px;
|
|
background: #fff;
|
|
border: 1px dashed #d0dce6;
|
|
border-radius: 8px;
|
|
}
|
|
.tpa-mis-dashboard .mis-toolbar {
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
margin-bottom: 10px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.tpa-mis-dashboard .mis-toolbar.is-visible {
|
|
display: flex;
|
|
}
|
|
.tpa-mis-dashboard .mis-toolbar h5 {
|
|
margin: 0;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
color: #152A54;
|
|
}
|
|
.tpa-mis-dashboard .mis-frame-wrap {
|
|
display: none;
|
|
background: #fff;
|
|
border: 1px solid #d0dce6;
|
|
border-radius: 8px;
|
|
overflow: visible;
|
|
}
|
|
.tpa-mis-dashboard .mis-frame-wrap.is-visible {
|
|
display: block;
|
|
}
|
|
.tpa-mis-dashboard #mis-report-frame {
|
|
display: block;
|
|
width: 100%;
|
|
height: 0;
|
|
min-height: 0;
|
|
border: 0;
|
|
background: #fff;
|
|
overflow: hidden;
|
|
}
|
|
</style>
|
|
|
|
<div class="row tpa-mis-dashboard">
|
|
<div class="col-xl-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="filter-bar">
|
|
<div class="filter-field">
|
|
<label for="filter-client">Client</label>
|
|
<select id="filter-client" class="form-control form-control-sm tpa-mis-select2">
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-field">
|
|
<label for="filter-branch">Branch</label>
|
|
<select id="filter-branch" class="form-control form-control-sm tpa-mis-select2" disabled>
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-field">
|
|
<label for="filter-policy">Policy</label>
|
|
<select id="filter-policy" class="form-control form-control-sm tpa-mis-select2" disabled>
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="dashboard-status" class="dashboard-status"></div>
|
|
|
|
<div id="mis-toolbar" class="mis-toolbar">
|
|
<h5 id="mis-title">TPA MIS Report</h5>
|
|
<a id="mis-pdf-link" class="btn btn-sm btn-outline-primary" href="#" target="_blank" rel="noopener" style="display:none;">Download PDF</a>
|
|
</div>
|
|
|
|
<div id="dashboard-container">
|
|
<div class="dashboard-placeholder" id="dashboard-placeholder">
|
|
Select client, branch, and policy to load the report.
|
|
</div>
|
|
<div id="mis-frame-wrap" class="mis-frame-wrap">
|
|
<iframe id="mis-report-frame" title="TPA MIS Report" scrolling="no"></iframe>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$(function () {
|
|
const CLIENTS_API = <?= json_encode(base_url('/util/getClientAndBranchAndPolicy')) ?>;
|
|
const MIS_API = <?= json_encode($misApiUrl ?? base_url('/util/tpa-reports/mis')) ?>;
|
|
|
|
const select2Options = {
|
|
placeholder: 'Select',
|
|
allowClear: true,
|
|
width: '100%',
|
|
minimumResultsForSearch: 0,
|
|
dropdownParent: $(document.body)
|
|
};
|
|
|
|
let branchByClient = {};
|
|
let policyByClient = {};
|
|
|
|
const $elClient = $('#filter-client');
|
|
const $elBranch = $('#filter-branch');
|
|
const $elPolicy = $('#filter-policy');
|
|
const elStatus = document.getElementById('dashboard-status');
|
|
const elPlaceholder = document.getElementById('dashboard-placeholder');
|
|
const elMisToolbar = document.getElementById('mis-toolbar');
|
|
const elMisFrameWrap = document.getElementById('mis-frame-wrap');
|
|
const elMisFrame = document.getElementById('mis-report-frame');
|
|
const elMisTitle = document.getElementById('mis-title');
|
|
const elMisPdf = document.getElementById('mis-pdf-link');
|
|
|
|
function setStatus(message, type) {
|
|
elStatus.textContent = message || '';
|
|
elStatus.className = 'dashboard-status' + (type ? ' is-' + type : '');
|
|
}
|
|
|
|
function initSelect2($select, disabled) {
|
|
if ($select.hasClass('select2-hidden-accessible')) {
|
|
$select.select2('destroy');
|
|
}
|
|
$select.prop('disabled', false);
|
|
$select.select2(select2Options);
|
|
if (disabled) {
|
|
$select.prop('disabled', true);
|
|
}
|
|
}
|
|
|
|
function rebuildSelect($select, placeholder, disabled, items, getValue, getLabel) {
|
|
if ($select.hasClass('select2-hidden-accessible')) {
|
|
$select.select2('destroy');
|
|
}
|
|
$select.empty().append($('<option>', { value: '', text: placeholder }));
|
|
(items || []).forEach(function (item) {
|
|
$select.append($('<option>', {
|
|
value: String(getValue(item)),
|
|
text: getLabel(item)
|
|
}));
|
|
});
|
|
$select.val('');
|
|
initSelect2($select, disabled);
|
|
}
|
|
|
|
function filtersComplete() {
|
|
return !!($elClient.val() && $elBranch.val() && $elPolicy.val());
|
|
}
|
|
|
|
function clearMisReport() {
|
|
if (elMisToolbar) elMisToolbar.classList.remove('is-visible');
|
|
if (elMisFrameWrap) elMisFrameWrap.classList.remove('is-visible');
|
|
if (elMisFrame) {
|
|
elMisFrame.onload = null;
|
|
elMisFrame.removeAttribute('src');
|
|
elMisFrame.style.height = '0px';
|
|
}
|
|
if (elMisPdf) {
|
|
elMisPdf.style.display = 'none';
|
|
elMisPdf.setAttribute('href', '#');
|
|
}
|
|
if (elPlaceholder) elPlaceholder.style.display = '';
|
|
}
|
|
|
|
function prepareMisDocument(doc) {
|
|
if (!doc || doc.getElementById('tpa-mis-embed-style')) return;
|
|
const style = doc.createElement('style');
|
|
style.id = 'tpa-mis-embed-style';
|
|
style.textContent = [
|
|
'html, body { height: auto !important; min-height: 0 !important; overflow: hidden !important; margin: 0 !important; padding: 0 !important; background: #fff !important; }',
|
|
'.page, .wrap { margin: 0 auto !important; box-shadow: none !important; }',
|
|
'body { padding: 0 !important; }'
|
|
].join('\n');
|
|
(doc.head || doc.documentElement).appendChild(style);
|
|
}
|
|
|
|
/** Fit iframe to report content only — avoids leftover grey scroll after load. */
|
|
function resizeMisFrame() {
|
|
if (!elMisFrame || !elMisFrame.contentWindow) return;
|
|
try {
|
|
const doc = elMisFrame.contentDocument || elMisFrame.contentWindow.document;
|
|
if (!doc || !doc.body) return;
|
|
|
|
prepareMisDocument(doc);
|
|
|
|
const roots = doc.querySelectorAll('.page, .wrap');
|
|
let height = 0;
|
|
if (roots.length) {
|
|
roots.forEach(function (el) {
|
|
const bottom = el.offsetTop + el.offsetHeight;
|
|
if (bottom > height) height = bottom;
|
|
});
|
|
} else {
|
|
height = doc.body.scrollHeight || doc.body.offsetHeight || 0;
|
|
}
|
|
|
|
// Prefer content box over inflated html/body min-heights.
|
|
height = Math.ceil(height);
|
|
if (height < 200) {
|
|
height = Math.max(
|
|
doc.body.scrollHeight || 0,
|
|
(doc.documentElement && doc.documentElement.scrollHeight) || 0
|
|
);
|
|
}
|
|
|
|
if (height > 0) {
|
|
const next = height + 8;
|
|
const prev = parseInt(elMisFrame.style.height, 10) || 0;
|
|
// Only grow when content actually needs more room; shrink when excess grey space.
|
|
if (Math.abs(next - prev) > 4) {
|
|
elMisFrame.style.height = next + 'px';
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Same-origin expected; leave height alone on failure.
|
|
}
|
|
}
|
|
|
|
function bindMisFrameResize() {
|
|
if (!elMisFrame) return;
|
|
elMisFrame.onload = function () {
|
|
resizeMisFrame();
|
|
// Charts/images can settle after first paint (ABHI Chart.js).
|
|
[200, 600, 1200, 2000].forEach(function (ms) {
|
|
setTimeout(resizeMisFrame, ms);
|
|
});
|
|
};
|
|
}
|
|
|
|
async function loadFilterData() {
|
|
setStatus('Loading clients…', 'loading');
|
|
try {
|
|
const res = await fetch(CLIENTS_API, { credentials: 'same-origin' });
|
|
const json = await res.json();
|
|
if (!json.status) {
|
|
setStatus('Could not load client list.', 'error');
|
|
return;
|
|
}
|
|
branchByClient = json.branch_data || {};
|
|
policyByClient = json.policyListByClient || {};
|
|
|
|
rebuildSelect($elClient, 'Select', false, json.client_data || [], function (c) { return c.id; }, function (c) {
|
|
return c.client_name || c.client_short_name || ('Client ' + c.id);
|
|
});
|
|
rebuildSelect($elBranch, 'Select', true);
|
|
rebuildSelect($elPolicy, 'Select', true);
|
|
setStatus('');
|
|
} catch (e) {
|
|
setStatus('Failed to load filter options.', 'error');
|
|
}
|
|
}
|
|
|
|
async function fetchMisReport(policyId) {
|
|
clearMisReport();
|
|
if (!filtersComplete() || !policyId) {
|
|
setStatus('Select client, branch, and policy to load the report.');
|
|
return;
|
|
}
|
|
|
|
setStatus('Loading MIS report…', 'loading');
|
|
try {
|
|
const url = MIS_API + '?client_policy=' + encodeURIComponent(policyId);
|
|
const res = await fetch(url, { credentials: 'same-origin' });
|
|
const json = await res.json();
|
|
if (json.status !== 'success' || !json.data || !json.data.preview_url) {
|
|
setStatus(json.message || 'No MIS report for this TPA.', 'error');
|
|
return;
|
|
}
|
|
|
|
if (elMisTitle) elMisTitle.textContent = json.data.title || 'TPA MIS Report';
|
|
if (elMisFrame) {
|
|
bindMisFrameResize();
|
|
elMisFrame.src = json.data.preview_url;
|
|
}
|
|
if (elMisPdf && json.data.pdf_url) {
|
|
elMisPdf.href = json.data.pdf_url;
|
|
elMisPdf.style.display = '';
|
|
}
|
|
if (elPlaceholder) elPlaceholder.style.display = 'none';
|
|
if (elMisToolbar) elMisToolbar.classList.add('is-visible');
|
|
if (elMisFrameWrap) elMisFrameWrap.classList.add('is-visible');
|
|
setStatus('');
|
|
} catch (e) {
|
|
setStatus('Failed to load MIS report.', 'error');
|
|
}
|
|
}
|
|
|
|
$(window).on('resize', function () {
|
|
// Parent width change may reflow report; re-measure after layout.
|
|
setTimeout(resizeMisFrame, 100);
|
|
});
|
|
|
|
$elClient.on('change', function () {
|
|
const clientId = $(this).val();
|
|
rebuildSelect($elBranch, 'Select', !clientId);
|
|
rebuildSelect($elPolicy, 'Select', true);
|
|
clearMisReport();
|
|
setStatus(clientId ? '' : 'Select client, branch, and policy to load the report.');
|
|
|
|
if (!clientId) return;
|
|
const branches = branchByClient[clientId] || [];
|
|
rebuildSelect($elBranch, 'Select', branches.length === 0, branches, function (b) { return b.id; }, function (b) {
|
|
return b.branch_name || ('Branch ' + b.id);
|
|
});
|
|
});
|
|
|
|
$elBranch.on('change', function () {
|
|
const branchId = $(this).val();
|
|
const clientId = $elClient.val();
|
|
rebuildSelect($elPolicy, 'Select', !branchId);
|
|
clearMisReport();
|
|
setStatus(branchId ? '' : 'Select branch and policy to load the report.');
|
|
|
|
if (!branchId || !clientId) return;
|
|
|
|
const policiesForClient = policyByClient[clientId] || [];
|
|
const policies = policiesForClient.filter(function (p) {
|
|
return String(p.client_branch_id) === String(branchId);
|
|
});
|
|
|
|
rebuildSelect($elPolicy, 'Select', policies.length === 0, policies, function (p) { return p.id; }, function (p) {
|
|
const type = p.policy_type || '';
|
|
const no = p.policy_no || '';
|
|
return (type && no) ? (type + ' - ' + no) : (no || type || ('Policy ' + p.id));
|
|
});
|
|
if (policies.length === 0) {
|
|
setStatus('No policies found for this branch.', 'error');
|
|
}
|
|
});
|
|
|
|
$elPolicy.on('change', function () {
|
|
fetchMisReport($(this).val());
|
|
});
|
|
|
|
initSelect2($elClient, false);
|
|
initSelect2($elBranch, true);
|
|
initSelect2($elPolicy, true);
|
|
loadFilterData();
|
|
});
|
|
</script>
|