feat:chat modules

This commit is contained in:
amazuecos
2024-09-25 17:42:55 +00:00
parent 2fc9af9db4
commit c651db61ff
16 changed files with 808 additions and 382 deletions

View File

@ -742,6 +742,8 @@ $routes->group('chat', ['namespace' => 'App\Controllers\Chat'], function ($route
$routes->get('department/presupuesto/(:num)/(:num)', 'ChatController::get_chat_presupuesto/$1/$2', ['as' => 'getChatPresupuesto']);
$routes->get('department/pedido/(:num)/(:num)', 'ChatController::get_chat_pedido/$1/$2', ['as' => 'getChatPedido']);
$routes->get('department/factura/(:num)/(:num)', 'ChatController::get_chat_factura/$1/$2', ['as' => 'getChatFactura']);
$routes->get('department/(:num)/users', 'ChatController::get_chat_department_users/$1', ['as' => 'getChatDepartmentUsers']);
$routes->get('(:num)', 'ChatController::get_chat/$1', ['as' => 'getChat']);
$routes->post('message/presupuesto', 'ChatController::store_chat_message_presupuesto', ['as' => 'storeChatMessagePresupuesto']);
@ -751,6 +753,8 @@ $routes->group('chat', ['namespace' => 'App\Controllers\Chat'], function ($route
$routes->get('contacts', 'ChatController::get_chat_internal_contacts', ['as' => 'getChatInternalContacts']);
$routes->get('contacts/(:num)', 'ChatController::get_chat_internal_contact/$1', ['as' => 'getChatInternalContact']);
$routes->get('contact/(:num)/messages', 'ChatController::get_chat_internal_messages/$1', ['as' => 'getChatInternalMessages']);
$routes->get('notifications', 'ChatController::get_chat_cliente/$1', ['as' => 'getChatCliente']);

View File

@ -7,6 +7,7 @@ use App\Models\Chat\ChatDeparmentModel;
use App\Models\Chat\ChatDeparmentUserModel;
use App\Models\Chat\ChatMessageModel;
use App\Models\Chat\ChatModel;
use App\Models\Clientes\ClienteModel;
use App\Models\Usuarios\UserModel;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\HTTP\RequestInterface;
@ -20,6 +21,8 @@ class ChatController extends BaseController
protected ChatModel $chatModel;
protected ChatMessageModel $chatMessageModel;
protected UserModel $userModel;
protected ClienteModel $clienteModel;
@ -36,6 +39,8 @@ class ChatController extends BaseController
$this->chatModel = model(ChatModel::class);
$this->chatMessageModel = model(ChatMessageModel::class);
$this->userModel = model(UserModel::class);
$this->clienteModel = model(ClienteModel::class);
}
public function index() {}
public function get_chat_departments()
@ -161,6 +166,9 @@ class ChatController extends BaseController
}
public function get_chat_internal_contacts()
{
if(auth()->user()->cliente_id){
return $this->response->setJSON([]);
}
$users = $this->userModel->builder()
->where("cliente_id", null)
->whereNotIn("id", [auth()->user()->id])
@ -173,6 +181,9 @@ class ChatController extends BaseController
}
public function get_chat_internal_contact(int $user_id)
{
if(auth()->user()->cliente_id){
return $this->response->setJSON([]);
}
$users = $this->userModel->builder()
->where("cliente_id", null)
->where("deleted_at", null)
@ -186,4 +197,23 @@ class ChatController extends BaseController
$conversation = $this->chatMessageModel->get_chat_contact_messages($user_id);
return $this->response->setJSON($conversation);
}
public function get_chat_cliente()
{
$cliente_id = auth()->user()->cliente_id;
$response = [];
if($cliente_id){
$data = $this->clienteModel->getClienteDataPresupuestoPedidoFactura($cliente_id);
$response["chatFacturas"] = $this->chatModel->getClienteChatFacturas($data["facturas"]);
$response["chatPresupuestos"] = $this->chatModel->getClienteChatPresupuestos($data["presupuestos"]);
$response["chatPedidos"] = $this->chatModel->getClienteChatPedidos($data["pedidos"]);
$response["data"] = $data;
}
return $this->response->setJSON($response);
}
public function get_chat_department_users(int $chat_department_id)
{
$data = $this->chatDeparmentModel->getChatDepartmentUsers($chat_department_id);
return $this->response->setJSON($data);
}
}

View File

@ -1,8 +1,8 @@
<?php namespace App\Controllers\Configuracion;
use App\Entities\Usuarios\UserEntity;
use App\Models\Chat\ChatDeparmentModel;
use App\Models\Chat\ChatDeparmentUserModel;
use App\Models\Usuarios\GroupModel;
use App\Models\UserModel;
@ -16,6 +16,9 @@ class Users extends \App\Controllers\GoBaseController
private $group_model;
private $group_user_model;
private $user_model;
private ChatDeparmentModel $chat_department_model;
private ChatDeparmentUserModel $chat_department_user_model;
use \CodeIgniter\API\ResponseTrait;
@ -38,6 +41,9 @@ class Users extends \App\Controllers\GoBaseController
$this->group_model = new GroupModel();
$this->group_user_model = new GroupsUsersModel();
$this->user_model = new UserModel();
$this->chat_department_model = model(ChatDeparmentModel::class);
$this->chat_department_user_model = model(ChatDeparmentUserModel::class);
$this->viewData['pageTitle'] = lang('Users.moduleTitle');
@ -76,7 +82,10 @@ class Users extends \App\Controllers\GoBaseController
}
// Obtener los grupos a los que pertenece
$currentGroups = $postData['group'] ?? [];
$chatDepartments = $postData['chatDepartments'] ?? [];
unset($postData['group']);
unset($postData['chatDepartments']);
// Generar el nombre de usuario
$postData['username'] = strstr($postData['email'], '@', true);
$sanitizedData = $this->sanitized($postData, true);
@ -128,6 +137,14 @@ class Users extends \App\Controllers\GoBaseController
];
$this->group_user_model->insert($group_user_data);
}
$this->chat_department_user_model->where("user_id",$id)->delete();
foreach($chatDepartments as $chatDepartment)
{
$this->chat_department_user_model->insert([
"user_id" => $id,
"chat_department_id" => $this->chat_department_model->where("name",$chatDepartment)->first()["id"]
]);
}
$message = lang('Basic.global.saveSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message = ucfirst(str_replace("'", "\'", $message));
@ -150,6 +167,7 @@ class Users extends \App\Controllers\GoBaseController
$this->viewData['clienteList'] = $this->getClienteListItems();
$this->viewData['formAction'] = route_to('createUser');
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['chatDepartments'] = $this->chat_department_model->findAll();
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.addNewSuffix');
@ -176,7 +194,10 @@ class Users extends \App\Controllers\GoBaseController
$postData = $this->request->getPost();
$currentGroups = $postData['group'] ?? [];
$chatDepartments = $postData['chatDepartments'] ?? [];
unset($postData['group']);
unset($postData['chatDepartments']);
// Obtener contraseña nueva si se ha introducido en texto plano
// Obtener contraseña nueva si se ha introducido en texto plano
@ -233,7 +254,14 @@ class Users extends \App\Controllers\GoBaseController
];
$this->group_user_model->insert($group_user_data);
}
$this->chat_department_user_model->where("user_id",$id)->delete();
foreach($chatDepartments as $chatDepartment)
{
$this->chat_department_user_model->insert([
"user_id" => $id,
"chat_department_id" => $this->chat_department_model->where("name",$chatDepartment)->first()["id"]
]);
}
$id = $user->id ?? $id;
$message = lang('Basic.global.updateSuccess', [mb_strtolower(lang('Users.user'))]) . '.';
$message = ucfirst(str_replace("'", "\'", $message));
@ -256,6 +284,8 @@ class Users extends \App\Controllers\GoBaseController
$this->viewData['formAction'] = route_to('updateUser', $id);
$this->viewData['selectedGroups'] = $this->group_model->getUsersRoles($requestedId);
$this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll();
$this->viewData['chatDepartments'] = $this->chat_department_model->select(["display","name","id as chatDepartmentId"])->findAll();
$this->viewData['chatDepartmentUser'] = $this->chat_department_user_model->getChatDepartmentUser($user->id);
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.edit3');
return $this->displayForm(__METHOD__, $id);

