// public/js/client-index.js
$(document).ready(function() {
$('#clientService').select2({
placeholder: "-- Select Services --",
allowClear: true,
dropdownParent: $('#createClientModal')
});
let searchTimer;
// Initialize the table on page load
fetchClients();
// Event Listeners for Search and Filters
$('#searchClient').on('keyup', function() {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => fetchClients(1), 400);
});
$('#filterService, #filterBilling').on('change', function() {
fetchClients(1);
});
$('#filterService, #filterStatus').on('change', function() {
fetchClients(1);
});
// Handle Pagination Clicks dynamically
$(document).on('click', '.page-link-ajax', function(e) {
e.preventDefault();
let page = $(this).data('page');
if (page) fetchClients(page);
});
$('#btnOpenClientModal').on('click', function(e) {
e.preventDefault();
$('#createClientModal').modal('show');
});
$(document).on('click', '.btn-view-client', function(e) {
e.preventDefault();
let clientId = $(this).data('id');
window.location.href = base_url + "/clients/" + clientId;
});
// ---------------------------------------------------------
// EDIT CLIENT MODAL TRIGGER & POPULATION
// ---------------------------------------------------------
$(document).on('click', '.btn-edit-client', function(e) {
e.preventDefault();
let clientId = $(this).data('id');
let $form = $('#editClientForm');
// Set dynamic action URL for update
$form.attr('action', base_url + '/clients/' + clientId);
// Fetch Services first, then Client data to populate the edit modal
$.ajax({
url: base_url + '/api/services',
type: 'GET',
success: function(services) {
let $servicesSelect = $('#edit_services');
$servicesSelect.empty();
if (services && Array.isArray(services)) {
services.forEach(function(s) {
$servicesSelect.append(new Option(s.name, s.id));
});
}
// Fetch client details JSON
$.ajax({
url: base_url + '/clients/' + clientId + '/json',
type: 'GET',
success: function(client) {
$('#edit_name').val(client.name);
$('#edit_email').val(client.email);
$('#edit_phone').val(client.phone);
$('#edit_contact_person').val(client.contact_person);
$('#edit_company_type').val(client.company_type);
$('#edit_contract_type').val(client.contract_type);
$('#edit_industry').val(client.industry);
$('#edit_status').val(client.status);
$('#edit_currency').val(client.currency);
// $('#edit_country').val(client.country);
loadCountries(client.country);
// Helper for multi-select Select2 fields
function setSelect2Values(selector, values) {
let $el = $(selector);
$el.val(null).trigger('change');
if (values && Array.isArray(values)) {
values.forEach(function(val) {
if ($el.find("option[value='" + val + "']").length === 0) {
$el.append(new Option(val, val, true, true));
}
});
$el.val(values).trigger('change');
}
}
// Parse services if stored as JSON string
let clientServices = client.services;
if (typeof clientServices === 'string') {
try { clientServices = JSON.parse(clientServices); } catch(err) {}
}
setSelect2Values('#edit_services', clientServices);
setSelect2Values('#edit_message_types', client.message_types);
setSelect2Values('#edit_connections', client.connections);
setSelect2Values('#edit_support_phones', client.support_phones);
setSelect2Values('#edit_support_emails', client.support_emails);
setSelect2Values('#edit_rate_emails', client.rate_emails);
setSelect2Values('#edit_support_skype', client.support_skype);
// Show the modal after populating
$('#editClientModal select[multiple]').each(function() {
if (!$(this).hasClass("select2-hidden-accessible")) {
$(this).select2({
theme: 'bootstrap-5',
dropdownParent: $('#editClientModal'),
tags: true, // Allows typing custom entries for emails, phones, etc.
tokenSeparators: [',', ' '],
placeholder: 'Select or type and hit enter...'
});
}
});
$('#editClientModal').modal('show');
},
error: function() {
Swal.fire('Error', 'Could not fetch client details.', 'error');
}
});
}
});
});
$('#createClientModal, #editClientModal').on('hidden.bs.modal', function () {
let $form = $(this).find('form');
if ($form.length) {
$form[0].reset();
// Reset any select elements or select2 tags back to blank
$form.find('select').val(null).trigger('change');
}
});
// ---------------------------------------------------------
// AJAX FORM SUBMISSION (Create Client)
// ---------------------------------------------------------
$('#createClientForm').on('submit', function(e) {
e.preventDefault();
let $form = $(this);
let $submitBtn = $('#btnSubmitClient');
let originalText = $submitBtn.html();
let $alertBox = $('#clientModalAlert');
$submitBtn.html('Saving...').prop('disabled', true);
$alertBox.html('');
$form.find('.is-invalid').removeClass('is-invalid');
$form.find('.invalid-feedback').remove();
$.ajax({
url: $form.attr('action'),
method: 'POST',
data: $form.serialize(),
success: function(response) {
if(response.success) {
$alertBox.html(`
${response.message || 'Client added successfully!'}
`);
fetchClients(1);
setTimeout(() => {
$('#createClientModal').modal('hide');
$form[0].reset();
$alertBox.html('');
}, 2000);
}
},
error: function(xhr) {
if (xhr.status === 401) {
window.location.href = base_url + '/login';
}
if (xhr.status === 422) {
let errors = xhr.responseJSON.errors;
$alertBox.html(`
Please fix the errors highlighted below.
`);
$.each(errors, function(key, value) {
let fieldName = key;
if(key === 'services') fieldName = 'services[]';
let $input = $form.find('[name="' + fieldName + '"]');
if ($input.length) {
$input.addClass('is-invalid');
$input.parent().append('' + value[0] + '
');
}
});
} else {
$alertBox.html(`
An unexpected server error occurred. Please try again.
`);
}
},
complete: function() {
$submitBtn.html(originalText).prop('disabled', false);
}
});
});
$('#createClientModal').on('hidden.bs.modal', function () {
$('#createClientForm')[0].reset();
$('#clientService').val(null).trigger('change');
$('#clientModalAlert').html('');
$('#createClientForm').find('.is-invalid').removeClass('is-invalid');
$('#createClientForm').find('.invalid-feedback').remove();
});
// AJAX Fetch Function
function fetchClients(page = 1) {
const search = $('#searchClient').val();
const service = $('#filterService').val();
const billing = $('#filterBilling').val();
const status = $('#filterStatus').val();
$('#clientTableBody').html(`
|
Loading clients...
|
`);
$.ajax({
url: base_url + "/clients/data",
type: "GET",
data: { page: page, search: search, service: service, billing: billing, status: status },
success: function(response) {
renderTable(response.data);
renderPagination(response);
},
error: function() {
$('#clientTableBody').html('| Failed to load data. Please try again. |
');
}
});
}
// Handle Export Actions
$('.btn-export').on('click', function(e) {
e.preventDefault();
const search = $('#searchClient').val();
const service = $('#filterService').val();
const billing = $('#filterBilling').val();
const status = $('#filterStatus').val();
const format = $(this).data('format');
const queryParams = $.param({
search: search,
service: service,
billing: billing,
status: status,
format: format
});
window.location.href = base_url + "/clients/export?" + queryParams;
});
// Render Table Rows
// Render Table Rows
function renderTable(clients) {
let html = '';
if (clients.length === 0) {
$('#clientTableBody').html('| No clients found matching your criteria. |
');
return;
}
clients.forEach(client => {
let initials = client.name.substring(0, 2).toUpperCase();
let servicesHtml = 'N/A';
if (client.services) {
try {
let servicesArray = typeof client.services === 'string' ? JSON.parse(client.services) : client.services;
if (Array.isArray(servicesArray) && servicesArray.length > 0) {
servicesHtml = servicesArray.map(service =>
`${service}`
).join('');
}
} catch (e) {
console.error("Could not parse services for client: " + client.name);
}
}
let statusBadge = client.status === 'Live' || client.status === 'active'
? 'Active'
: '' + client.status + '';
let formattedDate = 'N/A';
if (client.created_at) {
const dateObj = new Date(client.created_at);
formattedDate = dateObj.toLocaleDateString('en-GB', {
day: 'numeric',
month: 'short',
year: 'numeric'
});
}
// Extract Account Manager name safely
let amName = 'Unassigned';
if (client.account_manager && client.account_manager.name) {
amName = client.account_manager.name;
}
// CONDITIONAL EDIT BUTTON LOGIC
let editButtonHtml = '';
if (typeof currentUserId !== 'undefined' && client.auth_user_id == currentUserId) {
editButtonHtml = `
`;
}
html += `
${initials}
${client.name}
${client.country || 'N/A'}
|
${client.contact_person || 'N/A'}
${client.email || 'N/A'}
|
${amName}
|
${servicesHtml}
|
${client.pay_mode || 'N/A'} |
${formattedDate} |
${statusBadge} |
${editButtonHtml}
|
`;
});
$('#clientTableBody').html(html);
}
// Render Pagination Links
function renderPagination(response) {
$('#paginationInfo').text(`Showing ${response.from || 0} to ${response.to || 0} of ${response.total} entries`);
let paginationHtml = '';
if (response.last_page > 1) {
let prevDisabled = response.current_page === 1 ? 'disabled' : '';
paginationHtml += `Previous`;
for (let i = 1; i <= response.last_page; i++) {
let activeClass = response.current_page === i ? 'active' : '';
let style = response.current_page === i ? 'style="background-color: #5c4df0; border-color: #5c4df0;"' : 'class="page-link text-dark"';
paginationHtml += `${i}`;
}
let nextDisabled = response.current_page === response.last_page ? 'disabled' : '';
paginationHtml += `Next`;
}
$('#paginationLinks').html(paginationHtml);
}
// Helper function to populate country dropdowns dynamically
function loadCountries(selectedCountry = '') {
$.ajax({
url: base_url + '/api/countries',
type: 'GET',
success: function(countries) {
// Target both create and edit country dropdowns if they exist
let $selectors = $('#create_country, #edit_country');
$selectors.each(function() {
let $select = $(this);
let currentVal = $select.val() || selectedCountry;
$select.empty().append('');
if (countries && Array.isArray(countries)) {
countries.forEach(function(c) {
$select.append(new Option(c.en_short_name, c.en_short_name));
});
}
if (currentVal) {
$select.val(currentVal);
}
});
}
});
}
// Call loadCountries on page load so it's ready for the create modal
loadCountries();
});