2026-03-04 23:34:45 +07:00
< ? = $this -> extend ( 'layouts/main.php' ) ?>
< ? = $this -> section ( 'content' ) ?>
< div class = " page-wrapper " >
2026-03-10 08:43:43 +07:00
< div class = " container-fluid " >
< div class = " row page-titles " >
< div class = " col-md-5 align-self-center " >
< h4 class = " text-themecolor " > Certificates Installation Management </ h4 >
</ div >
</ div >
< div class = " row " >
< div class = " col-12 " >
< div class = " card " >
< div class = " card-body " >
< div class = " row mb-3 " >
< div class = " col-12 mb-3 " >
< div class = " input-group input-group-sm " >
< span class = " input-group-text " >< i class = " fas fa-search " ></ i ></ span >
< input type = " text " id = " searchInput " class = " form-control "
placeholder = " Search certificates by name, product, type, vendor, or dates... " >
</ div >
</ div >
< div class = " col-md-4 mb-2 " >
< select id = " productFilter " class = " form-select form-select-sm " >
< option value = " " >-- Product Filter --</ option >
< option value = " tms " > TMS </ option >
< option value = " jokoh " > Jokoh </ option >
< option value = " mindray " > Mindray </ option >
</ select >
</ div >
< div class = " col-md-4 mb-2 " >
< select id = " validationFilter " class = " form-select form-select-sm " >
< option value = " " >-- Validation Filter --</ option >
< option value = " valid " > Validated </ option >
< option value = " unval " > Unvalidated </ option >
</ select >
</ div >
< div class = " col-md-4 mb-2 " >
< button onclick = " resetFilters() " class = " btn btn-secondary btn-sm w-100 " >
< i class = " fas fa-redo " ></ i > Reset Filters
</ button >
</ div >
</ div >
2026-03-04 23:34:45 +07:00
< div class = " table-responsive " style = " width: 100%; " >
< table id = " certificatesTable " class = " table table-striped table-hover border " style = " width: 100%; " >
< thead class = " table-primary " >
< tr >
2026-04-08 08:40:10 +07:00
< th style = " width: 35% " > Certificate </ th >
< th style = " width: 35% " > Act Report </ th >
2026-03-10 08:43:43 +07:00
< th style = " width: 10% " > Issue Date </ th >
< th style = " width: 8% " > Validation </ th >
< th class = " text-center " style = " width: 12% " > Action </ th >
2026-03-04 23:34:45 +07:00
</ tr >
</ thead >
< tbody >
</ tbody >
</ table >
2026-03-10 08:43:43 +07:00
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
2026-03-04 23:34:45 +07:00
</ div >
< div class = " modal fade " id = " validateModal " tabindex = " -1 " aria - labelledby = " validateModalLabel " aria - hidden = " true " >
2026-03-10 08:43:43 +07:00
< div class = " modal-dialog modal-xl modal-dialog-centered " >
< div class = " modal-content " >
< div class = " modal-header bg-warning text-dark " id = 'modalHeader' >
< h5 class = " modal-title " id = " validateModalLabel " >
Validate installation Certificate
</ h5 >
< button type = " button " class = " btn-close " data - bs - dismiss = " modal "
aria - label = " Close " ></ button >
</ div >
< div class = " modal-body " >
< div class = " row border-bottom mb-3 pb-2 " >
< div class = " col-md-8 " >
< label class = " form-label " >< i class = " fa-solid fa-certificate me-2 " ></ i > Certificate Name </ label >
< h5 id = " modalCertName " class = " mt-2 fw-bolder " >-</ h5 >
</ div >
< div class = " col-md-4 text-md-end " >
< h5 id = " modalValidation " >-</ h5 >
</ div >
</ div >
< div class = " row " >
< div class = " col-md-6 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-book-medical me-2 " ></ i > Certificate Number </ label >
< p id = " modalCertNumber " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-6 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-microchip me-2 " ></ i > Product / Equipment </ label >
< p id = " modalProductName " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
2026-03-04 23:34:45 +07:00
< div class = " col-md-6 mb-3 " >
2026-03-10 08:43:43 +07:00
< label class = " form-label " >< i class = " fa-solid fa-hashtag me-2 " ></ i > Serial Number </ label >
< p id = " modalProductNumber " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-6 mb-3 " >
< label class = " form-label " >< i class = " fa-regular fa-hospital me-2 " ></ i > Site </ label >
< p id = " modalSiteName " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-12 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-calendar-check me-2 " ></ i > Issue Date </ label >
< p id = " modalIssueDate " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-12 mb-4 " >
< label class = " form-label " >< i class = " fa-solid fa-file-lines me-2 " ></ i > Activity Report Reference </ label >
< a href = " javascript:void(0) " id = " modalActivityLink " class = " activity-report-link text-decoration-none fw-bolder " style = " color:#d43215b0; " >
< div class = " p-2 border rounded bg-light " >
< i class = " fa-solid fa-up-right-from-square me-2 " ></ i >
< span id = " modalActivity " >-</ span >
</ div >
</ a >
</ div >
< div class = " col-md-4 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-user me-2 " ></ i > Owner Validation </ label >
< p id = " modalValOwner " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-4 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-user me-2 " ></ i > SPV Validation </ label >
< p id = " modalValSpv " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
< div class = " col-md-4 mb-3 " >
< label class = " form-label " >< i class = " fa-solid fa-user me-2 " ></ i > Manager Validation </ label >
< p id = " modalValManager " class = " form-control-plaintext border-bottom fw-bolder " >-</ p >
</ div >
</ div >
< div id = 'modalInfo' ></ div >
< div class = " row " >
< div class = " col-md-12 mb-3 " >
< div class = " border rounded p-2 " style = " height: 500px; overflow: hidden; " >
< iframe id = " certificatePreview " src = " " style = " width: 100%; height: 100%; border: none; " ></ iframe >
</ div >
</ div >
</ div >
</ div >
< div class = " modal-footer " >
< button type = " button " class = " btn btn-secondary " data - bs - dismiss = " modal " >
< i class = " fa-solid fa-times " ></ i > Cancel
</ button >
< button type = " button " class = " btn btn-warning text-dark " id = " confirmValidateBtn " >
< i class = " fa-solid fa-check " ></ i > Validate Certificate
</ button >
</ div >
</ div >
</ div >
2026-03-04 23:34:45 +07:00
</ div >
< ? = $this -> endSection () ?>
< ? = $this -> section ( 'style' ) ?>
< ? = $this -> endSection () ?>
< ? = $this -> section ( 'script' ) ?>
< script >
$ ( function () {
let table = $ ( '#certificatesTable' ) . DataTable ({
2026-03-10 08:43:43 +07:00
order : [[ 3 , 'asc' ]], // Order by Validation Column
2026-03-04 23:34:45 +07:00
pageLength : 25 ,
dom : '<"row"<"col-md-6"l>>rtip' ,
responsive : true ,
serverSide : false ,
autoWidth : false ,
ajax : function ( data , callback , settings ) {
fetch ( '<?= base_url(' certificates / api / getindexinstallation ') ?>' )
. then ( response => response . json ())
. then ( result => {
callback ({
2026-03-10 08:43:43 +07:00
data : result . map (( cert , index ) => {
let certid = cert . cert_id || '' ;
let certname = cert . cert_name || '-' ;
let certnumber = cert . cert_number || '' ;
let actid = cert . actid || '' ;
let issuedateRaw = cert . issued_date || '' ;
let status = cert . status ; // Validation status
let fullname = cert . fullname ;
let activity_subject = cert . activity_subject ;
2026-03-04 23:34:45 +07:00
2026-04-08 08:40:10 +07:00
let user_check = cert . user_validation_at ? 'checked' : '' ;
let spv_check = cert . spv_validation_at ? 'checked' : '' ;
let manager_check = cert . manager_validation_at ? 'checked' : '' ;
2026-03-04 23:34:45 +07:00
let issuedate = '-' ;
2026-03-10 08:43:43 +07:00
let validationBadge = '' ;
2026-04-08 08:40:10 +07:00
let statusBadge = '' ;
2026-03-10 08:43:43 +07:00
if ( issuedateRaw && issuedateRaw !== '0000-00-00' ) {
let date = new Date ( issuedateRaw );
let day = String ( date . getDate ()) . padStart ( 2 , '0' );
let month = date . toLocaleString ( 'en-US' , { month : 'short' });
let year = date . getFullYear ();
issuedate = `${day} ${month} ${year}` ;
}
if ( status == 'unvalidated' ) {
2026-04-08 08:40:10 +07:00
// validationBadge = "<div class=''><span class='badge bg-warning text-dark'>unvalidated</span><br></div>";
validationBadge = '<div class="">' +
'<span class="badge bg-warning text-dark mb-1 p-1 px-2">unvalidated</span><br>' +
'<div class="form-check text-sm">' +
'<input class="form-check-input" type="checkbox" ' + user_check + ' disabled>' +
'<label class="form-check-label small">TSO</label>' +
'</div>' +
'<div class="form-check">' +
'<input class="form-check-input" type="checkbox" ' + spv_check + ' disabled>' +
'<label class="form-check-label small">SPV</label>' +
'</div>' +
'<div class="form-check">' +
'<input class="form-check-input" type="checkbox" ' + manager_check + ' disabled>' +
'<label class="form-check-label small">Manager</label>' +
'</div>' +
'</div>' ;
statusBadge = '<span class="text-danger">❋</span>' ;
2026-03-10 08:43:43 +07:00
} else {
2026-04-08 08:40:10 +07:00
// validationBadge = '<div class=""><span class="badge bg-success">validated</span></div>';
validationBadge = '<div class="">' +
'<span class="badge bg-success mb-1 p-1 px-2">validated</span><br>' +
'<div class="form-check">' +
'<input class="form-check-input" type="checkbox" ' + user_check + ' disabled>' +
'<label class="form-check-label small">TSO</label>' +
'</div>' +
'<div class="form-check">' +
'<input class="form-check-input" type="checkbox" ' + spv_check + ' disabled>' +
'<label class="form-check-label small">SPV</label>' +
'</div>' +
'<div class="form-check">' +
'<input class="form-check-input" type="checkbox" ' + manager_check + ' disabled>' +
'<label class="form-check-label small">Manager</label>' +
'</div>' +
'</div>' ;
2026-03-04 23:34:45 +07:00
}
return [
2026-04-08 08:40:10 +07:00
`<strong>${statusBadge} ${certname}</strong><br><small class="text-muted">Cert# : ${certnumber}</small>` ,
2026-03-10 08:43:43 +07:00
`<a href="javascript:void(0)" class="activity-report-link text-decoration-none" data-certid="${certid}" data-actid="${actid}" style="color:#d43215b0;">#${actid} - ${activity_subject} <i class="fa-solid fa-up-right-from-square"></i></strong><br><small class="text-muted">Owner : ${fullname}</small></a>` ,
2026-03-04 23:34:45 +07:00
issuedate ,
2026-03-10 08:43:43 +07:00
validationBadge ,
status == 'unvalidated'
? `<div class="text-center"><button type="button" class="btn btn-sm btn-warning text-dark btn-validate-modal" data-certid="${certid}"><i class="fa-solid fa-triangle-exclamation me-2"></i>Need Validation</button></div>`
: ` < div class = " text-center mb-1 " >< button type = " button " class = " btn btn-sm btn-info btn-validate-modal " data - certid = " ${ certid } " >< i class = " fa-regular fa-eye me-2 " ></ i > Detail </ button ></ div >
< div class = " text-center " >< button type = " button " class = " btn btn-sm btn-success btn-view " data - certnumber = " ${ certnumber } " >< i class = " fa-regular fa-file-pdf me-2 " ></ i > Generated PDF </ button ></ div > `
2026-03-04 23:34:45 +07:00
];
})
});
})
. catch ( error => {
console . error ( 'Error fetching data:' , error );
callback ({ data : [] });
});
},
2026-03-10 08:43:43 +07:00
columnDefs : [
{
// Kondisi untuk Kolom 3 (Validation)
targets : 3 ,
render : function ( data , type ) {
if ( type === 'sort' ) {
let val = data . toLowerCase ();
if ( val . includes ( 'unvalidated' )) return 1 ;
if ( val . includes ( 'validated' )) return 2 ;
return 3 ;
}
return data ;
2026-03-04 23:34:45 +07:00
}
2026-03-10 08:43:43 +07:00
},
{
// Kondisi untuk Kolom 4 (Action)
targets : [ 4 ],
orderable : false
2026-03-04 23:34:45 +07:00
}
2026-03-10 08:43:43 +07:00
]
2026-03-04 23:34:45 +07:00
});
$ ( '#certificatesTable_filter' ) . hide ();
// Search
$ ( '#searchInput' ) . on ( 'keyup' , function () {
table . search ( this . value ) . draw ();
});
// Type filter using DataTables column filter
2026-03-10 08:43:43 +07:00
$ ( '#productFilter' ) . on ( 'change' , function () {
2026-03-04 23:34:45 +07:00
let type = $ ( this ) . val ();
if ( type === '' ) {
2026-03-10 08:43:43 +07:00
table . column ( 0 ) . search ( '' ) . draw ();
2026-03-04 23:34:45 +07:00
} else {
let typeText = type . charAt ( 0 ) . toUpperCase () + type . slice ( 1 );
2026-03-10 08:43:43 +07:00
table . column ( 0 ) . search ( typeText ) . draw ();
2026-03-04 23:34:45 +07:00
}
});
2026-03-10 08:43:43 +07:00
$ ( '#validationFilter' ) . on ( 'change' , function () {
let validation = $ ( this ) . val ();
if ( validation === '' ) {
table . column ( 3 ) . search ( '' ) . draw ();
} else if ( validation === 'unval' ) {
table . column ( 3 ) . search ( 'unv' ) . draw ();
} else if ( validation === 'valid' ) {
table . column ( 3 ) . search ( '^validated$' , true , false ) . draw ();
}
2026-03-04 23:34:45 +07:00
});
// Reset
window . resetFilters = function () {
2026-03-10 08:43:43 +07:00
$ ( '#searchInput, #productFilter, #validationFilter' ) . val ( '' );
table . search ( '' ) . columns () . search ( '' ) . draw ();
2026-03-04 23:34:45 +07:00
};
// View PDF
$ ( document ) . on ( 'click' , '.btn-view' , function () {
2026-03-10 08:43:43 +07:00
let certnumber = $ ( this ) . data ( 'certnumber' );
window . open ( '<?= base_url(' certificates / number / ') ?>' + certnumber , '_blank' );
2026-03-04 23:34:45 +07:00
});
// Activity report
$ ( document ) . on ( 'click' , '.activity-report-link' , function () {
2026-03-10 08:43:43 +07:00
let actid = $ ( this ) . data ( 'actid' );
2026-03-04 23:34:45 +07:00
window . open (
2026-03-10 08:43:43 +07:00
'<?= base_url(' activities / detail / ') ?>' + actid ,
2026-03-04 23:34:45 +07:00
'_blank' ,
'width=1200,height=800,scrollbars=yes,resizable=yes'
);
});
// Open modal
2026-03-10 08:43:43 +07:00
$ ( document ) . on ( 'click' , '.btn-validate-modal' , function () {
2026-03-04 23:34:45 +07:00
let btn = $ ( this );
2026-03-10 08:43:43 +07:00
let certid = btn . data ( 'certid' );
2026-03-04 23:34:45 +07:00
2026-03-10 08:43:43 +07:00
// POST API call to fetch certificate data
$ . post (
'<?= base_url(' certificates / api / showinstallation ') ?>' ,
{ certid },
function ( data ) {
$ ( '#modalCertName' ) . text ( data . cert_name || '-' );
$ ( '#modalCertNumber' ) . text ( data . cert_number || '-' );
$ ( '#modalProductName' ) . text ( data . productname || '-' );
$ ( '#modalProductNumber' ) . text ( data . productnumber || '-' );
$ ( '#modalIssueDate' ) . text ( data . issued_date || '-' );
$ ( '#modalSiteName' ) . text ( data . sitename || '-' );
// Cek status validasi
const isValid = data . status === 'validated' ;
const theme = isValid ? 'success' : 'warning' ;
const icon = isValid ? 'fa-regular fa-circle-check' : 'fa-solid fa-triangle-exclamation' ;
const note = isValid
? 'Sertifikat Sudah Divalidasi'
: 'Review data berikut dengan teliti, setelah divalidasi maka sertifikat akan dinyatakan <strong>Valid</strong> dan <strong>sah secara sistem.</strong>' ;
$ ( '#modalHeader' ) . removeClass ( 'bg-warning bg-success' ) . addClass ( `bg-${theme} text-dark` );
$ ( '#modalValidation' ) . html (
` < span class = " badge bg- ${ theme } text-dark py-2 px-3 " >
< i class = " ${ icon } me-2 " ></ i > $ { data . status || '-' }
</ span > `
);
$ ( '#modalInfo' ) . html (
` < div class = " alert alert- ${ theme } border-0 shadow-sm d-flex align-items-center " >
< i class = " ${ icon } fs-4 me-3 " ></ i >
< div >
< strong > Validation Note :</ strong >< br >
$ { note }
</ div >
</ div > `
);
$ ( '#modalActivity' ) . text ( data . actid ? `#${data.actid} - ${data.subject || '-'}` : '-' );
$ ( '#modalActivityLink' ) . attr ( 'data-actid' , data . actid || '' );
$ ( '#modalValOwner' ) . html ( data . user_validation_at ? `${data.username} - ${data.user_validation_at}<i class="fa-solid fa-circle-check text-success ms-2"></i>` : '-' );
$ ( '#modalValSpv' ) . html ( data . spv_validation_at ? `${data.spvname} - ${data.spv_validation_at}<i class="fa-solid fa-circle-check text-success ms-2"></i>` : '-' );
$ ( '#modalValManager' ) . html ( data . manager_validation_at ? `${data.managername} - ${data.manager_validation_at}<i class="fa-solid fa-circle-check text-success ms-2"></i>` : '-' );
},
'json'
) . fail ( function () {
console . error ( 'Error fetching certificate data' );
});
// INI JANGAN DIUBAH
$ ( '#confirmValidateBtn' ) . data ( 'certid' , certid );
$ ( '#certificatePreview' ) . attr ( 'src' , '<?= base_url(' certificates / installation / show / ') ?>' + certid );
2026-03-04 23:34:45 +07:00
$ ( '#validateModal' ) . modal ( 'show' );
});
// Confirm validate
$ ( '#confirmValidateBtn' ) . on ( 'click' , function () {
let certid = $ ( this ) . data ( 'certid' );
let certificateType = 'installation' ;
if ( ! confirm ( 'Are you sure?' )) return ;
$ . post (
2026-03-10 08:43:43 +07:00
'<?= base_url(' certificates / api / validatecertificate ') ?>' ,
2026-03-04 23:34:45 +07:00
{ certid , certificateType },
function ( response ) {
if ( response . success ) {
$ ( '#validateModal' ) . modal ( 'hide' );
alert ( response . message );
2026-03-10 08:43:43 +07:00
location . reload ();
2026-03-04 23:34:45 +07:00
} else {
alert ( response . message || 'Validation failed' );
}
}, 'json'
2026-03-10 08:43:43 +07:00
) . fail ( function ( xhr ) {
console . log ( xhr );
alert ( xhr . responseText );
2026-03-04 23:34:45 +07:00
});
});
});
</ script >
< ? = $this -> endSection () ?>