View File

@ -18,6 +18,7 @@ return [
'emailConfirmed' => 'Email Confirmado',
'firstName' => 'Nombre',
'group' => 'Rol',
'chatDepartments' => 'Chat departamento',
'idUser' => 'ID Usuario',
'language' => 'Idioma',
'lastAccess' => 'Último acceso',

View File

@ -98,4 +98,26 @@ class ChatDeparmentModel extends Model
}
return $departments;
}
public function getChatDepartmentUsers(int $chat_deparment_id)
{
$result = $this->db->table('chat_departments')
->select(
[
"users.*"
]
)
->join(
"chat_department_users",
"chat_department_users.chat_department_id = chat_departments.id",
'left'
)
->join(
"users",
"chat_department_users.user_id = users.id",
'left'
)->where("chat_departments.id",$chat_deparment_id)
->get()->getResultObject();
return $result;
}
}

View File

@ -47,4 +47,12 @@ class ChatDeparmentUserModel extends Model
protected $afterFind = [];
protected $beforeDelete = [];
protected $afterDelete = [];
public function getChatDepartmentUser(int $user_id)
{
return $this->db->table($this->table." t1")
->select("chat_departments.*")
->join("chat_departments","t1.chat_department_id = chat_departments.id","left")
->where("t1.user_id",$user_id)->get()->getResultObject();
}
}

View File

