Update Fix UI Certificate Maintenance Index
This commit is contained in:
parent
6250a1394c
commit
7a0b79e73e
@ -217,6 +217,13 @@ $routes->group('certificates', function($routes) {
|
|||||||
$routes->get('calibration', 'Certificates::calibrateIndex');
|
$routes->get('calibration', 'Certificates::calibrateIndex');
|
||||||
$routes->get('maintenance', 'Certificates::maintenanceIndex');
|
$routes->get('maintenance', 'Certificates::maintenanceIndex');
|
||||||
|
|
||||||
|
$routes->get('api/getindexmaintenance', 'Certificates::getDataIndexMaintenance');
|
||||||
|
$routes->get('api/getindextraining', 'Certificates::getDataIndexTraining');
|
||||||
|
|
||||||
|
|
||||||
|
$routes->post('validate', 'Certificates::validateCertificate');
|
||||||
|
|
||||||
|
|
||||||
// Untuk View Cerificate
|
// Untuk View Cerificate
|
||||||
$routes->get('training/show/(:any)', 'Certificates::createTraining/$1');
|
$routes->get('training/show/(:any)', 'Certificates::createTraining/$1');
|
||||||
$routes->get('calibration/show/(:any)/(:any)', 'Certificates::createCalibrate/$1/$2');
|
$routes->get('calibration/show/(:any)/(:any)', 'Certificates::createCalibrate/$1/$2');
|
||||||
|
|||||||
@ -193,8 +193,6 @@ class Activities extends Controller {
|
|||||||
$data['sql'] = $sql;
|
$data['sql'] = $sql;
|
||||||
$data['tampildata'] = $result;
|
$data['tampildata'] = $result;
|
||||||
|
|
||||||
// dd($sql);
|
|
||||||
|
|
||||||
return view('activities_index', $data);
|
return view('activities_index', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +364,7 @@ class Activities extends Controller {
|
|||||||
if( $this->request->getVar('siteid') != '' ) { $siteid = $this->request->getVar('siteid'); }
|
if( $this->request->getVar('siteid') != '' ) { $siteid = $this->request->getVar('siteid'); }
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'POST') {
|
if ($this->request->getMethod() === 'POST') {
|
||||||
|
// $allPostData = $this->request->getPost();
|
||||||
$rules = [
|
$rules = [
|
||||||
'subject' => 'required',
|
'subject' => 'required',
|
||||||
'siteid' => 'required',
|
'siteid' => 'required',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -174,8 +174,8 @@ if(isset($data)) {
|
|||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="type" class="form-label border-start border-5 border-primary ps-1">Activity Type</label>
|
<label for="acttypeid" class="form-label border-start border-5 border-primary ps-1">Activity Type</label>
|
||||||
<select name="acttypeid" id="type" class="form-select form-select-sm select2" required>
|
<select name="acttypeid" id="acttypeid" class="form-select form-select-sm select2" required>
|
||||||
<option value="" selected disabled>-- Choose one --</option>
|
<option value="" selected disabled>-- Choose one --</option>
|
||||||
<?php foreach($acttype as $data) {
|
<?php foreach($acttype as $data) {
|
||||||
$qacttypeid = $data['acttypeid'];
|
$qacttypeid = $data['acttypeid'];
|
||||||
@ -206,6 +206,55 @@ if(isset($data)) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label border-start border-5 border-primary ps-1">Certificate</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="calibration" id="calibration" value="1">
|
||||||
|
<label class="form-check-label" for="calibration">
|
||||||
|
Calibration
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="installation" id="installation" value="1">
|
||||||
|
<label class="form-check-label" for="installation">
|
||||||
|
Installation Certificate
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="maintenance" value="1" id="maintenance" >
|
||||||
|
<label class="form-check-label" for="maintenance">
|
||||||
|
Maintenance Certificate
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="offreport" value="1" id="offreport" >
|
||||||
|
<label class="form-check-label" for="offreport">
|
||||||
|
Berita Acara Instalasi
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="training" value="1" id="training" >
|
||||||
|
<label class="form-check-label" for="training">
|
||||||
|
User Training Certificate
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -244,6 +293,7 @@ if(isset($data)) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -315,6 +365,7 @@ if(isset($data)) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -694,6 +745,13 @@ $('#status').change(function() {
|
|||||||
else { $(".closedate").prop('disabled', false); $("#opendate").prop('disabled', false);}
|
else { $(".closedate").prop('disabled', false); $("#opendate").prop('disabled', false);}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$("#maintenance").prop('disabled', true); $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); $("#offreport").prop('disabled', true); $("#training").prop('disabled', true);
|
||||||
|
$('#acttypeid').change(function() {
|
||||||
|
if (this.value=='5'){ $("#maintenance").prop('disabled', false); $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); $("#offreport").prop('disabled', true); $("#training").prop('disabled', true);}
|
||||||
|
else if (this.value=='3'){ $("#maintenance").prop('disabled', true); $("#calibration").prop('disabled', false); $("#installation").prop('disabled', false); $("#offreport").prop('disabled', false); $("#training").prop('disabled', false); }
|
||||||
|
else { $("#maintenance").prop('disabled', true); $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); $("#offreport").prop('disabled', true); $("#training").prop('disabled', true);}
|
||||||
|
})
|
||||||
|
|
||||||
// reportdate change => opendate.value = reportdate.value
|
// reportdate change => opendate.value = reportdate.value
|
||||||
$('#reportdate').change(function() {
|
$('#reportdate').change(function() {
|
||||||
$('#opendate').val(this.value);
|
$('#opendate').val(this.value);
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
<option value="active">Active</option>
|
<option value="active">Active</option>
|
||||||
<option value="expired">Expired</option>
|
<option value="expired">Expired</option>
|
||||||
<option value="expiring">Expiring Soon</option>
|
<option value="expiring">Expiring Soon</option>
|
||||||
|
<option value="isval">Need Validation</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-2">
|
<div class="col-md-4 mb-2">
|
||||||
@ -45,105 +46,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="">
|
<!-- TABLE -->
|
||||||
<button type="button" class="btn btn-info text-white btn-sm" data-bs-toggle="modal"
|
<div class="table-responsive" style="width: 100%;">
|
||||||
data-bs-target="#createModal">
|
<table id="certificatesTable" class="table table-striped table-hover border" style="width: 100%;">
|
||||||
<i class="fas fa-plus-circle"></i> Create
|
<thead class="table-primary">
|
||||||
</button>
|
<tr>
|
||||||
</div>
|
<th style="width:20%">Certificate Name</th>
|
||||||
|
<th style="width:20%">Product/Equipment</th>
|
||||||
<div class="table-responsive">
|
<th style="width:20%">Activity Report</th>
|
||||||
<table id="certificatesTable" class="table table-striped table-hover border">
|
<th style="width:10%">Issue Date</th>
|
||||||
<thead class="table-primary">
|
<th style="width:10%">Expiry Date</th>
|
||||||
<tr>
|
<th style="width:10%">Status</th>
|
||||||
<th class="text-center" style="width: 5%;">No</th>
|
<th class="text-center" style="width:10%">Action</th>
|
||||||
<th style="width: 15%;">Certificate Name</th>
|
</tr>
|
||||||
<th style="width: 15%;">Product/Equipment</th>
|
</thead>
|
||||||
<th style="width: 12%;">Issue Date</th>
|
<tbody>
|
||||||
<th style="width: 12%;">Expiry Date</th>
|
</tbody>
|
||||||
<th style="width: 10%;">Status</th>
|
</table>
|
||||||
<th style="width: 10%;">Vendor</th>
|
|
||||||
<th class="text-center" style="width: 9%;">Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php
|
|
||||||
if(isset($certificates) && !empty($certificates)) {
|
|
||||||
$no = 1;
|
|
||||||
foreach($certificates as $cert) {
|
|
||||||
$certid = $cert['certid'] ?? '';
|
|
||||||
$certname = $cert['certname'] ?? '-';
|
|
||||||
$productname = $cert['productname'] ?? '-';
|
|
||||||
$productnumber = $cert['productnumber'] ?? '';
|
|
||||||
$type = $cert['type'] ?? '-';
|
|
||||||
$issuedate = $cert['issuedate'] ?? '';
|
|
||||||
$expirydate = $cert['expirydate'] ?? '';
|
|
||||||
$vendor = $cert['vendor'] ?? '-';
|
|
||||||
|
|
||||||
// Format dates
|
|
||||||
if($issuedate && $issuedate != '0000-00-00') {
|
|
||||||
$issuedate = date('M d, Y', strtotime($issuedate));
|
|
||||||
} else {
|
|
||||||
$issuedate = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
if($expirydate && $expirydate != '0000-00-00') {
|
|
||||||
$expirydate = date('M d, Y', strtotime($expirydate));
|
|
||||||
// Check expiry status
|
|
||||||
$today = date('Y-m-d');
|
|
||||||
$expiryCheck = date('Y-m-d', strtotime($cert['expirydate']));
|
|
||||||
$daysUntilExpiry = (strtotime($expiryCheck) - strtotime($today)) / (60 * 60 * 24);
|
|
||||||
|
|
||||||
if($daysUntilExpiry < 0) {
|
|
||||||
$statusBadge = '<span class="badge bg-danger">Expired</span>';
|
|
||||||
$statusClass = 'expired';
|
|
||||||
} elseif($daysUntilExpiry <= 30) {
|
|
||||||
$statusBadge = '<span class="badge bg-warning text-dark">Expiring Soon</span>';
|
|
||||||
$statusClass = 'expiring';
|
|
||||||
} else {
|
|
||||||
$statusBadge = '<span class="badge bg-success">Active</span>';
|
|
||||||
$statusClass = 'active';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$expirydate = '-';
|
|
||||||
$statusBadge = '<span class="badge bg-secondary">N/A</span>';
|
|
||||||
$statusClass = '';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center"><?= $no++; ?></td>
|
|
||||||
<td>
|
|
||||||
<strong><?= htmlspecialchars($certname) ?></strong>
|
|
||||||
<br>
|
|
||||||
<small class="text-muted">ID: <?= $certid ?></small>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?= htmlspecialchars($productname) ?>
|
|
||||||
<?php if($productnumber): ?>
|
|
||||||
<br><small class="text-muted">SN:
|
|
||||||
<?= htmlspecialchars($productnumber) ?></small>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td><?= $issuedate ?></td>
|
|
||||||
<td><?= $expirydate ?></td>
|
|
||||||
<td><?= $statusBadge ?></td>
|
|
||||||
<td><?= htmlspecialchars($vendor) ?></td>
|
|
||||||
<td class="text-center">
|
|
||||||
<div class="btn-group btn-group-sm">
|
|
||||||
<button type="button" class="btn btn-success btn-view"
|
|
||||||
data-certid="<?= $certid ?>" data-certtype="<?= $type ?>"
|
|
||||||
title="View PDF">
|
|
||||||
<i class="fas fa-file-pdf"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -152,210 +71,271 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Create Modal -->
|
<!-- Validate Modal -->
|
||||||
<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
|
<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-dialog modal-xl modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header bg-info text-white">
|
<div class="modal-header bg-warning text-dark">
|
||||||
<h5 class="modal-title" id="createModalLabel">
|
<h5 class="modal-title" id="validateModalLabel">
|
||||||
<i class="fas fa-plus-circle"></i> Create Certificate Maintenance
|
<i class="fa-solid fa-check-double"></i> Validate Certificate
|
||||||
</h5>
|
</h5>
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
aria-label="Close"></button>
|
aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form id="createForm" action="<?= base_url('certificates/create') ?>" method="post">
|
<div class="modal-body">
|
||||||
<div class="modal-body">
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
<div class="row">
|
<label class="form-label fw-bold">Certificate ID</label>
|
||||||
<div class="col-md-6 mb-3">
|
<p id="modalCertId" class="form-control-plaintext">-</p>
|
||||||
<label for="certname" class="form-label">Certificate Name <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<input type="text" class="form-control" id="certname" name="certname" required>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="certtype" class="form-label">Type Sertifikat</label>
|
|
||||||
<input type="text" class="form-control" id="certtype" name="certtype">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
<div class="row">
|
<label class="form-label fw-bold">Certificate Name</label>
|
||||||
<div class="col-md-6 mb-3">
|
<p id="modalCertName" class="form-control-plaintext">-</p>
|
||||||
<label for="issuedate" class="form-label">Start Date <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<input type="date" class="form-control" id="issuedate" name="issuedate">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="expirydate" class="form-label">Expiry Date <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<input type="date" class="form-control" id="expirydate" name="expirydate">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="type" class="form-label">Site <span class="text-danger">*</span></label>
|
|
||||||
<select class="form-select select2" id="type" name="type" required>
|
|
||||||
<option value=''>-- Choose one --</option>
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="productid" class="form-label">Product/Equipment <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<select class="form-select select2" id="productid" name="productid">
|
|
||||||
<option value=''>-- Choose one --</option>
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <div class="mb-3">
|
|
||||||
<label for="description" class="form-label">Description</label>
|
|
||||||
<textarea class="form-control" id="description" name="description" rows="2"></textarea>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="row">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
<div class="col-md-6 mb-3">
|
||||||
<i class="fas fa-times"></i> Cancel
|
<label class="form-label fw-bold">Product/Equipment</label>
|
||||||
</button>
|
<p id="modalProductName" class="form-control-plaintext">-</p>
|
||||||
<button type="submit" class="btn btn-info text-white">
|
</div>
|
||||||
<i class="fas fa-save"></i> Save
|
<div class="col-md-6 mb-3">
|
||||||
</button>
|
<label class="form-label fw-bold">Serial Number</label>
|
||||||
|
<p id="modalProductNumber" class="form-control-plaintext">-</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<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-12 mb-3">
|
||||||
|
<label class="form-label fw-bold">Vendor</label>
|
||||||
|
<p id="modalVendor" class="form-control-plaintext">-</p>
|
||||||
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
|
|
||||||
|
<?= $this->section('style') ?>
|
||||||
|
<style>
|
||||||
|
#certificatesTable {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
#certificatesTable_wrapper {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<?= $this->endSection() ?>
|
||||||
|
|
||||||
<?= $this->section('script') ?>
|
<?= $this->section('script') ?>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
// Store DataTable instance
|
|
||||||
let table = null;
|
|
||||||
|
|
||||||
// Initialize DataTable
|
let table = $('#certificatesTable').DataTable({
|
||||||
table = $('#certificatesTable').DataTable({
|
order: [[5, 'asc']],
|
||||||
"order": [
|
pageLength: 25,
|
||||||
[0, "asc"]
|
dom: '<"row"<"col-md-6"l>>rtip',
|
||||||
],
|
responsive: true,
|
||||||
"pageLength": 25,
|
serverSide: false,
|
||||||
"lengthMenu": [
|
autoWidth: false,
|
||||||
[10, 25, 50, 100, -1],
|
ajax: function (data, callback, settings) {
|
||||||
[10, 25, 50, 100, "All"]
|
fetch('<?= base_url('certificates/api/getindexmaintenance') ?>')
|
||||||
],
|
.then(response => response.json())
|
||||||
"language": {
|
.then(result => {
|
||||||
"emptyTable": "No certificates available",
|
callback({
|
||||||
"info": "Showing _START_ to _END_ of _TOTAL_ certificates",
|
data: result.map(cert => {
|
||||||
"infoEmpty": "No certificates found",
|
let certid = cert.certid || '';
|
||||||
"infoFiltered": "(filtered from _MAX_ total certificates)"
|
let certname = cert.certname || '-';
|
||||||
},
|
let productname = cert.productname || '-';
|
||||||
"dom": '<"row"<"col-md-6"l>>rtip',
|
let productnumber = cert.productnumber || '';
|
||||||
"columnDefs": [{
|
let issuedateRaw = cert.issuedate || '';
|
||||||
"orderable": false,
|
let expirydateRaw = cert.expirydate || '';
|
||||||
"targets": [7]
|
let vendor = cert.vendor || '-';
|
||||||
}, // Disable sorting on Action column
|
let isval = cert.isval || null;
|
||||||
{
|
|
||||||
"searchable": true,
|
|
||||||
"targets": [0, 1, 2, 3, 4, 5, 6]
|
|
||||||
} // Enable search on all columns except Action
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hide default DataTables search
|
let issuedate = '-';
|
||||||
$('#certificatesTable_filter').hide();
|
let expirydate = '-';
|
||||||
|
let statusBadge = '<span class="badge bg-warning text-dark">Need Validation</span>';
|
||||||
|
|
||||||
// Initialize Select2
|
if (isval != null) {
|
||||||
$('.select2').select2({
|
if (issuedateRaw && issuedateRaw !== '0000-00-00') {
|
||||||
theme: 'bootstrap-5',
|
issuedate = new Date(issuedateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
||||||
width: '100%',
|
}
|
||||||
dropdownParent: $('.modal')
|
|
||||||
});
|
|
||||||
|
|
||||||
// Custom search functionality
|
if (expirydateRaw && expirydateRaw !== '0000-00-00') {
|
||||||
$('#searchInput').on('keyup', function () {
|
expirydate = new Date(expirydateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
||||||
let searchValue = $(this).val().toLowerCase();
|
let today = new Date();
|
||||||
table.search(searchValue).draw();
|
let expiryDate = new Date(expirydateRaw);
|
||||||
});
|
let days = Math.ceil((expiryDate - today) / (1000 * 60 * 60 * 24));
|
||||||
|
|
||||||
// Status filter using DataTables column filter
|
if (days < 0) {
|
||||||
$('#statusFilter').on('change', function () {
|
statusBadge = '<span class="badge bg-danger">Expired</span>';
|
||||||
let status = $(this).val();
|
} 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>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Filter by status column (index 6)
|
return [
|
||||||
if (status === '') {
|
`<strong>${certname}</strong><br><small class="text-muted">ID: ${certid}</small>`,
|
||||||
table.column(6).search('').draw();
|
`${productname}${productnumber ? '<br><small class="text-muted">SN: ' + productnumber + '</small>' : ''}`,
|
||||||
} else {
|
`<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>`,
|
||||||
// Search for the badge text in status column
|
issuedate,
|
||||||
let statusText = '';
|
expirydate,
|
||||||
switch (status) {
|
statusBadge,
|
||||||
case 'active':
|
isval == null
|
||||||
statusText = 'Active';
|
? `<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>`
|
||||||
break;
|
: `<button type="button" class="btn btn-success btn-view" data-certid="${certid}"><i class="fa-regular fa-file-pdf"></i></button>`
|
||||||
case 'expired':
|
];
|
||||||
statusText = 'Expired';
|
})
|
||||||
break;
|
});
|
||||||
case 'expiring':
|
})
|
||||||
statusText = 'Expiring Soon';
|
.catch(error => {
|
||||||
break;
|
console.error('Error fetching data:', error);
|
||||||
}
|
callback({ data: [] });
|
||||||
table.column(6).search(statusText).draw();
|
});
|
||||||
}
|
},
|
||||||
});
|
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;
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
// Type filter using DataTables column filter
|
$('#certificatesTable_filter').hide();
|
||||||
$('#typeFilter').on('change', function () {
|
|
||||||
let type = $(this).val();
|
|
||||||
|
|
||||||
// Filter by type column (index 3)
|
// Search
|
||||||
if (type === '') {
|
$('#searchInput').on('keyup', function () {
|
||||||
table.column(2).search('').draw();
|
table.search(this.value).draw();
|
||||||
} else {
|
});
|
||||||
// Capitalize first letter for search
|
|
||||||
let typeText = type.charAt(0).toUpperCase() + type.slice(1);
|
|
||||||
table.column(2).search(typeText).draw();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Reset filters
|
// Status filter
|
||||||
window.resetFilters = function () {
|
$('#statusFilter').on('change', function () {
|
||||||
$('#searchInput').val('');
|
let map = {
|
||||||
$('#statusFilter').val('');
|
active: 'Active',
|
||||||
$('#typeFilter').val('');
|
expired: 'Expired',
|
||||||
|
expiring: 'Expiring Soon',
|
||||||
|
isval: 'Need Validation'
|
||||||
|
};
|
||||||
|
table.column(5).search(map[this.value] || '').draw();
|
||||||
|
});
|
||||||
|
|
||||||
// Reset DataTables search and filters
|
// Reset
|
||||||
table.search('').columns().search('').draw();
|
window.resetFilters = function () {
|
||||||
|
$('#searchInput, #statusFilter').val('');
|
||||||
|
table.search('').columns().search('').order([5,'asc']).draw();
|
||||||
|
};
|
||||||
|
|
||||||
// Re-apply default ordering
|
// View PDF
|
||||||
table.order([5, 'asc']).draw();
|
$(document).on('click', '.btn-view', function () {
|
||||||
};
|
let certid = $(this).data('certid');
|
||||||
|
window.open('<?= base_url('certificates/maintenance/show/') ?>' + certid, '_blank');
|
||||||
|
});
|
||||||
|
|
||||||
// View button click - Open PDF in new tab based on certificate type
|
// Activity report
|
||||||
$(document).on('click', '.btn-view', function () {
|
$(document).on('click', '.activity-report-link', function () {
|
||||||
let certid = $(this).data('certid');
|
let certid = $(this).data('certid');
|
||||||
let certType = $(this).data('certtype');
|
window.open(
|
||||||
let url = '<?= base_url('certificates/maintenance/show/') ?>' + certid;
|
'<?= base_url('certificates/maintenance/activity/') ?>' + certid,
|
||||||
window.open(url, '_blank');
|
'_blank',
|
||||||
});
|
'width=1200,height=800,scrollbars=yes,resizable=yes'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Print button
|
// Open modal
|
||||||
$('#btnPrint').on('click', function () {
|
$(document).on('click', '.btn-validate', function () {
|
||||||
window.print();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Date picker enhancement
|
let btn = $(this);
|
||||||
$('input[type="date"]').on('focus', function () {
|
|
||||||
this.showPicker();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Re-attach event handlers after DataTables pagination/draw
|
$('#modalCertId').text(btn.data('certid'));
|
||||||
table.on('draw.dt', function () {
|
$('#modalCertName').text(btn.data('certname'));
|
||||||
// Event handlers are already attached using $(document).on(), so no need to re-attach
|
$('#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/maintenance/show/') ?>' + btn.data('certid')
|
||||||
|
);
|
||||||
|
|
||||||
|
$('#validateModal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm validate
|
||||||
|
$('#confirmValidateBtn').on('click', function () {
|
||||||
|
|
||||||
|
let certid = $(this).data('certid');
|
||||||
|
let certificateType = 'maintenance';
|
||||||
|
if (!confirm('Are you sure?')) return;
|
||||||
|
|
||||||
|
$.post(
|
||||||
|
'<?= base_url('certificates/validate') ?>',
|
||||||
|
{ certid, certificateType},
|
||||||
|
function (response) {
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
$('#validateModal').modal('hide');
|
||||||
|
alert('Certificate maintenance validated successfully');
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert(response.message || 'Validation failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 'json'
|
||||||
|
).fail(function () {
|
||||||
|
$('#validateModal').modal('hide');
|
||||||
|
alert('Server error.');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
<?= $this->extend('layouts/main.php') ?>
|
<?= $this->extend('layouts/main.php') ?>
|
||||||
|
|
||||||
<?= $this->section('content') ?>
|
<?= $this->section('content') ?>
|
||||||
@ -5,9 +6,16 @@
|
|||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row page-titles">
|
<div class="row page-titles">
|
||||||
<div class="col-md-5 align-self-center">
|
<div class="col-md-6 align-self-center">
|
||||||
<h4 class="text-themecolor">Certificates Training Management</h4>
|
<h4 class="text-themecolor">Certificates Training Management</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 align-self-center text-end">
|
||||||
|
<button type="button" class="btn btn-info text-white btn-sm" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#createModal">
|
||||||
|
<i class="fas fa-plus-circle"></i> Create
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -22,15 +30,7 @@
|
|||||||
placeholder="Search certificates by name, product, type, vendor, or dates...">
|
placeholder="Search certificates by name, product, type, vendor, or dates...">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-2">
|
<div class="col-md-6 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>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 mb-2">
|
|
||||||
<select id="typeFilter" class="form-select form-select-sm">
|
<select id="typeFilter" class="form-select form-select-sm">
|
||||||
<option value="">All Types</option>
|
<option value="">All Types</option>
|
||||||
<option value="tms">TMS</option>
|
<option value="tms">TMS</option>
|
||||||
@ -38,110 +38,27 @@
|
|||||||
<option value="boeki">Tokyo Boeki</option>
|
<option value="boeki">Tokyo Boeki</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-2">
|
<div class="col-md-6 mb-2">
|
||||||
<button onclick="resetFilters()" class="btn btn-secondary btn-sm w-100">
|
<button onclick="resetFilters()" class="btn btn-secondary btn-sm w-100">
|
||||||
<i class="fas fa-redo"></i> Reset Filters
|
<i class="fas fa-redo"></i> Reset Filters
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<button type="button" class="btn btn-info text-white btn-sm" data-bs-toggle="modal"
|
|
||||||
data-bs-target="#createModal">
|
|
||||||
<i class="fas fa-plus-circle"></i> Create
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="certificatesTable" class="table table-striped table-hover border">
|
<table id="certificatesTable" class="table table-striped table-hover border">
|
||||||
<thead class="table-primary">
|
<thead class="table-primary">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center" style="width: 5%;">No</th>
|
<th class="text-center" style="width: 5%;">No</th>
|
||||||
<th style="width: 15%;">Certificate Name</th>
|
<th style="width: 37%;">Certificate Name</th>
|
||||||
<th style="width: 15%;">Product/Equipment</th>
|
<th style="width: 15%;">Product/Equipment</th>
|
||||||
<th style="width: 12%;">Issue Date</th>
|
<th style="width: 12%;">Issue Date</th>
|
||||||
<th style="width: 12%;">Expiry Date</th>
|
|
||||||
<th style="width: 10%;">Status</th>
|
|
||||||
<th style="width: 10%;">Vendor</th>
|
<th style="width: 10%;">Vendor</th>
|
||||||
<th class="text-center" style="width: 9%;">Action</th>
|
<th class="text-center" style="width: 9%;">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<!-- Saya Ingin Ini Pakai JSON -->
|
||||||
if(isset($certificates) && !empty($certificates)) {
|
|
||||||
$no = 1;
|
|
||||||
foreach($certificates as $cert) {
|
|
||||||
$certid = $cert['certid'] ?? '';
|
|
||||||
$certname = $cert['certname'] ?? '-';
|
|
||||||
$productname = $cert['productname'] ?? '-';
|
|
||||||
$productnumber = $cert['productnumber'] ?? '';
|
|
||||||
$type = $cert['type'] ?? '-';
|
|
||||||
$issuedate = $cert['issuedate'] ?? '';
|
|
||||||
$expirydate = $cert['expirydate'] ?? '';
|
|
||||||
$vendor = $cert['vendor'] ?? '-';
|
|
||||||
|
|
||||||
// Format dates
|
|
||||||
if($issuedate && $issuedate != '0000-00-00') {
|
|
||||||
$issuedate = date('M d, Y', strtotime($issuedate));
|
|
||||||
} else {
|
|
||||||
$issuedate = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
if($expirydate && $expirydate != '0000-00-00') {
|
|
||||||
$expirydate = date('M d, Y', strtotime($expirydate));
|
|
||||||
// Check expiry status
|
|
||||||
$today = date('Y-m-d');
|
|
||||||
$expiryCheck = date('Y-m-d', strtotime($cert['expirydate']));
|
|
||||||
$daysUntilExpiry = (strtotime($expiryCheck) - strtotime($today)) / (60 * 60 * 24);
|
|
||||||
|
|
||||||
if($daysUntilExpiry < 0) {
|
|
||||||
$statusBadge = '<span class="badge bg-danger">Expired</span>';
|
|
||||||
$statusClass = 'expired';
|
|
||||||
} elseif($daysUntilExpiry <= 30) {
|
|
||||||
$statusBadge = '<span class="badge bg-warning text-dark">Expiring Soon</span>';
|
|
||||||
$statusClass = 'expiring';
|
|
||||||
} else {
|
|
||||||
$statusBadge = '<span class="badge bg-success">Active</span>';
|
|
||||||
$statusClass = 'active';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$expirydate = '-';
|
|
||||||
$statusBadge = '<span class="badge bg-secondary">N/A</span>';
|
|
||||||
$statusClass = '';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center"><?= $no++; ?></td>
|
|
||||||
<td>
|
|
||||||
<strong><?= htmlspecialchars($certname) ?></strong>
|
|
||||||
<br>
|
|
||||||
<small class="text-muted">ID: <?= $certid ?></small>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?= htmlspecialchars($productname) ?>
|
|
||||||
<?php if($productnumber): ?>
|
|
||||||
<br><small class="text-muted">SN:
|
|
||||||
<?= htmlspecialchars($productnumber) ?></small>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td><?= $issuedate ?></td>
|
|
||||||
<td><?= $expirydate ?></td>
|
|
||||||
<td><?= $statusBadge ?></td>
|
|
||||||
<td><?= htmlspecialchars($vendor) ?></td>
|
|
||||||
<td class="text-center">
|
|
||||||
<div class="btn-group btn-group-sm">
|
|
||||||
<button type="button" class="btn btn-success btn-view"
|
|
||||||
data-certid="<?= $certid ?>" data-certtype="<?= $type ?>"
|
|
||||||
title="View PDF">
|
|
||||||
<i class="fas fa-file-pdf"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -166,6 +83,27 @@
|
|||||||
<form id="createForm" action="<?= base_url('certificates/create') ?>" method="post">
|
<form id="createForm" action="<?= base_url('certificates/create') ?>" method="post">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 mb-3">
|
||||||
|
<label for="type" class="form-label">Activity Report <span class="text-danger">*</span></label>
|
||||||
|
<select class="form-select select2" id="type" name="type" required>
|
||||||
|
<option value=''>-- Choose one --</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="site" class="form-label">Site<span
|
||||||
|
class="text-danger">*</span></label>
|
||||||
|
<input type="text" class="form-control" id="site" name="site" required readonly>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="productid" class="form-label">Product/Equipment<span
|
||||||
|
class="text-danger">*</span></label>
|
||||||
|
<input type="text" class="form-control" id="productid" name="productid" required readonly>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="certname" class="form-label">Certificate Name <span
|
<label for="certname" class="form-label">Certificate Name <span
|
||||||
@ -173,41 +111,22 @@
|
|||||||
<input type="text" class="form-control" id="certname" name="certname" required>
|
<input type="text" class="form-control" id="certname" name="certname" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="certtype" class="form-label">Type Sertifikat</label>
|
<label for="mainTrainingDate" class="form-label">Training Date<span
|
||||||
<input type="text" class="form-control" id="certtype" name="certtype">
|
class="text-danger">*</span></label>
|
||||||
|
<input type="date" class="form-control" id="mainTrainingDate" name="trainingdate">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<hr>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="row mb-3">
|
||||||
<label for="issuedate" class="form-label">Start Date <span
|
<div class="col-12">
|
||||||
class="text-danger">*</span></label>
|
<button type="button" class="btn btn-sm btn-success" onclick="addAnalystRow()">
|
||||||
<input type="date" class="form-control" id="issuedate" name="issuedate">
|
<i class="fas fa-plus-circle"></i> Add Analyst
|
||||||
</div>
|
</button>
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="expirydate" class="form-label">Expiry Date <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<input type="date" class="form-control" id="expirydate" name="expirydate">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="analystRowsContainer">
|
||||||
<div class="row">
|
<!-- Dynamic analyst rows will be added here -->
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="type" class="form-label">Site <span class="text-danger">*</span></label>
|
|
||||||
<select class="form-select select2" id="type" name="type" required>
|
|
||||||
<option value=''>-- Choose one --</option>
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="productid" class="form-label">Product/Equipment <span
|
|
||||||
class="text-danger">*</span></label>
|
|
||||||
<select class="form-select select2" id="productid" name="productid">
|
|
||||||
<option value=''>-- Choose one --</option>
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="mb-3">
|
<!-- <div class="mb-3">
|
||||||
@ -255,11 +174,11 @@
|
|||||||
"dom": '<"row"<"col-md-6"l>>rtip',
|
"dom": '<"row"<"col-md-6"l>>rtip',
|
||||||
"columnDefs": [{
|
"columnDefs": [{
|
||||||
"orderable": false,
|
"orderable": false,
|
||||||
"targets": [7]
|
"targets": [5]
|
||||||
}, // Disable sorting on Action column
|
}, // Disable sorting on Action column
|
||||||
{
|
{
|
||||||
"searchable": true,
|
"searchable": true,
|
||||||
"targets": [0, 1, 2, 3, 4, 5, 6]
|
"targets": [0, 1, 2, 3, 4]
|
||||||
} // Enable search on all columns except Action
|
} // Enable search on all columns except Action
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -274,48 +193,152 @@
|
|||||||
dropdownParent: $('.modal')
|
dropdownParent: $('.modal')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fetch data from API and populate table
|
||||||
|
async function fetchCertificateData() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('<?= base_url('certificates/api/getindextraining') ?>');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data && Array.isArray(data)) {
|
||||||
|
populateTable(data);
|
||||||
|
} else {
|
||||||
|
console.log('No data available or invalid response format');
|
||||||
|
table.clear().draw();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching certificate data:', error);
|
||||||
|
table.clear().draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate DataTable with fetched data
|
||||||
|
function populateTable(certificates) {
|
||||||
|
table.clear();
|
||||||
|
|
||||||
|
certificates.forEach((cert, index) => {
|
||||||
|
const certid = cert.certid || '';
|
||||||
|
const certname = cert.certname || '-';
|
||||||
|
const productname = cert.productname || '-';
|
||||||
|
const productnumber = cert.productnumber || '';
|
||||||
|
const issuedate = cert.issuedate || '-';
|
||||||
|
const vendor = cert.vendor || '-';
|
||||||
|
const type = cert.type || '-';
|
||||||
|
|
||||||
|
// Format issue date
|
||||||
|
let formattedDate = '-';
|
||||||
|
if (issuedate && issuedate !== '0000-00-00') {
|
||||||
|
const dateObj = new Date(issuedate);
|
||||||
|
if (!isNaN(dateObj.getTime())) {
|
||||||
|
formattedDate = dateObj.toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowData = [
|
||||||
|
index + 1,
|
||||||
|
`<strong>${escapeHtml(certname)}</strong><br><small class="text-muted">ID: ${escapeHtml(certid)}</small>`,
|
||||||
|
`${escapeHtml(productname)}${productnumber ? `<br><small class="text-muted">SN: ${escapeHtml(productnumber)}</small>` : ''}`,
|
||||||
|
formattedDate,
|
||||||
|
escapeHtml(vendor),
|
||||||
|
`<div class="btn-group btn-group-sm"><button type="button" class="btn btn-success btn-view" data-certid="${escapeHtml(certid)}" data-certtype="${escapeHtml(type)}" title="View PDF"><i class="fas fa-file-pdf"></i></button></div>`
|
||||||
|
];
|
||||||
|
|
||||||
|
table.row.add(rowData);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to escape HTML
|
||||||
|
function escapeHtml(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch data on page load
|
||||||
|
fetchCertificateData();
|
||||||
|
|
||||||
|
// Handle Activity Report dropdown change
|
||||||
|
$('#type').on('change', function() {
|
||||||
|
const certid = $(this).val();
|
||||||
|
|
||||||
|
if (!certid) {
|
||||||
|
$('#site').val('');
|
||||||
|
$('#productid').val('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch certificate data from API
|
||||||
|
$.ajax({
|
||||||
|
url: '<?= base_url('certificates/api/getindextraining') ?>',
|
||||||
|
method: 'GET',
|
||||||
|
data: { actid: certid },
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
if (response) {
|
||||||
|
$('#site').val(response.sitename || '');
|
||||||
|
$('#productid').val(response.productname || '');
|
||||||
|
} else {
|
||||||
|
$('#site').val('');
|
||||||
|
$('#productid').val('');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('Error fetching certificate data:', error);
|
||||||
|
$('#site').val('');
|
||||||
|
$('#productid').val('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add one default analyst row when modal opens
|
||||||
|
$('#createModal').on('shown.bs.modal', function() {
|
||||||
|
if($('#analystRowsContainer .analyst-row').length === 0) {
|
||||||
|
addAnalystRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate Activity Report dropdown
|
||||||
|
populateActivityDropdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate Activity Report dropdown from API
|
||||||
|
async function populateActivityDropdown() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('<?= base_url('certificates/api/getindextraining') ?>');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
const dropdown = $('#type');
|
||||||
|
dropdown.empty();
|
||||||
|
dropdown.append('<option value="">-- Choose one --</option>');
|
||||||
|
|
||||||
|
if (data && Array.isArray(data)) {
|
||||||
|
data.forEach(item => {
|
||||||
|
dropdown.append(`<option value="${escapeHtml(item.certid)}">${escapeHtml(item.certname)}</option>`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching activity data:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Custom search functionality
|
// Custom search functionality
|
||||||
$('#searchInput').on('keyup', function () {
|
$('#searchInput').on('keyup', function () {
|
||||||
let searchValue = $(this).val().toLowerCase();
|
let searchValue = $(this).val().toLowerCase();
|
||||||
table.search(searchValue).draw();
|
table.search(searchValue).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status filter using DataTables column filter
|
|
||||||
$('#statusFilter').on('change', function () {
|
|
||||||
let status = $(this).val();
|
|
||||||
|
|
||||||
// Filter by status column (index 6)
|
|
||||||
if (status === '') {
|
|
||||||
table.column(6).search('').draw();
|
|
||||||
} else {
|
|
||||||
// Search for the badge text in status column
|
|
||||||
let statusText = '';
|
|
||||||
switch (status) {
|
|
||||||
case 'active':
|
|
||||||
statusText = 'Active';
|
|
||||||
break;
|
|
||||||
case 'expired':
|
|
||||||
statusText = 'Expired';
|
|
||||||
break;
|
|
||||||
case 'expiring':
|
|
||||||
statusText = 'Expiring Soon';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
table.column(6).search(statusText).draw();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Type filter using DataTables column filter
|
// Type filter using DataTables column filter
|
||||||
$('#typeFilter').on('change', function () {
|
$('#typeFilter').on('change', function () {
|
||||||
let type = $(this).val();
|
let type = $(this).val();
|
||||||
|
|
||||||
// Filter by type column (index 3)
|
// Filter by type column (index 1 - Certificate Name contains type info)
|
||||||
if (type === '') {
|
if (type === '') {
|
||||||
table.column(2).search('').draw();
|
table.column(1).search('').draw();
|
||||||
} else {
|
} else {
|
||||||
// Capitalize first letter for search
|
// Capitalize first letter for search
|
||||||
let typeText = type.charAt(0).toUpperCase() + type.slice(1);
|
let typeText = type.charAt(0).toUpperCase() + type.slice(1);
|
||||||
table.column(2).search(typeText).draw();
|
table.column(1).search(typeText).draw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -323,20 +346,18 @@
|
|||||||
// Reset filters
|
// Reset filters
|
||||||
window.resetFilters = function () {
|
window.resetFilters = function () {
|
||||||
$('#searchInput').val('');
|
$('#searchInput').val('');
|
||||||
$('#statusFilter').val('');
|
|
||||||
$('#typeFilter').val('');
|
$('#typeFilter').val('');
|
||||||
|
|
||||||
// Reset DataTables search and filters
|
// Reset DataTables search and filters
|
||||||
table.search('').columns().search('').draw();
|
table.search('').columns().search('').draw();
|
||||||
|
|
||||||
// Re-apply default ordering
|
// Re-apply default ordering
|
||||||
table.order([5, 'asc']).draw();
|
table.order([0, 'asc']).draw();
|
||||||
};
|
};
|
||||||
|
|
||||||
// View button click - Open PDF in new tab based on certificate type
|
// View button click - Open PDF in new tab based on certificate type
|
||||||
$(document).on('click', '.btn-view', function () {
|
$(document).on('click', '.btn-view', function () {
|
||||||
let certid = $(this).data('certid');
|
let certid = $(this).data('certid');
|
||||||
let certType = $(this).data('certtype');
|
|
||||||
let url = '<?= base_url('certificates/training/show/') ?>' + certid;
|
let url = '<?= base_url('certificates/training/show/') ?>' + certid;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
});
|
});
|
||||||
@ -351,6 +372,58 @@
|
|||||||
this.showPicker();
|
this.showPicker();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Re-attach date picker focus for dynamically added elements
|
||||||
|
$(document).on('focus', '.analyst-training-date', function() {
|
||||||
|
this.showPicker();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add analyst row
|
||||||
|
window.addAnalystRow = function() {
|
||||||
|
let rowCount = $('#analystRowsContainer .analyst-row').length;
|
||||||
|
let defaultTrainingDate = $('#mainTrainingDate').val();
|
||||||
|
|
||||||
|
let newRow = `
|
||||||
|
<div class="row analyst-row mb-2" data-row-index="${rowCount}">
|
||||||
|
<div class="col-md-6 mb-2">
|
||||||
|
<label class="form-label">Analyst Name <span class="text-danger">*</span></label>
|
||||||
|
<input type="text" class="form-control analyst-name" name="analyst_name[]" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-5 mb-2">
|
||||||
|
<label class="form-label">Training Date <span class="text-danger">*</span></label>
|
||||||
|
<input type="date" class="form-control analyst-training-date" name="analyst_training_date[]" value="${defaultTrainingDate}" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1 mb-2">
|
||||||
|
<label class="form-label"> </label>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm w-100" onclick="removeAnalystRow(this)">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
$('#analystRowsContainer').append(newRow);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove analyst row
|
||||||
|
window.removeAnalystRow = function(btn) {
|
||||||
|
let totalRows = $('#analystRowsContainer .analyst-row').length;
|
||||||
|
|
||||||
|
if(totalRows <= 1) {
|
||||||
|
alert('At least one analyst is required. Cannot delete the last row.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(confirm('Are you sure you want to remove this analyst?')) {
|
||||||
|
$(btn).closest('.analyst-row').remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// When main training date changes, update all analyst training dates
|
||||||
|
$('#mainTrainingDate').on('change', function() {
|
||||||
|
let newDate = $(this).val();
|
||||||
|
$('.analyst-training-date').val(newDate);
|
||||||
|
});
|
||||||
|
|
||||||
// Re-attach event handlers after DataTables pagination/draw
|
// Re-attach event handlers after DataTables pagination/draw
|
||||||
table.on('draw.dt', function () {
|
table.on('draw.dt', function () {
|
||||||
// Event handlers are already attached using $(document).on(), so no need to re-attach
|
// Event handlers are already attached using $(document).on(), so no need to re-attach
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user