forked from mahdahar/crm-summit
441 lines
18 KiB
PHP
441 lines
18 KiB
PHP
<?= $this->extend('layouts/main.php') ?>
|
|
|
|
<?= $this->section('content') ?>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="container-fluid">
|
|
<div class="row page-titles">
|
|
<div class="col-md-5 align-self-center">
|
|
<h4 class="text-themecolor">Certificates Training 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="statusFilter" class="form-select form-select-sm">
|
|
<option value="">All Status</option>
|
|
<option value="active">Active</option>
|
|
<option value="expired">Expired</option>
|
|
<option value="expiring">Expiring Soon</option>
|
|
<option value="isval">Need Validation</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4 mb-2">
|
|
<select id="typeFilter" class="form-select form-select-sm">
|
|
<option value="">All Types</option>
|
|
<option value="tms">TMS</option>
|
|
<option value="joko">Jokoh</option>
|
|
<option value="boeki">Tokyo Boeki</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>
|
|
|
|
<!-- TABLE -->
|
|
<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>
|
|
<th style="width:20%">Certificate Name</th>
|
|
<th style="width:20%">Product/Equipment</th>
|
|
<th style="width:20%">Activity Report</th>
|
|
<th style="width:10%">Issue Date</th>
|
|
<th style="width:10%">Expiry Date</th>
|
|
<th style="width:10%">Status</th>
|
|
<th class="text-center" style="width:10%">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Validate Modal -->
|
|
<div class="modal fade" id="validateModal" tabindex="-1" aria-labelledby="validateModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-warning text-dark">
|
|
<h5 class="modal-title" id="validateModalLabel">
|
|
<i class="fa-solid fa-check-double"></i> Validate Certificate
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
|
aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Certificate ID</label>
|
|
<p id="modalCertId" class="form-control-plaintext">-</p>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Certificate Name</label>
|
|
<p id="modalCertName" class="form-control-plaintext">-</p>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Product/Equipment</label>
|
|
<p id="modalProductName" class="form-control-plaintext">-</p>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Serial Number</label>
|
|
<p id="modalProductNumber" class="form-control-plaintext">-</p>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Issue Date</label>
|
|
<p id="modalIssueDate" class="form-control-plaintext">-</p>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Expiry Date</label>
|
|
<p id="modalExpiryDate" class="form-control-plaintext">-</p>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Vendor</label>
|
|
<p id="modalVendor" class="form-control-plaintext">-</p>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">Activity Report</label>
|
|
<p id="modalExpiryDate" class="form-control-plaintext">
|
|
<a href="javascript:void(0)" class="activity-report-link text-decoration-none" data-certid="${certid}" style="color:#d43215b0;">Act ID - Nama AR - Nama User <i class="fa-solid fa-up-right-from-square"></i></a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
<div class='row mb-3'>
|
|
<label class='form-label fw-bold'>User Analyst yang ditraining</label>
|
|
<div class='table-responsive'>
|
|
<table class='table table-bordered table-sm'>
|
|
<thead>
|
|
<tr>
|
|
<th style='width:10%'>No</th>
|
|
<th style='width:45%'>Nama</th>
|
|
<th style='width:45%'>Tanggal</th>
|
|
|
|
</tr>
|
|
</thead>
|
|
<tbody id='training-table'>
|
|
<tr>
|
|
<td>1</td>
|
|
<td>Ahmad Fauzi</td>
|
|
<td>2024-01-15</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2</td>
|
|
<td>Budi Santoso</td>
|
|
<td>2024-01-16</td>
|
|
</tr>
|
|
<tr>
|
|
<td>3</td>
|
|
<td>Citra Dewi</td>
|
|
<td>2024-01-17</td>
|
|
</tr>
|
|
<tr>
|
|
<td>4</td>
|
|
<td>Dian Pratama</td>
|
|
<td>2024-01-18</td>
|
|
</tr>
|
|
<tr>
|
|
<td>5</td>
|
|
<td>Eko Wijaya</td>
|
|
<td>2024-01-19</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="alert alert-warning">
|
|
<i class="fa-solid fa-info-circle"></i>
|
|
<strong>Validation Information:</strong> Please review the certificate details above before validating. Once validated, the certificate status will change from "Need Validation" to "Active".
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label fw-bold">Certificate Preview</label>
|
|
<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>
|
|
</div>
|
|
|
|
<?= $this->endSection() ?>
|
|
|
|
<?= $this->section('style') ?>
|
|
<style>
|
|
#certificatesTable {
|
|
width: 100% !important;
|
|
}
|
|
#certificatesTable_wrapper {
|
|
width: 100% !important;
|
|
}
|
|
</style>
|
|
<?= $this->endSection() ?>
|
|
|
|
<?= $this->section('script') ?>
|
|
<script>
|
|
$(function () {
|
|
|
|
let table = $('#certificatesTable').DataTable({
|
|
order: [[5, 'asc']],
|
|
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/getindextraining') ?>')
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
callback({
|
|
data: result.map(cert => {
|
|
let certid = cert.certid || '';
|
|
let certname = cert.certname || '-';
|
|
let productname = cert.productname || '-';
|
|
let productnumber = cert.productnumber || '';
|
|
let issuedateRaw = cert.issuedate || '';
|
|
let expirydateRaw = cert.expirydate || '';
|
|
let vendor = cert.vendor || '-';
|
|
let isval = cert.isval || null;
|
|
|
|
let issuedate = '-';
|
|
let expirydate = '-';
|
|
let statusBadge = '<span class="badge bg-warning text-dark">Need Validation</span>';
|
|
|
|
if (isval != null) {
|
|
if (issuedateRaw && issuedateRaw !== '0000-00-00') {
|
|
issuedate = new Date(issuedateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
|
}
|
|
|
|
if (expirydateRaw && expirydateRaw !== '0000-00-00') {
|
|
expirydate = new Date(expirydateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
|
let today = new Date();
|
|
let expiryDate = new Date(expirydateRaw);
|
|
let days = Math.ceil((expiryDate - today) / (1000 * 60 * 60 * 24));
|
|
|
|
if (days < 0) {
|
|
statusBadge = '<span class="badge bg-danger">Expired</span>';
|
|
} else if (days <= 30) {
|
|
statusBadge = '<span class="badge bg-info">Expiring Soon</span>';
|
|
} else {
|
|
statusBadge = '<span class="badge bg-success">Active</span>';
|
|
}
|
|
} else {
|
|
statusBadge = '<span class="badge bg-secondary">N/A</span>';
|
|
}
|
|
}
|
|
|
|
return [
|
|
`<strong>${certname}</strong><br><small class="text-muted">ID: ${certid}</small>`,
|
|
`${productname}${productnumber ? '<br><small class="text-muted">SN: ' + productnumber + '</small>' : ''}`,
|
|
`<a href="javascript:void(0)" class="activity-report-link text-decoration-none" data-certid="${certid}" style="color:#d43215b0;">Act ID - Nama AR - Nama User <i class="fa-solid fa-up-right-from-square"></i></a>`,
|
|
issuedate,
|
|
expirydate,
|
|
statusBadge,
|
|
isval == null
|
|
? `<div class="text-center"><button type="button" class="btn btn-warning text-dark btn-validate" data-certid="${certid}" data-certname="${certname}" data-productname="${productname}" data-productnumber="${productnumber}" data-issuedate="${issuedate}" data-expirydate="${expirydate}" data-vendor="${vendor}"><i class="fa-solid fa-check-double"></i></button></div>`
|
|
: `<div class="text-center"><button type="button" class="btn btn-success btn-view" data-certid="${certid}"><i class="fa-regular fa-file-pdf"></i></button></div>`
|
|
];
|
|
})
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching data:', error);
|
|
callback({ data: [] });
|
|
});
|
|
},
|
|
columnDefs: [{
|
|
targets: 5,
|
|
render: function (data, type) {
|
|
if (type === 'sort') {
|
|
if (data.includes('Need Validation')) return 1;
|
|
if (data.includes('Expired')) return 2;
|
|
if (data.includes('Expiring Soon')) return 3;
|
|
if (data.includes('Active')) return 4;
|
|
return 5;
|
|
}
|
|
return data;
|
|
}
|
|
}]
|
|
});
|
|
|
|
$('#certificatesTable_filter').hide();
|
|
|
|
// Search
|
|
$('#searchInput').on('keyup', function () {
|
|
table.search(this.value).draw();
|
|
});
|
|
|
|
// Type filter using DataTables column filter
|
|
$('#typeFilter').on('change', function () {
|
|
let type = $(this).val();
|
|
|
|
// Filter by type column (index 1 - Certificate Name contains type info)
|
|
if (type === '') {
|
|
table.column(1).search('').draw();
|
|
} else {
|
|
// Capitalize first letter for search
|
|
let typeText = type.charAt(0).toUpperCase() + type.slice(1);
|
|
table.column(1).search(typeText).draw();
|
|
}
|
|
});
|
|
|
|
// Status filter
|
|
$('#statusFilter').on('change', function () {
|
|
let map = {
|
|
active: 'Active',
|
|
expired: 'Expired',
|
|
expiring: 'Expiring Soon',
|
|
isval: 'Need Validation'
|
|
};
|
|
table.column(5).search(map[this.value] || '').draw();
|
|
});
|
|
|
|
// Reset
|
|
window.resetFilters = function () {
|
|
$('#searchInput, #statusFilter').val('');
|
|
table.search('').columns().search('').order([5,'asc']).draw();
|
|
};
|
|
|
|
// View PDF
|
|
$(document).on('click', '.btn-view', function () {
|
|
let certid = $(this).data('certid');
|
|
window.open('<?= base_url('certificates/training/show/') ?>' + certid, '_blank');
|
|
});
|
|
|
|
// Activity report
|
|
$(document).on('click', '.activity-report-link', function () {
|
|
let certid = $(this).data('certid');
|
|
window.open(
|
|
'<?= base_url('certificates/training/activity/') ?>' + certid,
|
|
'_blank',
|
|
'width=1200,height=800,scrollbars=yes,resizable=yes'
|
|
);
|
|
});
|
|
|
|
// Open modal
|
|
$(document).on('click', '.btn-validate', function () {
|
|
|
|
let btn = $(this);
|
|
|
|
$('#modalCertId').text(btn.data('certid'));
|
|
$('#modalCertName').text(btn.data('certname'));
|
|
$('#modalProductName').text(btn.data('productname'));
|
|
$('#modalProductNumber').text(btn.data('productnumber'));
|
|
$('#modalIssueDate').text(btn.data('issuedate'));
|
|
$('#modalExpiryDate').text(btn.data('expirydate'));
|
|
$('#modalVendor').text(btn.data('vendor'));
|
|
|
|
$('#confirmValidateBtn').data('certid', btn.data('certid'));
|
|
$('#certificatePreview').attr(
|
|
'src',
|
|
'<?= base_url('certificates/training/show/') ?>' + btn.data('certid')
|
|
);
|
|
|
|
$('#validateModal').modal('show');
|
|
});
|
|
|
|
// Confirm validate
|
|
$('#confirmValidateBtn').on('click', function () {
|
|
|
|
let certid = $(this).data('certid');
|
|
let certificateType = 'training';
|
|
if (!confirm('Are you sure?')) return;
|
|
|
|
$.post(
|
|
'<?= base_url('certificates/api/validateCertificate') ?>',
|
|
{ certid, certificateType},
|
|
function (response) {
|
|
|
|
if (response.success) {
|
|
$('#validateModal').modal('hide');
|
|
alert(response.message);
|
|
|
|
// Generate and save PDF after successful validation
|
|
$.post(
|
|
'<?= base_url('certificates/api/generatepdf') ?>',
|
|
{ certid, certificateType },
|
|
function (pdfResponse) {
|
|
if (pdfResponse.success) {
|
|
alert('PDF generated and saved successfully!');
|
|
location.reload();
|
|
} else {
|
|
alert('Validation successful but PDF generation failed: ' + (pdfResponse.message || 'Unknown error'));
|
|
location.reload();
|
|
}
|
|
},
|
|
'json'
|
|
).fail(function () {
|
|
alert('Validation successful but failed to generate PDF');
|
|
location.reload();
|
|
});
|
|
|
|
} else {
|
|
alert(response.message || 'Validation failed');
|
|
}
|
|
|
|
}, 'json'
|
|
).fail(function () {
|
|
$('#validateModal').modal('hide');
|
|
alert('Server error.');
|
|
});
|
|
|
|
});
|
|
|
|
// Delete training user
|
|
window.deleteTrainingUser = function(btn) {
|
|
if(confirm('Are you sure you want to delete this user?')) {
|
|
var row = btn.closest('tr');
|
|
row.remove();
|
|
updateRowNumbers();
|
|
}
|
|
};
|
|
|
|
// Update row numbers after deletion
|
|
function updateRowNumbers() {
|
|
var tbody = $('#training-table');
|
|
var rows = tbody.find('tr');
|
|
rows.each(function(index) {
|
|
$(this).find('td:first').text(index + 1);
|
|
});
|
|
}
|
|
|
|
});
|
|
</script>
|
|
<?= $this->endSection() ?>
|