518 lines
26 KiB
HTML
518 lines
26 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Manage Onboarding Content" %}{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.page-header-gradient {
|
|
background: linear-gradient(135deg, #005696 0%, #0069a8 50%, #007bbd 100%);
|
|
color: white;
|
|
padding: 1.5rem 2rem;
|
|
border-radius: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
box-shadow: 0 10px 15px -3px rgba(0, 86, 150, 0.2);
|
|
}
|
|
|
|
.section-card {
|
|
background: white;
|
|
border-radius: 1rem;
|
|
border: 2px solid #e2e8f0;
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
}
|
|
.section-card:hover {
|
|
border-color: #005696;
|
|
box-shadow: 0 10px 25px -5px rgba(0, 86, 150, 0.15);
|
|
}
|
|
|
|
.section-header {
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 2px solid #e2e8f0;
|
|
background: linear-gradient(to right, #f8fafc, #f1f5f9);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.section-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 0.75rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="p-6 md:p-8 bg-gradient-to-br from-light to-blue-50 min-h-screen">
|
|
<!-- Page Header -->
|
|
<div class="page-header-gradient">
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
|
<div class="flex items-center gap-3">
|
|
<div class="section-icon bg-white/20">
|
|
<i data-lucide="file-text" class="w-6 h-6 text-white"></i>
|
|
</div>
|
|
<div>
|
|
<a href="{% url 'accounts:onboarding-dashboard' %}" class="inline-flex items-center text-white/80 hover:text-white mb-1 font-medium transition">
|
|
<i data-lucide="arrow-left" class="w-4 h-4 mr-2"></i>
|
|
{% trans "Back to Dashboard" %}
|
|
</a>
|
|
<h1 class="text-2xl font-bold">
|
|
{% trans "Onboarding Content" %}
|
|
</h1>
|
|
<p class="text-white/80">{% trans "Manage the content shown during staff onboarding" %}</p>
|
|
</div>
|
|
</div>
|
|
<button type="button" onclick="openCreateModal()" class="bg-white text-[#005696] px-6 py-3 rounded-xl font-bold hover:bg-white/90 transition shadow-lg flex items-center gap-2">
|
|
<i data-lucide="plus" class="w-5 h-5"></i>
|
|
{% trans "Add Content" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content List -->
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon bg-gradient-to-br from-blue to-indigo-500">
|
|
<i data-lucide="folder-open" class="w-5 h-5 text-white"></i>
|
|
</div>
|
|
<h3 class="font-bold text-navy text-lg">{% trans "All Content Items" %}</h3>
|
|
</div>
|
|
{% if content_items %}
|
|
<div class="divide-y divide-blue-50">
|
|
{% for item in content_items %}
|
|
<div class="p-6 hover:bg-blue-50/50 transition">
|
|
<div class="flex items-start gap-4">
|
|
<div class="flex items-center justify-center w-12 h-12 bg-gradient-to-br from-blue to-indigo-500 rounded-xl flex-shrink-0">
|
|
<i data-lucide="file-text" class="w-6 h-6 text-white"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<h3 class="text-xl font-bold text-navy">{{ item.get_localized_title }}</h3>
|
|
{% if item.is_active %}
|
|
<span class="inline-flex items-center gap-1 bg-emerald-100 text-emerald-700 text-xs font-bold px-3 py-1 rounded-full">
|
|
<i data-lucide="check" class="w-3 h-3"></i>
|
|
{% trans "Active" %}
|
|
</span>
|
|
{% else %}
|
|
<span class="inline-flex items-center gap-1 bg-slate-100 text-slate-700 text-xs font-bold px-3 py-1 rounded-full">
|
|
<i data-lucide="x" class="w-3 h-3"></i>
|
|
{% trans "Inactive" %}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
<p class="text-slate text-sm mb-3">
|
|
{{ item.get_localized_description|truncatewords:20 }}
|
|
</p>
|
|
<div class="flex items-center gap-4 text-sm">
|
|
<span class="flex items-center gap-1 text-blue-700 font-medium">
|
|
<i data-lucide="tag" class="w-4 h-4"></i>
|
|
{{ item.code|default:"N/A" }}
|
|
</span>
|
|
{% if item.category %}
|
|
<span class="flex items-center gap-1 text-indigo-700 font-medium">
|
|
<i data-lucide="folder" class="w-4 h-4"></i>
|
|
{{ item.category.get_localized_name }}
|
|
</span>
|
|
{% endif %}
|
|
<span class="flex items-center gap-1 text-slate-500">
|
|
<i data-lucide="calendar" class="w-4 h-4"></i>
|
|
{{ item.created_at|date:"M d, Y" }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-2 flex-shrink-0">
|
|
<button type="button" onclick="editContentItem('{{ item.id }}')" class="p-2.5 text-blue-600 bg-blue-50 hover:bg-blue-100 rounded-xl transition" title="{% trans 'Edit' %}">
|
|
<i data-lucide="pencil" class="w-5 h-5"></i>
|
|
</button>
|
|
<button type="button" onclick="deleteContentItem('{{ item.id }}')" class="p-2.5 text-red-600 bg-red-50 hover:bg-red-100 rounded-xl transition" title="{% trans 'Delete' %}">
|
|
<i data-lucide="trash-2" class="w-5 h-5"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="p-12 text-center">
|
|
<div class="inline-flex items-center justify-center w-20 h-20 bg-gradient-to-br from-blue-100 to-indigo-100 rounded-full mb-4">
|
|
<i data-lucide="file-text" class="w-10 h-10 text-blue-500"></i>
|
|
</div>
|
|
<h3 class="text-xl font-bold text-navy mb-2">{% trans "No Content Yet" %}</h3>
|
|
<p class="text-slate mb-6">{% trans "Start by adding your first onboarding content item" %}</p>
|
|
<button type="button" onclick="openCreateModal()" class="inline-flex items-center bg-gradient-to-r from-blue to-navy text-white px-8 py-3 rounded-xl font-bold hover:from-navy hover:to-blue transition shadow-lg shadow-blue-200">
|
|
<i data-lucide="plus" class="w-5 h-5 mr-2"></i>
|
|
{% trans "Add Content" %}
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create/Edit Content Modal -->
|
|
<div id="contentModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50" style="display:none;">
|
|
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-y-auto m-4">
|
|
<div class="px-6 py-5 border-b border-blue-100 bg-gradient-to-r from-blue-50 to-transparent flex justify-between items-center sticky top-0 rounded-t-2xl">
|
|
<h3 id="modalTitle" class="font-bold text-navy flex items-center gap-2 text-lg">
|
|
<i data-lucide="plus-circle" class="w-5 h-5 text-blue"></i>
|
|
{% trans "Add New Content" %}
|
|
</h3>
|
|
<button type="button" onclick="closeModal()" class="text-slate hover:text-navy transition">
|
|
<i data-lucide="x" class="w-6 h-6"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-6">
|
|
<!-- Error Alert -->
|
|
<div id="formError" class="hidden mb-4 p-4 bg-red-50 border border-red-200 rounded-xl">
|
|
<p id="errorMessage" class="text-red-700 text-sm font-medium"></p>
|
|
</div>
|
|
|
|
<form id="contentForm">
|
|
{% csrf_token %}
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Code -->
|
|
<div>
|
|
<label for="code" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="tag" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Code" %} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" id="code" name="code" required
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'e.g. GENERAL_ORIENT_01' %}">
|
|
</div>
|
|
|
|
<!-- Category -->
|
|
<div>
|
|
<label for="category" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="folder" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Category" %} <span class="text-red-500">*</span>
|
|
</label>
|
|
<select id="category" name="category" required class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition">
|
|
{% for cat in category_list %}
|
|
<option value="{{ cat.id }}">{{ cat.name_en }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Title (English) -->
|
|
<div>
|
|
<label for="title_en" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="type" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Title (English)" %} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" id="title_en" name="title_en" required
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Content title in English' %}">
|
|
</div>
|
|
|
|
<!-- Title (Arabic) -->
|
|
<div>
|
|
<label for="title_ar" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="type" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Title (Arabic)" %}
|
|
</label>
|
|
<input type="text" id="title_ar" name="title_ar" dir="rtl"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Content title in Arabic' %}">
|
|
</div>
|
|
|
|
<!-- Description (English) -->
|
|
<div class="md:col-span-2">
|
|
<label for="description_en" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="align-left" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Description (English)" %} <span class="text-red-500">*</span>
|
|
</label>
|
|
<textarea id="description_en" name="description_en" required rows="3"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Describe the content in English' %}"></textarea>
|
|
</div>
|
|
|
|
<!-- Description (Arabic) -->
|
|
<div class="md:col-span-2">
|
|
<label for="description_ar" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="align-left" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Description (Arabic)" %}
|
|
</label>
|
|
<textarea id="description_ar" name="description_ar" dir="rtl" rows="3"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Describe the content in Arabic' %}"></textarea>
|
|
</div>
|
|
|
|
<!-- Content (English) -->
|
|
<div class="md:col-span-2">
|
|
<label for="content_en" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="file-text" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Content Body (English)" %}
|
|
</label>
|
|
<textarea id="content_en" name="content_en" rows="6"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Full content text in English' %}"></textarea>
|
|
</div>
|
|
|
|
<!-- Content (Arabic) -->
|
|
<div class="md:col-span-2">
|
|
<label for="content_ar" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="file-text" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Content Body (Arabic)" %}
|
|
</label>
|
|
<textarea id="content_ar" name="content_ar" dir="rtl" rows="6"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'Full content text in Arabic' %}"></textarea>
|
|
</div>
|
|
|
|
<!-- Icon -->
|
|
<div>
|
|
<label for="icon" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="image" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Icon" %}
|
|
</label>
|
|
<input type="text" id="icon" name="icon"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans 'e.g. fa-user, fa-shield' %}">
|
|
</div>
|
|
|
|
<!-- Color -->
|
|
<div>
|
|
<label for="color" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="palette" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Color" %}
|
|
</label>
|
|
<input type="text" id="color" name="color"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition"
|
|
placeholder="{% trans '#007bff' %}">
|
|
</div>
|
|
|
|
<!-- Order -->
|
|
<div>
|
|
<label for="order" class="block text-sm font-bold text-navy mb-2">
|
|
<i data-lucide="arrow-down-1-0" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "Display Order" %}
|
|
</label>
|
|
<input type="number" id="order" name="order" value="0" min="0"
|
|
class="w-full px-4 py-2.5 border-2 border-blue-100 rounded-xl text-navy focus:ring-2 focus:ring-blue focus:border-transparent transition">
|
|
</div>
|
|
|
|
<!-- Active -->
|
|
<div class="flex items-center gap-3">
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" id="is_active" name="is_active" checked class="sr-only peer">
|
|
<div class="w-11 h-6 bg-slate-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue"></div>
|
|
<span class="ms-3 text-sm font-bold text-navy">{% trans "Active" %}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="flex justify-end gap-3 mt-8 pt-6 border-t border-blue-100">
|
|
<button type="button" onclick="closeModal()" class="px-6 py-2.5 border-2 border-blue-100 text-slate rounded-xl font-bold hover:bg-blue-50 transition">
|
|
{% trans "Cancel" %}
|
|
</button>
|
|
<button type="submit" id="saveBtn" class="px-8 py-2.5 bg-gradient-to-r from-blue to-navy text-white rounded-xl font-bold hover:from-navy hover:to-blue transition shadow-lg flex items-center gap-2">
|
|
<svg id="saveBtnSpinner" class="hidden animate-spin w-4 h-4" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<span id="saveBtnText">{% trans "Save Content" %}</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const API_BASE = '/accounts/api/content-items/';
|
|
let editItemId = null;
|
|
|
|
function openCreateModal() {
|
|
editItemId = null;
|
|
document.getElementById('contentForm').reset();
|
|
document.getElementById('is_active').checked = true;
|
|
document.getElementById('modalTitle').innerHTML = '<i data-lucide="plus-circle" class="w-5 h-5 text-blue"></i> {% trans "Add New Content" %}';
|
|
document.getElementById('saveBtnText').textContent = '{% trans "Save Content" %}';
|
|
document.getElementById('formError').classList.add('hidden');
|
|
document.getElementById('contentModal').style.display = 'flex';
|
|
lucide.createIcons();
|
|
}
|
|
|
|
function closeModal() {
|
|
document.getElementById('contentModal').style.display = 'none';
|
|
document.getElementById('contentForm').reset();
|
|
document.getElementById('formError').classList.add('hidden');
|
|
editItemId = null;
|
|
}
|
|
|
|
document.getElementById('contentModal').addEventListener('click', function(e) {
|
|
if (e.target === this) closeModal();
|
|
});
|
|
|
|
document.getElementById('contentForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const form = this;
|
|
if (!form.checkValidity()) {
|
|
form.reportValidity();
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData(form);
|
|
const data = {
|
|
code: formData.get('code'),
|
|
category: formData.get('category'),
|
|
title_en: formData.get('title_en'),
|
|
title_ar: formData.get('title_ar'),
|
|
description_en: formData.get('description_en'),
|
|
description_ar: formData.get('description_ar'),
|
|
content_en: formData.get('content_en'),
|
|
content_ar: formData.get('content_ar'),
|
|
icon: formData.get('icon') || '',
|
|
color: formData.get('color') || '',
|
|
order: parseInt(formData.get('order')) || 0,
|
|
is_active: formData.get('is_active') === 'on',
|
|
};
|
|
|
|
const saveBtn = document.getElementById('saveBtn');
|
|
const saveBtnText = document.getElementById('saveBtnText');
|
|
const saveBtnSpinner = document.getElementById('saveBtnSpinner');
|
|
const errorAlert = document.getElementById('formError');
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
|
|
saveBtn.disabled = true;
|
|
saveBtnText.textContent = '{% trans "Saving..." %}';
|
|
saveBtnSpinner.classList.remove('hidden');
|
|
|
|
try {
|
|
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
const url = editItemId ? `${API_BASE}${editItemId}/` : API_BASE;
|
|
const method = editItemId ? 'PUT' : 'POST';
|
|
|
|
const response = await fetch(url, {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': csrfToken
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const responseData = await response.json();
|
|
|
|
if (response.ok) {
|
|
closeModal();
|
|
showAlert(editItemId
|
|
? '{% trans "Content updated successfully!" %}'
|
|
: '{% trans "Content created successfully!" %}', 'success');
|
|
setTimeout(() => { window.location.reload(); }, 1000);
|
|
} else {
|
|
const errors = [];
|
|
for (const [field, msgs] of Object.entries(responseData)) {
|
|
errors.push(`${field}: ${msgs.join(', ')}`);
|
|
}
|
|
errorMessage.textContent = errors.join(' | ');
|
|
errorAlert.classList.remove('hidden');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
errorMessage.textContent = '{% trans "An error occurred. Please try again." %}';
|
|
errorAlert.classList.remove('hidden');
|
|
} finally {
|
|
saveBtn.disabled = false;
|
|
saveBtnText.textContent = '{% trans "Save Content" %}';
|
|
saveBtnSpinner.classList.add('hidden');
|
|
}
|
|
});
|
|
|
|
async function editContentItem(itemId) {
|
|
try {
|
|
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
const response = await fetch(`${API_BASE}${itemId}/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': csrfToken
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const item = await response.json();
|
|
|
|
document.getElementById('code').value = item.code || '';
|
|
document.getElementById('category').value = item.category || '';
|
|
document.getElementById('title_en').value = item.title_en || '';
|
|
document.getElementById('title_ar').value = item.title_ar || '';
|
|
document.getElementById('description_en').value = item.description_en || '';
|
|
document.getElementById('description_ar').value = item.description_ar || '';
|
|
document.getElementById('content_en').value = item.content_en || '';
|
|
document.getElementById('content_ar').value = item.content_ar || '';
|
|
document.getElementById('icon').value = item.icon || '';
|
|
document.getElementById('color').value = item.color || '';
|
|
document.getElementById('order').value = item.order || 0;
|
|
document.getElementById('is_active').checked = item.is_active !== false;
|
|
|
|
editItemId = itemId;
|
|
document.getElementById('modalTitle').innerHTML = '<i data-lucide="pencil" class="w-5 h-5 text-blue"></i> {% trans "Edit Content" %}';
|
|
document.getElementById('saveBtnText').textContent = '{% trans "Update Content" %}';
|
|
document.getElementById('formError').classList.add('hidden');
|
|
document.getElementById('contentModal').style.display = 'flex';
|
|
lucide.createIcons();
|
|
} else {
|
|
showAlert('{% trans "Failed to load content item" %}', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
showAlert('{% trans "An error occurred loading the item" %}', 'error');
|
|
}
|
|
}
|
|
|
|
async function deleteContentItem(itemId) {
|
|
if (!confirm('{% trans "Are you sure you want to delete this content item?" %}')) return;
|
|
|
|
try {
|
|
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
const response = await fetch(`${API_BASE}${itemId}/`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': csrfToken
|
|
}
|
|
});
|
|
|
|
if (response.ok || response.status === 204) {
|
|
showAlert('{% trans "Content item deleted successfully!" %}', 'success');
|
|
setTimeout(() => { window.location.reload(); }, 1000);
|
|
} else {
|
|
showAlert('{% trans "Failed to delete content item" %}', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
showAlert('{% trans "An error occurred. Please try again." %}', 'error');
|
|
}
|
|
}
|
|
|
|
function showAlert(message, type = 'info') {
|
|
const alert = document.createElement('div');
|
|
const bgColor = type === 'success' ? 'bg-gradient-to-r from-emerald-500 to-emerald-600' : 'bg-gradient-to-r from-blue-500 to-blue-600';
|
|
alert.className = `${bgColor} text-white px-6 py-4 rounded-xl shadow-xl z-50 flex items-center gap-3 fixed top-4 right-4`;
|
|
alert.innerHTML = `
|
|
<i data-lucide="${type === 'success' ? 'check-circle' : 'info'}" class="w-5 h-5"></i>
|
|
<span class="font-semibold">${message}</span>
|
|
<button type="button" onclick="this.parentElement.remove()" class="text-white/80 hover:text-white">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
</button>
|
|
`;
|
|
document.body.appendChild(alert);
|
|
lucide.createIcons();
|
|
setTimeout(() => { alert.remove(); }, 3000);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
lucide.createIcons();
|
|
});
|
|
</script>
|
|
{% endblock %}
|