nhance/app/Views/UserList.php
2026-04-20 10:45:11 +05:30

2230 lines
96 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- <style>
body {
.multiselect-native-select {
position: relative;
/* bottom: 32px; */
select {
border: 0 !important;
clip: rect(0 0 0 0) !important;
height: 1px !important;
margin: -1px -1px -1px -3px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
left: 50%;
top: 30px;
}
}
.multiselect-container{
width: 100% !important;
}
.multiselect-selected-text{
float: left !important;
}
}
.table th,
.table td {
padding: 8px;
}
table.dataTable tbody td {
padding: 4px 4px !important;
}
</style> -->
<style>
/* body {
font-family: Arial, sans-serif;
padding: 20px;
} */
#mobile::placeholder,
#mobile_no::placeholder {
font-size: 13px;
}
.custom-select{
border-radius: 10px !important ;
background-color: #ECECEC !important ;
box-shadow: 0px 2px 4px 0px #00000024 !important;
}
.multiselect-native-select {
position: relative;
}
.multiselect-native-select select {
border: 0 !important;
clip: rect(0 0 0 0) !important;
height: 1px !important;
margin: -1px -1px -1px -3px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
left: 50%;
top: 30px;
}
.multiselect-container {
width: 100% !important;
}
.multiselect-selected-text {
float: left !important;
}
.col-12 {
max-width: 98% !important;
}
/* Tooltip Styles */
.tooltip-trigger {
color: #007bff;
cursor: pointer;
font-size: 16px;
display: inline-block;
}
.tooltip-trigger:hover {
color: #0056b3;
}
.tooltip-container {
position: fixed;
top: 0;
left: 0;
pointer-events: none;
z-index: 9999;
}
.tooltip {
visibility: hidden;
opacity: 0;
position: absolute;
background-color: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 15px;
transition: opacity 0.3s, visibility 0.3s;
max-width: 600px;
min-width: 500px;
max-height: 600px; /* Limits height */
overflow-y: auto; /* Enables scrolling */
pointer-events: auto;
}
/* Optional: Custom scrollbar styling */
.tooltip::-webkit-scrollbar {
width: 8px;
}
.tooltip::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.tooltip::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
}
.tooltip::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* .tooltip {
visibility: hidden;
opacity: 0;
position: absolute;
background-color: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 15px;
transition: opacity 0.3s, visibility 0.3s;
max-width: 600px;
min-width: 500px;
pointer-events: auto;
} */
.tooltip::after {
content: "";
position: absolute;
border-width: 5px;
border-style: solid;
}
.tooltip.show {
visibility: visible;
opacity: 1;
}
.tooltip-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
margin: 0;
}
.tooltip-table th {
background-color: #f8f9fa;
font-weight: bold;
padding: 8px;
border: 1px solid #dee2e6;
text-align: left;
font-size: 11px;
}
.tooltip-table td {
padding: 6px 8px;
border: 1px solid #dee2e6;
vertical-align: top;
font-size: 11px;
line-height: 1.3;
}
.tooltip-table tbody tr:nth-child(even) {
background-color: #f8f9fa;
}
.tooltip-table tbody tr:hover {
background-color: #e3f2fd;
}
.team-cell {
font-weight: bold;
background-color: #e7f3ff !important;
}
/* Form styling for demo */
.form-group {
margin-bottom: 1rem;
}
.form-control {
display: block;
width: 100%;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.25rem;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
font-weight: 600;
}
.text-danger {
color: #dc3545;
}
.btn-color{
background-color: rgba(52, 174, 178, 1);
color: white;
border:1px solid rgba(52, 174, 178, 1);
}
.btn-color:hover{
background-color: rgba(41, 139, 142, 1);
color: white;
border:1px solid rgba(41, 139, 142, 1);
}
.dt-buttons.btn-group{
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
#user-table_filter input{ width:100%; }
button.dt-button,
button.dt-button:focus,
button.dt-button:active,
button.dt-button:hover {
background: none !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
/* main button wrapper */
.tab-button {
width: 201px;
height: 37px;
border-radius: 10px !important;
font-weight: 700;
font-size: 14px;
line-height: 100%;
border: 1px solid #BAF1F3;
background: #F5FFFF;
cursor: pointer;
transition: all 0.2s ease-in-out;
display: flex;
justify-content: center;
align-items: center;
gap: 6px;
}
/* divider style */
.divider-line {
color: #DBDBDB;
font-weight: 400;
}
/* active state */
.highlight-link.active {
color: #00999E;
}
/* inactive state */
.highlight-link:not(.active) {
color: #707070;
}
.no-files-message {
width: 900px;
height: 300px;
background: #ECECEC;
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
font-weight: 500; /* Medium */
font-size: 18px;
line-height: 100%;
letter-spacing: 0;
color: #333; /* Adjust text color if needed */
text-align: center;
border-radius: 8px; /* optional for smooth edges */
margin: 13px; /* center horizontally */
}
#container {
max-height: 400px; /* set fixed height */
overflow-y: auto; /* enable vertical scroll */
overflow-x: hidden; /* prevent horizontal scroll */
}
.file-icon-box {
/* width: 40px;
height: 50px;
display: flex;
align-items: center;
justify-content: center; */
border-radius: 10px;
background: #F4F6F8;
border: 1px solid #ddd; /* matches border-width:1px */
padding: 3px;
}
.dataTables_length label {height: 21px !important;}
</style>
<?php
helper('datatable_view');
$UserList = $UserList ?? [];
$ul_header_labels = ['Name', 'Email', 'Mobile No', 'Role', 'Status', 'Action'];
$ul_col_count = count($ul_header_labels);
$ul_col_max_len = array_fill(0, $ul_col_count, 0);
for ($i = 0; $i < $ul_col_count; $i++) {
$ul_col_max_len[$i] = mb_strlen($ul_header_labels[$i]);
}
if (!empty($UserList)) {
foreach ($UserList as $row) {
$ul_col_max_len[0] = max($ul_col_max_len[0], mb_strlen((string) ($row->first_name ?? '')));
$ul_col_max_len[1] = max($ul_col_max_len[1], mb_strlen((string) ($row->email ?? '')));
$ul_col_max_len[2] = max($ul_col_max_len[2], mb_strlen((string) ($row->mobile ?? '')));
$ul_col_max_len[3] = max($ul_col_max_len[3], mb_strlen((string) ($row->user_role ?? '')));
$statusLabel = (($row->is_active ?? 0) == 1) ? 'Active' : 'In-Active';
$ul_col_max_len[4] = max($ul_col_max_len[4], mb_strlen($statusLabel));
$ul_col_max_len[5] = max($ul_col_max_len[5], 4);
}
}
$ul_col_min_px = array_fill(0, $ul_col_count, 80);
$ul_col_max_px = array_fill(0, $ul_col_count, 360);
$ul_col_min_px[0] = 72;
$ul_col_max_px[0] = 280;
$ul_col_min_px[5] = 72;
$ul_col_max_px[5] = 96;
$ul_col_width_px = nhance_dt_column_widths_px($ul_header_labels, $ul_col_max_len, $ul_col_min_px, $ul_col_max_px);
?>
<style>
<?php for ($i = 0; $i < $ul_col_count; $i++) : ?>
#user-table_wrapper .dataTables_scrollHead table thead th:nth-child(<?= $i + 1 ?>),
#user-table thead th:nth-child(<?= $i + 1 ?>) {
min-width: <?= (int) $ul_col_width_px[$i] ?>px;
width: <?= (int) $ul_col_width_px[$i] ?>px;
box-sizing: border-box;
vertical-align: middle;
overflow: visible !important;
}
#user-table tbody td:nth-child(<?= $i + 1 ?>) {
width: <?= (int) $ul_col_width_px[$i] ?>px;
max-width: <?= (int) $ul_col_width_px[$i] ?>px;
min-width: <?= (int) $ul_col_width_px[$i] ?>px;
box-sizing: border-box;
vertical-align: middle;
}
<?php endfor; ?>
#user-table tbody td:not(:last-child) {
overflow: hidden;
text-overflow: ellipsis;
}
#user-table tbody td:last-child {
overflow: visible;
text-overflow: clip;
}
</style>
<?php
$session = \Config\Services::session();
$currentLogInRole = $session->get()['userData']->role;
?>
<!-- End ADD and EDIT Page HTML -->
<div class="row" id="List-page">
<div class="col-12">
<div class="card">
<div class="card-body">
<!-- <div class="row" style="margin-bottom:1rem;">
<div class="col-6" style="align-self: center;">
<h4 style="position: relative;">Users</h4>
</div>
</div> -->
<table data-custom-table-css="table" class="table mb-0 nowrap" cellspacing="0" id="user-table">
<thead class="bg-light">
<tr>
<th class="font-weight-medium">Name&nbsp;</th>
<th class="font-weight-medium">Email&nbsp;</th>
<th class="font-weight-medium">Mobile No&nbsp;</th>
<th class="font-weight-medium">Role&nbsp;</th>
<th class="font-weight-medium">Status&nbsp;</th>
<th class="font-weight-medium text-center">Action&nbsp;</th>
</tr>
</thead>
<tbody>
<?php foreach($UserList as $row) { ?>
<tr id="<?php echo $row->id;?>">
<td class="text-dark"><?php echo $row->first_name; ?></td>
<td><?php echo $row->email; ?></td>
<td><?php echo $row->mobile; ?></td>
<td><?php echo $row->user_role; ?></td>
<td>
<span class="<?php if($row->is_active == 1){ echo 'badge badge-primary'; }else{ echo 'badge badge-danger'; } ?>">
<?php if($row->is_active == 1){ echo 'Active'; }else{ echo 'In-Active'; } ?>
</span>
</td>
<td class="text-center table-action-cell">
<div class="btn-group dropdown">
<a href="javascript: void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown" aria-expanded="false"><i class="mdi mdi-dots-horizontal"></i></a>
<div class="dropdown-menu dropdown-menu-right" style="cursor: pointer;">
<a class="dropdown-item btnEdit" data-id="<?php echo $row->id; ?>"><i data-id="<?php echo $row->id; ?>" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit</a>
<?php if (in_array(get_role_id(), [1, 5])): ?>
<?php if ($row->is_active == 1): ?>
<a class="dropdown-item btnDelete" data-id="<?php echo $row->id; ?>">
<i class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle"></i>Delete
</a>
<?php else: ?>
<a class="dropdown-item btnActivate" data-id="<?php echo $row->id; ?>">
<i class="mdi mdi-account-check mr-2 text-muted font-18 vertical-middle"></i>Activate
</a>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</td>
</tr>
<?php } ?>
</tbody>
</table>
<!-- <table data-custom-table-css="table" id="scroll-horizontal-datatable" class="table w-100 nowrap text-custom-black text-custom app-datatable">
<thead class="bg-light">
<tr>
<th>Ticket ID</th>
<th class="text-left">Name</th>
<th>Policy Number</th>
<th>Ticket Type</th>
<th>Subject</th>
<th>Status</th>
<th class="text-left">Assign To</th>
<th>Created At</th>
<th>Updated At</th>
</tr>
</thead>
<tbody class="app-table-body">
<?php if (isset($ticket_data)) { ?>
<?php foreach($ticket_data as $index => $row){ ?>
<tr data-id="<?= $row['thz_id']; ?>" style="cursor: pointer;">
<td class="text-right"><?php echo $row['thz_id']; ?></td>
<td class="text-left">
<?php echo $row['name']; ?>
<span class="text-custom-grey"><?php if (!empty($row['empcode'])): echo '('.$row['empcode'].')'; endif; ?></span><br>
<span class="text-custom-grey"><?php if (!empty($row['mobile'])): echo $row['mobile']; endif; ?></span>
</td>
<td class="text-center"><?php echo (!empty($row['policy_no']) && strtolower($row['policy_no']) !== 'null')
? $row['policy_no']
: 'N/A'; ?>
</td>
<td class="text-center"><?php echo $row['ticket_type'] ? $row['ticket_type'] : '-'; ?></td>
<td class="text-center wrap" title="<?php echo htmlspecialchars($row['subject']); ?>">
<?php
$subject = $row['subject'] ? $row['subject'] : 'N/A';
echo (strlen($subject) > 50)
? htmlspecialchars(substr($subject, 0, 50)) . "..."
: htmlspecialchars($subject);
?>
</td>
<td class="text-center"><?php echo $row['status'] ? $row['status'] : '-' ; ?></td>
<td class="text-left"><?php echo $row['assignee_name'] ? $row['assignee_name'] : '-'; ?></td>
<td class="text-left">
<?php if (!empty($row['created_at'])):
$cd = date("j F Y", strtotime($row['created_at']));
$ct = date("h:i A", strtotime($row['created_at']));
echo $cd . "<br><span class='time'> " . $ct . "</span>";
endif;
?>
</td>
<td class="text-left">
<?php if (!empty($row['updated_at'])):
$ud = date("j F Y", strtotime($row['updated_at']));
$ut = date("h:i A", strtotime($row['updated_at']));
echo $ud . "<br><span class='time'> " . $ut . "</span>";
endif;
?>
</td>
</tr>
<?php } ?>
<?php } ?>
</tbody> -->
</table>
</div>
</div>
</div>
<!-- end col -->
</div>
<!-- end row-->
<!-- modal content -->
<div id="con-close-modal" class="modal fade app-font-family" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: none;" data-backdrop="static">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add User</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body p-4">
<div class="">
<form role="form" class="parsley-examples" method="post" id="UserForm" action="" enctype="multipart/form-data">
<input type="hidden" value="<?= csrf_hash() ?>" name="<?= csrf_token() ?>"/>
<input type="hidden" name="PrimaryKey" id="UserId"/>
<div class="form-group">
<div class="form-row">
<div class="form-group col-md-6">
<label for="nhance_branch_id">Nhance Branch<span class="text-danger">*</span></label>
<select class="form-control" id="nhance_branch_id" name="nhance_branch_id" required>
<option value="">Select Nhance Branch</option>
<?php foreach($NHanceBranchData as $value) { ?>
<option value="<?= $value['id'] ?>" <?= old('nhance_branch_id') == $value['id'] ? 'selected' : '' ?>><?= $value['branch_name'] ?></option>
<?php } ?>
</select>
</div>
<div class="form-group col-md-6">
<label for="rm_id">Reporting Manager<span class="text-danger">*</span></label>
<select class="form-control" id="rm_id" name="rm_id" required>
<option value="">Select Reporting Manager</option>
<?php foreach($user_data as $value) { ?>
<option value="<?= $value['id'] ?>" <?= old('rm_id') == $value['id'] ? 'selected' : '' ?>><?= $value['first_name'] ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="emp_code">Employee Code<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="emp_code" placeholder="Enter Code" name="emp_code" onchange="validateInput(this, 'user_profiles', 'emp_code', 'btnSubmit')" required value="<?= old('emp_code') ?>">
</div>
<div class="form-group col-md-6">
<label for="first_name">Name<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="first_name" placeholder="Enter Name" name="first_name" required value="<?= old('first_name') ?>">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="email">Email<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="email" placeholder="Enter Email" name="email" data-parsley-trigger="change" data-parsley-type="email" onchange="validateInput(this, 'user_profiles', 'email', 'btnSubmit')" required value="<?= old('email') ?>">
</div>
<div class="form-group col-md-6">
<label for="mobile">Mobile Number<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="mobile" placeholder="Enter Mobile Number ( starting with 6, 7, 8, or 9 only. )" name="mobile" onkeypress="return onlyNumbers(event)" onchange="validateInput(this, 'user_profiles', 'mobile', 'btnSubmit')" maxlength="10" minlength="10" pattern="^[6-9]\d{9}$" data-parsley-type-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." data-parsley-required-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." required value="<?= old('mobile') ?>">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="role">User Role<span class="text-danger">*</span>
<span class="tooltip-trigger mdi mdi-information-outline" id="roleAccessMatrixTrigger"></span>
</label>
<select class="form-control" id="role" name="role" required>
<option value="">Select Role</option>
<?php foreach($roleData as $value) {
// $headRoleValue = $value['id']??"";
// // we are showing head role only to head's who logged in
// if($headRoleValue == "5" && $currentLogInRole != "5" ){
// continue;
// }
?>
<option value="<?= $value['id'] ?>"><?= $value['role'] ?></option>
<?php } ?>
</select>
</div>
<div class="form-group col-md-6">
<label for="team">User Team<span class="text-danger">*</span>
<span class="tooltip-trigger mdi mdi-information-outline" id="accessMatrixTrigger"></span>
</label>
<select hidden class="form-control" id="team" name="team[]" multiple required>
<?php foreach($teamData as $value) {
$teamValue = $value['id']??"";
// we are showing head role only to head's who logged in
if( ($teamValue == "4" || $teamValue =="6" ) && $currentLogInRole != "5" ){
continue;
}
?>
<option value="<?= $value['id'] ?>"><?= $value['name'] ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<div class="form-group text-right m-b-0">
<button class="btn app-btn-outline-secondary mr-2 " type="button" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="submit" class="btn app-btn-secondary waves-effect waves-light" id="btnSubmit">Submit</button>
<!-- <button type="button" class="btn btn-secondry waves-effect waves-light mr-1" data-dismiss="modal" aria-hidden="true">Close</button> -->
</div>
</form>
</div>
</div>
</div>
</div>
</div><!-- /.modal -->
<div id="nhance-partner-modal" class="modal fade app-font-family" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: none;">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add Nhance Partner Manager </h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body p-4">
<div class="">
<form role="form" class="parsley-examples" method="post" id="PartnerForm" action="" enctype="multipart/form-data" data-parsley-validate>
<input type="hidden" value="<?= csrf_hash() ?>" name="<?= csrf_token() ?>"/>
<input type="hidden" name="PrimaryKey" id="partner_id" name="id"/>
<div class="form-group">
<div class="form-row">
<div class="form-group col-md-6">
<label for="partner_name">Name<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="partner_name" placeholder="Enter Name" name="name" required data-parsley-pattern="^[a-zA-Z\s\.]+$" data-parsley-trigger="keyup" data-parsley-pattern-message="Please enter a valid name (letters, spaces, dots only).">
</div>
<div class="form-group col-md-6">
<label for="mobile_no">Mobile Number<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="mobile_no" placeholder="Enter Mobile Number ( starting with 6, 7, 8, or 9 only. )" name="mobile" maxlength="10" minlength="10" pattern="^[6-9]\d{9}$" data-parsley-type-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." data-parsley-required-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." required data-parsley-trigger="keyup">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="email_addr">Email<span class="text-danger">*</span></label>
<input type="email" class="form-control" id="email_addr" placeholder="Enter Email" name="email" data-parsley-trigger="keyup" data-parsley-type="email" required>
</div>
<div class="form-group col-md-6">
<label for="retention_rate">Retention Rate<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="retention_rate" name="retention_rate" placeholder="Enter Retention Rate" inputmode="decimal" required data-parsley-type="number" data-parsley-min="0" data-parsley-min-message="Retention rate cannot be negative.">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="partner_nhance_branch_id">Nhance Branch<span class="text-danger">*</span></label>
<select class="form-control" id="partner_nhance_branch_id" name="nhance_branch_id" required>
<option value="">Select Nhance Branch</option>
<?php foreach($NHanceBranchData as $value) { ?>
<option value="<?= $value['id'] ?>"><?= $value['branch_name'] ?></option>
<?php } ?>
</select>
</div>
<!-- <div class="form-group col-md-6">
<label for="locn">Address</label>
<textarea class="form-control" id="locn" name="address" placeholder="Enter address" rows="3" maxlength="1500"></textarea>
</div> -->
</div>
</div>
<div class="form-group text-right m-b-0">
<button class="btn app-btn-outline-secondary mr-2 " type="button" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button class="btn app-btn-secondary waves-effect waves-light" type="submit" id="btnPartnerSubmit">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div><!-- /.modal -->
<div id="upload-incentive-file-modal" class="modal fade app-font-family" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: none;">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body p-4">
<form role="form" class="parsley-examples" method="post" id="PartnerIncentiveForm" action="" enctype="multipart/form-data">
<input type="hidden" value="<?= csrf_hash() ?>" name="<?= csrf_token() ?>"/>
<input type="hidden" id="manager_id" name="manager_id" />
<div class="form-group">
<div class="form-row">
<div class="form-group col-md-5">
<label for="incentive_month">Date</label>
<div class="input-icon">
<input type="text" class="form-control" name="incentive_month" id="incentive_month" required>
<i class="mdi mdi-calendar-blank-outline additional-icon"></i>
</div>
</div>
<div class="form-group col-md-5">
<label for="incentive_file_name">Upload File</label>
<div class="input-icon">
<input type="file" class="form-control" name="incentive_file_name" id="incentive_file_name" required accept=".jpg,.jpeg,.png">
<i class="mdi mdi-upload additional-icon"></i>
</div>
</div>
<div class="form-group col-md-2 text-right" style="margin-top: 27px;">
<button class="btn app-btn-secondary waves-effect waves-light" type="button" id="btnPartnerIncentiveSubmit" onclick="submitIncentivePartner(event)">Submit</button>
</div>
</div>
</div>
</form>
<!-- <div class="row">
<div class="col-2">
<label for="filter">Files </label>
</div>
<div class="offset-col-7 col-3">
<div class="input-icon text-right">
<input type="text" class="form-control" id="filter">
<i class="mdi mdi-magnify additional-icon"></i>
</div>
</div> -->
<div class="row align-items-center">
<div class="col-2">
<label for="filter" class="mb-0">Files</label>
</div>
<div class="col-5 ml-auto">
<div class="input-icon">
<input type="text" class="form-control" id="filter" placeholder="Search...">
<i class="mdi mdi-magnify additional-icon"></i>
</div>
</div>
</div>
<div class="row" id="container"></div>
</div>
</div>
</div>
</div><!-- /.modal -->
<!-- Tooltip container separate from trigger -->
<div class="tooltip-container" id="tooltipContainer">
<div class="tooltip" id="accessMatrixTooltip">
<table data-custom-table-css="table" class="tooltip-table" style="color: black;">
<thead>
<tr>
<th>Team</th>
<th>Module</th>
<th>Access Rights</th>
</tr>
</thead>
<tbody>
<tr>
<td class="team-cell">Management</td>
<td>BDS - All access</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell" rowspan="6">Accounts</td>
<td>BDS - Policy Transaction</td>
<td>Policy | Endorsement | Statement Upload</td>
</tr>
<tr>
<td>BDS - Report</td>
<td>TAT wise | ACM Status wise | ACM TAT wise</td>
</tr>
<tr>
<td>BDS - Policy Report</td>
<td>BDS | Variance | Outstanding | IRDA | Renewal | TAT Band </td>
</tr>
<tr>
<td>BDS - Pending Actions</td>
<td>Finance Team</td>
</tr>
<tr>
<td>BDS - Masters</td>
<td>Vehicle | CD | Insurer</td>
</tr>
<tr>
<td>BDS - Documents</td>
<td>✓</td>
</tr>
<!-- Temporary please don't delete (start's) -->
<!--
<tr>
<td class="team-cell" rowspan="5">Finance</td>
<td>BDS - Policy Transaction</td>
<td>Policy | Endorsement | Statement Upload</td>
</tr>
<tr>
<td>BDS - Report</td>
<td>TAT wise | ACM Status wise | ACM TAT wise</td>
</tr>
<tr>
<td>BDS - Pending Actions</td>
<td>Finance Team</td>
</tr>
<tr>
<td>BDS - Masters</td>
<td>Vehicle | CD</td>
</tr>
<tr>
<td>BDS - Documents</td>
<td>✓</td>
</tr>
<tr>
<td class="team-cell" rowspan="5">Business</td>
<td>BDS - Policy Transaction</td>
<td>Policy | Endorsement</td>
</tr>
<tr>
<td>BDS - Report</td>
<td>TAT wise | ACM Status wise | ACM TAT wise</td>
</tr>
<tr>
<td>BDS - Pending Actions</td>
<td>Business Team</td>
</tr>
<tr>
<td>BDS - Masters</td>
<td>Vehicle | CD</td>
</tr>
<tr>
<td>BDS - Documents</td>
<td>✓</td>
</tr>
-->
<!-- Temporary please don't delete (ends) -->
<tr>
<td class="team-cell" rowspan="2">POS</td>
<td>BDS - Policy Transaction</td>
<td>Policy | Endorsement</td>
</tr>
<tr>
<td>BDS - Report</td>
<td>BDS, TAT wise | ACM Status wise | ACM TAT wise</td>
</tr>
<tr>
<td class="team-cell">Enrollment</td>
<td>Inception File Upload</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell">Claims</td>
<td>Claims</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell">Sales</td>
<td>LEAD</td>
<td>Lead creation | RFQ creation</td>
</tr>
<tr>
<td class="team-cell">Business Support</td>
<td>LEAD</td>
<td>All access</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="tooltip-container" id="roleTooltipContainer">
<div class="tooltip" id="roleAccessMatrixTooltip">
<table data-custom-table-css="table" class="tooltip-table" style="color: black;">
<thead>
<tr>
<th>Team</th>
<th>Module</th>
<th>Access Rights</th>
</tr>
</thead>
<tbody>
<tr>
<td class="team-cell">Head</td>
<td>All modules</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell">Admin</td>
<td>All modules</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell">Manager</td>
<td>Access to all modules except the "Masters" module</td>
<td>All access</td>
</tr>
<tr>
<td class="team-cell">Account Manager</td>
<td>Access to all modules except the "Masters" module</td>
<td>All access without "Delete option"</td>
</tr>
<tr>
<td class="team-cell">Staff</td>
<td>Based on the "Teams"</td>
<td>Based on the "Teams"</td>
</tr>
</tbody>
</table>
</div>
</div>
<?php if (session()->getFlashdata('errors')): ?>
<script>
$(document).ready(function() {
<?php foreach (session()->getFlashdata('errors') as $error): ?>
toastr.error("<?= addslashes($error) ?>", "Validation Error");
<?php endforeach; ?>
var errorModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
errorModal.show();
<?php if(old('PrimaryKey')): ?>
$('#UserForm').attr('action', '<?= base_url('/user/edit') ?>');
$('#UserId').val('<?= old('PrimaryKey') ?>');
$('#btnSubmit').html('Update');
$('.modal-title').text('Update User');
$('#email').attr('data-original', '<?= old('email') ?>');
$('#mobile').attr('data-original', '<?= old('mobile') ?>');
$('#emp_code').attr('data-original', '<?= old('emp_code') ?>');
<?php else: ?>
$('#UserForm').attr('action', '<?= base_url('/user/create') ?>');
<?php endif; ?>
});
</script>
<?php endif; ?>
<?php if (session()->getFlashdata('error')) : ?>
<script>
var errorModal = new bootstrap.Modal(
document.getElementById('con-close-modal')
);
errorModal.show();
</script>
<?php endif; ?>
<script>
var table;
$(document).ready(function () {
$('#nhance_branch_id').select2();
$('#partner_nhance_branch_id').select2();
$('#rm_id').select2();
$('#nhance_branch_id')
.val(null) // ✅ MUST be null
.trigger('change.select2'); // ✅ correct trigger
$('#partner_nhance_branch_id')
.val(null) // ✅ MUST be null
.trigger('change.select2'); // ✅ correct trigger
var incentiveMonthPicker = flatpickr("#incentive_month", {
dateFormat: "Y-m-d", // real value stored (hidden)
altInput: true, // show a user-friendly display
altFormat: "M Y", // what you want to display (Aug 2025)
allowInput: false,
});
nhanceListDataTableBeforeInit();
table = $('#user-table').DataTable(nhanceMergeListDataTableOptions({
// dom: "<'row'<'col-sm-3'f><'col-sm-9'B>>" +
// "<'row'<'col-sm-12'tr>>" +
// "<'row'<'col-sm-5'i><'col-sm-7'p>>",
dom: "<'row'<'col-sm-3'f><'col-sm-9'B>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>",
lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]],
buttons: [
// {
// extend: 'collection',
// text: '<i class="mdi mdi-account-multiple"></i><span class="btn-custom"> Load Data </span>',
// className: 'btn app-btn-primary mr-2',
// buttons: [
// {
// text: 'Load User',
// action: function () { loadUser(); }
// },
// {
// text: 'Load Nhance Partner',
// action: function () { loadPartner(); }
// }
// ]
// },
// {
// text: '<i class="mdi mdi-account-multiple"></i><span class="btn-custom">Load User</span>',
// className: 'btn app-btn-primary mr-2 toggleLoadBtn',
// action: function (e, dt, node, config) {
// let $btn = $(node).find('span.btn-custom');
// let currentText = $btn.text().trim();
// if (currentText === "Load User") {
// loadUser();
// $btn.text("Load user"); // toggle text
// } else {
// loadPartner();
// $btn.text("Load partner"); // toggle back
// }
// }
// },
// {
// text: '<i class="mdi mdi-account-multiple"></i><span class="btn-custom">Load User</span>',
// className: 'btn app-btn-primary mr-2 toggleLoadBtn',
// action: function (e, dt, node, config) {
// let $btn = $(node).find('span.btn-custom');
// // check current mode from button dataset (default: user)
// let currentMode = $btn.data("mode") || "user";
// if (currentMode === "user") {
// loadUser();
// $btn.text("Load Nhance Partner");
// $btn.data("mode", "partner"); // switch mode
// } else {
// loadPartner();
// $btn.text("Load User");
// $btn.data("mode", "user"); // switch back
// }
// }
// },
{
text: '<i class="mdi mdi-plus"></i><span class="btn-custom"> Add User </span>',
className: 'btn app-btn-primary mr-2',
attr: { id: 'btnAdd' }
},
{
text: '<i class="mdi mdi-plus"></i><span class="btn-custom"> Add Nhance Partner </span>',
className: 'btn app-btn-primary mr-2',
attr: { id: 'btnNhancePartnerAdd' }
},
{
extend: 'collection',
text: '<span class="btn-custom"> Export </span><i class="mdi mdi-menu-down"></i>',
className: 'btn app-btn-secondary',
buttons: [
{
extend: 'csv',
text: '<i class="mdi mdi-file-delimited"></i><span class="btn-custom"> CSV </span>',
className: 'app-btn-primary',
exportOptions: {
columns: ':not(:last-child)'
}
},
{
extend: 'excel',
sheetName: 'Users',
text: '<i class="mdi mdi-file-excel"></i><span class="btn-custom"> EXCEL </span>',
exportOptions: { orthogonal: 'sort' },
className: 'app-btn-primary',
exportOptions: {
columns: ':not(:last-child)'
}
}
]
}
],
paging: true,
pageLength: 10,
language: {
search: `
<div class="datatable-search-wrapper" style="position:relative; display:inline-block;">
_INPUT_
<i class="mdi mdi-magnify datatable-search-icon"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); color:#666;"></i>
<i class="mdi mdi-close-circle datatable-clear-icon"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); color:#666; display:none;"></i>
</div>`,
searchPlaceholder: "Search",
emptyTable: '<div class="text-center text-muted">No Data found</div>',
paginate: {
previous: '◄',
next: '►'
}
},
initComplete: function () {
$(".dt-buttons").prepend(`
<div class="tab-button mr-2" id="toggleButton" style="margin-right:auto;">
<span id="btnUsers" class="highlight-link active">Users</span>
<span class="divider-line"> | </span>
<span id="btnPartners" class="highlight-link">Nhance Partner</span>
</div>
`);
$('#btnUsers').on('click', function () {
$('#btnPartners').removeClass('active');
$(this).addClass('active');
loadUser();
});
$('#btnPartners').on('click', function () {
$('#btnUsers').removeClass('active');
$(this).addClass('active');
loadPartner();
});
},
columnDefs: [
<?php for ($i = 0; $i < $ul_col_count; $i++) : ?>
{ targets: <?= $i ?>, width: '<?= (int) $ul_col_width_px[$i] ?>px' },
<?php endfor; ?>
]
}));
nhanceListDataTableAfterInit();
nhanceListDataTableBindAdjust(table);
function applyBottomRowDropup() {
if (!table) return;
const currentRows = table.rows({ page: 'current' }).nodes().toArray();
$('#user-table tbody tr').removeClass('nh-force-dropup');
$('#user-table tbody tr td.table-action-cell .btn-group.dropdown').removeClass('dropup');
// Mark last two rows on current page to open action menu upward.
const targetCount = Math.min(2, currentRows.length);
for (let i = 0; i < targetCount; i++) {
const row = currentRows[currentRows.length - 1 - i];
if (!row) continue;
$(row).addClass('nh-force-dropup');
$(row).find('td.table-action-cell .btn-group.dropdown').addClass('dropup');
}
}
applyBottomRowDropup();
$('#user-table').on('draw.dt', applyBottomRowDropup);
// IMPORTANT — DataTables draw event REF: TTS
table.on('draw.dt', function () {
let rowCount = table.rows({ filter: 'applied' }).count();
if (rowCount <= 2) {
$('#user-table_wrapper .dataTables_scrollBody').css('overflow', 'inherit');
} else {
$('#user-table_wrapper .dataTables_scrollBody').css('overflow', 'auto');
}
});
$('#team').multiselect({
nonSelectedText: 'Select Team',
enableFiltering: false,
enableCaseInsensitiveFiltering: false,
includeSelectAllOption : false,
buttonWidth:'100%',
dropUp: true
});
$('.close').click(function(){
$('#UserId').val('');
$('#first_name').val('');
$('#email').val('').removeAttr('data-original');
$('#mobile').val('').removeAttr('data-original');
$('#emp_code').val('').removeAttr('data-original');
$('#role').val('')
$('#btnSubmit').prop('disabled', false);
})
// $('body').on('click', '#btnUsers', function () {
// $('#btnPartners').removeClass('active');
// $(this).addClass('active');
// loadUser();
// });
// $('body').on('click', '#btnPartners', function () {
// $('#btnUsers').removeClass('active');
// $(this).addClass('active');
// loadPartner();
// });
$('body').on('click', '.btnEdit', function () {
$('#UserForm').parsley().reset();
var user_id = $(this).attr('data-id');
$.ajax({
url: '<?php echo base_url('user/getuser/');?>' + user_id,
type: "GET",
dataType: 'json',
success: function (res) {
// Set form action to edit
$('#UserForm').attr('action', '<?php echo base_url('user/edit');?>');
$('#UserId').val(res.data.id);
$('#first_name').val(res.data.first_name);
$('#email').val(res.data.email).attr('data-original', res.data.email);
$('#mobile').val(res.data.mobile).attr('data-original', res.data.mobile);
$('#emp_code').val(res.data.emp_code).attr('data-original', res.data.emp_code);
$('#role').val(res.data.role).trigger('change');
$('#rm_id').val(res.data.rm_id).trigger('change.select2');
if (res.data.nhance_branch_id) {
$('#nhance_branch_id').val(res.data.nhance_branch_id).trigger('change.select2');
} else {
$('#nhance_branch_id').val(null).trigger('change.select2');
}
// Reset team first, then set selected
$('#team').multiselect('deselectAll', false);
$.each(res.userTeamData, function(index, item) {
$('#team option[value="' + item.team_id + '"]').prop('selected', true);
});
$('#team').multiselect('refresh');
$('.modal-title').text('Update User');
$('#btnSubmit').html('Update');
// ✅ Open modal AFTER data is loaded
var myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
myModal.show();
},
error: function (xhr) {
if (xhr.status === 400) {
let response = JSON.parse(xhr.responseText);
let errorMessages = "";
let seenMessages = [];
if (response.errors) {
$.each(response.errors, function (field, message) {
if (!seenMessages.includes(message)) {
errorMessages += `• ${message}<br>`;
seenMessages.push(message);
}
});
toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
} else {
toastr.warning(response.message || 'Validation failed', 'Warning');
}
} else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText);
toastr.error(response.message, 'Security Policy');
} else if (xhr.status === 500) {
toastr.error('Something went wrong. Please try again later.', 'Server Error');
} else {
toastr.error('An unexpected error occurred.', 'Error');
}
}
});
});
$('body').on('click', '.btnDelete', function () {
Swal.fire({
title: "Are you sure?",
text: "You need to remove this user",
icon: "info",
showCancelButton: true,
confirmButtonColor: "#3085d6",
confirmButtonText: "Yes",
}).then((result) => {
if (result.isConfirmed) {
var student_id = $(this).attr('data-id');
$.get('<?php echo base_url('user/deactive/');?>'+student_id, function (data) {
console.log(data);
toastr.success('User removed successfully', 'Success');
window.location.reload()
})
}
});
});
$('body').on('click', '.btnActivate', function () {
Swal.fire({
title: "Are you sure?",
text: "You need to active this user",
icon: "info",
showCancelButton: true,
confirmButtonColor: "#3085d6",
confirmButtonText: "Yes",
}).then((result) => {
if (result.isConfirmed) {
var student_id = $(this).attr('data-id');
$.get('<?php echo base_url('user/activateUser/');?>'+student_id, function (data) {
console.log(data);
toastr.success('User actived successfully', 'Success');
window.location.reload()
})
}
});
});
$('body').on('click', '.btnPartnerEdit', function () {
$('#PartnerForm').parsley().reset();
let user = JSON.parse($(this).attr('data-obj')); // ✅ convert back to object
$('#PartnerForm').attr('action', '<?php echo base_url('/user/partner');?>');
$('#partner_id').val(user.id);
$('#partner_name').val(user.name);
$('#email_addr').val(user.email);
$('#mobile_no').val(user.mobile);
// $('#locn').val(user.address);
$('#retention_rate').val(user.retention_rate);
if (user.nhance_branch_id !== null &&
user.nhance_branch_id !== "" &&
user.nhance_branch_id !== 0) {
$('#partner_nhance_branch_id')
.val(user.nhance_branch_id)
.trigger('change.select2');
} else {
$('#partner_nhance_branch_id')
.val(null) // ✅ MUST be null
.trigger('change.select2'); // ✅ correct trigger
}
// $('#btnPartnerSubmit').html('Update');
$('.modal-title').html('Update Nhance Partner Manager');
let myModal = new bootstrap.Modal(document.getElementById('nhance-partner-modal'));
myModal.show(); // open modal
});
$('body').on('click', '.btnPartnerDelete', function () {
var partner_role = $(this).attr('data-role');
var alertText = "You need to remove this user";
if (partner_role == 3) {
alertText = "You need to remove this Staff";
} else if (partner_role == 2) {
alertText = "You need to remove this Handler";
} else if (partner_role == 1) {
alertText = "You need to remove this Manager and related Handler and Staff are also delete";
}
Swal.fire({
title: "Are you sure?",
text: alertText,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#3085d6",
confirmButtonText: "Yes",
}).then((result) => {
if (result.isConfirmed) {
var partner_id = $(this).attr('data-id');
$.ajax({ url: "<?= base_url('user/partner') ?>",
type: "PUT",
data: { id: partner_id },
success: function(response) {
console.log("Deleted:", response);
toastr.success(response.message, 'Success');
loadPartner(); // refresh table
},
error: function(xhr) {
console.error("Delete Error:", xhr.responseText);
let res = xhr.responseJSON || {};
toastr.error(res.message || "Unable to delete staff", 'Error');
}
});
}
});
});
$('body').on('click', '.btnPartnerIncentive', function () {
let user = JSON.parse($(this).attr('data-obj'));
$('#PartnerIncentiveForm').attr('action', '<?= base_url('/user/partnerIncentive');?>');
$('#manager_id').val(user.id);
$('#incentive_file_name').val(user.incentive_file_name);
$('#incentive_month').val(user.incentive_month);
$('.modal-title').text(user.name);
// ✅ Load files separately
loadIncentiveFiles(user.id);
let myModal = new bootstrap.Modal(document.getElementById('upload-incentive-file-modal'));
myModal.show();
});
});
var form = document.getElementById("UserForm");
form.addEventListener("submit", function(event) {
event.preventDefault();
var btn = document.getElementById('btnSubmit');
var currentUserId = $('#UserId').val(); // capture BEFORE ajax
btn.disabled = true;
btn.innerText = "Saving...";
var actionUrl = $('#UserForm').attr('action');
var formData = new FormData(form);
$.ajax({
url: actionUrl,
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function(responseText) {
// Parse returned HTML and look for toastr.error calls (validation errors injected by CI flashdata)
var tempDiv = document.createElement('div');
tempDiv.innerHTML = responseText;
var errorMessages = [];
tempDiv.querySelectorAll('script').forEach(function(script) {
var content = script.innerText || script.textContent;
var matches = content.match(/toastr\.error\("([^"]+)"/g);
if (matches) {
matches.forEach(function(m) {
var msg = m.replace(/toastr\.error\("/, '').replace(/"$/, '');
if (!errorMessages.includes(msg)) {
errorMessages.push(msg);
}
});
}
});
if (errorMessages.length > 0) {
// ❌ VALIDATION FAILED — keep modal OPEN, show all errors in one toast
var errorList = '<ul style="margin:4px 0 0 0; padding-left:18px; text-align:left;">';
errorMessages.forEach(function(msg) {
errorList += '<li>' + msg + '</li>';
});
errorList += '</ul>';
toastr.error(errorList, 'Validation Errors', {
"allowHtml": true,
"timeOut": 8000,
"closeButton": true
});
// ✅ Modal stays OPEN — do NOT hide it
} else {
// ✅ SUCCESS
toastr.success('User saved successfully!', 'Success');
// ✅ Bootstrap 4 way to close modal
$('#con-close-modal').modal('hide');
// Full reset
form.reset();
$('#UserForm').parsley().reset();
$('#UserId').val('');
$('#nhance_branch_id').val(null).trigger('change.select2');
$('#rm_id').val(null).trigger('change.select2');
$('#role').val('').trigger('change');
$('#team').multiselect('deselectAll', false);
$('#team').multiselect('refresh');
$('#email').removeAttr('data-original');
$('#mobile').removeAttr('data-original');
$('#emp_code').removeAttr('data-original');
$('.modal-title').text('Add User');
$('#btnSubmit').text('Submit').prop('disabled', false);
window.location.reload();
loadUser();
}
},
error: function(xhr) {
toastr.error('An unexpected error occurred. Please try again.', 'Error');
},
complete: function() {
btn.disabled = false;
btn.innerText = currentUserId ? 'Update' : 'Submit';
}
});
});
$('#PartnerForm').on('submit', function(e) {
e.preventDefault();
var $form = $(this);
$form.parsley().validate();
if ($form.parsley().isValid()) {
var btn = document.getElementById('btnPartnerSubmit');
btn.disabled = true;
btn.innerText = "Saving...";
var formData = new FormData(this);
$.ajax({
url: "<?= base_url('user/partner') ?>",
type: "POST",
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function(response) {
if (response.status === "success") {
toastr.success('Partner saved successfully!', 'Success');
$('#nhance-partner-modal').modal('hide');
$form[0].reset();
$('#partner_nhance_branch_id').val(null).trigger('change.select2');
} else {
toastr.warning(response.message || 'Something went wrong.', 'Warning');
}
},
error: function(xhr) {
console.log("Error: " + xhr.statusText);
if (xhr.status === 400) {
let response = JSON.parse(xhr.responseText);
let errorMessages = "";
let seenMessages = [];
if (response.errors) {
$.each(response.errors, function (field, message) {
if (!seenMessages.includes(message)) {
errorMessages += `• ${message}<br>`;
seenMessages.push(message);
}
});
toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
} else {
toastr.warning(response.message || 'Validation failed', 'Warning');
}
} else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText);
toastr.error(response.message, 'Security Policy');
} else if (xhr.status === 500) {
toastr.error('Something went wrong . Please try again later.', 'Server Error');
} else {
toastr.error('An unexpected error occurred. Please try again later.', 'Error');
}
console.error('Unexpected error:', xhr.responseText);
},
complete: function() {
btn.disabled = false;
btn.innerText = "Submit";
loadPartner();
}
});
}
});
function submitIncentivePartner(event) {
event.preventDefault();
var form = document.getElementById('PartnerIncentiveForm');
var btn = document.getElementById('btnPartnerIncentiveSubmit');
var myModal = new bootstrap.Modal(document.getElementById('upload-incentive-file-modal'));
// reset any old error styles
form.classList.remove('was-validated');
var month = document.getElementById('incentive_month').value.trim();
var fileInput = document.getElementById('incentive_file_name');
if (month === "" || !fileInput.files.length) {
toastr.warning('Please fill all required fields.', 'Warning');
form.classList.add('was-validated');
return;
}
// Disable button during submit
btn.disabled = true;
btn.innerText = "Saving...";
var formData = new FormData(form);
$.ajax({
url: "<?= base_url('user/partnerIncentive') ?>",
type: "POST",
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function(response) {
if (response.status === "success") {
toastr.success('Partner Incentive saved successfully!', 'Success');
form.reset();
// ✅ Reload incentive files list
let manager_id = $('#manager_id').val();
loadIncentiveFiles(manager_id);
} else {
toastr.warning(response.message || 'Something went wrong.', 'Warning');
}
},
error: function(xhr) {
console.log("Error: " + xhr.statusText);
console.error(xhr.responseText);
if (xhr.status === 400) {
let response = JSON.parse(xhr.responseText);
let errorMessages = "";
let seenMessages = []; // Array to store unique messages
if (response.errors) {
$.each(response.errors, function (field, message) {
if (!seenMessages.includes(message)) {
errorMessages += `• ${message}<br>`;
seenMessages.push(message); // Mark this message as "seen"
}
});
toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
} else {
toastr.warning(response.message || 'Validation failed', 'Warning');
}
} else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText);
toastr.error(response.message, 'Security Policy');
} else if (xhr.status === 500) {
toastr.error('Something went wrong . Please try again later.', 'Server Error');
} else {
toastr.error('An unexpected error occurred. Please try again later.', 'Error');
}
},
complete: function() {
btn.disabled = false;
btn.innerText = "Submit";
}
});
}
function renderRows(data, type = 'user') {
table.clear(); // Remove old rows
if (Array.isArray(data) && data.length) {
data.forEach(row => {
let statusClass = row.is_active == 1 ? 'badge-success' : 'badge-danger';
let statusText = row.is_active == 1 ? 'Active' : 'In-Active';
let rowData = [];
if (type === 'user') {
rowData = [
row.first_name,
row.email,
row.mobile,
row.user_role,
`<span class="badge ${statusClass}">${statusText}</span>`,
`<div class="btn-group dropdown">
<a href="javascript:void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown">
<i class="mdi mdi-dots-horizontal"></i>
</a>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item btnEdit" data-id="${row.id}" style="cursor:pointer;">
<i data-id="${row.id}" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit
</a>
<a class="dropdown-item btnDelete" data-id="${row.id}">
<i data-id="${row.id}" class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle btnDelete"></i>Delete
</a>
</div>
</div>`
];
} else { // partner
let roleName = "";
switch(parseInt(row.role_id)) {
case 1: roleName = "Manager"; break;
case 2: roleName = "Handler"; break;
case 3: roleName = "Staff"; break;
default: roleName = "Others";
}
rowData = [
row.name,
row.email,
row.mobile,
roleName,
`<span class="badge ${statusClass}">${statusText}</span>`,
`<div class="btn-group dropdown">
<a href="javascript:void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown">
<i class="mdi mdi-dots-horizontal"></i>
</a>
<div class="dropdown-menu dropdown-menu-right">
<a data-toggle="modal" data-target="#nhance-partner-modal" class="dropdown-item btnPartnerEdit" data-obj='${JSON.stringify(row)}'>
<i data-obj='${JSON.stringify(row)}' class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnPartnerEdit"></i>Edit
</a>
<a class="dropdown-item btnPartnerDelete" data-id="${row.id}" data-role="${row.role_id}">
<i data-id="${row.id}" data-role="${row.role_id}" class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle btnPartnerDelete"></i>Delete
</a>
<a class="dropdown-item btnPartnerPerformance" data-id="${row.id}">
<i data-id="${row.id}" class="mdi mdi-speedometer mr-2 text-muted font-18 vertical-middle btnPartnerPerformance"></i>View Performance
</a>
<a data-toggle="modal" data-target="#upload-incentive-file-modal" class="dropdown-item btnPartnerIncentive" data-obj='${JSON.stringify(row)}'>
<i data-obj='${JSON.stringify(row)}' class="mdi mdi-upload mr-2 text-muted font-18 vertical-middle btnPartnerIncentive"></i>Upload Incentive File
</a>
</div>
</div>`
];
}
let newRow = table.row.add(rowData);
$(newRow.node()).find('td:last').addClass('text-center table-action-cell');
});
} else {
// Show placeholder if no data
table.row.add([
`<td colspan="6" class="text-center text-muted">No ${type === 'user' ? 'users' : 'partners'} found</td>`
]);
}
table.draw(); // Redraw table
}
// function loadUser() {
// let tbody = $('#loadDynamicDetails');
// tbody.empty();
// let users = <?= json_encode($UserList) ?>;
// users.forEach(row => {
// let statusClass = row.is_active == 1 ? 'badge-success' : 'badge-danger';
// let statusText = row.is_active == 1 ? 'Active' : 'In-Active';
// tbody.append(`
// <tr id="${row.id}">
// <td class="text-dark">${row.first_name}</td>
// <td>${row.email}</td>
// <td>${row.mobile}</td>
// <td>${row.user_role}</td>
// <td><span class="badge ${statusClass}">${statusText}</span></td>
// <td>
// <div class="btn-group dropdown">
// <a href="javascript:void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown">
// <i class="mdi mdi-dots-horizontal"></i>
// </a>
// <div class="dropdown-menu dropdown-menu-right">
// <a data-toggle="modal" data-target="#con-close-modal" class="dropdown-item btnEdit" data-id="${row.id}">
// <i data-id="${row.id}" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit
// </a>
// <a class="dropdown-item btnDelete" data-id="${row.id}">
// <i data-id="${row.id}" class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle btnDelete"></i>Delete
// </a>
// </div>
// </div>
// </td>
// </tr>
// `);
// });
// }
function loadUser() {
let users = <?= json_encode($UserList) ?>;
renderRows(users, 'user');
}
// function loadPartner() {
// $.ajax({
// url: '<?= base_url("user/partner"); ?>',
// method: 'GET',
// success: function(response) {
// console.log(response); // {status: "success", data: [...]}
// if (response.status === "success" && Array.isArray(response.data)) {
// let tbody = $('#loadDynamicDetails');
// tbody.empty();
// response.data.forEach(row => {
// let statusClass = row.is_active == 1 ? 'badge-success' : 'badge-danger';
// let statusText = row.is_active == 1 ? 'Active' : 'In-Active';
// tbody.append(`
// <tr id="${row.id}">
// <td class="text-dark">${row.name}</td>
// <td>${row.email}</td>
// <td>${row.mobile}</td>
// <td>Staff</td>
// <td><span class="badge ${statusClass}">${statusText}</span></td>
// <td>
// <div class="btn-group dropdown">
// <a href="javascript:void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown">
// <i class="mdi mdi-dots-horizontal"></i>
// </a>
// <div class="dropdown-menu dropdown-menu-right">
// <a data-toggle="modal" data-target="#nhance-partner-modal" class="dropdown-item btnPartnerEdit" data-obj='${JSON.stringify(row)}'>
// <i data-obj='${JSON.stringify(row)}' class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnPartnerEdit"></i>Edit
// </a>
// <a class="dropdown-item btnPartnerDelete" data-id="${row.id}">
// <i data-id="${row.id}" class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle btnPartnerDelete"></i>Delete
// </a>
// <a class="dropdown-item btnPartnerPerformance" data-id="${row.id}">
// <i data-id="${row.id}" class="mdi mdi-speedometer mr-2 text-muted font-18 vertical-middle btnPartnerPerformance"></i>View Performance
// </a>
// <a data-toggle="modal" data-target="#upload-incentive-file-modal" class="dropdown-item btnPartnerIncentive" data-obj='${JSON.stringify(row)}'>
// <i data-obj='${JSON.stringify(row)}' class="mdi mdi-upload mr-2 text-muted font-18 vertical-middle btnPartnerIncentive"></i>Upload Incentive File
// </a>
// </div>
// </div>
// </td>
// </tr>
// `);
// });
// } else {
// console.warn("No partner data found");
// $('#loadDynamicDetails').html(`<tr><td colspan="6" class="text-center text-muted">No partners found</td></tr>`);
// }
// },
// error: function(xhr, status, error) {
// console.error("Error loading partners:", error);
// }
// });
// }
function loadPartner() {
$.ajax({
url: '<?= base_url("user/partner"); ?>',
method: 'GET',
success: function(response) {
if (response.status === "success" && Array.isArray(response.data)) {
renderRows(response.data, 'partner');
} else {
renderRows([], 'partner');
}
},
error: function(xhr, status, error) {
console.error("Error loading partners:", error);
renderRows([], 'partner');
}
});
}
function loadIncentiveFiles(manager_id) {
// let modal = $("#upload-incentive-file-modal");
// let container = modal.find(".container");
let container = $("#container");
container.html(`<div class="col-md-12 mt-2">
<div class="d-flex align-items-center justify-content-center p-2 bg-white">
<div class="text-muted small">Loading...</div>
</div></div>`);
$.ajax({
url: "<?= base_url('user/partnerIncentive') ?>",
method: 'GET',
data: { manager_id: manager_id }, // pass manager_id if required
success: function(response) {
container.empty();
if (response.status === "success" && response.data && response.data.length) {
response.data.forEach((file) => {
let date = new Date(file.updated_on);
let options = {
day: '2-digit',
month: 'short',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false
};
let uploaded = date.toLocaleString('en-GB', options).replace(',', '');
let color = file.incentive_file_name ? "app-text-success" : "font-color-black";
let download_url = "<?= base_url('user/download-incentive-file/') ?>" + encodeURIComponent(file.id);
let im = file.incentive_month;
let card = `<div class="col-md-6 mt-2 file-card"
data-name="${file.incentive_file_name.toLowerCase()}"
data-date="${uploaded.toLowerCase()}">
<div class="d-flex align-items-center justify-content-between border rounded p-2 bg-white">
<div class="d-flex align-items-center">
<div class="file-icon-box d-flex align-items-center justify-content-center">
<i class="mdi mdi-file-document-outline font-color-black" style="font-size: 24px;"></i>
</div>
<div class="ml-2">
<div class="font-weight-bold font-color-black small text-truncate"
title="${file.incentive_file_name}"
style="max-width: 265px;">
${file.incentive_file_name}
</div>
<div class="text-muted small">Uploaded : ${im}</div>
</div>
</div>
<div>
<a href="${download_url}" target="_blank" class="text-decoration-none">
<i class="mdi mdi-download ${color}" style="font-size: 22px;"></i>
</a>
</div>
</div>
</div>`;
container.append(card);
});
} else {
container.append(`<div class="no-files-message">No Files have been Uploaded</div>`);
}
},
error: function (xhr, status, errorThrown) {
container.html(`<div class="no-files-message">No Files have been Uploaded</div>`);
console.log("Error: " + xhr.status + " - " + errorThrown);
if (xhr.status !== 404) toastr.error(errorThrown || xhr.responseText || 'Something went wrong', 'Error');
}
});
}
$('#filter').on('keyup', function () {
let value = $(this).val().toLowerCase().trim();
let cards = $("#container .file-card");
let matchCount = 0;
cards.each(function () {
let name = $(this).data('name');
let date = $(this).data('date');
if (name.includes(value) || date.includes(value)) {
$(this).show();
matchCount++;
} else {
$(this).hide();
}
});
// Handle "no files" message
$(".no-files-message").remove();
if (matchCount === 0) {
$("#container").append(`<div class="no-files-message col-12">No Files have been Uploaded</div>`);
}
});
</script>
<script>
function initializeTooltip() {
const trigger = document.getElementById('accessMatrixTrigger');
console.log(trigger);
const tooltip = document.getElementById('accessMatrixTooltip');
console.log(tooltip);
const tooltipContainer = document.getElementById('tooltipContainer');
console.log(tooltipContainer);
if (!trigger || !tooltip || !tooltipContainer) {
console.error('Tooltip elements not found');
return;
}
function positionTooltip(event) {
const triggerRect = trigger.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let left = triggerRect.right + 10; // 10px to the right of trigger
let top = triggerRect.top;
// Check if tooltip goes off-screen to the right
if (left + tooltipRect.width > viewportWidth) {
left = triggerRect.left - tooltipRect.width - 10; // Show to the left instead
}
// Check if tooltip goes off-screen at the bottom
if (top + tooltipRect.height > viewportHeight) {
top = viewportHeight - tooltipRect.height - 10;
}
// Ensure tooltip doesn't go above viewport
if (top < 10) {
top = 10;
}
tooltipContainer.style.left = left + 'px';
tooltipContainer.style.top = top + 'px';
// Position arrow
const arrow = tooltip.querySelector('::after');
if (left < triggerRect.left) {
// Tooltip is to the left, arrow should point right
tooltip.style.setProperty('--arrow-position', 'right');
} else {
// Tooltip is to the right, arrow should point left
tooltip.style.setProperty('--arrow-position', 'left');
}
}
// Show tooltip on hover
trigger.addEventListener('mouseenter', function(event) {
positionTooltip(event);
tooltip.classList.add('show');
});
// Hide tooltip when mouse leaves trigger
trigger.addEventListener('mouseleave', function() {
tooltip.classList.remove('show');
});
// Keep tooltip visible when hovering over the tooltip itself
tooltip.addEventListener('mouseenter', function() {
tooltip.classList.add('show');
});
tooltip.addEventListener('mouseleave', function() {
tooltip.classList.remove('show');
});
// Reposition on window resize
window.addEventListener('resize', function() {
if (tooltip.classList.contains('show')) {
positionTooltip();
}
});
}
function initializeRoleTooltip() {
const trigger = document.getElementById('roleAccessMatrixTrigger');
console.log(trigger);
const tooltip = document.getElementById('roleAccessMatrixTooltip');
console.log(tooltip);
const tooltipContainer = document.getElementById('roleTooltipContainer');
console.log(tooltipContainer);
if (!trigger || !tooltip || !tooltipContainer) {
console.error('Tooltip elements not found');
return;
}
function positionTooltip(event) {
const triggerRect = trigger.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let left = triggerRect.right + 10; // 10px to the right of trigger
let top = triggerRect.top;
// Check if tooltip goes off-screen to the right
if (left + tooltipRect.width > viewportWidth) {
left = triggerRect.left - tooltipRect.width - 10; // Show to the left instead
}
// Check if tooltip goes off-screen at the bottom
if (top + tooltipRect.height > viewportHeight) {
top = viewportHeight - tooltipRect.height - 10;
}
// Ensure tooltip doesn't go above viewport
if (top < 10) {
top = 10;
}
tooltipContainer.style.left = left + 'px';
tooltipContainer.style.top = top + 'px';
// Position arrow
const arrow = tooltip.querySelector('::after');
if (left < triggerRect.left) {
// Tooltip is to the left, arrow should point right
tooltip.style.setProperty('--arrow-position', 'right');
} else {
// Tooltip is to the right, arrow should point left
tooltip.style.setProperty('--arrow-position', 'left');
}
}
// Show tooltip on hover
trigger.addEventListener('mouseenter', function(event) {
positionTooltip(event);
tooltip.classList.add('show');
});
// Hide tooltip when mouse leaves trigger
trigger.addEventListener('mouseleave', function() {
tooltip.classList.remove('show');
});
// Keep tooltip visible when hovering over the tooltip itself
tooltip.addEventListener('mouseenter', function() {
tooltip.classList.add('show');
});
tooltip.addEventListener('mouseleave', function() {
tooltip.classList.remove('show');
});
// Reposition on window resize
window.addEventListener('resize', function() {
if (tooltip.classList.contains('show')) {
positionTooltip();
}
});
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeTooltip);
document.addEventListener('DOMContentLoaded', initializeRoleTooltip);
} else {
initializeTooltip();
initializeRoleTooltip();
}
</script>
<script>
$(document).on('click', '#btnAdd', function() {
$('#UserForm')[0].reset(); // 1⃣ reset form values first
$('#UserForm').parsley().reset(); // 2⃣ then reset parsley validation
$('#btnSubmit').prop('disabled', false); // 3⃣ re-enable submit button
$('#nhance_branch_id').val(null).trigger('change.select2');
$('#rm_id').val(null).trigger('change.select2');
$('#team').multiselect('deselectAll', false);
$('#team').multiselect('refresh');
// remove data-original attributes
$('#email').removeAttr('data-original');
$('#mobile').removeAttr('data-original');
$('#emp_code').removeAttr('data-original');
$('.modal-title').text('Add User');
$('#btnSubmit').text('Submit');
$('#UserForm').attr('action', '<?php echo base_url('/user/create');?>');
var myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
myModal.show();
});
// $(document).on('click', '#btnAdd', function(){
// $('#first_name').val('');
// $('#last_name').val('');
// $('#email').val('');
// $('#mobile').val('');
// $('#emp_code').val('');
// $('#nhance_branch_id').val('0');
// $('#rm_id').val('0');
// $('#UserForm').attr('action', '<?php echo base_url('/user/create');?>');
// let myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
// myModal.show(); // open modal
// });
$(document).on('click', '#btnNhancePartnerAdd', function(){
$('#PartnerForm')[0].reset();
$('#PartnerForm').parsley().reset();
$('#partner_name').val('');
$('#email_addr').val('');
$('#partner_id').val('');
$('#mobile_no').val('');
// $('#locn').val('');
$('#retention_rate').val('');
$('#partner_nhance_branch_id').val('0');
$('.modal-title').html('Add Nhance Partner Manager');
$('#PartnerForm').attr('action', '<?php echo base_url('/user/partner');?>');
let myModal = new bootstrap.Modal(document.getElementById('nhance-partner-modal'));
myModal.show(); // open modal
});
function validateInput(input, table, field, submitButId){
let value = $(input).val();
let originalValue = $(input).attr('data-original');
if (originalValue && value.trim().toLowerCase() === originalValue.trim().toLowerCase()) {
$('#' + submitButId).prop('disabled', false);
return;
}
let label = $(input).closest('.form-group').find('label').text().replace('*', '').trim();
let message = "Value is duplicate!";
if(label){
message = label + " already exists!";
}
checkDuplicateTableFieldValue(table, field, value, function(isDuplicate) {
if (isDuplicate) {
toastr.warning(message, 'Warning');
$(input).focus();
// $(input).val('')
$('#' + submitButId).prop('disabled', true);
} else{
$('#' + submitButId).prop('disabled', false);
}
});
}
$('#retention_rate').on('input', function () {
let value = this.value;
// Allow only digits and dot
value = value.replace(/[^0-9.]/g, '');
// Allow only ONE dot
const parts = value.split('.');
if (parts.length > 2) {
value = parts[0] + '.' + parts.slice(1).join('');
}
// Allow max 2 decimals
if (parts[1] && parts[1].length > 2) {
value = parts[0] + '.' + parts[1].slice(0, 2);
}
this.value = value;
});
</script>