classify admin

This commit is contained in:
Husanjonazamov
2026-02-24 12:52:01 +05:00
commit e0f1989655
769 changed files with 1263008 additions and 0 deletions

View File

@@ -0,0 +1,506 @@
window.languageEvents = {
'click .edit_btn': function (e, value, row) {
$('.filepond').filepond('removeFile');
$("#edit_name").val(row.name);
$("#edit_name_in_english").val(row.name_in_english);
$("#edit_code").val(row.code);
$("#edit_country_code").val(row.country_code);
$("#edit_rtl_switch").prop('checked', row.rtl);
$("#edit_rtl").val(row.rtl ? 1 : 0);
// ✅ Update download links dynamically
$("#download_panel_file").attr("href", "/language/" + row.id + "/download/panel");
$("#download_app_file").attr("href", "/language/" + row.id + "/download/app");
$("#download_web_file").attr("href", "/language/" + row.id + "/download/web");
},
'click .delete_btn': function (e, value, row) {
e.preventDefault();
showDeleteLanguagePopupModal($(this).attr('href'), {
successCallBack: function () {
$('#table_list').bootstrapTable('refresh');
}
});
}
};
// window.SeoSettingEvents = {
// 'click .edit_btn': function (e, value, row) {
// $('.filepond').filepond('removeFile')
// $("#edit_page").val(row.page);
// $("#edit_title").val(row.title);
// $("#edit_description").val(row.description);
// $("#edit_keywords").val(row.keywords);
// }
// };
window.SeoSettingEvents = {
'click .edit_btn': function (e, value, row) {
$("#edit_page").val(row.page);
$('.filepond').filepond('removeFile');
if (row.image) {
$('.filepond').filepond('addFile', row.image);
}
$("#edit_title_1").val(row.title ?? '');
$("#edit_description_1").val(row.description ?? '');
$("#edit_keywords_1").val(row.keywords ?? '');
let translations = row.translations ?? [];
translations.forEach(function (translation) {
const langId = translation.language_id;
$("#edit_title_" + langId).val(translation.title);
$("#edit_description_" + langId).val(translation.description);
$("#edit_keywords_" + langId).val(translation.keywords);
});
}
};
window.customFieldValueEvents = {
'click .edit_btn': function (e, value, row) {
$("#new_custom_field_value").val(row.value);
$("#old_custom_field_value").val(row.value);
}
}
window.verificationFieldValueEvents = {
'click .edit_btn': function (e, value, row) {
$("#new_verification_field_value").val(row.value);
$("#old_verification_field_value").val(row.value);
}
}
window.itemEvents = {
'click .editdata': function (e, value, row) {
let html = `<table class="table">
<tr>
<th width="10%">${trans("No.")}</th>
<th width="25%" class="text-center">${trans("Image")}</th>
<th width="25%">${trans("Name")}</th>
<th width="40%">${trans("Value")}</th>
</tr>`;
$.each(row.custom_fields, function (key, value) {
html += `<tr class="mb-2">
<td>${key + 1}</td>
<td class="text-center">
<a class="image-popup-no-margins" href="${value.image}" >
<img src=${value.image} height="30px" width="30px" style="border-radius:8px;" alt="" onerror="onErrorImage(event)">
</a>
</td>
<td>${value.name}</td>`;
if (value.type == "fileinput") {
if (value.value != undefined) {
if (value.value?.value.match(/\.(jpg|jpeg|png|svg)$/i)) {
html += `<td><img src="${value.value?.value}" alt="Custom Field Files" class="w-25" onerror="onErrorImage(event)"></td>`
} else {
html += `<td><a target="_blank" href="${value.value?.value}">View File</a></td>`
}
} else {
html += `<td></td>`
}
} else {
html += `<td class="text-break">${value.value?.value || ''}</td>`
}
html += `</tr>`;
});
html += "</table>";
$('#custom_fields').html(html)
},
'click .edit-status': function (e, value, row) {
$('#status').val(row.status).trigger('change');
$('#rejected_reason').val(row.rejected_reason);
}
}
window.packageEvents = {
'click .edit_btn': function (e, value, row) {
// Clear all translation fields first
$('[id^="edit_name_"]').val('');
$('[id^="edit_description_"]').val('');
// Set English (language ID 1) fields
$('#edit_name_1').val(row.name);
$('#edit_description_1').val(row.description);
// Set non-translatable fields (in English tab)
$('#edit_price').val(row.price);
$('#edit_discount_in_percentage').val(row.discount_in_percentage);
$('#edit_final_price').val(row.final_price);
$('#edit_ios_product_id').val(row.ios_product_id);
// Populate translations for other languages
if (row.translations && Array.isArray(row.translations)) {
row.translations.forEach(function (trans) {
const langId = trans.language_id;
if (langId != 1) { // Skip English as it's already set above
$('#edit_name_' + langId).val(trans.name || '');
$('#edit_description_' + langId).val(trans.description || '');
}
});
}
// Handle duration
if (row.duration && row.duration.toString().toLowerCase() === "unlimited") {
$('#edit_duration_type_unlimited').prop('checked', true);
$('#edit_durationLimit').val('');
$('#edit_limitation_for_duration').hide();
} else {
$('#edit_duration_type_limited').prop('checked', true);
$('#edit_limitation_for_duration').show();
$('#edit_durationLimit').val(row.duration || '');
}
// Handle item limit
if (row.item_limit && row.item_limit.toString().toLowerCase() === "unlimited") {
$('#edit_item_limit_type_unlimited').prop('checked', true);
$('#edit_ForLimit').val('');
$('#edit_limitation_for_limit').hide();
} else {
$('#edit_item_limit_type_limited').prop('checked', true);
$('#edit_limitation_for_limit').show();
$('#edit_ForLimit').val(row.item_limit || '');
}
}
};
window.advertisementPackageEvents = {
'click .edit_btn': function (e, value, row) {
// Clear all translation fields first
$('[id^="edit_name_"]').val('');
$('[id^="edit_description_"]').val('');
// Set English (language ID 1) fields
$('#edit_name_1').val(row.name);
$('#edit_description_1').val(row.description);
// Set non-translatable fields (in English tab)
$('#edit_price').val(row.price);
$('#edit_discount_in_percentage').val(row.discount_in_percentage);
$('#edit_final_price').val(row.final_price);
$('#edit_durationLimit').val(row.duration || '');
$('#edit_ForLimit').val(row.item_limit || '');
$('#edit_ios_product_id').val(row.ios_product_id);
row.translations.forEach(function (translation) {
const langId = translation.language_id;
$("#edit_name_" + langId).val(translation.name);
$("#edit_description_" + langId).val(translation.description);
});
}
};
window.reportReasonEvents = {
'click .edit_btn': function (e, value, row) {
let translations = row.translations ?? [];
// Reset all language inputs first (clear old values)
$("[id^=edit_reason_]").val("");
// Set English reason (default)
$("#edit_reason_1").val(row.reason);
// Fill translations if available
translations.forEach(function (translation) {
const langId = translation.language_id;
$("#edit_reason_" + langId).val(translation.reason);
});
// Set the form action URL if needed
// $(".edit-form").attr("action", `/report-reasons/${row.id}`);
}
}
window.featuredSectionEvents = {
'click .edit_btn': function (e, value, row) {
// Clear all translation fields first
$('[id^="edit_title_"]').val('');
$('[id^="edit_description_"]').val('');
// Set English (language ID 1) fields
$('#edit_title_1').val(row.title);
$('#edit_description_1').val(row.description);
// Set non-translatable fields (in English tab)
$('#edit_slug').val(row.slug);
$('#edit_filter').val(row.filter).trigger('change');
// Populate translations for other languages
if (row.translations && Array.isArray(row.translations)) {
row.translations.forEach(function (trans) {
const langId = trans.language_id;
if (langId != 1) { // Skip English as it's already set above
$('#edit_title_' + langId).val(trans.name || '');
$('#edit_description_' + langId).val(trans.description || '');
}
});
}
// Handle filter-specific fields
if (row.filter === "price_criteria") {
$('#edit_price_criteria').show();
$('#edit_min_price').val(row.min_price || '');
$('#edit_max_price').val(row.max_price || '');
} else {
$('#edit_price_criteria').hide();
$('#edit_min_price').val('');
$('#edit_max_price').val('');
}
if (row.filter == "category_criteria") {
$('#edit_category_criteria').show();
if (row.value && row.value != '') {
$('#edit_category_id').val(row.value.split(',')).trigger('change');
} else {
$('#edit_category_id').val('').trigger('change');
}
} else {
$('#edit_category_criteria').hide();
$('#edit_category_id').val('').trigger('change');
}
// Set style
$('input[name="style"]').prop('checked', false);
$('input[name="style"][value="' + row.style + '"]').prop('checked', true);
}
};
window.staffEvents = {
'click .edit_btn': function (e, value, row) {
$('#edit_role').val(row.roles[0].id);
$('#edit_name').val(row.name);
$('#edit_email').val(row.email);
}
}
window.verificationfeildEvents = {
'click .edit_btn': function (e, value, row) {
$('#edit_name').val(row.name);
$('#edit_is_required').val(row.is_required)
}
}
window.userEvents = {
'click .assign_package': function (e, value, row) {
$("#user_id").val(row.id);
$('.package_type').prop('checked', false);
// $('#item-listing-package-div').hide();
// $('#advertisement-package-div').hide();
$('#advertisement-package').attr('required', false);
$('#item-listing-package').attr('required', false);
$('#package_details').hide();
$('.payment').hide();
$('.cheque').hide();
},
'click .manage_packages': function (e, value, row) {
// This is handled in the customer/index.blade.php file
// The button already has data-user-id attribute
}
}
// window.faqEvents = {
// 'click .edit_btn': function (e, value, row) {
// $('#edit_question').val(row.question);
// $('#edit_answer').val(row.answer);
// }
// }
window.faqEvents = {
'click .edit_btn': function (e, value, row) {
let updateUrl = "{{ url('admin/faq') }}/" + row.id;
$('.edit-form').attr('action', updateUrl);
$("[id^=edit_question_]").val("");
$("[id^=edit_answer_]").val("");
$('#edit_faq_id').val(row.id);
$("#edit_question_1").val(row.question);
$("#edit_answer_1").val(row.answer);
let translations = row.translations ?? [];
translations.forEach(function (translation) {
const langId = translation.language_id;
$("#edit_question_" + langId).val(translation.question);
$("#edit_answer_" + langId).val(translation.answer);
});
}
};
window.areaEvents = {
'click .edit_btn': function (e, value, row) {
$('#edit_name').val(row.name);
$('#edit_country').val(row.country_id);
$('#edit_state').val(row.state_id);
$('#edit_city').val(row.city_id);
$('#edit_latitude').val(row.latitude);
$('#edit_longitude').val(row.longitude);
// Initialize map after modal is shown
$('#editModal').on('shown.bs.modal', function () {
// Get coordinates from the row data
const lat = parseFloat(row.latitude) || 0;
const lng = parseFloat(row.longitude) || 0;
// Initialize map with current coordinates
const editMap = window.mapUtils.initializeMap('edit_map', lat, lng);
// Create a marker at the current position
let currentMarker = L.marker([lat, lng], {
draggable: true
}).addTo(editMap);
// Update coordinates when marker is dragged
currentMarker.on('dragend', function(event) {
const position = event.target.getLatLng();
$('#edit_latitude').val(position.lat);
$('#edit_longitude').val(position.lng);
});
// Update marker position and coordinates when map is clicked
editMap.on('click', function(e) {
const position = e.latlng;
currentMarker.setLatLng(position);
$('#edit_latitude').val(position.lat);
$('#edit_longitude').val(position.lng);
});
});
// Clean up when modal is hidden
$('#editModal').on('hidden.bs.modal', function () {
window.mapUtils.removeMap('edit_map');
$(this).off('shown.bs.modal');
$(this).off('hidden.bs.modal');
});
}
}
window.cityEvents = {
'click .edit_btn': function (e, value, row) {
$('#edit_country').val(row.country_id);
$('#edit_state').val(row.state_id);
$('#edit_name').val(row.name);
$('#edit_latitude').val(row.latitude);
$('#edit_longitude').val(row.longitude);
// Initialize map after modal is shown
$('#editModal').on('shown.bs.modal', function () {
// Get coordinates from the row data
const lat = parseFloat(row.latitude) || 0;
const lng = parseFloat(row.longitude) || 0;
// Initialize map with current coordinates
const editMap = window.mapUtils.initializeMap('edit_map', lat, lng);
// Create a marker at the current position
let currentMarker = L.marker([lat, lng], {
draggable: true
}).addTo(editMap);
// Update coordinates when marker is dragged
currentMarker.on('dragend', function(event) {
const position = event.target.getLatLng();
$('#edit_latitude').val(position.lat);
$('#edit_longitude').val(position.lng);
});
// Update marker position and coordinates when map is clicked
editMap.on('click', function(e) {
const position = e.latlng;
currentMarker.setLatLng(position);
$('#edit_latitude').val(position.lat);
$('#edit_longitude').val(position.lng);
});
});
// Clean up when modal is hidden
$('#editModal').on('hidden.bs.modal', function () {
window.mapUtils.removeMap('edit_map');
$('#edit_map').html('');
$(this).off('shown.bs.modal');
$(this).off('hidden.bs.modal');
});
}
}
window.verificationEvents = {
'click .view-verification-fields': function (e, value, row) {
let tabs = '<ul class="nav nav-tabs" role="tablist">';
let content = '<div class="tab-content mt-3">';
$.each(row.languages, function (index, lang) {
let activeClass = index === 0 ? 'active' : '';
let showClass = index === 0 ? 'show active' : '';
// Tab header
tabs += `
<li class="nav-item">
<button class="nav-link ${activeClass}" data-bs-toggle="tab" data-bs-target="#lang-${lang.id}">
${lang.name}
</button>
</li>
`;
// Tab body
content += `<div class="tab-pane fade ${showClass}" id="lang-${lang.id}">`;
content += `<table class="table">
<tr>
<th width="10%">${trans("No.")}</th>
<th width="25%">${trans("Name")}</th>
<th width="65%">${trans("Value")}</th>
</tr>`;
let count = 1;
console.log(row.verification_field_values);
$.each(row.verification_field_values, function (key, field) {
// ✅ Filter based on language for this tab
let showField = false;
if (lang.id === 1 && (field.language_id === null || field.language_id === 1)) {
showField = true;
} else if (field.language_id === lang.id) {
showField = true;
}
if (showField) {
let fieldName = field.verification_field.name;
let fieldValue = field.value;
let displayValue = '';
if (fieldValue) {
if (typeof fieldValue === 'string' && fieldValue.includes('verification_field_files')) {
displayValue = `<a class='text-decoration-underline' href='${fieldValue}' target='_blank'>${trans('Click Here')}</a>`;
} else {
displayValue = Array.isArray(fieldValue) ? fieldValue.join(', ') : fieldValue;
}
} else {
displayValue = trans('No value provided');
}
content += `<tr>
<td>${count}</td>
<td>${fieldName}</td>
<td class="text-break">${displayValue}</td>
</tr>`;
count++;
}
});
content += `</table></div>`;
});
tabs += '</ul>';
content += '</div>';
$('#verification_fields').html(tabs + content);
$('#editModal').modal('show');
},
'click .edit_btn': function (e, value, row) {
$('#status').val(row.status).trigger('change');
$('#rejection_reason').val(row.rejection_reason);
}
};
window.reviewReportEvents = {
'click .edit-status': function (e, value, row) {
$('#report_status').val(row.report_status).trigger('change');
$('#report_rejected_reason').val(row.report_rejected_reason);
}
}

