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

934 lines
33 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);">Header Management</h1>
<p class="text-muted mb-0">Edit header content and menu structure</p>
</div>
</div>
<div class="row">
<div class="col-12">
<form action="/admin/header/update" method="POST" class="content-with-fixed-buttons" id="headerForm">
<!-- Hidden inputs for JSON data -->
<input type="hidden" name="topbarJson" id="topbarJson">
<input type="hidden" name="logo" id="logoInput">
<input type="hidden" name="activeTab" id="activeTabInput" value="topbar">
<input type="hidden" name="menuUpdates" id="menuUpdates">
<!-- 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="#topbar" role="tab">
<i class="fas fa-bars me-2"></i>Topbar
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#logo" role="tab">
<i class="fas fa-image me-2"></i>Logo
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#menu" role="tab">
<i class="fas fa-sitemap me-2"></i>Menu Structure
</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<!-- Topbar Tab -->
<div class="tab-pane fade show active" id="topbar" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-header bg-light">
<h6 class="mb-0">Topbar Configuration</h6>
</div>
<div class="card-body">
<!-- Contact Info -->
<div class="row mb-4">
<div class="col-12">
<h6 class="fw-medium mb-3">Contact Information</h6>
</div>
<div class="col-md-6">
<label class="form-label fw-medium">Phone Number</label>
<input type="text" class="form-control" id="contactPhone"
value="<%= data.topbar.contactInfo.phone %>">
</div>
<div class="col-md-6">
<label class="form-label fw-medium">Email</label>
<input type="email" class="form-control" id="contactEmail"
value="<%= data.topbar.contactInfo.email || '' %>">
</div>
</div>
<!-- Quick Links -->
<div class="row">
<div class="col-12">
<h6 class="fw-medium mb-3">Quick Links</h6>
<div id="quickLinksContainer">
<% data.topbar.links.forEach((link, index)=> { %>
<div class="card mb-3 border">
<div class="card-body">
<div class="row g-3">
<div class="col-md-5">
<label class="form-label fw-medium">Link Text</label>
<input type="text" class="form-control quick-link-text" value="<%= link.text %>"
data-index="<%= index %>">
</div>
<div class="col-md-6">
<label class="form-label fw-medium">URL</label>
<input type="url" class="form-control quick-link-url" value="<%= link.url %>"
data-index="<%= index %>">
</div>
<div class="col-md-1">
<label class="form-label">&nbsp;</label>
<button type="button" class="btn btn-outline-danger btn-sm w-100 remove-quick-link"
data-index="<%= index %>">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
<% }); %>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" id="addQuickLink">
<i class="fas fa-plus me-1"></i>Add Quick Link
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Logo Tab -->
<div class="tab-pane fade" id="logo" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-header bg-light">
<h6 class="mb-0">Logo Configuration</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-5">
<label class="form-label fw-medium">Logo Image</label>
<div class="input-group mb-2">
<input type="text" class="form-control" id="logoImage" value="<%= data.logo %>">
<button type="button" class="btn btn-outline-primary btn-upload-image"
data-target-input="logoImage" data-image-type="layout">
<i class="fas fa-upload me-1"></i>Upload
</button>
</div>
<small class="form-text text-muted">Recommended size: 200x60px</small>
</div>
<div class="col-md-7">
<% if (data.logo) { %>
<img src="<%= data.logo %>" class="img-thumbnail"
style="max-height: 100px; max-width: 300px; object-fit: contain; background: #b8b76a;"
alt="Logo preview">
<% } %>
</div>
</div>
</div>
</div>
</div>
<!-- Menu Structure Tab -->
<div class="tab-pane fade" id="menu" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<h6 class="mb-0">Menu Structure</h6>
<div>
<button type="button" class="btn btn-outline-success btn-sm me-2" id="saveMenuChanges"
style="display: none;">
<i class="fas fa-save me-1"></i>Save Changes
</button>
<button type="button" class="btn btn-outline-primary btn-sm" id="refreshMenuTree">
<i class="fas fa-sync-alt me-1"></i>Refresh Menu Tree
</button>
</div>
</div>
<div class="card-body">
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
Click "Save Changes" on top right to apply changes.
</div>
<div id="menuTreeContainer">
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading menu structure...</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Move buttons to fixed bottom -->
<div class="fixed-bottom-buttons">
<button type="reset" class="btn btn-secondary">
<i class="fas fa-undo"></i>
<span>Reset</span>
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
<span>Save Changes</span>
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Menu Tree Template -->
<template id="menuTreeTemplate">
<div class="menu-tree">
<div class="menu-items">
<!-- Menu items will be populated here -->
</div>
</div>
</template>
<!-- Menu Item Template -->
<template id="menuItemTemplate">
<div class="menu-item card mb-2 border" data-menuid="">
<div class="card-body p-3">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="d-flex align-items-center mb-2">
<span class="badge bg-primary me-2 menu-type"></span>
<h6 class="mb-0 menu-title"></h6>
<small class="text-muted ms-2 menu-url"></small>
</div>
<div class="menu-details">
<div class="row g-2">
<div class="col-md-3">
<label class="form-label form-label-sm mb-1">Title:</label>
<input type="text" class="form-control form-control-sm menu-title-input" style="width: 120px;">
</div>
<div class="col-md-2">
<label class="form-label form-label-sm mb-1">Order:</label>
<input type="number" class="form-control form-control-sm menu-order-input" min="0" style="width: 80px;">
</div>
<div class="col-md-2">
<label class="form-label form-label-sm mb-1">Type:</label>
<select class="form-select form-select-sm menu-type-select" style="width: 100px;">
<option value="static">Static</option>
<option value="page">Page</option>
<option value="level">Level</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label form-label-sm mb-1">Menu Parent:</label>
<select class="form-select form-select-sm menu-parent-select" style="width: 130px;">
<option value="">Main menu</option>
</select>
</div>
<div class="col-md-2">
<div class="form-check form-switch fetch-toggle" style="display: none;">
<input class="form-check-input" type="checkbox" role="switch" data-menuid="">
<label class="form-check-label form-label-sm">Programmes</label>
</div>
<div class="form-check form-switch active-toggle">
<input class="form-check-input" type="checkbox" role="switch" data-menuid="" checked>
<label class="form-check-label form-label-sm">Active</label>
</div>
<small class="text-muted menu-fetch-display"></small>
</div>
</div>
</div>
</div>
<div class="ms-2">
<button type="button" class="btn btn-outline-info btn-sm view-programmes" style="display: none;">
<i class="fas fa-list me-1"></i>Programmes
</button>
</div>
</div>
<div class="menu-children mt-2" style="display: none;">
<!-- Children will be populated here -->
</div>
</div>
</div>
</template>
<style>
.menu-tree {
max-height: 600px;
overflow-y: auto;
}
.menu-item {
transition: all 0.3s ease;
}
.menu-item:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.menu-children {
margin-left: 20px;
border-left: 2px solid #e9ecef;
padding-left: 15px;
}
.menu-type {
font-size: 0.7rem;
}
.content-with-fixed-buttons {
padding-bottom: 80px;
}
.fixed-bottom {
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
}
.form-label-sm {
font-size: 0.75rem;
font-weight: 500;
margin-bottom: 0.25rem;
}
.menu-item .form-control-sm,
.menu-item .form-select-sm {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
}
.menu-item .card-body {
padding: 0.75rem;
}
.menu-item .row.g-2 {
margin: 0;
}
.menu-item .col-md-3,
.menu-item .col-md-6 {
padding: 0 0.25rem;
}
/* Toggle switch styling */
.form-check-input:checked {
background-color: #b8b76a;
border-color: #b8b76a;
}
.form-check-input:focus {
border-color: #b8b76a;
box-shadow: 0 0 0 0.25rem rgba(4, 78, 39, 0.25);
}
.form-check-label {
font-size: 0.75rem;
font-weight: 500;
margin-bottom: 0;
cursor: pointer;
}
.fetch-toggle {
margin-top: 0.5rem;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
let quickLinkIndex = <%= data.topbar.links.length %>;
// Initialize form data
updateHiddenInputs();
// Handle Active Tab Persistence
const urlParams = new URLSearchParams(window.location.search);
const activeTabObj = urlParams.get('activeTab');
if (activeTabObj) {
const tabTrigger = document.querySelector(`a[href="#${activeTabObj}"]`);
if (tabTrigger) {
new bootstrap.Tab(tabTrigger).show();
// Update hidden input to match restored tab
document.getElementById('activeTabInput').value = activeTabObj;
}
}
// Update hidden input on tab change
document.querySelectorAll('a[data-bs-toggle="tab"]').forEach(tab => {
tab.addEventListener('shown.bs.tab', function (event) {
const targetId = event.target.getAttribute('href').substring(1); // remove #
document.getElementById('activeTabInput').value = targetId;
});
});
// Load menu tree on tab show
document.querySelector('a[href="#menu"]').addEventListener('shown.bs.tab', function () {
loadMenuTree();
});
// Add Quick Link
document.getElementById('addQuickLink').addEventListener('click', function () {
const container = document.getElementById('quickLinksContainer');
const newLink = document.createElement('div');
newLink.className = 'card mb-3 border';
newLink.innerHTML =
'<div class="card-body">' +
'<div class="row g-3">' +
'<div class="col-md-5">' +
'<label class="form-label fw-medium">Link Text</label>' +
'<input type="text" class="form-control quick-link-text" value="" data-index="' + quickLinkIndex + '">' +
'</div>' +
'<div class="col-md-6">' +
'<label class="form-label fw-medium">URL</label>' +
'<input type="url" class="form-control quick-link-url" value="" data-index="' + quickLinkIndex + '">' +
'</div>' +
'<div class="col-md-1">' +
'<label class="form-label">&nbsp;</label>' +
'<button type="button" class="btn btn-outline-danger btn-sm w-100 remove-quick-link" data-index="' + quickLinkIndex + '">' +
'<i class="fas fa-trash"></i>' +
'</button>' +
'</div>' +
'</div>' +
'</div>';
container.appendChild(newLink);
quickLinkIndex++;
updateHiddenInputs();
});
// Remove Quick Link
document.addEventListener('click', function (e) {
if (e.target.closest('.remove-quick-link')) {
e.target.closest('.card').remove();
updateHiddenInputs();
}
});
// Update hidden inputs when form changes
document.addEventListener('input', updateHiddenInputs);
document.addEventListener('change', updateHiddenInputs);
// Refresh Menu Tree
document.getElementById('refreshMenuTree').addEventListener('click', function () {
loadMenuTree();
});
// Save Menu Changes
document.getElementById('saveMenuChanges').addEventListener('click', function () {
saveMenuChanges();
});
// 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);
});
});
// Form submission
document.getElementById('headerForm').addEventListener('submit', function (e) {
e.preventDefault();
updateHiddenInputs();
// Show loading state
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Saving...';
submitBtn.disabled = true;
// Submit form
this.submit();
});
function updateHiddenInputs() {
// Update topbar JSON
const topbarData = {
contactInfo: {
phone: document.getElementById('contactPhone').value,
email: document.getElementById('contactEmail').value
},
links: []
};
// Collect quick links
document.querySelectorAll('.quick-link-text').forEach((input, index) => {
const urlInput = document.querySelector(`.quick-link-url[data-index="${input.dataset.index}"]`);
if (input.value.trim() && urlInput.value.trim()) {
topbarData.links.push({
text: input.value.trim(),
url: urlInput.value.trim()
});
}
});
document.getElementById('topbarJson').value = JSON.stringify(topbarData);
document.getElementById('logoInput').value = document.getElementById('logoImage').value;
// Update menu updates hidden input
try {
const menuUpdates = collectMenuUpdates();
document.getElementById('menuUpdates').value = JSON.stringify(menuUpdates);
} catch (e) {
console.error('Error collecting menu updates:', e);
// Fallback to empty array to avoid server errors
document.getElementById('menuUpdates').value = '[]';
}
}
function loadMenuTree() {
const container = document.getElementById('menuTreeContainer');
container.innerHTML = `
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading menu structure...</p>
</div>
`;
fetch('/admin/header/menu-tree')
.then(response => response.json())
.then(data => {
// Store all menu items for parent options
allMenuItems = flattenMenuItems(data);
renderMenuTree(data);
})
.catch(error => {
console.error('Error loading menu tree:', error);
container.innerHTML = `
<div class="alert alert-danger">
<i class="fas fa-exclamation-triangle me-2"></i>
Error loading menu structure. Please try again.
</div>
`;
});
}
function flattenMenuItems(menuItems) {
const flattened = [];
function flatten(items) {
items.forEach(item => {
flattened.push({
menuid: item.menuid,
title: item.title,
parent: item.parent
});
if (item.children && item.children.length > 0) {
flatten(item.children);
}
});
}
flatten(menuItems);
return flattened;
}
function renderMenuTree(menuItems) {
const container = document.getElementById('menuTreeContainer');
const template = document.getElementById('menuTreeTemplate');
const menuTree = template.content.cloneNode(true);
const menuItemsContainer = menuTree.querySelector('.menu-items');
menuItems.forEach(item => {
const menuItem = createMenuItem(item);
menuItemsContainer.appendChild(menuItem);
});
container.innerHTML = '';
container.appendChild(menuTree);
}
function createMenuItem(item) {
const template = document.getElementById('menuItemTemplate');
const menuItem = template.content.cloneNode(true);
const card = menuItem.querySelector('.menu-item');
const typeBadge = card.querySelector('.menu-type');
const title = card.querySelector('.menu-title');
const url = card.querySelector('.menu-url');
const titleInput = card.querySelector('.menu-title-input');
const orderInput = card.querySelector('.menu-order-input');
const typeSelect = card.querySelector('.menu-type-select');
const parentSelect = card.querySelector('.menu-parent-select');
const fetchToggle = card.querySelector('.fetch-toggle');
const fetchCheckbox = card.querySelector('.fetch-toggle input');
const activeToggle = card.querySelector('.active-toggle');
const activeCheckbox = card.querySelector('.active-toggle input');
const fetchDisplay = card.querySelector('.menu-fetch-display');
const viewProgrammesBtn = card.querySelector('.view-programmes');
const childrenContainer = card.querySelector('.menu-children');
// Set content
card.dataset.menuid = item.menuid;
typeBadge.textContent = item.type;
title.textContent = item.title;
url.textContent = item.url;
titleInput.value = item.title;
orderInput.value = item.order;
typeSelect.value = item.type;
// Populate parent select options
populateParentOptions(parentSelect, item.menuid);
parentSelect.value = item.parent || '';
// Show fetch toggle for level type menus
if (item.type === 'level') {
fetchToggle.style.display = 'block';
fetchCheckbox.checked = item.fetch;
fetchCheckbox.dataset.menuid = item.menuid;
// Add change listener for fetch toggle
fetchCheckbox.addEventListener('change', function () {
showSaveButton();
});
}
// Set active toggle state
activeCheckbox.checked = item.isActive !== false;
activeCheckbox.dataset.menuid = item.menuid;
// Add change listener for active toggle
activeCheckbox.addEventListener('change', function () {
showSaveButton();
});
// Add change listeners
titleInput.addEventListener('input', function () {
showSaveButton();
});
orderInput.addEventListener('change', function () {
showSaveButton();
});
typeSelect.addEventListener('change', function () {
showSaveButton();
// Show/hide fetch toggle based on type
if (this.value === 'level') {
fetchToggle.style.display = 'block';
} else {
fetchToggle.style.display = 'none';
fetchCheckbox.checked = false;
}
});
parentSelect.addEventListener('change', function () {
showSaveButton();
});
// Show programmes button for level types with fetch=true
if (item.type === 'level' && item.fetch) {
viewProgrammesBtn.style.display = 'inline-block';
viewProgrammesBtn.addEventListener('click', function () {
loadProgrammes(item.menuid, childrenContainer);
});
}
// Add children if any
if (item.children && item.children.length > 0) {
childrenContainer.style.display = 'block';
item.children.forEach(child => {
const childItem = createMenuItem(child);
childrenContainer.appendChild(childItem);
});
}
return menuItem;
}
function loadProgrammes(menuId, container) {
container.innerHTML = `
<div class="text-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<small class="text-muted">Loading programmes...</small>
</div>
`;
fetch(`/admin/header/programmes/${menuId}`)
.then(response => response.json())
.then(programmes => {
renderProgrammes(programmes, container);
})
.catch(error => {
console.error('Error loading programmes:', error);
container.innerHTML = `
<div class="alert alert-danger alert-sm">
<i class="fas fa-exclamation-triangle me-1"></i>
Error loading programmes
</div>
`;
});
}
function renderProgrammes(programmes, container) {
if (programmes.length === 0) {
container.innerHTML = '<small class="text-muted">No programmes found</small>';
return;
}
const programmesList = document.createElement('div');
programmesList.className = 'list-group list-group-flush';
programmes.forEach(programme => {
const item = document.createElement('div');
item.className = 'list-group-item d-flex justify-content-between align-items-center py-2';
item.innerHTML = `
<div>
<strong>${programme.name}</strong>
<br>
<small class="text-muted">${programme.code}</small>
</div>
<a href="${programme.url}" class="btn btn-outline-primary btn-sm" target="_blank">
<i class="fas fa-external-link-alt"></i>
</a>
`;
programmesList.appendChild(item);
});
container.innerHTML = '';
container.appendChild(programmesList);
}
// Global variable to store all menu items for parent options
let allMenuItems = [];
function populateParentOptions(select, currentMenuId) {
// Clear existing options except the first one
while (select.children.length > 1) {
select.removeChild(select.lastChild);
}
// Add options for all menu items except the current one
allMenuItems.forEach(item => {
if (item.menuid !== currentMenuId) {
const option = document.createElement('option');
option.value = item.menuid;
option.textContent = item.title;
select.appendChild(option);
}
});
}
function showSaveButton() {
document.getElementById('saveMenuChanges').style.display = 'inline-block';
}
function collectMenuUpdates() {
const menuItems = document.querySelectorAll('.menu-item');
const updates = [];
menuItems.forEach(item => {
const menuId = item.dataset.menuid;
const titleInput = item.querySelector('.menu-title-input');
const orderInput = item.querySelector('.menu-order-input');
const typeSelect = item.querySelector('.menu-type-select');
const parentSelect = item.querySelector('.menu-parent-select');
const fetchCheckbox = item.querySelector('.fetch-toggle input');
const activeCheckbox = item.querySelector('.active-toggle input');
const updateData = {
menuid: menuId,
title: titleInput.value.trim(),
order: parseInt(orderInput.value) || 0,
type: typeSelect.value,
parent: parentSelect.value || null
};
// Add fetch status for level type menus
if (fetchCheckbox) {
updateData.fetch = fetchCheckbox.checked;
}
// Add isActive status
if (activeCheckbox) {
updateData.isActive = activeCheckbox.checked;
}
updates.push(updateData);
});
return updates;
}
function saveMenuChanges() {
const updates = collectMenuUpdates();
// Show loading state
const saveBtn = document.getElementById('saveMenuChanges');
const originalText = saveBtn.innerHTML;
saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Saving...';
saveBtn.disabled = true;
// Send update request
fetch('/admin/header/update-menu', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ updates })
})
.then(response => response.json())
.then(result => {
if (result.success) {
// Hide save button
saveBtn.style.display = 'none';
saveBtn.disabled = false;
saveBtn.innerHTML = originalText;
// Show success message
showAlert('Menu structure updated successfully!', 'success');
// Reload menu tree after a short delay
setTimeout(() => {
loadMenuTree();
}, 1000);
} else {
throw new Error(result.error || 'Failed to update menu');
}
})
.catch(error => {
console.error('Error saving menu changes:', error);
showAlert('Error updating menu: ' + error.message, 'danger');
// Restore button
saveBtn.disabled = false;
saveBtn.innerHTML = originalText;
});
}
function showAlert(message, type) {
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
alertDiv.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
const container = document.getElementById('menuTreeContainer');
container.parentElement.insertBefore(alertDiv, container);
// Auto remove after 5 seconds
setTimeout(() => {
if (alertDiv.parentElement) {
alertDiv.remove();
}
}, 5000);
}
});
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
const input = document.getElementById(targetInput) || document.querySelector(`[name="${targetInput}"]`);
if (!input) {
throw new Error('Target input not found');
}
input.value = result.path;
// Tìm hoặc tạo preview container
let imgPreview = input.parentElement.nextElementSibling;
while (imgPreview && !imgPreview.classList.contains('mt-2')) {
imgPreview = imgPreview.nextElementSibling;
}
if (!imgPreview) {
// Tạo mới phần tử preview nếu chưa có
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.maxHeight = '100px';
img.style.maxWidth = '300px';
img.style.objectFit = 'contain';
} else {
img.style.height = '200px';
img.style.width = '100%';
img.style.objectFit = 'cover';
}
img.alt = 'Image preview';
imgPreview.appendChild(img);
input.parentElement.parentElement.appendChild(imgPreview);
}
// Cập nhật ảnh preview
const img = imgPreview.querySelector('img');
if (img) {
img.src = result.path;
}
// Restore nút upload
uploadBtn.disabled = false;
uploadBtn.innerHTML = originalBtnHtml;
// Cleanup
document.body.removeChild(fileInput);
} catch (error) {
console.error('Upload error:', error);
alert('Upload failed: ' + error.message);
// Restore nút upload
const uploadBtn = document.querySelector(`[data-target-input="${targetInput}"]`);
uploadBtn.disabled = false;
uploadBtn.innerHTML = originalBtnHtml;
// Cleanup
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
}
};
// Trigger file selection
fileInput.click();
}
</script>