CHANGE_User + Nhance Partner

This commit is contained in:
venba-Inspriron-3558 2025-09-04 18:41:09 +05:30
parent 9682865454
commit 33581a37a5
9 changed files with 1251 additions and 97 deletions

View File

@ -73,6 +73,9 @@ $routes->group("/user", ["filter" => "authMVC"], function ($routes) {
$routes->get("deactive/(:hash)", "UserController::deactive/$1"); $routes->get("deactive/(:hash)", "UserController::deactive/$1");
$routes->get("rolesandteams", "UserController::getRolesAndTeams"); $routes->get("rolesandteams", "UserController::getRolesAndTeams");
$routes->get("getUserActivityHistory", "UserController::getUserActivityHistory"); $routes->get("getUserActivityHistory", "UserController::getUserActivityHistory");
$routes->match(['get','post','put'], 'partner', 'UserController::partner');
$routes->match(['get','post','put'], 'partnerIncentive', 'UserController::partnerIncentive');
$routes->get("download-incentive-file/(:any)", "UserController::downloadIncentivesFile/$1");
}); });
$routes->group("/dashboard", ["filter" => "authMVC"], function ($routes) { $routes->group("/dashboard", ["filter" => "authMVC"], function ($routes) {

View File

@ -18,6 +18,8 @@ use App\Models\UserTeamsModel;
use App\Helpers\BookStackUserHelper; use App\Helpers\BookStackUserHelper;
use App\Models\AuthHistoryModel; use App\Models\AuthHistoryModel;
use App\Models\UserActivityHistoryModel; use App\Models\UserActivityHistoryModel;
use App\Models\PartnerStaffModel;
use App\Models\PartnerManagerIncentiveFileModel;
class UserController extends AdminController class UserController extends AdminController
@ -32,6 +34,8 @@ class UserController extends AdminController
protected $bookStack; protected $bookStack;
protected $authHistoryModel; protected $authHistoryModel;
protected $userActivityHistoryModel; protected $userActivityHistoryModel;
protected $partnerStaffModel;
protected $partnerManagerIncentiveFileModel;
public function __construct() public function __construct()
{ {
@ -45,6 +49,8 @@ class UserController extends AdminController
$this->bookStack = new BookStackUserHelper(); $this->bookStack = new BookStackUserHelper();
$this->authHistoryModel = new AuthHistoryModel(); $this->authHistoryModel = new AuthHistoryModel();
$this->userActivityHistoryModel = new UserActivityHistoryModel(); $this->userActivityHistoryModel = new UserActivityHistoryModel();
$this->partnerStaffModel = new PartnerStaffModel();
$this->partnerManagerIncentiveFileModel = new PartnerManagerIncentiveFileModel();
} }
public function list() public function list()
@ -563,4 +569,211 @@ class UserController extends AdminController
} }
} }
public function partner()
{
$method = $this->request->getMethod(); // get, post
try{
// Listing
if ($method === 'get') {
$types = $this->partnerStaffModel->findAll();
if (empty($types)) {
return $this->response->setJSON(['status' => 'error','message' => 'No Staff found'])->setStatusCode(404);
}
return $this->response->setJSON(['status' => 'success','data' => $types])->setStatusCode(200);
}
// add/update
if ($method === 'post') {
$data = $this->request->getPost();
if (!empty($data['id'])) {
$text = "update";
$result = $this->partnerStaffModel->update($data['id'], $data);
$updateID = $data['id'];
} else {
$text = "create";
$data['role_id'] = 1;
$data['created_by'] = get_session_userid();
$insertID = $this->partnerStaffModel->insert($data);
$result = true;
}
$id = isset($insertID) && !empty($insertID) ? $insertID : ($updateID ?? null);
return $this->response->setJSON([
'status' => $id ? 'success' : 'error',
'message' => $id ? "Staff {$text}d successfully" : "Unable to {$text} staff. Please try again.",
'id' => $id
])->setStatusCode($id ? 200 : 400);
}
// delete
if ($method === 'put') {
$data = $this->request->getRawInput();
$id = $data['id'] ?? null;
if (!$id) {
return $this->response->setJSON(['status' => 'error', 'message' => 'ID is required'])->setStatusCode(400);
}
$staff = $this->partnerStaffModel->find($id);
if (!$staff) {
return $this->response->setJSON(['status' => 'error','message' => 'Staff not found'])->setStatusCode(404);
}
if ($staff['is_active'] == 1) {
$result = $this->partnerStaffModel->update($id, ['is_active' => 0]);
$message = "Staff deleted successfully";
} else {
return $this->response->setJSON(['status' => 'error','message' => 'Staff already deleted'])->setStatusCode(400);
}
return $this->response->setJSON([
'status' => $result ? 'success' : 'error',
'message' => $result ? $message : "Unable to delete staff. Please try again.",
'id' => $id
])->setStatusCode($result ? 200 : 400);
}
return $this->response->setJSON([ 'status' => 'error', 'message' => 'Invalid request method' ])->setStatusCode(405);
}
catch (\Throwable $e) {
$code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) ? $e->getCode() : 500;
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
$context = ['title' => get_class($e),'type' => get_class($e),'code' => $code,'message' => $e->getMessage(),'file' => $e->getFile(),'line' => $e->getLine()];
$this->myLogger->logme('error', "Exception: {message} in {file} on line {line}", $context, 0);
return $this->response->setJSON([ 'status' => 'error', 'message' => $isDbError ? 'Data Access Error' : $e->getMessage(),
'ref' => $isDbError ? 'database - ' : 'application - ' . $code . ' - ' . $e->getLine()
])->setStatusCode($code);
}
}
public function partnerIncentive()
{
$method = $this->request->getMethod(); // get, post
try{
// Listing
if ($method === 'get') {
$manager_id = $this->request->getGet('manager_id');
$files = $this->partnerManagerIncentiveFileModel->where('manager_id', $manager_id)->findAll();
if (empty($files)) {
return $this->response->setJSON(['status' => 'error','message' => 'No Records found'])->setStatusCode(404);
}
return $this->response->setJSON(['status' => 'success','data' => $files])->setStatusCode(200);
}
// add/update
if ($method === 'post') {
$file = $this->request->getFile('incentive_file_name');
$month = $this->request->getPost('incentive_month');
$managerId = $this->request->getPost('manager_id');
$fileId = $this->request->getPost('id');
if ($file && $file->isValid() && !$file->hasMoved()) {
$fileName = $file->getName();
$path = WRITEPATH.'uploads/incentives';
$file->move($path, $fileName);
$data = [
'manager_id' => $managerId,
'incentive_month' => date('Y-m-d', strtotime($month)),
'incentive_file_name' => $fileName,
'created_by' => get_session_userid()
];
if ($fileId) {
$text = "update";
$this->partnerManagerIncentiveFileModel->update($fileId, $data);
$updateID = $data['id'];
} else {
$text = "create";
$insertID = $this->partnerManagerIncentiveFileModel->insert($data);
$result = true;
}
$id = isset($insertID) && !empty($insertID) ? $insertID : ($updateID ?? null);
return $this->response->setJSON([
'status' => $id ? 'success' : 'error',
'message' => $id ? "File {$text}d successfully" : "Unable to {$text} file. Please try again.",
'id' => $id
])->setStatusCode($id ? 200 : 400);
}
return $this->response->setJSON([
'status' => 'error',
'message' => "Unable to Upload file. Please try again.",
'id' => ''
])->setStatusCode(400);
}
// delete
if ($method === 'put') {
$data = $this->request->getRawInput();
$id = $data['id'] ?? null;
if (!$id) {
return $this->response->setJSON(['status' => 'error', 'message' => 'ID is required'])->setStatusCode(400);
}
$files = $this->partnerManagerIncentiveFileModel->find($id);
if (!$files) {
return $this->response->setJSON(['status' => 'error','message' => 'No Records found'])->setStatusCode(404);
}
if ($files['is_active'] == 1) {
$result = $this->partnerManagerIncentiveFileModel->update($id, ['is_active' => 0]);
$message = "Files deleted successfully";
} else {
return $this->response->setJSON(['status' => 'error','message' => 'files already deleted'])->setStatusCode(400);
}
return $this->response->setJSON([
'status' => $result ? 'success' : 'error',
'message' => $result ? $message : "Unable to delete staff. Please try again.",
'id' => $id
])->setStatusCode($result ? 200 : 400);
}
return $this->response->setJSON([ 'status' => 'error', 'message' => 'Invalid request method' ])->setStatusCode(405);
}
catch (\Throwable $e) {
$code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) ? $e->getCode() : 500;
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
$context = ['title' => get_class($e),'type' => get_class($e),'code' => $code,'message' => $e->getMessage(),'file' => $e->getFile(),'line' => $e->getLine()];
$this->myLogger->logme('error', "Exception: {message} in {file} on line {line}", $context, 0);
return $this->response->setJSON([ 'status' => 'error', 'message' => $isDbError ? 'Data Access Error' : $e->getMessage(),
'ref' => $isDbError ? 'database - ' : 'application - ' . $code . ' - ' . $e->getLine()
])->setStatusCode($code);
}
}
public function downloadIncentivesFile($file_name)
{
$file_name = basename($file_name);
$filePath = WRITEPATH . 'uploads/incentives/' . $file_name;
try {
if (file_exists($filePath)) {
return $this->response->download($filePath, null);
} else {
$data['message'] = 'File Not Found';
echo view('errors/404', $data);
}
} catch (\Exception $e) {
// Handle any exceptions
$errorMessage = $e->getMessage();
$this->myLogger->logme('error', $errorMessage);
// You can return an error response here
echo $errorMessage;
}
}
} }