View File

@@ -0,0 +1,377 @@
function imageFormatter(value) {
if (value) {
return '<a class="image-popup-no-margins one-image" href="' + value + '">' +
'<img class="rounded avatar-md shadow img-fluid " alt="" src="' + value + '" style="height: 55px !important;" width="55" onerror="onErrorImage(event)">' +
'</a>'
} else {
return '-'
}
}
function galleryImageFormatter(value) {
if (value) {
let html = '<div class="gallery">';
$.each(value, function (index, data) {
html += '<a href="' + data.image + '"><img class="rounded avatar-md shadow img-fluid m-1" alt="" src="' + data.image + '" width="55" onerror="onErrorImage(event)"></a>';
})
html += "</div>"
return html;
} else {
return '-'
}
}
function subCategoryFormatter(value, row) {
const subcategoriesLabel = window?.languageLabels["Subcategories"] || "Subcategories";
let url = `/category/${row.id}/subcategories`;
return '<span> <div class="category_count">' + value + ' '+ subcategoriesLabel + '</div></span>';
}
function customFieldFormatter(value, row) {
const customFieldsLabel =window?.languageLabels["Custom Fields"] || "Custom Fields";
let url = `/category/${row.id}/custom-fields`;
return '<a href="' + url + '"><div class="category_count">' + value + ' ' + customFieldsLabel + '</div></a>';
}
function statusSwitchFormatter(value, row) {
return `<div class="form-check form-switch">
<input class = "form-check-input switch1 update-status" id="${row.id}" type = "checkbox" role = "switch${status}" ${value ? 'checked' : ''}>
</div>`
}
function autoApproveItemSwitchFormatter(value, row) {
return `<div class="form-check form-switch">
<input class="form-check-input switch1 update-auto-approve-status" id="${row.id}" type="checkbox" role="switch" ${value ? 'checked' : ''}>
</div>`;
}
function itemStatusSwitchFormatter(value, row) {
return `<div class="form-check form-switch">
<input class = "form-check-input switch1 update-item-status" id="${row.item_id}" type = "checkbox" role = "switch${status}" ${value ? 'checked' : ''}>
</div>`
}
function userStatusSwitchFormatter(value, row) {
return `<div class="form-check form-switch">
<input class = "form-check-input switch1 update-user-status" id="${row.item.user_id}" type = "checkbox" role = "switch${status}" ${value ? 'checked' : ''}>
</div>`
}
function trans(label) {
// return window.languageLabels.hasOwnProperty(label) ? window.languageLabels[label] : label;
return window?.languageLabels[label] || label;
}
function itemStatusFormatter(value) {
const statusMap = {
"review": { badge: "primary", text: window?.languageLabels?.["Under Review"] || "Under Review" },
"approved": { badge: "success", text: window?.languageLabels?.["Approved"] || "Approved" },
"permanent rejected": { badge: "danger", text: window?.languageLabels?.["Permanent Rejected"] || "Permanent Rejected" },
"sold out": { badge: "warning", text: window?.languageLabels?.["Sold Out"] || "Sold Out" },
"featured": { badge: "black", text: window?.languageLabels?.["Featured"] || "Featured" },
"inactive": { badge: "danger", text: window?.languageLabels?.["Inactive"] || "Inactive" },
"expired": { badge: "danger", text: window?.languageLabels?.["Expired"] || "Expired" },
"soft rejected": { badge: "black", text: window?.languageLabels?.["Soft Rejected"] || "Soft Rejected" },
"resubmitted": { badge: "primary", text: window?.languageLabels?.["Resubmitted"] || "Resubmitted" },
};
const status = statusMap[value] || { badge: "secondary", text: value || "Unknown" };
return `<span class="badge rounded-pill bg-${status.badge}">${status.text}</span>`;
}
function featuredItemStatusFormatter(value) {
let badgeClass, badgeText;
if (value == "Not-Featured") {
badgeClass = 'primary';
badgeText = window?.languageLabels["Not-featured"] || "Not-featured";
} else if (value == "Featured") {
badgeClass = 'success';
badgeText = window?.languageLabels["Featured"] || "Featured";
}
return '<span class="badge rounded-pill bg-' + badgeClass + '">' + badgeText + '</span>';
}
function status_badge(value, row) {
let badgeClass, badgeText;
if (value == '0') {
badgeClass = 'danger';
badgeText = 'OFF';
} else {
badgeClass = 'success';
badgeText = 'ON';
}
return '<span class="badge rounded-pill bg-' + badgeClass + '">' + badgeText + '</span>';
}
function userStatusBadgeFormatter(value, row) {
let badgeClass, badgeText;
if (value == '0') {
badgeClass = 'danger';
badgeText = 'Inactive';
} else {
badgeClass = 'success';
badgeText = 'Active';
}
return '<span class="badge rounded-pill bg-' + badgeClass +'">' + badgeText + '</span>';
}
function styleImageFormatter(value, row) {
return '<a class="image-popup-no-margins" href="images/app_styles/' + value + '.png"><img src="images/app_styles/' + value + '.png" alt="style_4" height="60" width="60" class="rounded avatar-md shadow img-fluid"></a>';
}
function filterTextFormatter(value) {
let filter;
if (value == "most_liked") {
filter = "Most Liked";
} else if (value == "price_criteria") {
filter = "Price Criteria";
} else if (value == "category_criteria") {
filter = "Category Criteria";
} else if (value == "most_viewed") {
filter = "Most Viewed";
}
return filter;
}
function adminFile(value, row) {
return "<a href='languages/" + row.code + ".json ' )+' > View File < /a>";
}
function appFile(value, row) {
return "<a href='lang/" + row.code + ".json ' )+' > View File < /a>";
}
function textReadableFormatter(value, row) {
let string = value.replace("_", " ");
return string.charAt(0).toUpperCase() + string.slice(1);
}
function userPackageStatusBadgeFormatter(value) {
let badgeClass, badgeText;
if (value == 'Expired') {
badgeClass = 'danger';
badgeText = 'Expired';
} else {
badgeClass = 'success';
badgeText = 'Active';
}
return '<span class="badge rounded-pill bg-' + badgeClass +'">' + badgeText + '</span>';
}
function unlimitedBadgeFormatter(value) {
if (!value) {
return 'Unlimited';
}
return value;
}
function detailFormatter(index, row) {
let html = []
if (row.translations && row.translations.length > 0) {
$.each(row.translations, function (key, value) {
html.push('<p><b>' + value.language.name + ':</b> ' + value.description + '</p>')
})
} else {
const noTranslations = window?.languageLabels?.["No translations available"] || "No translations available";
html.push('<p class="text-muted"><i>' + noTranslations + '</i></p>')
}
return html.join('')
}
function truncateDescription(value, row, index) {
if (!value) {
return '<span class="no-description">No Description Available</span>';
}
// Create a temporary DOM element to handle HTML safely
let tempDiv = document.createElement("div");
tempDiv.innerHTML = value;
let textContent = tempDiv.textContent || tempDiv.innerText || "";
if (textContent.length > 100) {
let shortText = textContent.substring(0, 50);
return `
<div class="short-description">
${shortText}...
<a href="#" class="view-more" data-index="${index}">${window?.languageLabels?.["View More"] || "View More"}</a>
</div>
<div class="full-description" style="display:none;">
${value}
<a href="#" class="view-more" data-index="${index}">${window?.languageLabels?.["View Less"] || "View Less"}</a>
</div>
`;
} else {
return value;
}
}
function videoLinkFormatter(value, row, index) {
if (!value) {
return '';
}
const maxLength = 20;
const displayText = value.length > maxLength ? value.substring(0, maxLength) + '...' : value;
return `<a href="${value}" target="_blank">${displayText}</a>`;
}
function dateFormatter(value, row, index) {
if (!value) {
return '<span class="text-muted">-</span>';
}
try {
const date = new Date(value);
if (isNaN(date.getTime())) {
return '<span class="text-muted">-</span>';
}
// Format: MM/DD/YYYY HH:MM AM/PM (US format)
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const year = date.getFullYear();
let hours = date.getHours();
const minutes = String(date.getMinutes()).padStart(2, '0');
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
const formattedHours = String(hours).padStart(2, '0');
return `${month}/${day}/${year} ${formattedHours}:${minutes} ${ampm}`;
} catch (error) {
console.error('Date formatting error:', error);
return '<span class="text-muted">-</span>';
}
}
function sellerverificationStatusFormatter(value) {
let badgeClass, badgeText;
if (value == "review") {
badgeClass = 'primary';
badgeText = window?.languageLabels?.["Under Review"] || "Under Review";
} else if (value == "approved") {
badgeClass = 'success';
badgeText = window?.languageLabels?.["Approved"] || "Approved";
} else if (value == "rejected") {
badgeClass = 'danger';
badgeText = window?.languageLabels?.["Rejected"] || "Rejected";
} else if (value == "pending") {
badgeClass = 'warning';
badgeText = window?.languageLabels?.["Pending"] || "Pending";
}
return '<span class="badge rounded-pill bg-' + badgeClass + '">' + badgeText + '</span>';
}
function categoryNameFormatter(value, row) {
let buttonHtml = '';
let count = parseInt(row.subcategories_count);
if (count > 0) {
buttonHtml = `<button class="btn icon btn-xs btn-icon rounded-pill toggle-subcategories float-left btn-outline-primary text-center"
style="padding:.20rem; font-size:.875rem;cursor: pointer; margin-right: 5px;" data-id="${row.id}">
<i class="fa fa-plus"></i>
</button>`;
} else {
buttonHtml = `<span style="display:inline-block; width:30px;"></span>`;
}
return `${buttonHtml}${value}`;
}
function subCategoryNameFormatter(value, row, level) {
let dataLevel = 0;
let indent = level * 35;
let buttonHtml = '';
let count = parseInt(row.subcategories_count);
if (count > 0) {
buttonHtml = `<button class="btn icon btn-xs btn-icon rounded-pill toggle-subcategories float-left btn-outline-primary text-center"
style="padding:.20rem; cursor: pointer; margin-right: 5px;" data-id="${row.id}" data-level="${dataLevel}">
<i class="fa fa-plus"></i>
</button>`;
} else {
buttonHtml = `<span style="display:inline-block; width:30px;"></span>`;
}
dataLevel += 1;
return `<div style="padding-left:${indent}px;" class="justify-content-center">${buttonHtml}<span>${value}</span></div>`;
}
function descriptionFormatter(value, row, index) {
if (value.length >= 50) {
return '<div class="short-description">' + value.substring(0, 50) +
'... <a href="#" class="view-more" data-index="' + index + '">' + (window?.languageLabels["View More"]) + '</a></div>' +
'<div class="full-description" style="display:none;">' + value +
' <a href="#" class="view-more" data-index="' + index + '">' + (window?.languageLabels["View Less"]) + '</a></div>';
} else {
return value;
}
}
function rejectedReasonFormatter(value, row, index) {
if (value !== null && value !== undefined && value !== '') {
if (value.length > 20) {
return '<div class="short-description">' + value.substring(0, 100) +
'... <a href="#" class="view-more" data-index="' + index + '">' + (window?.languageLabels["View More"]) + '</a></div>' +
'<div class="full-description" style="display:none;">' + value +
' <a href="#" class="view-more" data-index="' + index + '">' + (window?.languageLabels["View Less"]) + '</a></div>';
} else {
return value;
}
}
return '<span class="no-description">-</span>';
}
function ratingFormatter(value, row, index) {
const maxRating = 5;
let stars = '';
for (let i = 1; i <= maxRating; i++) {
if (i <= Math.floor(value)) {
stars += '<i class="fa fa-star text-warning"></i>';
} else if (i === Math.ceil(value) && value % 1 !== 0) {
stars += '<i class="fa fa-star-half text-warning" aria-hidden></i>';
} else {
stars += '<i class="fa fa-star text-secondary"></i>';
}
}
return stars;
}
function reportStatusFormatter(value) {
let badgeClass, badgeText;
if (value == "reported") {
badgeClass = 'primary';
badgeText = window?.languageLabels?.["Reported"] || "Reported";
} else if (value == "approved") {
badgeClass = 'success';
badgeText = window?.languageLabels?.["Approved"] || "Approved";
} else if (value == "rejected") {
badgeClass = 'danger';
badgeText = window?.languageLabels?.["Rejected"] || "Rejected";
}
return '<span class="badge rounded-pill bg-' + badgeClass + '">' + badgeText + '</span>';
}
function typeFormatter(value, row) {
if (value === 'App\\Models\\Category') {
return 'Category';
} else if (value === 'App\\Models\\Item') {
return 'Advertisement';
} else {
return '-';
}
}
function packageTypeFormatter(value, row, index) {
if (value === 'item_listing') {
return '<span class="badge bg-primary">' + (window?.languageLabels["Item Listing (Ads)"]) + '</span>';
} else if (value === 'advertisement') {
return '<span class="badge bg-success">' + (window?.languageLabels["Advertisement (Featured Ads)"]) + '</span>';
}
return value;
}
function categoryNamesFormatter(value, row, index) {
if (row.is_global == 1) {
return '<span class="badge bg-info">' + (window?.languageLabels["Global"]) + '</span>';
}
if (value === 'Category Based') {
return '<span class="badge bg-warning">' + (window?.languageLabels["Category Based"]) + '</span>';
}
return '<span class="badge bg-warning">' + (window?.languageLabels["Category Based"]) + '</span>';
}