@ -2,7 +2,7 @@
namespace App\Models\Chat;
use App\Models\Usuarios\UserModel;
use CodeIgniter\Model;
use stdClass;
@ -192,5 +192,74 @@ class ChatModel extends Model
->get()->getResultObject();
return $query;
}
public function getClienteChatPedidos(array $pedidos) : array
{
$results = $this->db->table("chats")
->select([
"chats.id as chatId",
"chats.pedido_id as pedidoId",
"chats.chat_department_id as chatDepartmentId",
"chat_departments.display as chatDisplay",
"pedidos.id as title"
])
->join("chat_departments","chat_departments.id = chats.chat_department_id","left")
->join("pedidos","pedidos.id = chats.pedido_id","left")
->join("chat_messages","pedidos.id = chats.pedido_id","left")
->whereNotIn("chat_messages.sender_id",[auth()->user()->id])
->whereIn("pedidos.id",$pedidos)
->get()->getResultObject();
$chatMessageModel = model(ChatMessageModel::class);
foreach ($results as $row) {
$row->messages = $chatMessageModel->get_chat_messages($row->chatId);
}
return $results;
}
public function getClienteChatFacturas(array $facturas) : array
{
$results = $this->db->table("chats")
->select([
"chats.id as chatId",
"chats.factura_id as facturaId",
"chats.chat_department_id as chatDepartmentId",
"chat_departments.display as chatDisplay",
"facturas.numero as title"
])
->join("chat_departments","chat_departments.id = chats.chat_department_id","left")
->join("facturas","facturas.id = chats.factura_id","left")
->join("chat_messages","chats.id = chat_messages.chat_id","left")
->whereNotIn("chat_messages.sender_id",[auth()->user()->id])
->whereIn("facturas.id",$facturas)
->get()->getResultObject();
$chatMessageModel = model(ChatMessageModel::class);
foreach ($results as $row) {
$row->messages = $chatMessageModel->get_chat_messages($row->chatId);
}
return $results;
}
public function getClienteChatPresupuestos(array $presupuestos) : array
{
$results = $this->db->table("chats")
->select([
"chats.id as chatId",
"chats.presupuesto_id as presupuestoId",
"chats.chat_department_id as chatDepartmentId",
"chat_departments.display as chatDisplay",
"presupuestos.titulo as title"
])
->join("chat_departments","chat_departments.id = chats.chat_department_id","left")
->join("presupuestos","presupuestos.id = chats.presupuesto_id","left")
->join("chat_messages","chats.id = chat_messages.chat_id","left")
->whereNotIn("chat_messages.sender_id",[auth()->user()->id])
->whereIn("presupuestos.id",$presupuestos)
->get()->getResultObject();
$chatMessageModel = model(ChatMessageModel::class);
foreach ($results as $row) {
$row->messages = $chatMessageModel->get_chat_messages($row->chatId);
}
return $results;
}
}

View File

@ -332,4 +332,39 @@ class ClienteModel extends \App\Models\BaseModel
return $builder->get()->getResultArray();
}
public function getClienteDataPresupuestoPedidoFactura(int $cliente_id) : array
{
$query = $this->db
->table($this->table." t1")
->select([
"t1.id as clienteId",
"presupuestos.id as presupuestoId",
"pedidos.id as pedidoId",
"presupuesto_estados.estado as presupuestoEstado",
"facturas_pedidos_lineas.factura_id as facturaId",
])
->join("presupuestos","t1.id = presupuestos.cliente_id","left")
->join("presupuesto_estados","presupuestos.estado_id = presupuesto_estados.id","left")
->join("pedidos_linea","presupuestos.id = pedidos_linea.presupuesto_id","left")
->join("pedidos","pedidos.id = pedidos_linea.pedido_id","left")
->join("facturas_pedidos_lineas","facturas_pedidos_lineas.pedido_linea_id = pedidos_linea.id","left")
->where("t1.id",$cliente_id);
$data = $query->get()->getResultObject();
$facturas = [];
$presupuestos = [];
$pedidos = [];
$result = [];
foreach ($data as $row) {
$facturas[] = $row->facturaId;
$presupuestos[] = $row->presupuestoId;
$pedidos[] = $row->pedidoId;
}
$result["facturas"] = array_unique(array_filter($facturas));
$result["presupuestos"] = array_unique(array_filter($presupuestos));
$result["pedidos"] = array_unique(array_filter($pedidos));
return $result;
}
}

View File

@ -64,7 +64,7 @@
<!-- Chat History -->
<div class="col app-chat-history bg-body">
<div class="chat-history-wrapper ">
<div class="chat-history-header border-bottom">
<div class="chat-history-header border-bottom">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex overflow-hidden align-items-center">
<i class="ti ti-menu-2 ti-sm cursor-pointer d-lg-none d-block me-2"
@ -75,26 +75,23 @@
class="avatar-initial rounded-circle bg-label-primary">P</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="m-0">Departamento Producción</h6>
<small class="user-status text-muted">Consulta sobre el presupuesto
P001</small>
<h6 class="m-0"></h6>
<small class="user-status text-muted"></small>
</div>
</div>
<div class="d-flex align-items-center">
<div class="dropdown d-flex align-self-center">
<button class="btn p-0" type="button" id="chat-header-actions"
data-bs-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="ti ti-dots-vertical"></i>
<div class="dropdown d-flex align-self-center ml-2 px-2 d-none" id="chat-header-dropdown-users">
<button type="button" class="btn btn-primary btn-icon rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="ti ti-users"></i>
</button>
<div class="dropdown-menu dropdown-menu-end d-none"
aria-labelledby="chat-header-actions">
<a class="dropdown-item" href="javascript:void(0);">Silenciar
Conversacion</a>
<a class="dropdown-item" href="javascript:void(0);">Limpiar
Conversacion</a>
<div class="dropdown-menu dropdown-menu-end" id="chat-header-users"
aria-labelledby="chat-header-users">
</div>
</div>
</div>
</div>
</div>

View File

@ -46,15 +46,15 @@
<h6 class="text-muted mb-0">No Contacts Found</h6>
</li>
<!-- <li class="chat-contact-list-item">
<a class="d-flex align-items-center">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">JJ</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">Jaime Jimenez</h6>
</div>
</a>
</li> -->
<a class="d-flex align-items-center">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">JJ</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">Jaime Jimenez</h6>
</div>
</a>
</li> -->
</ul>
</div>

View File