View File

@ -0,0 +1,56 @@
<?php
namespace App\Models;
use CodeIgniter\Model;
class PartnerManagerIncentiveFileModel extends Model
{
protected $table = 'partner_manager_incentive_file';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array'; // or 'object'
protected $useSoftDeletes = false;
protected $allowedFields = [
'manager_id',
'incentive_month',
'incentive_file_name',
'is_active',
'created_by',
'created_on',
'updated_by',
'updated_on'
];
// Timestamps
protected $useTimestamps = true;
protected $createdField = 'created_on';
protected $updatedField = 'updated_on';
protected $dateFormat = 'datetime'; // can be 'date' or 'int'
// Validation Rules (optional, can add more)
// protected $validationRules = [
// 'manager_id' => 'required|integer',
// 'incentive_month' => 'required|valid_date',
// 'incentive_file_name'=> 'required|string|max_length[150]',
// ];
// protected $validationMessages = [
// 'manager_id' => [
// 'required' => 'Manager ID is required',
// 'integer' => 'Manager ID must be a number',
// ],
// 'incentive_month' => [
// 'required' => 'Incentive Month is required',
// 'valid_date' => 'Incentive Month must be a valid date (Y-m-d)',
// ],
// 'incentive_file_name' => [
// 'required' => 'File name is required',
// 'max_length' => 'File name cannot exceed 150 characters',
// ],
// ];
// protected $skipValidation = false;
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Models;
use CodeIgniter\Model;
class PartnerStaffModel extends Model
{
protected $table = 'partner_staff'; // table name
protected $primaryKey = 'id'; // primary key
protected $useAutoIncrement = true;
// return results as array
protected $returnType = 'array';
protected $useSoftDeletes = false;
// allowed fields for insert/update
protected $allowedFields = ['name','email','mobile','emp_id','role_id','email_otp','is_active','created_by','updated_by','manager_id'];
// automatic timestamps
protected $useTimestamps = true;
protected $createdField = 'created_on';
protected $updatedField = 'updated_on';
protected $dateFormat = 'datetime';
// validation rules
// protected $validationRules = [
// 'name' => 'required|min_length[2]|max_length[150]',
// 'email' => 'permit_empty|valid_email|max_length[150]',
// 'mobile' => 'permit_empty|regex_match[/^[0-9]{10,20}$/]',
// ];
// protected $validationMessages = [
// 'name' => [
// 'required' => 'Name is required',
// 'min_length' => 'Name must have at least 2 characters',
// 'max_length' => 'Name cannot exceed 150 characters'
// ],
// 'email' => [
// 'valid_email' => 'Please provide a valid email address',
// 'max_length' => 'Email cannot exceed 150 characters'
// ],
// 'mobile' => [
// 'regex_match' => 'Mobile number must be 1020 digits only'
// ]
// ];
// protected $skipValidation = false;
}

View File

@ -42,7 +42,8 @@ table.dataTable tbody td {
padding: 20px; padding: 20px;
} }
#mobile::placeholder { #mobile::placeholder,
#mobile_no::placeholder {
font-size: 13px; font-size: 13px;
} }
@ -246,9 +247,102 @@ table.dataTable tbody td {
border:1px solid rgba(41, 139, 142, 1); border:1px solid rgba(41, 139, 142, 1);
} }
.dt-buttons.btn-group{
display: grid;
grid-template-columns: 1fr .4fr .5fr .2fr;
}
#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;
}
</style> </style>
<!-- End ADD and EDIT Page HTML --> <!-- End ADD and EDIT Page HTML -->
<div class="row" id="List-page"> <div class="row" id="List-page">
<div class="col-12"> <div class="col-12">
@ -259,7 +353,7 @@ table.dataTable tbody td {
<h4 style="position: relative;">Users</h4> <h4 style="position: relative;">Users</h4>
</div> </div>
</div> </div>
<table data-custom-table-css="table" class="table table-sm table-hover m-0 table-centered dt-responsive nowrap w-100" cellspacing="0" id="tickets-table"> <table data-custom-table-css="table" class="table table-sm table-hover m-0 table-centered dt-responsive nowrap w-100" cellspacing="1" id="user-table">
<thead class="bg-light"> <thead class="bg-light">
<tr> <tr>
<th class="font-weight-medium">Name</th> <th class="font-weight-medium">Name</th>
@ -278,7 +372,7 @@ table.dataTable tbody td {
<td><?php echo $row->mobile; ?></td> <td><?php echo $row->mobile; ?></td>
<td><?php echo $row->user_role; ?></td> <td><?php echo $row->user_role; ?></td>
<td> <td>
<span class="<?php if($row->is_active == 1){ echo 'badge badge-success'; }else{ echo 'badge badge-danger'; } ?>"> <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'; } ?> <?php if($row->is_active == 1){ echo 'Active'; }else{ echo 'In-Active'; } ?>
</span> </span>
</td> </td>
@ -296,6 +390,67 @@ table.dataTable tbody td {
</tbody> </tbody>
</table> </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="app-table-head">
<tr>
<th>Ticket ID</th>
<th class="app-text-left">Name</th>
<th>Policy Number</th>
<th>Ticket Type</th>
<th>Subject</th>
<th>Status</th>
<th class="app-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="app-text-right"><?php echo $row['thz_id']; ?></td>
<td class="app-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="app-text-center"><?php echo (!empty($row['policy_no']) && strtolower($row['policy_no']) !== 'null')
? $row['policy_no']
: 'N/A'; ?>
</td>
<td class="app-text-center"><?php echo $row['ticket_type'] ? $row['ticket_type'] : '-'; ?></td>
<td class="app-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="app-text-center"><?php echo $row['status'] ? $row['status'] : '-' ; ?></td>
<td class="app-text-left"><?php echo $row['assignee_name'] ? $row['assignee_name'] : '-'; ?></td>
<td class="app-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="app-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> </div>
</div> </div>
@ -387,6 +542,119 @@ table.dataTable tbody td {
</div> </div>
</div> </div>
</div><!-- /.modal --> </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;" 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 Nhance Partner </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">
<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="Ente Name" name="name" required>
</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" onkeypress = "return onlyNumbers(event)" 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>
</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="text" class="form-control" id="email_addr" placeholder="Enter Email" name="email" data-parsley-trigger="change" data-parsley-type="email" required>
</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="button" id="btnPartnerSubmit" onclick="submitPartner(event)">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;" data-backdrop="static">
<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>
<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 --> <!-- Tooltip container separate from trigger -->
<div class="tooltip-container" id="tooltipContainer"> <div class="tooltip-container" id="tooltipContainer">
@ -523,43 +791,129 @@ table.dataTable tbody td {
</div> </div>
<script> <script>
var table;
$(document).ready(function () { $(document).ready(function () {
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,
});
$('#tickets-table').DataTable({ table = $('#user-table').DataTable({
dom: "<'row'<'col-sm-0'f><'col-sm-9 text-right'B>>" + // Keep your original alignment for the search and buttons scrollX: true,
"<'row'<'col-sm-12'tr>>" + // Table rows dom: "<'row'<'col-sm-3'f><'col-sm-9'B>>" +
"<'row'<'col-sm-6'i><'col-sm-6'p>>", "<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
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: [ buttons: [
{ {
extend: 'csv', extend: 'csv',
text: 'CSV', text: '<i class="mdi mdi-file-delimited"></i><span class="btn-custom"> CSV </span>',
title: 'UserList', className: 'app-btn-primary'
exportOptions: {
columns: ':not(:last-child)'
}
}, },
{ {
text: 'ADD', extend: 'excel',
className: 'btn-color', text: '<i class="mdi mdi-file-excel"></i><span class="btn-custom"> EXCEL </span>',
attr: { exportOptions: { orthogonal: 'sort' },
id: 'btnAdd', className: 'app-btn-primary'
title: 'Add'
} }
]
} }
], ],
paging: true,
pageLength: 25,
language: { language: {
search: "_INPUT_", search: "_INPUT_",
searchPlaceholder: "Search..." searchPlaceholder: "Search..."
}, },
initComplete: function () {
$(".dt-buttons").prepend(`
<div class="tab-button mr-2" id="toggleButton" style="float:left;">
<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();
});
}
});
$('#team').multiselect({ $('#team').multiselect({
nonSelectedText: 'Select Team', nonSelectedText: 'Select Team',
@ -569,9 +923,6 @@ table.dataTable tbody td {
buttonWidth:'100%' buttonWidth:'100%'
}); });
$('.close').click(function(){ $('.close').click(function(){
$('#UserId').val(''); $('#UserId').val('');
$('#first_name').val(''); $('#first_name').val('');
@ -581,6 +932,17 @@ table.dataTable tbody td {
$('#role').val('') $('#role').val('')
}) })
// $('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 () { $('body').on('click', '.btnEdit', function () {
var user_id = $(this).attr('data-id'); var user_id = $(this).attr('data-id');
@ -622,7 +984,6 @@ table.dataTable tbody td {
}); });
}); });
$('body').on('click', '.btnDelete', function () { $('body').on('click', '.btnDelete', function () {
Swal.fire({ Swal.fire({
@ -645,6 +1006,68 @@ table.dataTable tbody td {
}); });
}); });
$('body').on('click', '.btnPartnerEdit', function () {
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);
// $('#btnPartnerSubmit').html('Update');
$('.modal-title').html('Update Nhance Partner');
let myModal = new bootstrap.Modal(document.getElementById('nhance-partner-modal'));
myModal.show(); // open modal
});
$('body').on('click', '.btnPartnerDelete', 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 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();
});
}); });
function onlyNumbers(event){ function onlyNumbers(event){
@ -662,6 +1085,418 @@ table.dataTable tbody td {
// document.getElementById("btnSubmit").disabled = true; // document.getElementById("btnSubmit").disabled = true;
}); });
function submitPartner(event) {
event.preventDefault();
var form = document.getElementById('PartnerForm');
var btn = document.getElementById('btnPartnerSubmit');
var myModal = new bootstrap.Modal(document.getElementById('nhance-partner-modal'));
// reset any old error styles
form.classList.remove('was-validated');
var name = document.getElementById('partner_name').value.trim();
var mobile = document.getElementById('mobile_no').value.trim();
var email = document.getElementById('email_addr').value.trim();
var address = document.getElementById('locn').value.trim();
// Validation checks
if (name === "" || mobile === "" || email === "") {
console.log(name);
console.log(mobile);
console.log(email);
toastr.warning('Please fill all required fields.', 'Warning');
form.classList.add('was-validated');
return;
}
if (address.length > 1500) {
toastr.error('Address cannot exceed 1500 characters', 'Warning');
form.classList.add('was-validated');
return;
}
var mobilePattern = /^[6-9]\d{9}$/; // must start with 69 and be 10 digits
if (!mobilePattern.test(mobile)) {
toastr.warning('Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9.', 'Warning');
document.getElementById('mobile').focus();
return;
}
var emailPattern = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
if (!emailPattern.test(email)) {
toastr.warning('Please enter a valid email address.', 'Warning');
document.getElementById('email').focus();
return;
}
// Disable button during submit
btn.disabled = true;
btn.innerText = "Saving...";
var formData = new FormData(form);
$.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');
myModal.hide();
form.reset(); // reset form after success
} else {
toastr.warning(response.message || 'Something went wrong.', 'Warning');
}
},
error: function(xhr) {
console.log("Error: " + xhr.statusText);
toastr.error('Server error occurred.', 'Error');
},
complete: function() {
btn.disabled = false;
btn.innerText = "Submit";
}
});
}
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);
toastr.error('Server error occurred.', '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 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>`
];
} else { // partner
rowData = [
row.name,
row.email,
row.mobile,
'Staff',
`<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}">
<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>`
];
}
table.row.add(rowData);
});
} 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="text-muted small">Loading...</div>`); // temporary loading msg
$.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" : "app-text-black";
let download_url = "<?= base_url('user/download-incentive-file/') ?>" + encodeURIComponent(file.incentive_file_name);
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 app-text-black" style="font-size: 24px;"></i>
</div>
<div class="ml-2">
<div class="font-weight-bold app-text-black small">${file.incentive_file_name}</div>
<div class="text-muted small">Uploaded ${uploaded}</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) {
container.html(`<div class="no-files-message">No Files have been Uploaded</div>`);
toastr.error('Server error occurred.', '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>
<script> <script>
@ -848,5 +1683,17 @@ table.dataTable tbody td {
myModal.show(); // open modal myModal.show(); // open modal
}); });
$(document).on('click', '#btnNhancePartnerAdd', function(){
$('#partner_name').val('');
$('#email').val('');
$('#partner_id').val('');
$('#mobile_no').val('');
$('#locn').val('');
$('#PartnerForm').attr('action', '<?php echo base_url('/user/partner');?>');
let myModal = new bootstrap.Modal(document.getElementById('nhance-partner-modal'));
myModal.show(); // open modal
});
</script> </script>

View File

@ -1,25 +1,4 @@
<style>
.input-icon {
position: relative;
display: block;
width: 100%;
}
.input-icon .form-control {
width: 100%;
box-sizing: border-box;
}
.input-icon .additional-icon {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
font-size: 18px;
}
</style>
<!-- modal content --> <!-- modal content -->
<div id="con-close-modal" class="modal fade app-font-family" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static"> <div id="con-close-modal" class="modal fade app-font-family" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
<div class="modal-dialog modal-dialog-centered modal-lg" <?= !isset($CD_Master_Data) ? 'style="max-width: 35% !important; margin:5px auto!important;"' : '' ?>> <div class="modal-dialog modal-dialog-centered modal-lg" <?= !isset($CD_Master_Data) ? 'style="max-width: 35% !important; margin:5px auto!important;"' : '' ?>>

View File

@ -61,37 +61,6 @@ input:checked + .slider:before {
} }
</style> </style>
<style>
.form-input-icon {
position: relative;
width: 100%; /* match Bootstrap's width */
}
.form-input-icon input[type="file"].form-control {
padding-right: 40px; /* space for the icon */
cursor: pointer;
}
.form-input-icon input[type="file"].form-control::file-selector-button {
display: none;
}
.form-input-icon .form-additional-icon {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
color: #555;
pointer-events: none;
}
input[type="radio"] {
accent-color: #40B2B6; /* sets the checked color */
}
</style>
<div class="tab-pane fade active show" id="general-q-tab"> <div class="tab-pane fade active show" id="general-q-tab">
@ -190,10 +159,10 @@ input:checked + .slider:before {
<div class="form-group row"> <div class="form-group row">
<label for="insurer_logo" class="col-md-4 col-form-label">Insurer Logo</label> <label for="insurer_logo" class="col-md-4 col-form-label">Insurer Logo</label>
<div class="col-md-5"> <div class="col-md-5">
<div class="form-input-icon"> <div class="input-icon">
<input type="file" class="form-control" id="insurer_logo" name="insurer_logo" <input type="file" class="form-control" id="insurer_logo" name="insurer_logo"
accept="image/jpeg, image/jpg, image/png" onchange="PreviewImage();"> accept="image/jpeg, image/jpg, image/png" onchange="PreviewImage();">
<i class="mdi mdi-upload form-additional-icon"></i> <i class="mdi mdi-upload additional-icon"></i>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">

View File

@ -1124,7 +1124,59 @@ a.app-badge-secondary:focus, a.app-badge-secondary.focus {
padding-top: 0px; padding-top: 0px;
padding-left: 5px; padding-left: 5px;
} }
.btn-custom {
font-weight: 500;
font-style: normal;
font-size: 12px;
line-height: 1;
letter-spacing: 0;
text-align: center;
}
</style> </style>
<style>
/* Common wrapper (works for text/file inputs) */
.input-icon {
position: relative;
display: block;
width: 100%;
}
/* All form controls inside */
.input-icon .form-control {
width: 100%;
box-sizing: border-box;
padding-right: 40px; /* always keep space for icon */
cursor: pointer;
}
/* Hide default file button */
.input-icon .form-control[type="file"]::file-selector-button {
display: none;
}
.input-icon input[type="file"].form-control {
padding-right: 40px; /* space for the icon */
cursor: pointer;
}
/* Common icon class */
.input-icon .additional-icon {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
color: #555;
pointer-events: none;
}
input[type="radio"] {
accent-color: #40B2B6; /* sets the checked color */
}
</style>
</head> </head>

View File

@ -32,21 +32,6 @@ table.dataTable td.wrap {
word-break: break-word; word-break: break-word;
} }
.btn-custom {
font-weight: 500;
font-style: normal;
font-size: 12px;
line-height: 1;
letter-spacing: 0;
text-align: center;
}
</style> </style>