Files
cms.uldp.edu.vn/views/admin/about/index.ejs
r2xrzh9q2z-lab d1b931d547 first commit
2026-02-02 11:07:09 +07:00

1024 lines
47 KiB
Plaintext

<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">Edit content displayed on About page</p>
</div>
<div>
<a href="<%= frontendUrl %>/about-us/" class="btn btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-2"></i>View About Page
</a>
</div>
</div>
<div class="row">
<div class="col-12">
<form action="/admin/about/update" method="POST" class="content-with-fixed-buttons" id="aboutForm">
<!-- Hidden inputs for JSON data -->
<input type="hidden" name="banner" id="bannerJson">
<input type="hidden" name="about" id="aboutJson">
<input type="hidden" name="values" id="valuesJson">
<input type="hidden" name="education" id="educationJson">
<input type="hidden" name="advantages" id="advantagesJson">
<input type="hidden" name="academic_board" id="academicBoardJson">
<!-- Navigation Tabs -->
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white border-bottom">
<ul class="nav nav-tabs card-header-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="tab" href="#banner" role="tab">
<i class="fas fa-image me-2"></i>Banner
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#about-section" role="tab">
<i class="fas fa-info-circle me-2"></i>About
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#values" role="tab">
<i class="fas fa-star me-2"></i>Values
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#education" role="tab">
<i class="fas fa-graduation-cap me-2"></i>Education
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#advantages" role="tab">
<i class="fas fa-check-circle me-2"></i>Advantages
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#academic-board" role="tab">
<i class="fas fa-users me-2"></i>Academic Board
</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<!-- Banner Tab -->
<div class="tab-pane fade show active" id="banner" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-body">
<div class="row">
<div class="col-md-5">
<label class="form-label fw-medium">Banner Image</label>
<div class="input-group mb-2">
<input type="text" class="form-control" id="bannerImage" name="bannerImage" value="<%= data.banner.image %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="bannerImage" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
<small class="form-text text-muted">Recommended size: 1920x1080px</small>
</div>
<div class="col-md-7">
<% if (data.banner.image) { %>
<img src="<%= data.banner.image %>" class="img-thumbnail" style="height: 300px; width: 100%; object-fit: cover;" alt="Banner image preview">
<% } %>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<label class="form-label fw-medium">Title</label>
<input type="text" class="form-control" id="bannerTitle" name="bannerTitle" value="<%= data.banner.title %>">
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<label class="form-label fw-medium">Description</label>
<textarea class="form-control" id="bannerText" name="bannerText" rows="3"><%= data.banner.text %></textarea>
</div>
</div>
</div>
</div>
</div>
<!-- About Section Tab -->
<div class="tab-pane fade" id="about-section" role="tabpanel">
<div class="card border shadow-sm mb-4">
<div class="card-body">
<div class="row g-3">
<div class="col-md-12">
<label class="form-label fw-medium">Title</label>
<input type="text" class="form-control" id="aboutTitle" name="aboutTitle" value="<%= data.about.title %>">
</div>
<!-- Paragraphs -->
<div class="col-md-12">
<label class="form-label fw-medium">Paragraphs</label>
<div id="paragraphsContainer">
<% data.about.paragraphs.forEach((paragraph, index) => { %>
<div class="input-group mb-3">
<textarea class="form-control" name="paragraph_<%= index %>" rows="3"><%= paragraph %></textarea>
<button type="button" class="btn btn-outline-danger" onclick="removeParagraph(this)">
<i class="fas fa-trash"></i>
</button>
</div>
<% }); %>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addParagraph()">
<i class="fas fa-plus me-2"></i>Add Paragraph
</button>
</div>
<!-- List Items -->
<div class="col-md-12 mt-4">
<label class="form-label fw-medium">List Items</label>
<div id="listItemsContainer">
<% data.about.list_items.forEach((item, index) => { %>
<div class="input-group mb-3">
<input type="text" class="form-control" name="listItem_<%= index %>" value="<%= item %>">
<button type="button" class="btn btn-outline-danger" onclick="removeListItem(this)">
<i class="fas fa-trash"></i>
</button>
</div>
<% }); %>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addListItem()">
<i class="fas fa-plus me-2"></i>Add List Item
</button>
</div>
<!-- Button -->
<div class="col-md-6">
<label class="form-label fw-medium">Button Text</label>
<input type="text" class="form-control" id="aboutButtonText" name="aboutButtonText" value="<%= data.about.button.text %>">
</div>
<div class="col-md-6">
<label class="form-label fw-medium">Button URL</label>
<input type="text" class="form-control" id="aboutButtonUrl" name="aboutButtonUrl" value="<%= data.about.button.url %>">
</div>
<!-- Image -->
<div class="col-md-12 mt-4">
<label class="form-label fw-medium">Section Image</label>
<div class="row">
<div class="col-md-5">
<div class="input-group mb-2">
<input type="text" class="form-control" id="aboutImage" name="aboutImage" value="<%= data.about.image %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="aboutImage" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
</div>
<div class="col-md-7">
<% if (data.about.image) { %>
<img src="<%= data.about.image %>" class="img-thumbnail" style="height: 300px; width: 100%; object-fit: contain;" alt="Section image preview">
<% } %>
</div>
</div>
</div>
<!-- Quote -->
<div class="col-12 mt-4">
<div class="card border">
<div class="card-header bg-light">
<h6 class="mb-0">Quote Section</h6>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Quote Mark Image</label>
<div class="input-group">
<input type="text" class="form-control" id="quoteMarkImage" name="quoteMarkImage" value="<%= data.about.quote.mark_image %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="quoteMarkImage" data-image-type="icons">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Quote Title</label>
<input type="text" class="form-control" id="quoteTitle" name="quoteTitle" value="<%= data.about.quote.title %>">
</div>
<div class="col-md-12">
<label class="form-label">Quote Text</label>
<textarea class="form-control" id="quoteText" name="quoteText" rows="3"><%= data.about.quote.text %></textarea>
</div>
<div class="col-md-6">
<label class="form-label">Author</label>
<input type="text" class="form-control" id="quoteAuthor" name="quoteAuthor" value="<%= data.about.quote.author %>">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Values Tab -->
<div class="tab-pane fade" id="values" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-body">
<!-- Background Image -->
<div class="row mb-4">
<div class="col-md-5">
<label class="form-label fw-medium">Background Image</label>
<div class="input-group mb-2">
<input type="text" class="form-control" id="valuesBackgroundImage" name="valuesBackgroundImage" value="<%= data.values.background_image %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="valuesBackgroundImage" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
</div>
<div class="col-md-7">
<% if (data.values.background_image) { %>
<img src="<%= data.values.background_image %>" class="img-thumbnail" style="height: 200px; width: 100%; object-fit: contain;" alt="Background image preview">
<% } %>
</div>
</div>
<!-- Values Items -->
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="fw-medium mb-0">Values</h6>
<button type="button" class="btn btn-primary btn-sm" onclick="addValue()">
<i class="fas fa-plus"></i>
</button>
</div>
<div id="valuesContainer">
<% data.values.items.forEach((item, index) => { %>
<div class="card mb-3 value-item">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0 text-decoration-underline">Value Information</h6>
<button type="button" class="btn btn-danger btn-sm" onclick="removeValue(this)">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Icon</label>
<div class="input-group">
<input type="text" class="form-control" name="valueIcon_<%= index %>" value="<%= item.icon %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="valueIcon_<%= index %>" data-image-type="icons">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
<% if (item.icon) { %>
<div class="text-center mt-2">
<img src="<%= item.icon %>" class="img-thumbnail" style="height: 40px; width: 40px; object-fit: contain;" alt="Icon preview">
</div>
<% } %>
</div>
<div class="col-md-4">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="valueTitle_<%= index %>" value="<%= item.title %>">
</div>
<div class="col-md-4">
<label class="form-label">Text</label>
<textarea class="form-control" name="valueText_<%= index %>" rows="2"><%= item.text %></textarea>
</div>
</div>
</div>
</div>
<% }); %>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Education Tab -->
<div class="tab-pane fade" id="education" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-body">
<!-- Student Images -->
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label fw-medium">Student Image 1</label>
<div class="input-group mb-2">
<input type="text" class="form-control" id="student1Image" name="student1Image" value="<%= data.education.images.student1 %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="student1Image" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
<% if (data.education.images.student1) { %>
<img src="<%= data.education.images.student1 %>" class="img-thumbnail mt-2" style="height: 300px; width: 100%; object-fit: cover;" alt="Student 1 image preview">
<% } %>
</div>
<div class="col-md-6">
<label class="form-label fw-medium">Student Image 2 / YouTube Video</label>
<div class="input-group mb-2">
<input type="text" class="form-control" id="student2Image" name="student2Image" value="<%= data.education.images.student2 %>" placeholder="Enter YouTube URL (e.g., https://youtu.be/VIDEO_ID)">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="student2Image" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload Image
</button>
</div>
<div class="form-text text-muted mb-2">
Enter YouTube URL or upload an image file (jpg, png, gif).
</div>
<% if (data.education.images.student2) { %>
<% if (data.education.images.student2.includes('youtu.be') || data.education.images.student2.includes('youtube.com')) { %>
<div class="youtube-preview mt-2" style="height: 300px; width: 100%;">
<iframe width="100%" height="100%" src="<%= data.education.images.student2.replace('youtu.be/', 'youtube.com/embed/').replace('watch?v=', 'embed/') %>" frameborder="0" allowfullscreen></iframe>
</div>
<% } else { %>
<img src="<%= data.education.images.student2 %>" class="img-thumbnail mt-2" style="height: 300px; width: 100%; object-fit: cover;" alt="Student 2 image preview">
<% } %>
<% } %>
</div>
</div>
<!-- Education Content -->
<div class="row g-3">
<div class="col-md-12">
<label class="form-label fw-medium">Subtitle</label>
<input type="text" class="form-control" id="educationSubtitle" name="educationSubtitle" value="<%= data.education.subtitle %>">
</div>
<div class="col-md-12">
<label class="form-label fw-medium">Title</label>
<input type="text" class="form-control" id="educationTitle" name="educationTitle" value="<%= data.education.title %>">
</div>
<div class="col-md-12">
<label class="form-label fw-medium">Text</label>
<textarea class="form-control" id="educationText" name="educationText" rows="4"><%= data.education.text %></textarea>
</div>
</div>
</div>
</div>
</div>
<!-- Advantages Tab -->
<div class="tab-pane fade" id="advantages" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-body">
<div class="row mb-4">
<div class="col-12">
<label class="form-label fw-medium">Title</label>
<input type="text" class="form-control" id="advantagesTitle" name="advantagesTitle" value="<%= data.advantages.title %>">
</div>
</div>
<!-- Advantages Items -->
<div class="row">
<div class="col-12">
<label class="form-label fw-medium">Advantages</label>
<div id="advantagesContainer">
<% data.advantages.items.forEach((item, index) => { %>
<div class="card mb-3 advantage-item">
<div class="card-body">
<div class="row g-3">
<div class="col-md-2">
<label class="form-label">Number</label>
<input type="text" class="form-control" name="advantageNumber_<%= index %>" value="<%= item.number %>">
</div>
<div class="col-md-4">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="advantageTitle_<%= index %>" value="<%= item.title %>">
</div>
<div class="col-md-6">
<label class="form-label">Text</label>
<textarea class="form-control" name="advantageText_<%= index %>" rows="2"><%= item.text %></textarea>
</div>
</div>
<button type="button" class="btn btn-outline-danger btn-sm mt-3" onclick="removeAdvantage(this)">
<i class="fas fa-trash me-2"></i>Remove Advantage
</button>
</div>
</div>
<% }); %>
</div>
<button type="button" class="btn btn-outline-primary" onclick="addAdvantage()">
<i class="fas fa-plus me-2"></i>Add Advantage
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Academic Board Tab -->
<div class="tab-pane fade" id="academic-board" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-body">
<div class="row mb-4">
<div class="col-12">
<label class="form-label fw-medium">Title</label>
<input type="text" class="form-control" id="academicBoardTitle" name="academicBoardTitle" value="<%= data.academic_board.title %>">
</div>
</div>
<!-- Board Members -->
<div class="row">
<div class="col-12">
<label class="form-label fw-medium">Board Members</label>
<div id="boardMembersContainer">
<% data.academic_board.members.forEach((member, index) => { %>
<div class="card mb-3 board-member">
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<label class="form-label">Image</label>
<div class="input-group">
<input type="text" class="form-control" name="memberImage_<%= index %>" value="<%= member.image %>">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="memberImage_<%= index %>" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
<% if (member.image) { %>
<img src="<%= member.image %>" class="img-thumbnail mt-2" style="height: 300px; width: 100%; object-fit: cover;" alt="Member image preview">
<% } %>
</div>
<div class="col-md-3">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="memberTitle_<%= index %>" value="<%= member.title %>">
</div>
<div class="col-md-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="memberName_<%= index %>" value="<%= member.name %>">
</div>
<div class="col-md-3">
<label class="form-label">Color</label>
<select class="form-select" name="memberColor_<%= index %>">
<option value="#065c2e" <%= member.color === '#065c2e' ? 'selected' : '' %>>Green</option>
<option value="#ffa500" <%= member.color === '#ffa500' ? 'selected' : '' %>>Orange</option>
</select>
</div>
</div>
<button type="button" class="btn btn-outline-danger btn-sm mt-3" onclick="removeBoardMember(this)">
<i class="fas fa-trash me-2"></i>Remove Member
</button>
</div>
</div>
<% }); %>
</div>
<button type="button" class="btn btn-outline-primary" onclick="addBoardMember()">
<i class="fas fa-plus me-2"></i>Add Board Member
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Fixed Bottom Buttons -->
<div class="fixed-bottom-buttons">
<button type="reset" class="btn btn-secondary">
<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>
<!-- Scripts -->
<script>
let originalFormData = null;
document.addEventListener('DOMContentLoaded', function() {
// Initialize form data
// eslint-disable-next-line no-undef
originalFormData = <%- JSON.stringify(data) %>;
// Set initial JSON values
updateAllJsonInputs(originalFormData);
// Initialize form handlers
initializeFormHandlers();
});
function initializeFormHandlers() {
// Form submission
const form = document.getElementById('aboutForm');
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 {
updateJsonData();
this.submit();
} catch (error) {
console.error('Error updating data:', error);
showError('Failed to process form data. Please try again.');
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="fas fa-save me-2"></i>Save Changes';
}
});
// Initialize image upload buttons
document.querySelectorAll('.btn-upload-image').forEach(button => {
button.addEventListener('click', function() {
const targetInput = this.dataset.targetInput;
const imageType = this.dataset.imageType;
openImageUploader(targetInput, imageType);
});
});
// Initialize YouTube URL input handler
const student2Input = document.getElementById('student2Image');
if (student2Input) {
student2Input.addEventListener('input', function() {
updateStudent2Preview(this.value);
});
}
}
function openImageUploader(targetInput, imageType) {
// Tạo input file ẩn
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/*';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
// Xử lý khi chọn file
fileInput.onchange = async function(e) {
const file = e.target.files[0];
if (!file) return;
try {
// Tạo FormData
const formData = new FormData();
formData.append('image', file);
// Disable nút upload và hiển thị loading
const uploadBtn = document.querySelector(`[data-target-input="${targetInput}"]`);
const originalBtnHtml = uploadBtn.innerHTML;
uploadBtn.disabled = true;
uploadBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Uploading...';
// Gửi request upload
const response = await fetch(`/admin/upload/image?imageType=${imageType}`, {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error('Upload failed');
}
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'Upload failed');
}
// Cập nhật đường dẫn ảnh vào input (keep relative path for storage)
const input = document.getElementById(targetInput) || document.querySelector(`[name="${targetInput}"]`);
if (!input) {
throw new Error('Target input not found');
}
input.value = result.path;
// Build absolute URL for preview (works when frontend is on different origin)
let previewUrl = result.path;
if (!/^https?:\/\//i.test(previewUrl)) {
previewUrl = window.location.origin.replace(/\/$/, '') + previewUrl;
}
// Find a sensible container for preview: look for existing .mt-2 near the input, or append to input's column
let containerForPreview = input.closest('.col-md-7') || input.closest('.col-md-6') || input.parentElement;
let imgPreview = containerForPreview.querySelector('.mt-2');
if (!imgPreview) {
imgPreview = document.createElement('div');
imgPreview.className = 'mt-2';
const img = document.createElement('img');
img.className = 'img-thumbnail';
// Set style dựa vào loại ảnh
if (targetInput.toLowerCase().includes('logo') || targetInput.toLowerCase().includes('icon')) {
img.style.height = '100px';
img.style.objectFit = 'contain';
} else if (targetInput.toLowerCase().includes('member')) {
img.style.height = '300px';
img.style.width = '100%';
img.style.objectFit = 'cover';
} else {
img.style.height = '200px';
img.style.width = '100%';
img.style.objectFit = 'cover';
}
img.alt = 'Image preview';
imgPreview.appendChild(img);
containerForPreview.appendChild(imgPreview);
}
// Cập nhật ảnh preview
const imgEl = imgPreview.querySelector('img');
if (imgEl) imgEl.src = previewUrl;
// Nếu là student2Image, cập nhật preview (handles youtube or image)
if (targetInput === 'student2Image') {
updateStudent2Preview(result.path.startsWith('/') ? previewUrl : result.path);
}
// Hiển thị thông báo thành công
if (window.toastManager) {
window.toastManager.success('Image uploaded successfully');
} else {
showToast('Success', 'Image uploaded successfully', 'success');
}
} catch (error) {
console.error('Upload error:', error);
if (window.toastManager) {
window.toastManager.error('Failed to upload image: ' + error.message);
} else {
showToast('Error', 'Failed to upload image: ' + error.message, 'error');
}
} finally {
// Restore nút upload
const uploadBtn = document.querySelector(`[data-target-input="${targetInput}"]`);
if (uploadBtn) {
uploadBtn.disabled = false;
uploadBtn.innerHTML = originalBtnHtml;
}
// Xóa input file
document.body.removeChild(fileInput);
}
};
// Trigger click để mở dialog chọn file
fileInput.click();
}
// Function to update Student 2 preview (YouTube or Image)
function updateStudent2Preview(url) {
const input = document.getElementById('student2Image');
const parentElement = input.closest('.col-md-6');
// Remove existing preview
const existingPreview = parentElement.querySelector('.youtube-preview, .img-thumbnail');
if (existingPreview) {
existingPreview.remove();
}
if (!url || url.trim() === '') {
return;
}
const trimmedUrl = url.trim();
// Check if it's a YouTube URL
if (trimmedUrl.includes('youtu.be') || trimmedUrl.includes('youtube.com')) {
// Create YouTube embed preview
const youtubePreview = document.createElement('div');
youtubePreview.className = 'youtube-preview mt-2';
youtubePreview.style.height = '300px';
youtubePreview.style.width = '100%';
const iframe = document.createElement('iframe');
iframe.width = '100%';
iframe.height = '100%';
iframe.frameBorder = '0';
iframe.allowFullscreen = true;
// Convert YouTube URL to embed format
let embedUrl = trimmedUrl;
if (embedUrl.includes('youtu.be/')) {
embedUrl = embedUrl.replace('youtu.be/', 'youtube.com/embed/');
} else if (embedUrl.includes('watch?v=')) {
embedUrl = embedUrl.replace('watch?v=', 'embed/');
}
iframe.src = embedUrl;
youtubePreview.appendChild(iframe);
parentElement.appendChild(youtubePreview);
} else if (trimmedUrl.match(/\.(jpg|jpeg|png|gif|webp)$/i)) {
// It's an image URL
const imgPreview = document.createElement('img');
imgPreview.className = 'img-thumbnail mt-2';
imgPreview.style.height = '300px';
imgPreview.style.width = '100%';
imgPreview.style.objectFit = 'cover';
imgPreview.alt = 'Student 2 image preview';
imgPreview.src = trimmedUrl;
parentElement.appendChild(imgPreview);
}
}
// Hiển thị toast message
function showToast(title, message, type = 'info') {
const toast = document.createElement('div');
toast.className = `toast align-items-center text-white bg-${type === 'error' ? 'danger' : type} border-0`;
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomic', 'true');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">
<strong>${title}:</strong> ${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
// Thêm toast vào container
const container = document.querySelector('.toast-container');
if (!container) {
const newContainer = document.createElement('div');
newContainer.className = 'toast-container position-fixed top-0 end-0 p-3';
document.body.appendChild(newContainer);
newContainer.appendChild(toast);
} else {
container.appendChild(toast);
}
// Hiển thị toast
const bsToast = new bootstrap.Toast(toast, {
animation: true,
autohide: true,
delay: 3000
});
bsToast.show();
// Xóa toast sau khi ẩn
toast.addEventListener('hidden.bs.toast', () => {
toast.remove();
});
}
function resetForm() {
if (confirm('Are you sure you want to reset all changes?')) {
updateAllJsonInputs(originalFormData);
location.reload();
}
}
function showError(message) {
const alertHtml = `
<div class="alert alert-danger alert-dismissible fade show" role="alert">
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
`;
document.querySelector('.container').insertAdjacentHTML('afterbegin', alertHtml);
}
function updateAllJsonInputs(data) {
document.getElementById('bannerJson').value = JSON.stringify(data.banner || {});
document.getElementById('aboutJson').value = JSON.stringify(data.about || {});
document.getElementById('valuesJson').value = JSON.stringify(data.values || {});
document.getElementById('educationJson').value = JSON.stringify(data.education || {});
document.getElementById('advantagesJson').value = JSON.stringify(data.advantages || {});
document.getElementById('academicBoardJson').value = JSON.stringify(data.academic_board || {});
}
// Dynamic form functions
function addParagraph() {
const container = document.getElementById('paragraphsContainer');
const index = container.children.length;
const html = `
<div class="input-group mb-3">
<textarea class="form-control" name="paragraph_${index}" rows="3"></textarea>
<button type="button" class="btn btn-outline-danger" onclick="removeParagraph(this)">
<i class="fas fa-trash"></i>
</button>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
}
function removeParagraph(button) {
button.closest('.input-group').remove();
}
function addListItem() {
const container = document.getElementById('listItemsContainer');
const index = container.children.length;
const html = `
<div class="input-group mb-3">
<input type="text" class="form-control" name="listItem_${index}">
<button type="button" class="btn btn-outline-danger" onclick="removeListItem(this)">
<i class="fas fa-trash"></i>
</button>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
}
function removeListItem(button) {
button.closest('.input-group').remove();
}
function addValue() {
const container = document.getElementById('valuesContainer');
const index = container.children.length;
const html = `
<div class="card mb-3 value-item">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0 text-decoration-underline">Value Information</h6>
<button type="button" class="btn btn-danger btn-sm" onclick="removeValue(this)">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Icon</label>
<div class="input-group">
<input type="text" class="form-control" name="valueIcon_${index}">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="valueIcon_${index}" data-image-type="icons">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
</div>
<div class="col-md-4">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="valueTitle_${index}">
</div>
<div class="col-md-4">
<label class="form-label">Text</label>
<textarea class="form-control" name="valueText_${index}" rows="2"></textarea>
</div>
</div>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
}
function removeValue(button) {
button.closest('.value-item').remove();
}
function addAdvantage() {
const container = document.getElementById('advantagesContainer');
const index = container.children.length;
const html = `
<div class="card mb-3 advantage-item">
<div class="card-body">
<div class="row g-3">
<div class="col-md-2">
<label class="form-label">Number</label>
<input type="text" class="form-control" name="advantageNumber_${index}">
</div>
<div class="col-md-4">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="advantageTitle_${index}">
</div>
<div class="col-md-6">
<label class="form-label">Text</label>
<textarea class="form-control" name="advantageText_${index}" rows="2"></textarea>
</div>
</div>
<button type="button" class="btn btn-outline-danger btn-sm mt-3" onclick="removeAdvantage(this)">
<i class="fas fa-trash me-2"></i>Remove Advantage
</button>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
}
function removeAdvantage(button) {
button.closest('.advantage-item').remove();
}
function addBoardMember() {
const container = document.getElementById('boardMembersContainer');
const index = container.children.length;
const html = `
<div class="card mb-3 board-member">
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<label class="form-label">Image</label>
<div class="input-group">
<input type="text" class="form-control" name="memberImage_${index}">
<button type="button" class="btn btn-outline-primary btn-upload-image" data-target-input="memberImage_${index}" data-image-type="about">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
</div>
<div class="col-md-3">
<label class="form-label">Title</label>
<input type="text" class="form-control" name="memberTitle_${index}">
</div>
<div class="col-md-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="memberName_${index}">
</div>
<div class="col-md-3">
<label class="form-label">Color</label>
<select class="form-select" name="memberColor_${index}">
<option value="#065c2e">Green</option>
<option value="#ffa500">Orange</option>
</select>
</div>
</div>
<button type="button" class="btn btn-outline-danger btn-sm mt-3" onclick="removeBoardMember(this)">
<i class="fas fa-trash me-2"></i>Remove Member
</button>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
}
function removeBoardMember(button) {
button.closest('.board-member').remove();
}
function updateJsonData() {
try {
// Update banner data
const bannerData = {
image: document.getElementById('bannerImage').value.trim(),
title: document.getElementById('bannerTitle').value.trim(),
text: document.getElementById('bannerText').value.trim()
};
document.getElementById('bannerJson').value = JSON.stringify(bannerData);
// Update about data
const aboutData = {
title: document.getElementById('aboutTitle').value.trim(),
paragraphs: Array.from(document.querySelectorAll('[name^="paragraph_"]'))
.map(el => el.value.trim())
.filter(text => text !== ''),
list_items: Array.from(document.querySelectorAll('[name^="listItem_"]'))
.map(el => el.value.trim())
.filter(text => text !== ''),
button: {
text: document.getElementById('aboutButtonText').value.trim(),
url: document.getElementById('aboutButtonUrl').value.trim()
},
image: document.getElementById('aboutImage').value.trim(),
quote: {
mark_image: document.getElementById('quoteMarkImage').value.trim(),
title: document.getElementById('quoteTitle').value.trim(),
text: document.getElementById('quoteText').value.trim(),
author: document.getElementById('quoteAuthor').value.trim()
}
};
document.getElementById('aboutJson').value = JSON.stringify(aboutData);
// Update values data
const valuesData = {
background_image: document.getElementById('valuesBackgroundImage').value.trim(),
items: Array.from(document.querySelectorAll('.value-item'))
.map((item, index) => ({
icon: item.querySelector(`[name="valueIcon_${index}"]`).value.trim(),
title: item.querySelector(`[name="valueTitle_${index}"]`).value.trim(),
text: item.querySelector(`[name="valueText_${index}"]`).value.trim()
}))
.filter(item => item.title !== '' || item.text !== '')
};
document.getElementById('valuesJson').value = JSON.stringify(valuesData);
// Update education data
const educationData = {
images: {
student1: document.getElementById('student1Image').value.trim(),
student2: document.getElementById('student2Image').value.trim()
},
subtitle: document.getElementById('educationSubtitle').value.trim(),
title: document.getElementById('educationTitle').value.trim(),
text: document.getElementById('educationText').value.trim()
};
document.getElementById('educationJson').value = JSON.stringify(educationData);
// Update advantages data
const advantagesData = {
title: document.getElementById('advantagesTitle').value.trim(),
items: Array.from(document.querySelectorAll('.advantage-item'))
.map((item, index) => ({
number: item.querySelector(`[name="advantageNumber_${index}"]`).value.trim(),
title: item.querySelector(`[name="advantageTitle_${index}"]`).value.trim(),
text: item.querySelector(`[name="advantageText_${index}"]`).value.trim()
}))
.filter(item => item.title !== '' || item.text !== '')
};
document.getElementById('advantagesJson').value = JSON.stringify(advantagesData);
// Update academic board data
const academicBoardData = {
title: document.getElementById('academicBoardTitle').value.trim(),
members: Array.from(document.querySelectorAll('.board-member'))
.map((item, index) => ({
image: item.querySelector(`[name="memberImage_${index}"]`).value.trim(),
title: item.querySelector(`[name="memberTitle_${index}"]`).value.trim(),
name: item.querySelector(`[name="memberName_${index}"]`).value.trim(),
color: item.querySelector(`[name="memberColor_${index}"]`).value
}))
.filter(member => member.name !== '' || member.title !== '')
};
document.getElementById('academicBoardJson').value = JSON.stringify(academicBoardData);
} catch (error) {
console.error('Error updating JSON data:', error);
throw new Error('Failed to process form data');
}
}
</script>