@ -64,7 +64,7 @@
<!-- Chat History -->
<div class="col app-chat-history bg-body">
<div class="chat-history-wrapper ">
<div class="chat-history-header border-bottom">
<div class="chat-history-header border-bottom">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex overflow-hidden align-items-center">
<i class="ti ti-menu-2 ti-sm cursor-pointer d-lg-none d-block me-2"
@ -78,22 +78,20 @@
<h6 class="m-0"></h6>
<small class="user-status text-muted"></small>
</div>
</div>
<div class="d-flex align-items-center">
<div class="dropdown d-flex align-self-center">
<button class="btn p-0" type="button" id="chat-header-actions"
data-bs-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="ti ti-dots-vertical"></i>
<div class="dropdown d-flex align-self-center ml-2 px-2 d-none" id="chat-header-dropdown-users">
<button type="button" class="btn btn-primary btn-icon rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="ti ti-users"></i>
</button>
<div class="dropdown-menu dropdown-menu-end"
aria-labelledby="chat-header-actions">
<a class="dropdown-item" href="javascript:void(0);">Silenciar
Conversacion</a>
<a class="dropdown-item" href="javascript:void(0);">Limpiar
Conversacion</a>
<div class="dropdown-menu dropdown-menu-end" id="chat-header-users"
aria-labelledby="chat-header-users">
</div>
</div>
</div>
</div>
</div>

View File

@ -1,13 +1,13 @@
<div class="accordion accordion-bordered mt-3" id="accordionChatPresupuesto">
<div class="card accordion-item active">
<div class="card accordion-item">
<h2 class="accordion-header" id="headingChatPresupuesto">
<button type="button" class="accordion-button" data-bs-toggle="collapse"
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse"
data-bs-target="#accordionChatPresupuestoTip" aria-expanded="false"
aria-controls="accordionChatPresupuestoTip">
<h3><?= lang("Chat.chat") ?></h3>
</button>
</h2>
<div id="accordionChatPresupuestoTip" class="accordion-collapse collapse show"
<div id="accordionChatPresupuestoTip" class="accordion-collapse collapse"
data-bs-parent="#accordionChatPresupuesto">
<div class="accordion-body">
<div class="container-xxl flex-grow-1" id="chat-presupuesto" data-id="<?= $modelId ?>">
@ -77,26 +77,23 @@
class="avatar-initial rounded-circle bg-label-primary">P</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="m-0">Departamento Producción</h6>
<small class="user-status text-muted">Consulta sobre el presupuesto
P001</small>
<h6 class="m-0"></h6>
<small class="user-status text-muted"></small>
</div>
</div>
<div class="d-flex align-items-center">
<div class="dropdown d-flex align-self-center">
<button class="btn p-0" type="button" id="chat-header-actions"
data-bs-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="ti ti-dots-vertical"></i>
<div class="dropdown d-flex align-self-center ml-2 px-2 d-none" id="chat-header-dropdown-users">
<button type="button" class="btn btn-primary btn-icon rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="ti ti-users"></i>
</button>
<div class="dropdown-menu dropdown-menu-end"
aria-labelledby="chat-header-actions">
<a class="dropdown-item" href="javascript:void(0);">Silenciar
Conversacion</a>
<a class="dropdown-item" href="javascript:void(0);">Limpiar
Conversacion</a>
<div class="dropdown-menu dropdown-menu-end" id="chat-header-users"
aria-labelledby="chat-header-users">
</div>
</div>
</div>
</div>
</div>

View File

@ -52,6 +52,25 @@
</select>
</div>
</div>
<div class="mb-3">
<div class="form-group">
<label for="chat_departments" class="form-label"> <?= lang('Users.chatDepartments') ?></label>
<select tabindex="11" name="chatDepartments[]" id="chat_departments" multiple="multiple"
class="form-control select2 form-select">
<?php
$selectedChatDepartments = isset($chatDepartmentUser) && is_array($chatDepartmentUser) ? $chatDepartmentUser : [];
$selectedKeywords = array_map(fn($chatDepartment) => $chatDepartment->name, $selectedChatDepartments);
foreach ($chatDepartments as $item) :
$isSelected = in_array($item["name"], $selectedKeywords) ? 'selected' : '';
?>
<option value="<?= $item["name"] ?>"
data-select2-id=<?= $item["name"] ?> <?= $isSelected ?>>
<?= $item["display"] ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="mb-3">
<label for="cliente_id" class="form-label">
<?= lang('Presupuestos.clienteId') ?>

View File