View File

@@ -0,0 +1,24 @@
function queryParams(p) {
return p;
}
function reportReasonQueryParams(p) {
return {
...p,
"status": $('#filter_status').val(),
};
}
function userListQueryParams(p) {
return {
...p,
"status": $('#filter_status').val(),
};
}
function notificationUserList(p) {
return {
...p,
notification_list: 1
};
}

View File

@@ -0,0 +1,228 @@
/*
* Common JS is used to write code which is generally used for all the UI components
* Specific component related code won't be written here
*/
"use strict";
$(document).ready(function () {
$('#table_list').on('all.bs.table', function () {
$('#toolbar').parent().addClass('col-12 col-md-7 col-lg-7 p-0');
})
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
if ($('.permission-tree').length > 0) {
$(function () {
$('.permission-tree').on('changed.jstree', function (e, data) {
// let i, j = [];
let html = "";
for (let i = 0, j = data.selected.length; i < j; i++) {
let permissionName = data.instance.get_node(data.selected[i]).data.name;
if (permissionName) {
html += "<input type='hidden' name='permission[]' value='" + permissionName + "'/>"
}
}
$('#permission-list').html(html);
}).jstree({
"plugins": ["checkbox"],
});
});
}
})
//Setup CSRF Token default in AJAX Request
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('#create-form,.create-form,.create-form-without-reset').on('submit', function (e) {
e.preventDefault();
let formElement = $(this);
let submitButtonElement = $(this).find(':submit');
let url = $(this).attr('action');
let data = new FormData(this);
let preSubmitFunction = $(this).data('pre-submit-function');
if (preSubmitFunction) {
//If custom function name is set in the Form tag then call that function using eval
if (eval(preSubmitFunction + "()") == false) {
return false;
}
}
let customSuccessFunction = $(this).data('success-function');
// noinspection JSUnusedLocalSymbols
function successCallback(response) {
if (!$(formElement).hasClass('create-form-without-reset')) {
formElement[0].reset();
$(".select2").val("").trigger('change');
$('.filepond').filepond('removeFile')
}
$('#table_list').bootstrapTable('refresh');
if (customSuccessFunction) {
//If custom function name is set in the Form tag then call that function using eval
eval(customSuccessFunction + "(response)");
}
}
formAjaxRequest('POST', url, data, formElement, submitButtonElement, successCallback);
})
$('#edit-form,.edit-form').on('submit', function (e) {
e.preventDefault();
let formElement = $(this);
let submitButtonElement = $(this).find(':submit');
let data = new FormData(this);
$(formElement).parents('modal').modal('hide');
// let url = $(this).attr('action') + "/" + data.get('edit_id');
let url = $(this).attr('action');
let preSubmitFunction = $(this).data('pre-submit-function');
if (preSubmitFunction) {
//If custom function name is set in the Form tag then call that function using eval
eval(preSubmitFunction + "()");
}
let customSuccessFunction = $(this).data('success-function');
// noinspection JSUnusedLocalSymbols
function successCallback(response) {
$('#table_list').bootstrapTable('refresh');
setTimeout(function () {
$('#editModal').modal('hide');
$(formElement).parents('.modal').modal('hide');
}, 1000)
if (customSuccessFunction) {
//If custom function name is set in the Form tag then call that function using eval
eval(customSuccessFunction + "(response)");
}
}
formAjaxRequest('PUT', url, data, formElement, submitButtonElement, successCallback);
})
$(document).on('click', '.delete-form', function (e) {
e.preventDefault();
// console.log($(this).attr('href'));
showDeletePopupModal($(this).attr('href'), {
successCallBack: function () {
$('#table_list').bootstrapTable('refresh');
}, errorCallBack: function (response) {
showErrorToast(response.message);
}
})
})
$(document).on('click', '.restore-data', function (e) {
e.preventDefault();
showRestorePopupModal($(this).attr('href'), {
successCallBack: function () {
$('#table_list').bootstrapTable('refresh');
}
})
})
$(document).on('click', '.trash-data', function (e) {
e.preventDefault();
showPermanentlyDeletePopupModal($(this).attr('href'), {
successCallBack: function () {
$('#table_list').bootstrapTable('refresh');
}
})
})
$(document).on('click', '.set-form-url', function (e) {
//This event will be called when user clicks on the edit button of the bootstrap table
e.preventDefault();
$('#edit-form,.edit-form').attr('action', $(this).attr('href'));
})
$(document).on('click', '.delete-form-reload', function (e) {
e.preventDefault();
showDeletePopupModal($(this).attr('href'), {
successCallBack: function () {
setTimeout(() => {
window.location.reload();
}, 1000);
}
})
})
// Change event for Status toggle change in Bootstrap-table
$(document).on('change', '.update-status', function () {
let tableElement = $(this).parents('table');
let url = $(tableElement).data('custom-status-change-url') || window.baseurl + "common/change-status";
ajaxRequest('PUT', url, {
id: $(this).attr('id'),
table: $(tableElement).data('table'),
column: $(tableElement).data('status-column') || "",
status: $(this).is(':checked') ? 1 : 0
}, null, function (response) {
showSuccessToast(response.message);
}, function (error) {
showErrorToast(error.message);
})
})
//Fire Ajax request when the Bootstrap-table rows are rearranged
$('#table_list').on('reorder-row.bs.table', function (element, rows) {
let url = $(element.currentTarget).data('custom-reorder-row-url') || window.baseurl + "common/change-row-order";
ajaxRequest('PUT', url, {
table: $(element.currentTarget).data('table'),
column: $(element.currentTarget).data('reorder-column') || "",
data: rows
}, null, function (success) {
$('#table_list').bootstrapTable('refresh');
showSuccessToast(success.message);
}, function (error) {
showErrorToast(error.message);
})
})
$('.img_input').click(function () {
$('#edit_cs_image').click();
});
$('.preview-image-file').on('change', function () {
const [file] = this.files
if (file) {
$('.preview-image').attr('src', URL.createObjectURL(file));
}
})
$('.form-redirection').on('submit', function (e) {
let parsley = $(this).parsley({
excluded: 'input[type=button], input[type=submit], input[type=reset], :hidden'
});
parsley.validate();
if (parsley.isValid()) {
$(this).find(':submit').attr('disabled', true);
}
})
$('#editlanguage-form,.editlanguage-form').on('submit', function (e) {
e.preventDefault();
let formElement = $(this);
let submitButtonElement = $(this).find(':submit');
let data = new FormData(this);
$(formElement).parents('modal').modal('hide');
// let url = $(this).attr('action') + "/" + data.get('edit_id');
let url = $(this).attr('action');
let preSubmitFunction = $(this).data('pre-submit-function');
if (preSubmitFunction) {
//If custom function name is set in the Form tag then call that function using eval
eval(preSubmitFunction + "()");
}
let customSuccessFunction = $(this).data('success-function');
// noinspection JSUnusedLocalSymbols
function successCallback(response) {
setTimeout(() => {
window.location.reload();
}, 1000);
}
formAjaxRequest('PUT', url, data, formElement, submitButtonElement, successCallback);
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,443 @@
"use strict";
function trans(label) {
// return window.languageLabels.hasOwnProperty(label) ? window.languageLabels[label] : label;
return window?.languageLabels[label] || label;
}
function showErrorToast(message) {
Toastify({
text: trans(message),
duration: 6000,
close: !0,
style: {
background: '#dc3545'
}
}).showToast();
}
function showSuccessToast(message) {
Toastify({
text: message,
duration: 6000,
close: !0,
style: {
background: "linear-gradient(to right, #00b09b, #96c93d)"
}
}).showToast();
}
function showWarningToast(message) {
Toastify({
text: message,
duration: 6000,
close: !0,
style: {
background: "linear-gradient(to right, #a7b000, #b08d00)"
}
}).showToast();
}
/**
*
* @param type
* @param url
* @param data
* @param {function} beforeSendCallback
* @param {function} successCallback - This function will be executed if no Error will occur
* @param {function} errorCallback - This function will be executed if some error will occur
* @param {function} finalCallback - This function will be executed after all the functions are executed
* @param processData
*/
function ajaxRequest(type, url, data, beforeSendCallback = null, successCallback = null, errorCallback = null, finalCallback = null, processData = false) {
// Modifying the data attribute here according to the type method
if (!["get", "post"].includes(type.toLowerCase())) {
if (data instanceof FormData) {
data.append("_method", type);
} else {
data = {...data, "_method": type};
data = JSON.stringify(data);
}
type = "POST";
}
$.ajax({
type: type,
url: url,
data: data,
cache: false,
processData: processData,
contentType: data instanceof FormData ? false : "application/json",
dataType: 'json',
beforeSend: function () {
if (beforeSendCallback != null) {
beforeSendCallback();
}
},
success: function (data) {
try {
if (!data.error) {
if (successCallback != null) {
successCallback(data);
}
} else {
if (errorCallback != null) {
errorCallback(data);
}
}
} finally {
if (finalCallback != null) {
finalCallback(data);
}
}
}, error: function (jqXHR) {
if (jqXHR.responseJSON) {
showErrorToast(jqXHR.responseJSON.message);
}
if (finalCallback != null) {
finalCallback();
}
}
})
}
function formAjaxRequest(type, url, data, formElement, submitButtonElement, successCallback = null, errorCallback = null) {
// To Remove Red Border from the Validation tag.
// formElement.find('.has-danger').removeClass("has-danger");
// formElement.validate();
let parsley = formElement.parsley({
excluded: 'input[type=button], input[type=submit], input[type=reset], :hidden'
});
parsley.validate();
if (parsley.isValid()) {
let submitButtonText = submitButtonElement.val();
function beforeSendCallback() {
submitButtonElement.val('Please Wait...').attr('disabled', true);
}
function mainSuccessCallback(response) {
if (response.warning) {
showWarningToast(response.message);
} else {
showSuccessToast(response.message);
}
if (successCallback != null) {
successCallback(response);
}
}
function mainErrorCallback(response) {
showErrorToast(response.message);
if (errorCallback != null) {
errorCallback(response);
}
}
function finalCallback() {
submitButtonElement.val(submitButtonText).attr('disabled', false);
}
ajaxRequest(type, url, data, beforeSendCallback, mainSuccessCallback, mainErrorCallback, finalCallback)
}
}
function Select2SearchDesignTemplate(repo) {
/**
* This function is used in Select2 Searching Functionality
*/
if (repo.loading) {
return repo.text;
}
let $container;
if (repo.id && repo.text) {
$container = $(
"<div class='select2-result-repository clearfix'>" +
"<div class='select2-result-repository__title'></div>" +
"</div>"
);
$container.find(".select2-result-repository__title").text(repo.text);
} else {
$container = $(
"<div class='select2-result-repository clearfix'>" +
"<div class='row'>" +
"<div class='col-1 select2-result-repository__avatar' style='width:20px'>" +
"<img src='" + repo.image + "' class='w-100' alt=''/>" +
"</div>" +
"<div class='col-10'>" +
"<div class='select2-result-repository__title'></div>" +
"<div class='select2-result-repository__description'></div>" +
"</div>" +
"</div>"
);
$container.find(".select2-result-repository__title").text(repo.first_name + " " + repo.last_name);
$container.find(".select2-result-repository__description").text(repo.email);
}
return $container;
}
/**
*
* @param searchElement
* @param searchUrl
* @param {Object|null} data
* @param {number} data.total_count
* @param {string} data.email
* @param {number} data.page
* @param placeHolder
* @param templateDesignEvent
* @param onTemplateSelectEvent
*/
function select2Search(searchElement, searchUrl, data, placeHolder, templateDesignEvent, onTemplateSelectEvent) {
//Select2 Ajax Searching Functionality function
if (!data) {
data = {};
}
$(searchElement).select2({
tags: true,
ajax: {
url: searchUrl,
dataType: 'json',
delay: 250,
cache: true,
data: function (params) {
data.email = params.term;
data.page = params.page;
return data;
},
processResults: function (data, params) {
params.page = params.page || 1;
return {
results: data.data,
pagination: {
more: (params.page * 30) < data.total_count
}
};
}
},
placeholder: placeHolder,
minimumInputLength: 1,
templateResult: templateDesignEvent,
templateSelection: onTemplateSelectEvent,
});
}
/**
* @param {string} [url] - Ajax URL that will be called when the Confirm button will be clicked
* @param {string} [method] - GET / POST / PUT / PATCH / DELETE
* @param {Object} [options] - Options to Configure SweetAlert
* @param {string} [options.title] - Are you sure
* @param {string} [options.text] - You won't be able to revert this
* @param {string} [options.icon] - 'warning'
* @param {boolean} [options.showCancelButton] - true
* @param {string} [options.confirmButtonColor] - '#3085d6'
* @param {string} [options.cancelButtonColor] - '#d33'
* @param {string} [options.confirmButtonText] - Confirm
* @param {string} [options.cancelButtonText] - Cancel
* @param {function} [options.successCallBack] - function()
* @param {function} [options.errorCallBack] - function()
* @param {function} [options.data] - FormData Object / Object
*/
function showSweetAlertConfirmPopup(url, method, options = {}) {
let opt = {
title: trans("Are you sure"),
text: trans("You wont be able to revert this"),
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: trans("Confirm"),
cancelButtonText: trans("Cancel"),
successCallBack: function () {
},
errorCallBack: function (response) {
},
...options,
}
Swal.fire({
title: opt.title,
text: opt.text,
icon: opt.icon,
showCancelButton: opt.showCancelButton,
confirmButtonColor: opt.showCancelButton,
cancelButtonColor: opt.cancelButtonColor,
confirmButtonText: opt.confirmButtonText,
cancelButtonText: opt.cancelButtonText
}).then((result) => {
if (result.isConfirmed) {
function successCallback(response) {
showSuccessToast(response.message);
opt.successCallBack(response);
}
function errorCallback(response) {
showErrorToast(response.message);
opt.errorCallBack(response);
}
ajaxRequest(method, url, options.data || null, null, successCallback, errorCallback);
}
})
}
/**
*
* @param {string} [url] - Ajax URL that will be called when the Delete will be successfully
* @param {Object} [options] - Options to Configure SweetAlert
* @param {string} [options.text] - "Are you sure?"
* @param {string} [options.title] - "You won't be able to revert this!"
* @param {string} [options.icon] - "warning"
* @param {boolean} [options.showCancelButton] - true
* @param {string} [options.confirmButtonColor] - "#3085d6"
* @param {string} [options.cancelButtonColor] - "#d33"
* @param {string} [options.confirmButtonText] - "Yes, delete it!"
* @param {string} [options.cancelButtonText] - "Cancel"
* @param {function} [options.successCallBack] - function()
* @param {function} [options.errorCallBack] - function()
* @param {function} [options.data] - FormData Object / Object
*/
function showDeletePopupModal(url, options = {}) {
// console.log(windows.trans("Are you sure"));
// To Preserve OLD
let opt = {
title: window?.languageLabels["Are you sure"] || "Are you sure",
text: window?.languageLabels["You wont be able to revert this"] || "You wont be able to revert this",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: window?.languageLabels["Yes Delete"] || "Yes Delete",
cancelButtonText: window?.languageLabels["Cancel"] || "Cancel",
successCallBack: function () {
},
errorCallBack: function (response) {
},
...options,
}
showSweetAlertConfirmPopup(url, 'DELETE', opt);
}
/**
*
* @param {string} [url] - Ajax URL that will be called when the Delete will be successfully
* @param {Object} [options] - Options to Configure SweetAlert
* @param {string} [options.text] - "Are you sure?"
* @param {string} [options.title] - "You won't be able to revert this!"
* @param {string} [options.icon] - "warning"
* @param {boolean} [options.showCancelButton] - true
* @param {string} [options.confirmButtonColor] - "#3085d6"
* @param {string} [options.cancelButtonColor] - "#d33"
* @param {string} [options.confirmButtonText] - "Yes, delete it!"
* @param {string} [options.cancelButtonText] - "Cancel"
* @param {function} [options.successCallBack]
* @param {function} [options.errorCallBack]
*/
function showRestorePopupModal(url, options = {}) {
// To Preserve OLD
let opt = {
title: trans("Are you sure"),
text: trans("You wont be able to revert this"),
icon: 'success',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: trans('Yes Restore it'),
cancelButtonText: trans('Cancel'),
successCallBack: function () {
},
errorCallBack: function (response) {
},
...options,
}
showSweetAlertConfirmPopup(url, 'PUT', opt);
}
/**
*
* @param {string} [url] - Ajax URL that will be called when the Delete will be successfully
* @param {Object} [options] - Options to Configure SweetAlert
* @param {string} [options.text] - "Are you sure?"
* @param {string} [options.title] - "You won't be able to revert this!"
* @param {string} [options.icon] - "warning"
* @param {boolean} [options.showCancelButton] - true
* @param {string} [options.confirmButtonColor] - "#3085d6"
* @param {string} [options.cancelButtonColor] - "#d33"
* @param {string} [options.confirmButtonText] - "Yes, delete it!"
* @param {string} [options.cancelButtonText] - "Cancel"
* @param {function} [options.successCallBack]
* @param {function} [options.errorCallBack]
*/
function showPermanentlyDeletePopupModal(url, options = {}) {
// To Preserve OLD
let opt = {
title: trans("Are you sure"),
text: trans("You are about to Delete this data"),
icon: 'error',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: trans("Yes Delete Permanently"),
cancelButtonText: trans('Cancel'),
successCallBack: function () {
},
errorCallBack: function (response) {
},
...options,
}
showSweetAlertConfirmPopup(url, 'DELETE', opt);
}
/**
* Calculate Discounted price based on the Price and Discount(%)
* @param price
* @param discount
* @returns {string}
*/
function calculateDiscountedAmount(price, discount) {
let finalPrice = price - (price * discount / 100);
return finalPrice.toFixed(2);
}
/**
* Calculate Discount(%)
* @param price
* @param discountedPrice
* @returns {string}
*/
function calculateDiscount(price, discountedPrice) {
let finalDiscount = 100 - discountedPrice * 100 / price;
return finalDiscount.toFixed(2);
}
function generateSlug(text){
// Remove non-English and non-number/dash/underscore characters, replace spaces with dash, to lower case
return text
.toLowerCase()
.replace(/[^a-z0-9 -_]/g, '') // Remove non-English chars except dash/underscore
.replace(/\s+/g, '-') // Replace spaces with dash
.replace(/[-_]+/g, '-') // Collapse multiple - or _
.replace(/^-+|-+$/g, ''); // Remove leading/trailing dash
}
function showDeleteLanguagePopupModal(url, options = {}) {
let opt = {
title: trans("Are you sure?"),
text: trans("Deleting this language will delete all the language files and translations associated with it."),
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: trans("Yes Delete"),
cancelButtonText: trans('Cancel'),
successCallBack: function () {},
errorCallBack: function (response) {},
...options,
};
showSweetAlertConfirmPopup(url, 'DELETE', opt);
}

View File

@@ -0,0 +1,35 @@
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
// Function to apply translations to a table
function applyTableTranslations($table) {
$table.attr({
'data-search-text': window.trans('Search'),
'data-search-placeholder': window.trans('Search...'),
'data-refresh-text': window.trans('Refresh'),
'data-toggle-text': window.trans('Toggle'),
'data-columns-text': window.trans('Columns'),
'data-detail-view-text': window.trans('Detail'),
'data-detail-formatter-text': window.trans('Detail Formatter'),
'data-pagination-pre-text': window.trans('Previous'),
'data-pagination-next-text': window.trans('Next'),
'data-pagination-first-text': window.trans('First'),
'data-pagination-last-text': window.trans('Last'),
'data-pagination-info-text': window.trans('Showing {ctx.start} to {ctx.end} of {ctx.total} entries'),
'data-pagination-info-formatted': window.trans('Showing {ctx.start} to {ctx.end} of {ctx.total} entries')
});
}
// Apply translations to all translatable tables
$('.translatable-table').each(function() {
applyTableTranslations($(this));
});
// Listen for language change events (if you have a language switcher)
$(document).on('languageChanged', function() {
// Reload translations and update tables
if (typeof loadTableTranslations === 'function') {
loadTableTranslations();
}
});
});