Perfex CRM Documentation
Brands module
Controllers
Brands.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Brands extends AdminController
{
public function __construct()
{
parent::__construct();
$this->load->model('brands_model');
}
public function index()
{
if ($this->input->is_ajax_request()) {
$this->app->get_table_data(module_views_path('brands', 'table'));
}
$this->load->view('index');
}
// Add/edit letter form
public function brand($id = '')
{
if ($this->input->post()) {
$data = $this->input->post();
if ($id == '') {
$this->brands_model->add($data);
set_alert('success', 'Brands added successfully');
} else {
$this->brands_model->update($data, $id);
set_alert('success','Brands updated successfully');
}
redirect(admin_url('brands'));
}
$data['brands'] = $id ? $this->brands_model->get_by_id($id) : [];
$this->load->view('manage', $data);
}
public function delete($id)
{
$this->brands_model->delete($id);
set_alert('success',' Brands deleted successfully');
redirect(admin_url('brands'));
}
}
models
Brands_model.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Brands_model extends App_Model
{
public function add($data)
{
$this->db->insert(db_prefix() . 'brands', $data);
$insert_id = $this->db->insert_id();
return $insert_id;
}
public function update($data, $id)
{
$this->db->where('id', $id);
$this->db->update(db_prefix() . 'brands', $data);
return $this->db->affected_rows();
}
public function delete($id)
{
$this->db->where('id', $id);
$this->db->delete(db_prefix() . 'brands');
return $this->db->affected_rows();
}
public function get_by_id($id)
{
return $this->db->where('id', $id)->get(db_prefix() . 'brands')->row_array();
}
}
views
index.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');>
<?php init_head(); ?>
<div id="wrapper">
<div class="content">
<div class="row">
<div class="col-md-12">
<?php if (staff_can('create', 'brands')) { ?>
<div class="tw-mb-2 sm:tw-mb-4">
<a href="<?php echo admin_url('brands/brand'); ?>" class="btn btn-primary">
<i class="fa-regular fa-plus tw-mr-1"></i>
Add Brand
</a>
</div>
<?php } ?>
<div class="panel_s">
<div class="panel-body panel-table-full">
<div class="row mbot15">
<h4 class="tw-mt-0 tw-font-semibold tw-text-lg tw-flex tw-items-center">
<span>Brands</span>
</h4>
</div>
<?php render_datatable([
'#',
"Brand/Chain Name",
"Description",
], 'brands'); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php init_tail(); ?>
<script>
$(function () {
// var table = initDataTable('.table-brands', window.location.href, [0], [0]);
var table = initDataTable('.table-brands', window.location.href,[0], [0], {},
<?php echo hooks()->apply_filters('brands_table_default_order', json_encode([1, 'asc'])); ?>);
});
</script>
manage.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');>
<?php init_head(); ?>
<div id="wrapper">
<div class="content">
<?php echo form_open_multipart($this->uri->uri_string()); ?>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel_s">
<div class="panel-body">
<h4 class="tw-mt-0 tw-font-semibold tw-text-lg tw-text-neutral-700 tw-flex tw-items-center tw-space-x-2">
<?php echo isset($brands['id']) ? 'Update New Brands' : 'Add New Brands'; ?>
</h4>
<?php echo render_input('name', 'Brand/Chain Name', $brands['name'], 'text', ['required' => true]); ?>
<div class="form-group">
<label for="description" class="control-label">Description</label>
<textarea id="description" name="description" class="form-control" rows="4"><?php echo $brands['description'] ?? '' ?></textarea>
</div>
<div class="panel-footer text-right">
<button type="submit" class="btn btn-primary">
<?php
// Check if LinkedInProfileURL exists to determine if updating or saving
echo isset($brands['id']) && !empty($brands['id'])
? _l('Update ') : _l('Save '); ?>
</button>
</div>
</div>
</div>
</div>
<?php echo form_close(); ?>
</div>
</div>
<?php init_tail(); ?>
table.php
<?php
$default_task_id = $this->ci->input->post('id');
defined('BASEPATH') or exit('No direct script access allowed');
$aColumns = [
'name',
'description'
];
$sIndexColumn = 'id';
$sTable = db_prefix() . 'brands';
$where = [];
$result = data_tables_init($aColumns, $sIndexColumn, $sTable, [], $where, ['id']);
$output = $result['output'];
$rResult = $result['rResult'];
$rowNumber = 1;
foreach ($rResult as $key => $aRow) {
$row = [];
// Prepare the task name with options
$name = $aRow['name'];
$name = ' <a href="' . admin_url('brands/brand/' . $aRow['id']) . '">' . $aRow['name'] . ' </a>';
$name .= ' <div class="row-options">';
if (staff_can('edit', 'brands')) {
$name .= ' <a href="' . admin_url('brands/brand/' . $aRow['id']) . '">' . _l('edit') . ' </a>';
}
if (staff_can('delete', 'brands')) {
$name .= ' | <a href="' . admin_url('brands/delete/' . $aRow['id']) . '" class="text-danger _delete">' . _l('delete') . ' </a>';
}
$name .= ' </div>';
// Add the prepared data to the row
$row[] = $rowNumber++;
$row[] = $name;
$row[] = $aRow['description'];
$row['DT_RowClass'] = 'has-row-options';
$output['aaData'][] = $row;
}
brands.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/*
Module Name: Brands
Description: Brands module
Version: 1.0.2
Requires at least: 2.3.*
Author: CodingBandar
Author URI: https://codingbandar.com
*/
define('BRANDS_MODULE_NAME', 'brands');
hooks()->add_action('admin_init', 'add_brands_menu');
function add_brands_menu()
{
$CI = &get_instance();
if (has_permission('brands', '', 'view')) {
$CI->app_menu->add_sidebar_children_item('opportunity_parent', [
'slug' => 'brands',
'name' => _l('Brands'),
'href' => admin_url('brands'),
'position' => 2,
'icon' => '',
]);
}
}
hooks()->add_action('register_activation_hook', 'brands_activation_hook');
function brands_activation_hook()
{
require_once(__DIR__ . '/install.php');
}
hooks()->add_action('admin_init', 'register_brands_permissions');
function register_brands_permissions()
{
// Opportunity permissions
$capabilities = [
'capabilities' => [
'view' => _l('permission_view') . ' (' . _l('permission_global') . ')',
'create' => _l('permission_create'),
'edit' => _l('permission_edit'),
'delete' => _l('permission_delete'),
],
];
register_staff_capabilities('brands', $capabilities, _l('Brands'));
}
install.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
$CI = &get_instance();
if (!$CI->db->table_exists(db_prefix() . 'brands')) {
$CI->db->query('CREATE TABLE ' . db_prefix() . "brands (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
description text DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=" . $CI->db->char_set . ';');
}
Filters
For index.php (view table) , put in <div class="panel-body panel-table-full"></div> division
<div class="_filters _hidden_inputs">
<div
class="col-md-2 col-xs-6 md:tw-border-r md:tw-border-solid md:tw-border-neutral-300 last:tw-border-r-0">
<a href="#" id="awaiting_dgm_confirmation"
class="tw-text-neutral-600 hover:tw-opacity-70 tw-inline-flex tw-items-center"><span
class="tw-font-semibold tw-mr-3 rtl:tw-ml-3 tw-text-lg"> <?php echo $awaiting_dgm_confirmation; ?> </span><span
class="project-status-#475569" style="color: rgb(71, 85, 105);"> Awaiting DGM Confirmation
</span></a>
</div>
<div
class="col-md-2 col-xs-6 md:tw-border-r md:tw-border-solid md:tw-border-neutral-300 last:tw-border-r-0">
<a href="#" id="in_process"
class="tw-text-neutral-600 hover:tw-opacity-70 tw-inline-flex tw-items-center"><span
class="tw-font-semibold tw-mr-3 rtl:tw-ml-3 tw-text-lg"> <?php echo $in_process; ?> </span><span
class="project-status-#2563eb" style="color: rgb(37, 99, 235);"> In Process
</span><a>
</div>
<div
class="col-md-2 col-xs-6 md:tw-border-r md:tw-border-solid md:tw-border-neutral-300 last:tw-border-r-0">
<a href="#" id="internal_dgm_investigation"
class="tw-text-neutral-600 hover:tw-opacity-70 tw-inline-flex tw-items-center"><span
class="tw-font-semibold tw-mr-3 rtl:tw-ml-3 tw-text-lg"> <?php echo $internal_dgm_investigation; ?> </span><span
class="project-status-#f97316" style="color: rgb(249, 115, 22);"> Internal DGM Investigation
</span></a>
</div>
<div
class="col-md-2 col-xs-6 md:tw-border-r md:tw-border-solid md:tw-border-neutral-300 last:tw-border-r-0">
<a href="#" id="ready_for_retrieval"
class="tw-text-neutral-600 hover:tw-opacity-70 tw-inline-flex tw-items-center"><span
class="tw-font-semibold tw-mr-3 rtl:tw-ml-3 tw-text-lg"> <?php echo $ready_for_retrieval; ?> </span><span
class="project-status-#94a3b8" style="color: rgb(148, 163, 184);"> Ready for Retrieval
</span></a>
</div>
<div>
Script for filter
<script>
$(function() {
passport_tracking_kanban();
var urlParams = new URLSearchParams(window.location.search);
var statusFilter = urlParams.get('status');
var table = initDataTable('.table-passports', window.location.href, [0], [0], {},
<?php echo hooks()->apply_filters('passports_table_default_order', json_encode([1, 'asc'])); ?>);
$('#awaiting_dgm_confirmation').on("click", function() {
var AwaitingDGMConfirmation = 1;
table.settings()[0].ajax.data = function(d) {
d.awaiting_dgm_confirmation = AwaitingDGMConfirmation;
};
table.ajax.reload();
});
$('#in_process').on("click", function() {
var InProcess = 2;
table.settings()[0].ajax.data = function(d) {
d.in_process = InProcess;
};
table.ajax.reload();
});
$('#internal_dgm_investigation').on("click", function() {
var InternalDGMInvestigation = 3;
table.settings()[0].ajax.data = function(d) {
d.internal_dgm_investigation = InternalDGMInvestigation;
};
table.ajax.reload();
});
$('#ready_for_retrieval').on("click", function() {
var ReadyForRetrieval = 4;
table.settings()[0].ajax.data = function(d) {
d.ready_for_retrieval = ReadyForRetrieval;
};
table.ajax.reload();
});
});
</script>
Controller index function
public function index()
{
if ($this->input->is_ajax_request()) {
$data = $this->app->get_table_data(module_views_path('passport_tracking', 'table'));
}
$data['awaiting_dgm_confirmation'] = $this->Passports_model->get_status_count(1);
$data['in_process'] = $this->Passports_model->get_status_count(2);
$data['internal_dgm_investigation'] = $this->Passports_model->get_status_count(3);
$data['ready_for_retrieval'] = $this->Passports_model->get_status_count(4);
$this->load->view('index', $data);
}
Model function to count the status
public function get_status_count($status)
{
$this->db->where('statut', $status);
return $this->db->count_all_results('tblpassports_tracking');
}
Bulk Action (mass delete)
write it in index.php (table view) file
<a href="#" data-toggle="modal" data-target="#passport_bulk_action" class="bulk-actions-btn table-btn hide"
data-table=".table-passports"><?php echo _l('bulk_actions'); ?></a>
<div class="modal fade bulk_actions" id="passport_bulk_action" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title"><?php echo _l('bulk_actions'); ?></h4>
</div>
<div class="modal-body">
<div class="checkbox checkbox-danger">
<input type="checkbox" name="mass_delete" id="mass_delete">
<label for="mass_delete"><?php echo _l('mass_delete'); ?></label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal"><?php echo _l('close'); ?></button>
<a href="#" class="btn btn-primary"
onclick="passport_bulk_action(this); return false;"><?php echo _l('confirm'); ?></a>
</div>
</div>
</div>
</div>
write it in table for checkbox
'<span class="hide"> - </span><div class="checkbox mass_select_all_wrap"><input type="checkbox" id="mass_select_all" data-to-table="passports"><label></label></div>',
modify the foreach loop for check boxes in each row (table.php view file)
foreach ($rResult as $key => $aRow) {
$row = [];
$row[] = '<div class="checkbox"><input type="checkbox" value="' . $aRow['id'] . '"><label></label></div>';
write script in index.php (table view) file
<script>
var table = initDataTable('.table-passports', window.location.href, [0], [0], {},
<?php echo hooks()->apply_filters('passports_table_default_order', json_encode([1, 'asc'])); ?>);
function passport_bulk_action(event) {
var r = confirm(app.lang.confirm_action_prompt);
if (r == false) {
return false;
} else {
var mass_delete = $('#mass_delete').prop('checked');
var ids = [];
var data = {};
if (mass_delete == true) {
data.mass_delete = true;
}
var rows = $('.table-passports').find('tbody tr');
$.each(rows, function() {
var checkbox = $($(this).find('td').eq(0)).find('input');
if (checkbox.prop('checked') == true) {
ids.push(checkbox.val());
}
});
data.ids = ids;
$(event).addClass('disabled');
setTimeout(function() {
$.post(admin_url + 'passport_tracking/bulk_action', data).done(function() {
window.location.reload();
});
}, 50);
}
}
</script>
Controller function
public function bulk_action()
{
hooks()->do_action('before_do_bulk_action_for_passport');
$total_deleted = 0;
if ($this->input->post()) {
$ids = $this->input->post('ids');
if (is_array($ids)) {
foreach ($ids as $id) {
if ($this->input->post('mass_delete')) {
if ($this->Passports_model->delete($id)) {
$total_deleted++;
}
}
}
}
}
if ($this->input->post('mass_delete')) {
// set_alert('success', _l('total_clients_deleted', $total_deleted));
set_alert('success', ucfirst($type) . ' Passports Tracking deleted successfully', $total_deleted);
}
}
Kanban View
index.php (view file)
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php init_head(); ?>
<div id="wrapper">
<div class="content">
<div class="row">
<div class="col-md-12">
<?php if (staff_can('create', 'passports_tracking')) { ?>
<div class="tw-mb-2 sm:tw-mb-4">
<a href="<?php echo admin_url('passport_tracking/passportsTracking'); ?>" class="btn btn-primary mright10 pull-left tw-mb-4">
<i class="fa-regular fa-plus tw-mr-1"></i>
<?php echo _l('create_passport'); ?>
</a>
<a href="<?php echo admin_url('passport_tracking/switch_kanban/' . $switch_kanban); ?>"
class="btn btn-default mright10 pull-left hidden-xs"
data-toggle="tooltip"
data-placement="top"
data-title="<?php echo $switch_kanban == 1 ? _l('switch_to_list_view') : _l('leads_switch_to_kanban'); ?>">
<i class="<?php echo $switch_kanban == 1 ? 'fa-solid fa-table-list' : 'fa-solid fa-grip-vertical'; ?>"></i>
</a>
<div class="clearfix"></div>
</div>
<?php } ?>
<?php if ($this->session->has_userdata('passport_kanban_view') && $this->session->userdata('passport_kanban_view') == 'true') { ?>
<div class="kan-ban-tab" id="kan-ban-tab" style="overflow:auto;">
<div class="row">
<div id="kanban-params">
<?php echo form_hidden('project_id', $this->input->get('project_id')); ?>
</div>
<div class="container-fluid">
<div id="kan-ban"></div>
</div>
</div>
</div>
<?php } else { ?>
<div class="panel_s">
<div class="panel-body panel-table-full">
<div class="row mbot15">
<div class="col-md-12">
<h4 class="tw-mt-0 tw-font-semibold tw-text-lg tw-flex tw-items-center"><svg
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor"
class="tw-w-5 tw-h-5 tw-text-neutral-500 tw-mr-1.5">
<path stroke-linecap="round" stroke-linejoin="round"
d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z">
</path>
</svg><span> Passport Tracking </span></h4>
</div>
</div>
<?php
render_datatable([
'#',
_l('holder_name'),
_l('nationality'),
_l('passport_number'),
_l('last_update'),
_l('status'),
], 'passports');
?>
</div>
</div>
<?php } ?>
</div>
</div>
</div>
</div>
<?php init_tail(); ?>
script for index.php
<script>
$(function () {
passport_tracking_kanban();
var table = initDataTable('.table-passports', window.location.href, [0], [0], {},
<? php echo hooks() -> apply_filters('passports_table_default_order', json_encode([1, 'asc'])); ?>);
function passport_tracking_kanban() {
init_kanban(
"passport_tracking/kanban",
passport_tracking_kanban_update,
".tasks-status",
240,
360
);
}
function passport_tracking_kanban_update(ui, object) {
if (object === ui.item.parent()[0]) {
var status = $(ui.item.parent()[0]).attr("data-task-status-id");
var id = $(ui.item).attr("data-passport-tracking-id");
var data = {
status: status,
id: $(ui.item).attr("data-passport-tracking-id")
};
setTimeout(function () {
$.post(admin_url + "passport_tracking/update_order", data).done(function () {
passport_tracking_kanban();
});
}, 200);
}
}
</script>
Controller functions
public function index()
{
if ($this->input->is_ajax_request()) {
$data = $this->app->get_table_data(module_views_path('passport_tracking', 'table'));
}
if ($this->input->get('kanban')) {
$this->switch_kanban(0, true);
}
$data['switch_kanban'] = false;
$data['bodyclass'] = 'tasks-page';
if ($this->session->userdata('passport_kanban_view') == 'true') {
$data['switch_kanban'] = true;
$data['bodyclass'] = 'kan-ban-body';
}
$this->load->view('index', $data);
}
public function switch_kanban($set = 0, $manual = false)
{
if ($set == 1) {
$set = 'false';
} else {
$set = 'true';
}
$this->session->set_userdata([
'passport_kanban_view' => $set,
]);
if ($manual == false) {
redirect(previous_url() ?: $_SERVER['HTTP_REFERER']);
}
}
public function kanban()
{
echo $this->load->view('kan_ban', [], true);
}
public function update_order()
{
$this->Passports_model->update_order($this->input->post());
}
public function passport_kanban_load_more()
{
$status = $this->input->get('status_id'); // Get the status name
$page = (int) $this->input->get('page'); // Get the page number (cast to integer for safety)
$limit = 25; // Define the number of records per page
$offset = ($page - 1) * $limit; // Calculate the offset
// Fetch opportunities with limit and offset
$this->db->select('nom_titulaire, nationalite, numero_passeport, id');
$this->db->where('statut', $status);
$this->db->limit($limit, $offset); // Apply limit and offset
$passport = $this->db->get('tblpassports_tracking')->result_array();
// echo json_encode($status); die;
// Render each opportunity as a Kanban card
foreach ($passport as $list) {
$this->load->view('_kan_ban_card', [
'task' => $list,
'status' => $status,
]);
}
}
model function
public function upd`ate_order($data)
{
$updateData = [
'statut' => $data['status'],
];
// Perform the update query
$this->db->where('id', $data['id']);
$this->db->update('tblpassports_tracking', $updateData);
return true; // Return true if rows were updated
}
`
View file
kan_ban.php
<?php defined('BASEPATH') or exit('No direct script access allowed');
$where = [];
if ($this->input->get('project_id')) {
$where['rel_id'] = $this->input->get('project_id');
$where['rel_type'] = 'project';
}
$data = [
["id" => 1, "color" => "#0848a1", "name" => "Awaiting DGM Confirmation", "order" => 1, "filter_default" => true],
["id" => 2, "color" => "#096c85", "name" => "In Process", "order" => 2, "filter_default" => true],
["id" => 3, "color" => "#1579a3", "name" => "Internal DGM Investigation", "order" => 3, "filter_default" => true],
["id" => 4, "color" => "#15a350", "name" => "Ready for Retrieval", "order" => 4, "filter_default" => true],
["id" => 5, "color" => "#78a315", "name" => "Retrieved", "order" => 5, "filter_default" => true],
["id" => 6, "color" => "#a6820d", "name" => "Canceled/Replaced", "order" => 6, "filter_default" => true],
];
foreach ($data as $status) {
$this->db->select('nom_titulaire, nationalite, numero_passeport, id');
$this->db->where('statut', $status['id']);
$totalpassports = $this->db->get('tblpassports_tracking')->result_array();
$this->db->select('nom_titulaire, nationalite, numero_passeport, id');
$this->db->where('statut', $status['id']);
$this->db->limit(25);
$passports = $this->db->get('tblpassports_tracking')->result_array();
$total_passport = count($totalpassports);
$total_pages = $total_passport / 25;
// $total_pages = 2;
?>
<ul class="kan-ban-col tasks-kanban" data-col-status-name="<?php echo $status['id']; ?>"
data-total-pages="<?php echo $total_pages; ?>" data-total="<?php echo $total_passport; ?>">
<li class="kan-ban-col-wrapper">
<div class="border-right panel_s">
<div class="panel-heading"
style="background:<?php echo e($status['color']); ?>;border-color:<?php echo e($status['color']); ?>;color:#fff; ?>"
data-status-id="<?php echo e($status['id']); ?>">
<?php echo $status['name']; ?> -
<span class="tw-text-sm">
(<?php echo $total_passport; ?>)
</span>
</div>
<div class="kan-ban-content-wrapper">
<div class="kan-ban-content">
<ul class="status tasks-status sortable relative" data-task-status-id="<?php echo e($status['id']); ?>">
<?php
foreach ($passports as $passport) {
$this->load->view('_kan_ban_card', ['task' => $passport, 'status' => $status['id']]);
}
?>
<?php if ($total_passport > 0) { ?>
<li class="text-center not-sortable kanban-load-more" data-load-status="<?php echo e($status['id']); ?>">
<a href="#" class="btn btn-default btn-block<?php if ($total_pages <= 1 || 1 == $total_pages) {
echo ' disabled';
} ?>" data-page="1"
onclick="passport_kanban_load_more('<?php echo $status['id']; ?>',this,'passport_tracking/passport_kanban_load_more',265,360); return false;"
;><?php echo _l('</a>
</li>
<?php } ?>
<li class="text-center not-sortable mtop30 kanban-empty-<?php if ($total_passport > 0) {
echo ' hide';
} ?>">
<h4>
<i class="fa-solid fa-circle-notch" aria-hidden="true"></i><br /><br />
<?php echo _l('no Passport found'); ?>
</h4>
</li>
</ul>
</div>
</div>
</li>
</ul>
<?php } ?>
<script>
// Fixes kanban height to be compatible with content and screen height
function passport_kanban_load_more(status_id, e, url, column_px, container_px) {
var LoadMoreParameters = [];
var search = $('input[name="search"]').val();
var _kanban_param_val;
var page = $(e).attr("data-page");
var $column = $('[data-col-status-name="' + status_id + '"]'); // Updated to use status_name
var total_pages = $column.data("total-pages");
if (page <= total_pages) {
var sort_type = $('input[name="sort_type"]');
var sort = $('input[name="sort"]').val();
if (sort_type.length != 0 && sort_type.val() !== "") {
LoadMoreParameters["sort_by"] = sort_type.val();
LoadMoreParameters["sort"] = sort;
}
if (typeof search != "undefined" && search !== "") {
LoadMoreParameters["search"] = search;
}
$.each($("#kanban-params input"), function() {
if ($(this).attr("type") == "checkbox") {
_kanban_param_val =
$(this).prop("checked") === true ? $(this).val() : "";
} else {
_kanban_param_val = $(this).val();
}
if (_kanban_param_val !== "") {
LoadMoreParameters[$(this).attr("name")] = _kanban_param_val;
}
});
LoadMoreParameters["status_id"] = status_id; // Updated to use status_name
LoadMoreParameters["page"] = page;
LoadMoreParameters["page"]++;
requestGet(buildUrl(admin_url + url, LoadMoreParameters))
.done(function(response) {
page++;
$('[data-load-status="' + status_id + '"]').before(response); // Updated to use status_name
$('[data-col-status-name="' + status_id + '"]').attr( // Updated to use status_name
"data-total",
parseInt(
$('[data-col-status-name="' + status_id + '"]').attr("data-total")
) + $("
").append(response).find("li").length
);
$(e).attr("data-page", page);
fix_kanban_height(column_px, container_px);
})
.fail(function(error) {
alert_float("danger", error.responseText);
});
if (page >= total_pages - 1) {
$(e).addClass("disabled");
}
}
}
</script>
_kan_ban_card.php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<li data-passport-tracking-id="<?php echo $task['id']; ?>">
<div class="panel-body" style="border-top: 2px solid #03a9f4; padding: 15px;">
<div class="row">
<div class="col-md-12 task-name">
<a href="<?php echo admin_url('passport_tracking/passportsTracking/' . $task['id']); ?>"
style="color: #000; font-weight: bold; text-decoration: none;">
<span class="inline-block full-width mtop10 tw-truncate">
<?php echo $task['nom_titulaire']; ?>
</span>
</a>
<p class="passport-info m-0 tw-truncate" style="color: #555; font-weight: normal; margin-top: 5px;">
<strong>Nationality:</strong> <?php echo htmlspecialchars($task['nationalite']); ?><br>
<strong>Passport Number:</strong> <?php echo htmlspecialchars($task['numero_passeport']); ?>
</p>
</div>
</div>
</div>
</li>
Email Template
install.php (database installation file)
$existing_template = $CI->db->get_where(db_prefix() .'emailtemplates', ['slug' => 'new_funds_request_openby_email_template'])->row();
if (!$existing_template) {
$CI->db->query('INSERT INTO ' . db_prefix() . "emailtemplates (`type`, `slug`, `language`, `name`, `subject`, `message`,`active`) VALUES
('funds_request', 'new_funds_request_openby_email_template', 'english', 'New Funds Request Opened (Opened by Staff, Sent to Consultant)', 'Hello', 'Hi Consultant {created_by}, thank you for submitting your question. We appreciate your patience and will get back to you with a response shortly.
','1');");
}
$langCheckings = get_option('email_templates_language_checks');
if ($langCheckings == '') {
$langCheckings = [];
} else {
$langCheckings = unserialize($langCheckings);
}
$CI->db->where('language', 'english');
$CI->db->where('type', 'funds_request');
$email_templates_english = $CI->db->get(db_prefix() . 'emailtemplates')->result_array();
foreach ($CI->app->get_available_languages() as $avLanguage) {
if ($avLanguage != 'english') {
foreach ($email_templates_english as $template) {
// if (isset($langCheckings[$template['slug'] . '-' . $avLanguage])) {
// continue;
// }
$notExists = total_rows(db_prefix() . 'emailtemplates', [
'slug' => $template['slug'],
'language' => $avLanguage,
]) == 0;
$langCheckings[$template['slug'] . '-' . $avLanguage] = 1;
if ($notExists) {
$data = [];
$data['slug'] = $template['slug'];
$data['type'] = $template['type'];
$data['language'] = $avLanguage;
$data['name'] = $template['name'] . ' [' . $avLanguage . ']';
$data['subject'] = $template['subject'];
$data['message'] = '';
$data['fromname'] = $template['fromname'];
$data['plaintext'] = $template['plaintext'];
$data['active'] = $template['active'];
$data['order'] = $template['order'];
$CI->db->insert(db_prefix() . 'emailtemplates', $data);
}
}
}
}
brands.php (Module installation main file)
// EMAIL TEMPLATE INSTALLATION....
register_activation_hook(FUNDS_REQUEST_MODULE_NAME, 'funds_request_module_activation_hook');
function funds_request_module_activation_hook()
{
$CI = &get_instance();
require_once(__DIR__ . '/install.php');
}
Note: After insert query code in install.php , again active the module from website.....
Create controller, model, view files for email template view
view files...
emailtemplate/form.php
<div id="wrapper">
<div class="content">
<div class="panel-body">
<div class="row">
<div class="col-md-12">
<h4 class="tw-font-semibold email-template-heading">Email Template</h4>
<div class="table-responsive">
<?php foreach ($grouped_templates as $language => $templates) { ?>
<table class="table table-bordered">
<thead>
<tr>
<th><span class="tw-font-semibold"><?php echo ucfirst($language); ?> Template</span></th>
</tr>
</thead>
<tbody>
<?php foreach ($templates as $template) { ?>
<tr>
<td class="<?php echo $template->active == 1 ? '' : 'text-throught'; ?>">
<a href="<?php echo admin_url('marketplace/email_template/edit/' . $template->emailtemplateid); ?>">
<?php echo $template->name; ?>
</a>
<?php if ($template->active == 1) { ?>
<a href="<?php echo admin_url('marketplace/email_template/handleStatus/0/' . $template->emailtemplateid); ?>" class="pull-right">
<small>Disable</small>
</a>
<?php } else { ?>
<a href="<?php echo admin_url('marketplace/email_template/handleStatus/1/' . $template->emailtemplateid); ?>" class="pull-right">
<small>Enable</small>
</a>
<?php } ?>
</td>
</tr>
<?php } ?>
</tbody>
</table>
<?php } ?>
</div>
</div>
</div>
</div>
</div>
</div>
<?php init_tail(); ?>
<script>
appValidateForm('#email-message-form', {
'subject': 'required',
'description': 'required',
});
appValidateForm('#notifition-message-form', {
'message': 'required',
});
</script>
emailtemplate/edit.php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php init_head(); ?>
<div id="wrapper" style="min-height: 3949px;">
<div class="content">
<div class="row">
<div class="col-md-6">
<h4 class="tw-mt-0 tw-font-semibold tw-text-lg tw-text-neutral-700">
<?php echo $email_template->name; ?>
</h4>
<div class="panel_s">
<div class="panel-body">
<?php echo form_open_multipart('marketplace/email_template/index', ['id' => 'email-message-form', 'novalidate' => true]); ?>
<input type="hidden" name="<?php echo $this->security->get_csrf_token_name(); ?>"
value="<?php echo $this->security->get_csrf_hash(); ?>">
<div class="row">
<div class="col-md-12">
<div class="form-group" app-field-wrapper="name">
<label for="name" class="control-label">
<small class="req text-danger">*</small> Template Title
</label>
<input type="text" id="name" name="name" class="form-control" disabled="1"
value="<?php echo $email_template->name; ?>">
<?php echo render_input('emailtemplateid', '', $email_template->emailtemplateid, 'hidden'); ?>
</div>
<div class="form-group" app-field-wrapper="subject">
<?php echo render_input('subject', 'Subject', $email_template->subject, 'text'); ?>
</div>
<div class="form-group" app-field-wrapper="email_message">
<?php echo render_textarea('message', 'Message', $email_template->message, [], [], '', 'tinymce'); ?>
</div>
<div class="btn-bottom-toolbar text-right">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</div>
<?php echo form_close(); ?>
</div>
</div>
</div>
<div class="col-md-6 lg:tw-sticky lg:tw-top-2">
<h4 class="tw-mt-0 tw-font-semibold tw-text-lg tw-text-neutral-700">
Available merge fields
</h4>
<div class="panel_s">
<div class="panel-body">
<div class="row">
<div class="col-md-12">
<div class="row available_merge_fields_container">
<div class="col-md-12 merge_fields_col">
<?php if ($email_template->slug == 'new-offer-come-to-the-market-email-template') { ?>
<h5 class="bold tw-text-base tw-rounded-lg tw-bg-neutral-50 tw-py-2 tw-px-3">Offer</h5>
<p>Market <span class="pull-right">
<a href="#" class="add_merge_field" data-field="{market}">{market}</a>
</span></p>
<p>Category <span class="pull-right">
<a href="#" class="add_merge_field" data-field="{category}">{category}</a>
</span></p>
<?php } ?>
</div>
<div class="col-md-12 merge_fields_col">
<h5 class="bold tw-text-base tw-rounded-lg tw-bg-neutral-50 tw-py-2 tw-px-3">Others</h5>
<p>Date <span class="pull-right">
<a href="#" class="add_merge_field" data-field="{date}">{date}</a>
</span></p>
<p>Link <span class="pull-right">
<a href="#" class="add_merge_field" data-field="{link}">{link}</a>
</span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-bottom-pusher"></div>
</div>
</div>
<?php init_tail(); ?>
<script>
appValidateForm('#email-message-form', {
'subject': 'required',
'message': 'required',
});
document.querySelectorAll('.add_merge_field').forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
const field = this.getAttribute('data-field');
const textarea = tinymce.get('message');
if (textarea) {
textarea.execCommand('mceInsertContent', false, field);
} else {
const plainTextarea = document.getElementById('message');
if (plainTextarea) {
const start = plainTextarea.selectionStart;
const end = plainTextarea.selectionEnd;
const text = plainTextarea.value;
plainTextarea.value = text.substring(0, start) + field + text.substring(end);
}
}
});
});
</script>
</body>
</html>
Controller
emailtemplate.php
class Email_template extends AdminController
{
public function __construct()
{
parent::__construct();
$this->load->model('Email_template_model');
}
public function index()
{
if ($this->input->post()) {
$postData = $this->input->post();
$id = $this->input->post('emailtemplateid');
$this->Email_template_model->update($postData, $id);
set_alert('success', ' Email Template update successfully');
redirect(admin_url('marketplace/email_template'));
}
// $data['email_template'] =$this->Email_template_model->getEmailTemplate();
$email_templates = $this->Email_template_model->getEmailTemplate(); // Fetch all templates
$grouped_templates = [];
foreach ($email_templates as $template) {
$grouped_templates[$template->language][] = $template;
}
$data['grouped_templates'] = $grouped_templates;
$data['title'] = _l('Email Template');
// echo json_encode($data['grouped_templates']); die;
$this->load->view('email_template/form', $data);
}
public function handleStatus($status,$id){
$this->Email_template_model->handleStatus($status,$id);
set_alert('success', ' Email Template Status Change Successfully');
redirect(admin_url('marketplace/email_template'));
}
public function edit($id){
$data['email_template'] =$this->Email_template_model->getTemplateById($id);
$this->load->view('email_template/edit', $data);
}
}
model
emailtemplate_model.php
class Email_template_model extends App_Model
{
public function update($data, $id)
{
$this->db->where('emailtemplateid', $id);
$this->db->update('tblemailtemplates', $data);
return $this->db->affected_rows();
}
public function getEmailTemplate()
{
$this->db->where('type', 'new_offer_request');
$this->db->or_where('type', 'new_request');
$this->db->or_where('type', 'offer_in_interested_client');
$this->db->or_where('type', 'new_offer');
$this->db->or_where('type', 'request_in_interested_client');
// $this->db->group_by('language');
return $this->db->get('tblemailtemplates')->result();
}
public function handleStatus($status,$id){
$data = [
'active' => $status
];
$this->db->where('emailtemplateid', $id);
$this->db->update('tblemailtemplates', $data);
}
public function getTemplateById($id)
{
$this->db->where('emailtemplateid', $id);
return $this->db->get('tblemailtemplates')->row();
}
}
Send Email
Module Main File In Add Code
hooks()->add_action('after_offer_status_change_email_send', 'new_offer_email_template');
function new_offer_email_template($data) {
$ci =& get_instance(); // Get the CI instance
$ci->load->model('emails_model'); // Load the email model
$ci->load->model('Offers_model');
// Ensure 'id' exists in the provided data
if (!isset($data['id'])) {
return false; // Exit if no ID is provided
}
$id = $data['id'];
// Get offer details with necessary joins
$ci->db->select('offers.*, categories.name as category_name, countries.short_name as country_name, staff.firstname as staff_firstname, staff.lastname as staff_lastname');
$ci->db->from(db_prefix() . 'offers');
$ci->db->join(db_prefix() . 'categories', 'categories.id = offers.category_id', 'left');
$ci->db->join(db_prefix() . 'countries', 'countries.country_id = offers.country', 'left');
$ci->db->join(db_prefix() . 'staff', 'staff.staffid = offers.created_by', 'left'); // Assuming staff data is related to offers
$ci->db->where('offers.deleted_at', null);
$ci->db->where('offers.email_send', 0);
$ci->db->where('offers.id', $id);
$query = $ci->db->get();
$data_row = $query->row();
if (!$data_row) {
return false; // Exit if no offer is found
}
// Get selected staff IDs from marketplace_setting
$ci->db->select('selected_staff');
$ci->db->from(db_prefix() . 'marketplace_setting');
$query = $ci->db->get();
$staff_data = $query->result_array();
// Extract and decode JSON staff IDs
$staff_ids = [];
foreach ($staff_data as $row) {
$decoded_ids = json_decode($row['selected_staff'], true); // Decode JSON
if (is_array($decoded_ids)) {
$staff_ids = array_merge($staff_ids, $decoded_ids);
}
}
// Remove duplicates and ensure valid IDs
$staff_ids = array_unique(array_filter($staff_ids));
if (empty($staff_ids)) {
return false; // No valid staff IDs found
}
// Fetch all staff emails from the staff table
$ci->db->select('staff.email');
$ci->db->from(db_prefix() . 'staff');
$ci->db->where_in('staff.staffid', $staff_ids);
$query = $ci->db->get();
$result = $query->result_array();
// Extract emails into an array
$recipient_emails = array_column($result, 'email');
if (!empty($recipient_emails)) {
// Define the email template slug
$template_slug = 'new-offer-come-to-the-market-email-template';
if($data_row->market == 1){
$market = 'Civil';
}
else if($data_row->market == 2){
$market = 'Police & Law Enforcement';
}
else{
$market = 'Military';
}
$merge_fields = array(
'{market}' => $market,
'{category}' => $data_row->category_name,
'{subject}' => $data_row->subject,
'{expire_date}' => $data_row->expire_date,
'{youtube_link}' => $data_row->youtube_link,
'{country}' => $data_row->country_name,
'{price}' => $data_row->min_price,
'{max_price}' => $data_row->max_price,
'{date}' => date('d-m-Y'),
'{created_by}' => $data_row->staff_firstname . ' ' . $data_row->staff_lastname,
'{link}' => admin_url('marketplace/offers/offer/' . $id),
);
// Loop through each recipient and send the email
foreach ($recipient_emails as $email) {
$ci->emails_model->send_email_template(
$template_slug,
$email, // Single email per iteration
$merge_fields
);
}
}
return true;
}
Controller In Use this hook in function
Example : $data = ['id' => $id];
hooks()->do_action('after_offer_status_change_email_send',$data);
Hooks
Show Manu Client Side Using This hoook
hooks()->add_action('customers_navigation_start', function () {
if (is_client_logged_in()) {
echo '' . _l('Requests') . ' ';
}
});
Dashboard In Show Widgets Using this hook
hooks()->add_filter('get_dashboard_widgets', 'student_add_dashboard_widget');
function student_add_dashboard_widget($widgets)
{
$widgets[] = [
'path' => STUDENT_MODULE_NAME . '/widget_view',
'container' => 'top-12',
];
return $widgets;
}
View In Create file : widget_view.php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php
$student = [];
if (is_staff_member()) {
$this->load->model('student/Student_model');
$student = $this->Student_model->get_student_statuses();
}
?>
<div class="widget relative" id="widget-student" data-name="Funds Request">
<div class="widget-dragger"></div>
<div class="row">
<?php foreach ($student as $list) { ?>
<div class="quick-stats-invoices col-xs-12 col-md-6 col-sm-6 col-lg-3 tw-mb-2 tw-mt-2 sm:tw-mb-0">
<div class="top_stats_wrapper">
<div class="tw-text-neutral-800 mtop5 tw-flex tw-items-center tw-justify-between"
style="color:<?php echo htmlspecialchars($list['color']); ?>; font-size:20px">
<div class="tw-font-medium tw-inline-flex text-neutral-600 tw-items-center tw-truncate">
<a href="<?php
if ($list['slug'] === 'teacher') {
echo admin_url('teachers');
} elseif ($list['slug'] === 'class' || $list['slug'] === 'subject') {
echo admin_url('studentclass');
} else {
echo admin_url('student?status=' . $list['slug']);
}
?>"
style="color:<?php echo htmlspecialchars($list['color']); ?>; text-decoration: none;">
<span class="tw-truncate"><?php echo htmlspecialchars($list['name']); ?></span>
</a>
</div>
<span class="tw-font-semibold tw-text-neutral-600 tw-shrink-0"
style="color:<?php echo htmlspecialchars($list['color']); ?>;">
<?php echo $this->Student_model->get_status_count($list['id'], $list['slug']); ?>
</span>
</div>
</div>
</div>
<?php } ?>
</div>
</div>