@ -6,78 +6,77 @@ $picture = "/assets/img/default-user.png";
<!DOCTYPE html>
<html
lang="<?= $session->get('lang') ?>"
class="h-100 light-style layout-navbar-fixed layout-menu-fixed"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer"
>
lang="<?= $session->get('lang') ?>"
class="h-100 light-style layout-navbar-fixed layout-menu-fixed"
dir="ltr"
data-theme="theme-default"
data-assets-path="<?= site_url('themes/vuexy/') ?>"
data-template="vertical-menu-template-no-customizer">
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
<title><?= config('Safekat')->appName ?></title>
<meta name="description" content=""/>
<meta name="description" content="" />
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>"/>
<link rel="icon" type="image/x-icon" href="<?= site_url('themes/vuexy/img/favicon/favicon.ico') ?>" />
<link rel="apple-touch-icon" sizes="57x57" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-57x57.png') ?>">
<link rel="apple-touch-icon" sizes="60x60" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-60x60.png') ?>">
<link rel="apple-touch-icon" sizes="72x72" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-72x72.png') ?>">
<link rel="apple-touch-icon" sizes="76x76" href="<?= site_url('themes/vuexy/img/favicon/apple-icon-76x76.png') ?>">
<link rel="apple-touch-icon" sizes="114x114"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-114x114.png') ?>">
<link rel="apple-touch-icon" sizes="120x120"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-120x120.png') ?>">
<link rel="apple-touch-icon" sizes="144x144"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-144x144.png') ?>">
<link rel="apple-touch-icon" sizes="152x152"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-152x152.png') ?>">
<link rel="apple-touch-icon" sizes="180x180"
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/apple-icon-180x180.png') ?>">
<link rel="icon" type="image/png" sizes="192x192"
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/android-icon-192x192.png') ?>">
<link rel="icon" type="image/png" sizes="32x32"
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/favicon-32x32.png') ?>">
<link rel="icon" type="image/png" sizes="96x96"
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/favicon-96x96.png') ?>">
<link rel="icon" type="image/png" sizes="16x16"
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
href="<?= site_url('themes/vuexy/img/favicon/favicon-16x16.png') ?>">
<link rel="manifest" href="<?= site_url('themes/vuexy/img/favicon/manifest.json') ?>">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet" />
<!-- Icons -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/fontawesome.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/tabler-icons.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/fonts/flag-icons.css') ?>" />
<!-- Core CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/core.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/rtl/theme-semi-dark.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>" />
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/css/pages/app-chat.css') ?>">
<!-- Vendors CSS -->
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') ?>" />
<!-- Page CSS -->
<?= $this->renderSection('css') ?>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>"/>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/safekat.css') ?>" />
<!-- Helpers -->
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
@ -87,326 +86,358 @@ $picture = "/assets/img/default-user.png";
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<?php include "selector_menu.php" ?>
<?php include "selector_menu.php" ?>
<!-- Layout container -->
<div class="layout-page">
<!-- Layout container -->
<div class="layout-page">
<!-- Navbar -->
<nav
<!-- Navbar -->
<nav
class="layout-navbar container-fluid navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
id="layout-navbar">
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="ti ti-menu-2 ti-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<ul class="navbar-nav flex-row align-items-center ms-auto">
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
<ul class="navbar-nav flex-row align-items-center ms-auto">
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-bell ti-md"></i>
</a>
</li>
<!--/ Notification -->
<!-- Search Budgets -->
<li class="nav-item navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link hide-arrow"
href="<?= site_url('presupuestos/buscador'); ?>"
title="Acceso directo a buscador de presupuestos"
>
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
<!-- View Mode links -->
<?php
if (auth()->user()->inGroup('beta')) :
?>
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="ti ti-building ti-md"></i>
aria-expanded="false">
<span class="tf-icons ti-md ti ti-message-circle"></span>
<span id="chat-notification-number" class="badge bg-danger text-white badge-notifications"></span>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Vistas</h5>
<h5 class="text-body mb-0 me-auto">Chats</h5>
</div>
</div>
<div class="dropdown-shortcuts-list scrollable-container">
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-printer fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_impresion); ?>"
class="stretched-link">Impresión</a>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-ruler-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_maquetacion); ?>"
class="stretched-link">Maquetación</a>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-file-code-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_digitalizacion); ?>"
class="stretched-link">Digitalización</a>
<!-- Chat & Contacts -->
<div class="container">
<div class="col app-chat-contacts app-sidebar flex-grow-0 overflow-hidden"
id="app-chat-contacts">
<div class="container-m-nx m-2">
<div class="sidebar-body">
<!-- Contacts -->
<ul class="list-unstyled chat-contact-list mb-0" id="chat-notification-list">
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</li>
<?php
endif;
?>
<!-- View Mode links -->
<!-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false">
<i class="ti ti-bell ti-md"></i>
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<i class="fi <?= getCurrentLanguageFlag(); ?> fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
</a>
</li>
<!--/ Notification -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle"/>
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
<!-- Search Budgets -->
<li class="nav-item navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link hide-arrow"
href="<?= site_url('presupuestos/buscador'); ?>"
title="Acceso directo a buscador de presupuestos">
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
<!-- View Mode links -->
<?php
if (auth()->user()->inGroup('beta')) :
?>
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false">
<i class="ti ti-building ti-md"></i>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Vistas</h5>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
</nav>
<!-- / Navbar -->
<div class="dropdown-shortcuts-list scrollable-container">
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-printer fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_impresion); ?>"
class="stretched-link">Impresión</a>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-ruler-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_maquetacion); ?>"
class="stretched-link">Maquetación</a>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon rounded-circle mb-2">
<i class="ti ti-file-code-2 fs-4"></i>
</span>
<small class="text-muted mb-0">Vista</small>
<a href="<?= site_url('viewmode/' . config("Basics")->vista_digitalizacion); ?>"
class="stretched-link">Digitalización</a>
</div>
</div>
</div>
</div>
</li>
<?php
endif;
?>
<!-- View Mode links -->
<div class="container-fluid flex-grow-1 container-p-y">
<?php
// Include breadcrumbs block
include "breadcrumbs.php"
?>
<!-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<i class="fi <?= getCurrentLanguageFlag(); ?> fis rounded-circle me-1 fs-3"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="<?= site_url('lang/es'); ?>" data-language="es">
<i class="fi fi-es fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_es") ?></span>
</a>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('lang/en'); ?>" data-language="en">
<i class="fi fi-gb fis rounded-circle me-1 fs-3"></i>
<span class="align-middle"><?= lang("App.lang_en") ?></span>
</a>
</li>
</ul>
</li>
<!--/ Language -->
<?=
// Render the content section
$this->renderSection('content')
?>
</div>
<!-- / Content -->
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle" />
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar">
<img src="<?= $picture ?? '' ?>" alt class="h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url('profile'); ?>">
<i class="ti ti-user-check me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_profile") ?></span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="<?= site_url("logout") ?>">
<i class="ti ti-logout me-2 ti-sm"></i>
<span class="align-middle"><?= lang("App.menu_logout") ?></span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-fluid">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</nav>
<!-- / Navbar -->
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-fluid flex-grow-1 container-p-y">
<?php
// Include breadcrumbs block
include "breadcrumbs.php"
?>
<?=
// Render the content section
$this->renderSection('content')
?>
</div>
<!-- / Content -->
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-fluid">
<div class="footer-container d-flex align-items-center justify-content-between py-2 flex-md-row flex-column">
<div>
<a href="#" target="_blank" class="fw-semibold">Safekat</a> © <?= date('Y'); ?>
</div>
</div>
</div>
</div>
</footer>
<!-- / Footer -->
</footer>
<!-- / Footer -->
<div class="content-backdrop fade"></div>
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- Content wrapper -->
<!-- / Layout page -->
</div>
<!-- / Layout page -->
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<!-- Overlay -->
<div class="layout-overlay layout-menu-toggle"></div>
<?= $this->renderSection('footerAdditions') ?>
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
<div class="drag-target"></div>
</div>
<!-- / Layout wrapper -->
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<script type="module" src="<?= site_url('assets/js/safekat/pages/chatNotification.js') ?>"></script>
<?= $this->renderSection('footerAdditions') ?>
<!-- endbuild -->
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<?= site_url('themes/vuexy/vendor/libs/jquery/jquery.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/popper/popper.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/bootstrap.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<?= $this->renderSection('additionalExternalJs') ?>
<!-- Vendors JS -->
<?= $this->renderSection('additionalExternalJs') ?>
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Main JS -->
<script src="<?= site_url('themes/vuexy/js/main.js') ?>"></script>
<!-- Page JS -->
<?= sweetAlert() ?>
<!-- Page JS -->
<?= sweetAlert() ?>
<?php
if (isset($global_js_variables)) {
echo "<script>\n";
foreach ($global_js_variables as $name => $value):
echo "\t" . "var $name = $value;" . "\n";
endforeach;
echo "</script>\n";
}
?>
<script type="text/javascript">
<?= $this->renderSection('globalJsFunctions') ?>
var theTable;
var <?=csrf_token() ?? 'token'?>v = '<?= csrf_hash() ?>';
function yeniden(andac = null) {
if (andac == null) {
andac = <?= csrf_token() ?>v;
} else {
<?= csrf_token() ?>v = andac;
}
$('input[name="<?= csrf_token() ?>"]').val(andac);
$('meta[name="<?= config('Security')->tokenName ?>"]').attr('content', andac)
$.ajaxSetup({
headers: {'<?= config('Security')->headerName ?>': andac, 'X-Requested-With': 'XMLHttpRequest'},
<?=csrf_token()?>: andac
});
<?php
if (isset($global_js_variables)) {
echo "<script>\n";
foreach ($global_js_variables as $name => $value):
echo "\t" . "var $name = $value;" . "\n";
endforeach;
echo "</script>\n";
}
?>
document.addEventListener('DOMContentLoaded', function () {
function adjustSidebar4ContentWrapper() {
if ($('#sidebar').hasClass('d-none') && $(window).width() <= 768) {
$('#contentWrapper').addClass('full-width');
<script type="text/javascript">
<?= $this->renderSection('globalJsFunctions') ?>
var theTable;
var <?= csrf_token() ?? 'token' ?>v = '<?= csrf_hash() ?>';
function yeniden(andac = null) {
if (andac == null) {
andac = <?= csrf_token() ?>v;
} else {
if (!$('#sidebar').hasClass('inactive')) {
$('#contentWrapper').removeClass('full-width');
<?= csrf_token() ?>v = andac;
}
$('input[name="<?= csrf_token() ?>"]').val(andac);
$('meta[name="<?= config('Security')->tokenName ?>"]').attr('content', andac)
$.ajaxSetup({
headers: {
'<?= config('Security')->headerName ?>': andac,
'X-Requested-With': 'XMLHttpRequest'
},
<?= csrf_token() ?>: andac
});
}
document.addEventListener('DOMContentLoaded', function() {
function adjustSidebar4ContentWrapper() {
if ($('#sidebar').hasClass('d-none') && $(window).width() <= 768) {
$('#contentWrapper').addClass('full-width');
} else {
if (!$('#sidebar').hasClass('inactive')) {
$('#contentWrapper').removeClass('full-width');
}
}
}
}
adjustSidebar4ContentWrapper();
$('#sidebarCollapse').on('click', function () {
if ($('#sidebar').hasClass('d-none') && $(window).width() <= 768) {
$('#sidebar').removeClass('d-none d-sm-none d-md-block');
$('#contentWrapper').removeClass('full-width');
} else {
$('#sidebar').toggleClass('inactive');
$('#contentWrapper').toggleClass('full-width');
$('.collapse.in').toggleClass('in');
$('a[aria-expanded=true]').attr('aria-expanded', 'false');
}
});
$(window).resize(function () {
adjustSidebar4ContentWrapper();
$('#sidebarCollapse').on('click', function() {
if ($('#sidebar').hasClass('d-none') && $(window).width() <= 768) {
$('#sidebar').removeClass('d-none d-sm-none d-md-block');
$('#contentWrapper').removeClass('full-width');
} else {
$('#sidebar').toggleClass('inactive');
$('#contentWrapper').toggleClass('full-width');
$('.collapse.in').toggleClass('in');
$('a[aria-expanded=true]').attr('aria-expanded', 'false');
}
});
$(window).resize(function() {
adjustSidebar4ContentWrapper();
});
<?= $this->renderSection('additionalInlineJs') ?>
});
<?= $this->renderSection('additionalInlineJs') ?>
});
</script>
</script>
</body>
</html>
</html>

View File

@ -8,34 +8,58 @@ class Chat {
this.chatList = this.domItem.find("#chat-list")
this.chatHistory = this.domItem.find("#chat-conversation")
this.modelId = this.domItem.data("id")
this.chatHistoryBody = document.querySelector(".chat-history-body")
this.chatHistoryBody = this.domItem.find(".chat-history-body")
this.sendBtnMessageDepartment = this.domItem.find("#send-msg-btn-deparment")
this.sendBtnMessageInternal= this.domItem.find("#send-msg-btn-internal")
this.messageInput = this.domItem.find(".message-input")
this.sendBtnMessageInternal = this.domItem.find("#send-msg-btn-internal")
this.chatSidebarLeftUserAbout = this.domItem.find('.chat-sidebar-left-user-about'),
this.messageInput = this.domItem.find(".message-input")
this.sideBar = this.domItem.find(".sidebar-body")
this.chatDeparmentId = undefined
this.searchInput = this.domItem.find(".chat-search-input")
this.headers = {}
this.chatContactsBody = document.querySelector('.app-chat-contacts .sidebar-body')
this.chatContactsBody = this.domItem.find('.app-chat-contacts .sidebar-body')
this.chatContactListItems = [].slice.call(
document.querySelectorAll('.chat-contact-list-item:not(.chat-contact-list-item-title)')
)
}
init() {
// Inicializar PerfectScrollbar
if (this.searchInput.length) {
this.searchInput.on('keyup', () => {
const searchValue = this.searchInput.val(),
chatListItem0 = this.domItem.find('.chat-list-item-0'),
contactListItem0 = this.domItem.find('.contact-list-item-0'),
searchChatListItems = this.domItem.find('#chat-list li:not(.chat-contact-list-item-title)'),
searchContactListItems = this.domItem.find('#contact-list li:not(.chat-contact-list-item-title)');
// Buscar en chats
const chatListItemsCount = this._searchChatContacts(searchChatListItems, searchValue);
// Mostrar u ocultar mensaje de "No se encontraron resultados" en chats
if (chatListItem0.length) {
chatListItem0.toggleClass('d-none', chatListItemsCount === 0);
}
// Buscar en contactos
const contactListItemsCount = this._searchChatContacts(searchContactListItems, searchValue);
// Mostrar u ocultar mensaje de "No se encontraron resultados" en contactos
if (contactListItem0.length) {
contactListItem0.toggleClass('d-none', contactListItemsCount === 0);
}
});
}
this.sendBtnMessageDepartment.addClass("d-none")
this.sendBtnMessageInternal.addClass("d-none")
if (this.chatContactsBody) {
this.scrollbarContacts = new PerfectScrollbar(this.chatContactsBody, {
if (this.chatContactsBody[0]) {
this.scrollbarContacts = new PerfectScrollbar(this.chatContactsBody[0], {
wheelPropagation: false,
suppressScrollX: true
});
}
if (this.chatHistoryBody) {
this.scrollbarChatHistory = new PerfectScrollbar(this.chatHistoryBody, {
if (this.chatHistoryBody[0]) {
this.scrollbarChatHistory = new PerfectScrollbar(this.chatHistoryBody[0], {
wheelPropagation: false,
suppressScrollX: true
});
@ -69,13 +93,28 @@ class Chat {
this.chatType = "internal"
}
_setBtnInternal()
{
_searchChatContacts(searchListItems, searchValue) {
let searchListItemsCount = 0;
searchListItems.each(function () {
const searchListItemText = $(this).text().toLowerCase();
const matchesSearch = searchListItemText.indexOf(searchValue) !== -1;
$(this).toggleClass('d-flex', matchesSearch);
$(this).toggleClass('d-none', !matchesSearch);
if (matchesSearch) {
searchListItemsCount++;
}
});
return searchListItemsCount;
}
_setBtnInternal() {
this.sendBtnMessageInternal.removeClass("d-none")
this.sendBtnMessageDepartment.addClass("d-none")
}
_setBtnDeparment()
{
_setBtnDeparment() {
this.sendBtnMessageDepartment.removeClass("d-none")
this.sendBtnMessageInternal.addClass("d-none")
}
@ -98,10 +137,13 @@ class Chat {
Object.values(data).map(row => {
this.chatList.append(this._getContact(row))
this.chatList.find(`#chat_${row.name}`).on("click", (event) => {
let chatDeparmentId = this.chatList.find(`#chat_${row.name}`).data("id")
$(".chat-contact-list-item").removeClass("active")
$(event.currentTarget).parent().addClass("active")
this.chatDeparmentId = this.chatList.find(`#chat_${row.name}`).data("id")
this.domItem.find(".chat-history-header div.chat-contact-info h6").text(row.display)
this.domItem.find(".chat-history-header div.chat-contact-info small.user-status").text(row.display)
this._getChatMessage(chatDeparmentId)
this._getChatMessage()
this._getChatDeparmentUsers()
})
})
@ -110,6 +152,48 @@ class Chat {
_handleGetChatListError(error) {
console.error(error)
}
_getChatDeparmentUsers() {
this.domItem.find("#chat-header-users").empty()
this.domItem.find("#chat-header-dropdown-users").removeClass("d-none")
let ajax = new Ajax(
`/chat/department/${this.chatDeparmentId}/users`,
null,
null,
this._getChatDeparmentUsersSuccess.bind(this),
this._getChatDeparmentUsersError.bind(this),
)
ajax.get()
}
_getChatDeparmentUsersSuccess(deparmentUsers) {
deparmentUsers.map((user) => {
this.domItem.find("#chat-header-users").append(
`
<li class="chat-contact-list-item p-1">
<a class="d-flex align-items-center py-1"
id="chat-contact-list-item-${user.id}">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">
${user?.first_name?.charAt(0) ?? "?"
+ user?.last_name?.charAt(0) ?? "?"}</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">${user?.first_name ?? "" + " " +
user?.last_name ?? ""}</h6>
<p class="chat-contact-status text-muted text-truncate mb-0">
${user.username}
</p>
</div>
</a>
</li>
`
)
})
}
_getChatDeparmentUsersError(err) { }
_getContact(row) {
let chat = `
<li class="chat-contact-list-item">
@ -128,8 +212,7 @@ class Chat {
`
return chat
}
_getChatMessage(chatDeparmentId) {
this.chatDeparmentId = chatDeparmentId
_getChatMessage() {
let ajax = new Ajax(
`/chat/department/${this.chatType}/${this.chatDeparmentId}/${this.modelId}`,
null,
@ -213,7 +296,7 @@ class Chat {
}
_handleListContacts() {
this.sideBar.find("#contact-list").removeClass("d-none")
this.sendBtnMessageInternal.on("click",this._sendMessageInternal.bind(this))
this.sendBtnMessageInternal.on("click", this._sendMessageInternal.bind(this))
let ajax = new Ajax(
"/chat/contacts",
null,
@ -234,7 +317,11 @@ class Chat {
this.sideBar.find("#contact-list").removeClass("d-none")
}
this.sideBar.find(".contact-chat").on("click", (e) => {
$(".contact-chat").parent().removeClass("active")
$(".chat-contact-list-item").removeClass("active")
this.domItem.find("#chat-header-dropdown-users").addClass("d-none")
let userId = $(e.currentTarget).data("id")
$(e.currentTarget).parent().addClass('active')
this.receiverId = userId
this._handleGetSingleContact(userId)
this._setBtnInternal()
@ -314,17 +401,18 @@ class Chat {
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">
${contact?.first_name?.charAt(0) ?? "?"
+ contact?.last_name?.charAt(0) ?? "?"}</span>
+ contact?.last_name?.charAt(0) ?? "?"}</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">${contact?.first_name ?? "" + " " +
contact?.last_name ?? ""}</h6>
contact?.last_name ?? ""}</h6>
<p class="chat-contact-status text-muted text-truncate mb-0">
${contact.username}
</p>
</div>
${contact.unreadMessages ? `<span class="badge badge-center rounded-pill bg-primary">${contact.unreadMessages}</span>` : ""}
</div>
${contact.unreadMessages ? `<span
class="badge badge-center rounded-pill bg-primary">${contact.unreadMessages}</span>` : ""}
</a>
</li>
`
@ -339,6 +427,100 @@ class Chat {
}
export const showNotificationMessages = (dom) => {
let ajax = new Ajax(
'/chat/notifications',
null,
null,
(data) => {
let totalMessages = 0
data?.chatPresupuestos?.map((e) => {
console.log(e)
let numberOfMessages = 0
e.messages.forEach(m => {
m.viewed == "1" ? numberOfMessages++ : null
});
totalMessages+= numberOfMessages
if(numberOfMessages > 0){
dom.append(
`
<li class="">
<a href="/presupuestos/cosidotapablanda/edit/${e.presupuestoId}" class="d-flex align-items-center flex-grow">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">${e.presupuestoId}</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">[${e.title}] ${e.chatDisplay}</h6>
</div>
<span class="badge badge-center rounded-pill bg-primary">${numberOfMessages}</span>
</a>
</li>
`
)
}
})
data?.chatFacturas?.map((e) => {
console.log(e)
let numberOfMessages = 0
e.messages.forEach(m => {
m.viewed == "1" ? numberOfMessages++ : null
});
totalMessages+= numberOfMessages
if(numberOfMessages > 0){
dom.append(
`
<li class="">
<a href="/presupuestos/cosidotapablanda/edit/${e.facturaId}" class="d-flex align-items-center flex-grow">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">${e.facturaId}</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">[${e.title}] ${e.chatDisplay}</h6>
</div>
<span class="badge badge-center rounded-pill bg-primary">${numberOfMessages}</span>
</a>
</li>
`
)
}
})
data?.chatPedidos?.map((e) => {
console.log(e)
let numberOfMessages = 0
e.messages.forEach(m => {
m.viewed == "1" ? numberOfMessages++ : null
});
$("#chat-notification-number").text(numberOfMessages)
totalMessages+= numberOfMessages
if(numberOfMessages > 0){
dom.append(
`
<li class="">
<a href="/presupuestos/cosidotapablanda/edit/${e.pedidoId}" class="d-flex align-items-center flex-grow">
<div class="avatar d-block flex-shrink-0">
<span class="avatar-initial rounded-circle bg-label-primary">${e.pedidoId}</span>
</div>
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">[${e.title}] ${e.chatDisplay}</h6>
</div>
<span class="badge badge-center rounded-pill bg-primary">${numberOfMessages}</span>
</a>
</li>
`
)
}
})
$("#chat-notification-number").text(totalMessages)
},
(err) => { }
)
ajax.get()
}
export default Chat

View File

@ -0,0 +1,3 @@
import {showNotificationMessages} from "../components/chat.js";
showNotificationMessages($("#chat-notification-list"))