forked from UKSOURCE/cms.hailearning.edu.vn
fix: add leading slashes to image paths in service data
This commit is contained in:
@@ -11,17 +11,17 @@
|
|||||||
"slug": "immigration-appeal",
|
"slug": "immigration-appeal",
|
||||||
"name": "Immigration Appeal & Legal Support",
|
"name": "Immigration Appeal & Legal Support",
|
||||||
"description": "Our experts provide professional guidance for immigration appeals and legal matters, helping clients overcome visa rejections with personalized strategies and strong case representation.",
|
"description": "Our experts provide professional guidance for immigration appeals and legal matters, helping clients overcome visa rejections with personalized strategies and strong case representation.",
|
||||||
"image": "img/home-3/service/01.jpg",
|
"image": "/img/home-3/service/01.jpg",
|
||||||
"layout": "left",
|
"layout": "left",
|
||||||
"details": {
|
"details": {
|
||||||
"title": "Immigration Appeal & Legal Support",
|
"title": "Immigration Appeal & Legal Support",
|
||||||
"description": "Our experts provide professional guidance for immigration appeals and legal matters, helping clients overcome visa rejections with personalized strategies and strong case representation. We analyze your case thoroughly and develop custom strategies to maximize your chances of success.",
|
"description": "Our experts provide professional guidance for immigration appeals and legal matters, helping clients overcome visa rejections with personalized strategies and strong case representation. We analyze your case thoroughly and develop custom strategies to maximize your chances of success.",
|
||||||
"mainImage": "img/inner-page/service-details/details-1.jpg",
|
"mainImage": "/img/inner-page/service-details/details-1.jpg",
|
||||||
"overviewTitle": "Service Overview",
|
"overviewTitle": "Service Overview",
|
||||||
"overviewDescription": "Our Immigration Appeal & Legal Support service is designed to help clients navigate complex immigration challenges. We provide expert legal guidance, case analysis, and strategic representation to maximize your chances of success. With our expert consultants, personalized approach, and global network, we ensure a smooth transition for every client.",
|
"overviewDescription": "Our Immigration Appeal & Legal Support service is designed to help clients navigate complex immigration challenges. We provide expert legal guidance, case analysis, and strategic representation to maximize your chances of success. With our expert consultants, personalized approach, and global network, we ensure a smooth transition for every client.",
|
||||||
"additionalDescription": "From start to finish, we are committed to turning your immigration challenges into success stories through professional legal representation and strategic planning.",
|
"additionalDescription": "From start to finish, we are committed to turning your immigration challenges into success stories through professional legal representation and strategic planning.",
|
||||||
"keyFeaturesTitle": "Key Features",
|
"keyFeaturesTitle": "Key Features",
|
||||||
"keyFeaturesImage": "img/inner-page/service-details/details-2.jpg",
|
"keyFeaturesImage": "/img/inner-page/service-details/details-2.jpg",
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"title": "Personalized Guidance",
|
"title": "Personalized Guidance",
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"faqTitle": "Frequently Asked Question",
|
"faqTitle": "Frequently Asked Question",
|
||||||
"faqImage": "img/inner-page/service-details/details-3.jpg",
|
"faqImage": "/img/inner-page/service-details/details-3.jpg",
|
||||||
"faq": [
|
"faq": [
|
||||||
{
|
{
|
||||||
"id": "faq-appeal-1",
|
"id": "faq-appeal-1",
|
||||||
@@ -82,17 +82,17 @@
|
|||||||
"slug": "scholarship-guidance",
|
"slug": "scholarship-guidance",
|
||||||
"name": "Scholarship & Study Grant Guidance",
|
"name": "Scholarship & Study Grant Guidance",
|
||||||
"description": "We help students unlock opportunities to study abroad with the right financial support. Our expert advisors guide you in finding scholarships, grants, and funding options that match your academic background, chosen destination, and career goals.",
|
"description": "We help students unlock opportunities to study abroad with the right financial support. Our expert advisors guide you in finding scholarships, grants, and funding options that match your academic background, chosen destination, and career goals.",
|
||||||
"image": "img/home-3/service/02.jpg",
|
"image": "/img/home-3/service/02.jpg",
|
||||||
"layout": "right",
|
"layout": "right",
|
||||||
"details": {
|
"details": {
|
||||||
"title": "Scholarship & Study Grant Guidance",
|
"title": "Scholarship & Study Grant Guidance",
|
||||||
"description": "We help students unlock opportunities to study abroad with the right financial support. Our expert advisors guide you in finding scholarships, grants, and funding options that match your academic background, chosen destination, and career goals. From preparing strong applications to meeting eligibility criteria, we ensure you maximize your chances of securing financial aid.",
|
"description": "We help students unlock opportunities to study abroad with the right financial support. Our expert advisors guide you in finding scholarships, grants, and funding options that match your academic background, chosen destination, and career goals. From preparing strong applications to meeting eligibility criteria, we ensure you maximize your chances of securing financial aid.",
|
||||||
"mainImage": "img/inner-page/service-details/details-1.jpg",
|
"mainImage": "/img/inner-page/service-details/details-1.jpg",
|
||||||
"overviewTitle": "Service Overview",
|
"overviewTitle": "Service Overview",
|
||||||
"overviewDescription": "Our Education Visa Consultancy is dedicated to guiding students in achieving their study abroad dreams. We provide complete support including university selection, application assistance, scholarship guidance, visa documentation, and interview preparation. With our expert consultants, personalized approach, and global network, we ensure a smooth transition for every student.",
|
"overviewDescription": "Our Education Visa Consultancy is dedicated to guiding students in achieving their study abroad dreams. We provide complete support including university selection, application assistance, scholarship guidance, visa documentation, and interview preparation. With our expert consultants, personalized approach, and global network, we ensure a smooth transition for every student.",
|
||||||
"additionalDescription": "From start to finish, we are committed to turning your education journey into a successful international experience.",
|
"additionalDescription": "From start to finish, we are committed to turning your education journey into a successful international experience.",
|
||||||
"keyFeaturesTitle": "Key Features",
|
"keyFeaturesTitle": "Key Features",
|
||||||
"keyFeaturesImage": "img/inner-page/service-details/details-2.jpg",
|
"keyFeaturesImage": "/img/inner-page/service-details/details-2.jpg",
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"title": "Personalized Guidance",
|
"title": "Personalized Guidance",
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"faqTitle": "Frequently Asked Question",
|
"faqTitle": "Frequently Asked Question",
|
||||||
"faqImage": "img/inner-page/service-details/details-3.jpg",
|
"faqImage": "/img/inner-page/service-details/details-3.jpg",
|
||||||
"faq": [
|
"faq": [
|
||||||
{
|
{
|
||||||
"id": "faq-scholarship-1",
|
"id": "faq-scholarship-1",
|
||||||
@@ -153,17 +153,17 @@
|
|||||||
"slug": "permanent-residency",
|
"slug": "permanent-residency",
|
||||||
"name": "Permanent Residency (PR) Services",
|
"name": "Permanent Residency (PR) Services",
|
||||||
"description": "Our PR services guide clients through every step of the residency process, including documentation, eligibility assessment, and application support, ensuring a smooth and successful approval.",
|
"description": "Our PR services guide clients through every step of the residency process, including documentation, eligibility assessment, and application support, ensuring a smooth and successful approval.",
|
||||||
"image": "img/home-3/service/03.jpg",
|
"image": "/img/home-3/service/03.jpg",
|
||||||
"layout": "left",
|
"layout": "left",
|
||||||
"details": {
|
"details": {
|
||||||
"title": "Permanent Residency (PR) Services",
|
"title": "Permanent Residency (PR) Services",
|
||||||
"description": "Our PR services guide clients through every step of the residency process, including documentation, eligibility assessment, and application support, ensuring a smooth and successful approval.",
|
"description": "Our PR services guide clients through every step of the residency process, including documentation, eligibility assessment, and application support, ensuring a smooth and successful approval.",
|
||||||
"mainImage": "img/inner-page/service-details/details-1.jpg",
|
"mainImage": "/img/inner-page/service-details/details-1.jpg",
|
||||||
"overviewTitle": "Service Overview",
|
"overviewTitle": "Service Overview",
|
||||||
"overviewDescription": "Our Permanent Residency services provide comprehensive support for individuals seeking to establish permanent residence in their chosen country. We handle all aspects of the PR application process with expertise and care.",
|
"overviewDescription": "Our Permanent Residency services provide comprehensive support for individuals seeking to establish permanent residence in their chosen country. We handle all aspects of the PR application process with expertise and care.",
|
||||||
"additionalDescription": "Our experienced team ensures that your PR application is handled professionally and efficiently, maximizing your chances of approval.",
|
"additionalDescription": "Our experienced team ensures that your PR application is handled professionally and efficiently, maximizing your chances of approval.",
|
||||||
"keyFeaturesTitle": "Key Features",
|
"keyFeaturesTitle": "Key Features",
|
||||||
"keyFeaturesImage": "img/inner-page/service-details/details-2.jpg",
|
"keyFeaturesImage": "/img/inner-page/service-details/details-2.jpg",
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"title": "Eligibility Assessment",
|
"title": "Eligibility Assessment",
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"faqTitle": "Frequently Asked Question",
|
"faqTitle": "Frequently Asked Question",
|
||||||
"faqImage": "img/inner-page/service-details/details-3.jpg",
|
"faqImage": "/img/inner-page/service-details/details-3.jpg",
|
||||||
"faq": [
|
"faq": [
|
||||||
{
|
{
|
||||||
"id": "faq-pr-1",
|
"id": "faq-pr-1",
|
||||||
@@ -224,17 +224,17 @@
|
|||||||
"slug": "citizenship-naturalization",
|
"slug": "citizenship-naturalization",
|
||||||
"name": "Citizenship & Naturalization Guidance",
|
"name": "Citizenship & Naturalization Guidance",
|
||||||
"description": "We provide expert guidance for citizenship and naturalization processes, assisting clients with documentation, eligibility, and legal procedures to achieve a smooth and successful application.",
|
"description": "We provide expert guidance for citizenship and naturalization processes, assisting clients with documentation, eligibility, and legal procedures to achieve a smooth and successful application.",
|
||||||
"image": "img/home-3/service/04.jpg",
|
"image": "/img/home-3/service/04.jpg",
|
||||||
"layout": "right",
|
"layout": "right",
|
||||||
"details": {
|
"details": {
|
||||||
"title": "Citizenship & Naturalization Guidance",
|
"title": "Citizenship & Naturalization Guidance",
|
||||||
"description": "We provide expert guidance for citizenship and naturalization processes, assisting clients with documentation, eligibility, and legal procedures to achieve a smooth and successful application.",
|
"description": "We provide expert guidance for citizenship and naturalization processes, assisting clients with documentation, eligibility, and legal procedures to achieve a smooth and successful application.",
|
||||||
"mainImage": "img/inner-page/service-details/details-1.jpg",
|
"mainImage": "/img/inner-page/service-details/details-1.jpg",
|
||||||
"overviewTitle": "Service Overview",
|
"overviewTitle": "Service Overview",
|
||||||
"overviewDescription": "Our Citizenship & Naturalization service helps individuals navigate the complex process of becoming a citizen. We provide step-by-step guidance, documentation support, and legal expertise throughout the entire process.",
|
"overviewDescription": "Our Citizenship & Naturalization service helps individuals navigate the complex process of becoming a citizen. We provide step-by-step guidance, documentation support, and legal expertise throughout the entire process.",
|
||||||
"additionalDescription": "With our comprehensive approach, we make the path to citizenship clear, manageable, and successful for every client.",
|
"additionalDescription": "With our comprehensive approach, we make the path to citizenship clear, manageable, and successful for every client.",
|
||||||
"keyFeaturesTitle": "Key Features",
|
"keyFeaturesTitle": "Key Features",
|
||||||
"keyFeaturesImage": "img/inner-page/service-details/details-2.jpg",
|
"keyFeaturesImage": "/img/inner-page/service-details/details-2.jpg",
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"title": "Citizenship Test Preparation",
|
"title": "Citizenship Test Preparation",
|
||||||
@@ -262,7 +262,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"faqTitle": "Frequently Asked Question",
|
"faqTitle": "Frequently Asked Question",
|
||||||
"faqImage": "img/inner-page/service-details/details-3.jpg",
|
"faqImage": "/img/inner-page/service-details/details-3.jpg",
|
||||||
"faq": [
|
"faq": [
|
||||||
{
|
{
|
||||||
"id": "faq-citizenship-1",
|
"id": "faq-citizenship-1",
|
||||||
@@ -295,7 +295,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"destinations": {
|
"destinations": {
|
||||||
"backgroundImage": "img/home-3/choose-us/bg.png",
|
"backgroundImage": "/img/home-3/choose-us/bg.png",
|
||||||
"title": {
|
"title": {
|
||||||
"subTitle": "Countries we offer",
|
"subTitle": "Countries we offer",
|
||||||
"mainTitle": "Choose Your Immigration Destination"
|
"mainTitle": "Choose Your Immigration Destination"
|
||||||
@@ -336,7 +336,7 @@
|
|||||||
"subTitle": "What Our Clients Say",
|
"subTitle": "What Our Clients Say",
|
||||||
"mainTitle": "Immigration Success Stories"
|
"mainTitle": "Immigration Success Stories"
|
||||||
},
|
},
|
||||||
"thumb": "img/home-3/test-thumb.jpg",
|
"thumb": "/img/home-3/test-thumb.jpg",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": "client-review-1",
|
"id": "client-review-1",
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Features List -->
|
<!-- Features List -->
|
||||||
<div class="row">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h6 class="fw-medium mb-0">Features</h6>
|
<h6 class="fw-medium mb-0">Features</h6>
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FAQ List -->
|
<!-- FAQ List -->
|
||||||
<div class="row">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h6 class="fw-medium mb-0">FAQ Items</h6>
|
<h6 class="fw-medium mb-0">FAQ Items</h6>
|
||||||
|
|||||||
@@ -156,7 +156,7 @@
|
|||||||
<a href="/admin/service/<%= service.slug %>/details" class="btn btn-sm btn-outline-warning" title="Edit Details">
|
<a href="/admin/service/<%= service.slug %>/details" class="btn btn-sm btn-outline-warning" title="Edit Details">
|
||||||
<i class="fas fa-cog"></i>
|
<i class="fas fa-cog"></i>
|
||||||
</a>
|
</a>
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteService(<%= index %>)" title="Delete Service">
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteService('<%= service.slug %>')" title="Delete Service">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -570,18 +570,32 @@ function addService() {
|
|||||||
showSuccess('Service added successfully!');
|
showSuccess('Service added successfully!');
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteService(index) {
|
function deleteService(slug) {
|
||||||
const service = servicesData[index];
|
const serviceIndex = servicesData.findIndex(service => service && service.slug === slug);
|
||||||
if (!service) return;
|
if (serviceIndex === -1) {
|
||||||
|
showError('Service not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = servicesData[serviceIndex];
|
||||||
|
|
||||||
// Set service name in modal
|
// Set service name in modal
|
||||||
document.getElementById('deleteServiceName').textContent = service.name || 'Unnamed Service';
|
const serviceNameElement = document.getElementById('deleteServiceName');
|
||||||
|
if (serviceNameElement) {
|
||||||
|
serviceNameElement.textContent = service.name || 'Unnamed Service';
|
||||||
|
}
|
||||||
|
|
||||||
// Show custom modal
|
// Show custom modal
|
||||||
showDeleteModal();
|
showDeleteModal();
|
||||||
|
|
||||||
// Handle confirm delete
|
// Handle confirm delete
|
||||||
const confirmBtn = document.getElementById('confirmDeleteBtn');
|
const confirmBtn = document.getElementById('confirmDeleteBtn');
|
||||||
|
if (!confirmBtn) {
|
||||||
|
showError('Delete button not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any existing event listeners by cloning the button
|
||||||
const newConfirmBtn = confirmBtn.cloneNode(true);
|
const newConfirmBtn = confirmBtn.cloneNode(true);
|
||||||
confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
|
confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
|
||||||
|
|
||||||
@@ -593,36 +607,54 @@ function deleteService(index) {
|
|||||||
// Disable cancel button and close button during delete
|
// Disable cancel button and close button during delete
|
||||||
const cancelBtn = document.querySelector('.custom-modal .btn-secondary');
|
const cancelBtn = document.querySelector('.custom-modal .btn-secondary');
|
||||||
const closeBtn = document.querySelector('.custom-modal-close');
|
const closeBtn = document.querySelector('.custom-modal-close');
|
||||||
cancelBtn.disabled = true;
|
if (cancelBtn) cancelBtn.disabled = true;
|
||||||
closeBtn.disabled = true;
|
if (closeBtn) closeBtn.disabled = true;
|
||||||
|
|
||||||
// Add loading overlay to modal
|
// Add loading overlay to modal
|
||||||
showModalLoading();
|
showModalLoading();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Simulate API call delay for better UX
|
// Simulate API call delay for better UX
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 800));
|
||||||
|
|
||||||
|
// Check if service still exists (in case of concurrent modifications)
|
||||||
|
const currentServiceIndex = servicesData.findIndex(service => service && service.slug === slug);
|
||||||
|
if (currentServiceIndex === -1) {
|
||||||
|
throw new Error('Service no longer exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store service name for success message
|
||||||
|
const serviceName = servicesData[currentServiceIndex].name || 'Unnamed Service';
|
||||||
|
|
||||||
// Perform delete
|
// Perform delete
|
||||||
servicesData.splice(index, 1);
|
servicesData.splice(currentServiceIndex, 1);
|
||||||
updateServicesTable();
|
updateServicesTable();
|
||||||
updateStatistics();
|
updateStatistics();
|
||||||
|
|
||||||
|
// Hide loading overlay first
|
||||||
|
hideModalLoading();
|
||||||
|
|
||||||
|
// Reset button states
|
||||||
|
this.disabled = false;
|
||||||
|
this.innerHTML = '<i class="fas fa-trash me-2"></i>Delete Service';
|
||||||
|
if (cancelBtn) cancelBtn.disabled = false;
|
||||||
|
if (closeBtn) closeBtn.disabled = false;
|
||||||
|
|
||||||
// Hide modal
|
// Hide modal
|
||||||
closeDeleteModal();
|
closeDeleteModal();
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
showSuccess(`Service "${service.name}" deleted successfully!`);
|
showSuccess(`Service "${serviceName}" deleted successfully!`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting service:', error);
|
console.error('Error deleting service:', error);
|
||||||
showError('Failed to delete service. Please try again.');
|
showError('Failed to delete service. Please try again.');
|
||||||
} finally {
|
|
||||||
// Reset button states
|
// Reset button states on error
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
this.innerHTML = '<i class="fas fa-trash me-2"></i>Delete Service';
|
this.innerHTML = '<i class="fas fa-trash me-2"></i>Delete Service';
|
||||||
cancelBtn.disabled = false;
|
if (cancelBtn) cancelBtn.disabled = false;
|
||||||
closeBtn.disabled = false;
|
if (closeBtn) closeBtn.disabled = false;
|
||||||
|
|
||||||
// Hide loading overlay
|
// Hide loading overlay
|
||||||
hideModalLoading();
|
hideModalLoading();
|
||||||
@@ -632,6 +664,11 @@ function deleteService(index) {
|
|||||||
|
|
||||||
function showModalLoading() {
|
function showModalLoading() {
|
||||||
const modal = document.getElementById('customDeleteModal');
|
const modal = document.getElementById('customDeleteModal');
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
// Remove any existing loading overlay first
|
||||||
|
hideModalLoading();
|
||||||
|
|
||||||
const loadingOverlay = document.createElement('div');
|
const loadingOverlay = document.createElement('div');
|
||||||
loadingOverlay.className = 'modal-loading-overlay';
|
loadingOverlay.className = 'modal-loading-overlay';
|
||||||
loadingOverlay.innerHTML = `
|
loadingOverlay.innerHTML = `
|
||||||
@@ -640,7 +677,11 @@ function showModalLoading() {
|
|||||||
<p class="mt-2 mb-0">Deleting service...</p>
|
<p class="mt-2 mb-0">Deleting service...</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
modal.appendChild(loadingOverlay);
|
|
||||||
|
const modalContent = modal.querySelector('.custom-modal-content');
|
||||||
|
if (modalContent) {
|
||||||
|
modalContent.appendChild(loadingOverlay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideModalLoading() {
|
function hideModalLoading() {
|
||||||
@@ -650,8 +691,36 @@ function hideModalLoading() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeDeleteModal() {
|
||||||
|
const modal = document.getElementById('customDeleteModal');
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
// Check if loading - don't close if loading
|
||||||
|
if (document.querySelector('.modal-loading-overlay')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.classList.remove('show');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
// Remove ESC key listener
|
||||||
|
document.removeEventListener('keydown', handleEscKey);
|
||||||
|
|
||||||
|
// Clean up any existing event listeners
|
||||||
|
const backdrop = modal.querySelector('.custom-modal-backdrop');
|
||||||
|
if (backdrop) {
|
||||||
|
backdrop.onclick = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showDeleteModal() {
|
function showDeleteModal() {
|
||||||
const modal = document.getElementById('customDeleteModal');
|
const modal = document.getElementById('customDeleteModal');
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
modal.style.display = 'flex';
|
modal.style.display = 'flex';
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
|
|
||||||
@@ -662,11 +731,14 @@ function showDeleteModal() {
|
|||||||
|
|
||||||
// Close modal when clicking backdrop (only if not loading)
|
// Close modal when clicking backdrop (only if not loading)
|
||||||
const backdrop = modal.querySelector('.custom-modal-backdrop');
|
const backdrop = modal.querySelector('.custom-modal-backdrop');
|
||||||
backdrop.onclick = function() {
|
if (backdrop) {
|
||||||
if (!document.querySelector('.modal-loading-overlay')) {
|
backdrop.onclick = function(e) {
|
||||||
|
// Only close if clicking the backdrop itself, not its children
|
||||||
|
if (e.target === backdrop && !document.querySelector('.modal-loading-overlay')) {
|
||||||
closeDeleteModal();
|
closeDeleteModal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Close modal with ESC key (only if not loading)
|
// Close modal with ESC key (only if not loading)
|
||||||
document.addEventListener('keydown', handleEscKey);
|
document.addEventListener('keydown', handleEscKey);
|
||||||
@@ -728,7 +800,7 @@ function updateServicesTable() {
|
|||||||
<a href="/admin/service/${service.slug || 'unknown'}/details" class="btn btn-sm btn-outline-warning" title="Edit Details">
|
<a href="/admin/service/${service.slug || 'unknown'}/details" class="btn btn-sm btn-outline-warning" title="Edit Details">
|
||||||
<i class="fas fa-cog"></i>
|
<i class="fas fa-cog"></i>
|
||||||
</a>
|
</a>
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteService(${index})" title="Delete Service">
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteService('${service.slug || 'unknown'}')" title="Delete Service">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -963,6 +1035,7 @@ function showError(message) {
|
|||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-modal-header {
|
.custom-modal-header {
|
||||||
@@ -970,7 +1043,7 @@ function showError(message) {
|
|||||||
padding: 20px 25px 15px;
|
padding: 20px 25px 15px;
|
||||||
border-bottom: 1px solid #dee2e6;
|
border-bottom: 1px solid #dee2e6;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,13 +1068,20 @@ function showError(message) {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-modal-close:hover {
|
.custom-modal-close:hover:not(:disabled) {
|
||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
color: #495057;
|
color: #495057;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-modal-close:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.custom-modal-body {
|
.custom-modal-body {
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -1094,9 +1174,12 @@ function showError(message) {
|
|||||||
transform: none !important;
|
transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-modal-close:disabled {
|
/* Ensure modal content has relative positioning for overlay */
|
||||||
opacity: 0.6;
|
.custom-modal-content {
|
||||||
cursor: not-allowed;
|
background: white;
|
||||||
pointer-events: none;
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user