forked from UKSOURCE/cms.hailearning.edu.vn
feat: Implement admin management for FAQ, Testimonial, and Video Gallery sections with new controllers, views, and routing.
This commit is contained in:
216
views/admin/home/faq/index.ejs
Normal file
216
views/admin/home/faq/index.ejs
Normal file
@@ -0,0 +1,216 @@
|
||||
<div class="container">
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-0" style="color: var(--primary-dark);">
|
||||
<%= title %>
|
||||
</h1>
|
||||
<p class="text-muted mb-0">Manage FAQ section content</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="<%= frontendUrl %>/" class="btn btn-outline-primary" target="_blank">
|
||||
<i class="fas fa-external-link-alt me-2"></i>View Homepage
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<form method="POST" class="content-with-fixed-buttons" id="faqForm" action="/admin/faq/update">
|
||||
<!-- Hidden input for items JSON data -->
|
||||
<input type="hidden" name="items" id="itemsJson">
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white border-bottom">
|
||||
<h5 class="mb-0"><i class="fas fa-question-circle me-2"></i>FAQ Settings</h5>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<!-- Header Section -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Heading</label>
|
||||
<input type="text" class="form-control" name="heading" id="heading"
|
||||
value="<%= data.heading || '' %>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Subheading</label>
|
||||
<input type="text" class="form-control" name="subheading" id="subheading"
|
||||
value="<%= data.subheading || '' %>">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label fw-medium">Description</label>
|
||||
<textarea class="form-control" name="description" id="description"
|
||||
rows="2"><%= data.description || '' %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA Button Section -->
|
||||
<h6 class="fw-medium mb-3">CTA Button</h6>
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Button Label</label>
|
||||
<input type="text" class="form-control" name="ctaLabel"
|
||||
value="<%= data.ctaButton && data.ctaButton.label ? data.ctaButton.label : '' %>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Button Link</label>
|
||||
<input type="text" class="form-control" name="ctaHref"
|
||||
value="<%= data.ctaButton && data.ctaButton.href ? data.ctaButton.href : '' %>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<!-- FAQ Items -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h6 class="fw-medium mb-0">Frequently Asked Questions</h6>
|
||||
<button type="button" class="btn btn-primary btn-sm" onclick="addFaqItem()">
|
||||
<i class="fas fa-plus"></i> Add Question
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="faqItemsContainer">
|
||||
<% if (data.items && data.items.length> 0) { %>
|
||||
<% data.items.forEach((item, index)=> { %>
|
||||
<div class="card mb-3 faq-item">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">Question</label>
|
||||
<input type="text" class="form-control"
|
||||
name="itemQuestion_<%= index %>"
|
||||
value="<%= item.question || '' %>">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">Answer</label>
|
||||
<textarea class="form-control" name="itemAnswer_<%= index %>"
|
||||
rows="3"><%= item.answer || '' %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm mt-3"
|
||||
onclick="removeFaqItem(this)">
|
||||
<i class="fas fa-trash me-2"></i>Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% }); %>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fixed Bottom Buttons -->
|
||||
<div class="fixed-bottom-buttons">
|
||||
<button type="reset" class="btn btn-secondary" onclick="resetForm()">
|
||||
<i class="fas fa-undo me-2"></i>Reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" id="submitBtn">
|
||||
<i class="fas fa-save me-2"></i>Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="application/json" id="faqDataJson"><%- JSON.stringify(data) %></script>
|
||||
|
||||
<script>
|
||||
let originalFormData = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
try {
|
||||
var jsonScript = document.getElementById('faqDataJson');
|
||||
originalFormData = JSON.parse(jsonScript.textContent);
|
||||
} catch (e) {
|
||||
console.error('Error parsing originalFormData:', e);
|
||||
originalFormData = { items: [] };
|
||||
}
|
||||
|
||||
initializeFormHandlers();
|
||||
});
|
||||
|
||||
function initializeFormHandlers() {
|
||||
const form = document.getElementById('faqForm');
|
||||
form.addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Saving...';
|
||||
|
||||
try {
|
||||
updateItemsJson();
|
||||
this.submit();
|
||||
} catch (error) {
|
||||
console.error('Error updating data:', error);
|
||||
alert('Failed to process form data. Please try again.');
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = '<i class="fas fa-save me-2"></i>Save Changes';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateItemsJson() {
|
||||
const items = [];
|
||||
document.querySelectorAll('.faq-item').forEach((item, index) => {
|
||||
const question = item.querySelector(`[name="itemQuestion_${index}"]`)?.value ||
|
||||
item.querySelector('[name^="itemQuestion_"]')?.value || '';
|
||||
const answer = item.querySelector(`[name="itemAnswer_${index}"]`)?.value ||
|
||||
item.querySelector('[name^="itemAnswer_"]')?.value || '';
|
||||
|
||||
items.push({ question, answer });
|
||||
});
|
||||
|
||||
document.getElementById('itemsJson').value = JSON.stringify(items);
|
||||
}
|
||||
|
||||
function addFaqItem() {
|
||||
const container = document.getElementById('faqItemsContainer');
|
||||
const index = container.querySelectorAll('.faq-item').length;
|
||||
|
||||
const html = `
|
||||
<div class="card mb-3 faq-item">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">Question</label>
|
||||
<input type="text" class="form-control" name="itemQuestion_${index}" value="">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">Answer</label>
|
||||
<textarea class="form-control" name="itemAnswer_${index}" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm mt-3"
|
||||
onclick="removeFaqItem(this)">
|
||||
<i class="fas fa-trash me-2"></i>Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
|
||||
function removeFaqItem(button) {
|
||||
if (confirm('Are you sure you want to remove this question?')) {
|
||||
button.closest('.faq-item').remove();
|
||||
reindexItems();
|
||||
}
|
||||
}
|
||||
|
||||
function reindexItems() {
|
||||
document.querySelectorAll('.faq-item').forEach((item, index) => {
|
||||
item.querySelectorAll('[name^="item"]').forEach(input => {
|
||||
const baseName = input.name.replace(/_\d+$/, '');
|
||||
input.name = `${baseName}_${index}`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
if (confirm('Are you sure you want to reset all changes?')) {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user