39647-vm/js/box-editor.js
Flatlogic Bot 986d159d20 1
2026-04-15 10:39:38 +00:00

139 lines
4.6 KiB
JavaScript

const EDITOR_CODE_KEY = 'boxEditorCode';
const editorCodeInput = document.getElementById('editor-code');
const loadButton = document.getElementById('load-boxes');
const saveButton = document.getElementById('save-boxes');
const editorForm = document.getElementById('editor-form');
const editorActions = document.getElementById('editor-actions');
const editorMessage = document.getElementById('editor-message');
editorCodeInput.value = localStorage.getItem(EDITOR_CODE_KEY) || '';
function setEditorMessage(message) {
editorMessage.innerHTML = message;
}
function apiBase() {
return `${window.location.protocol}//${window.location.host}/api/boxes`;
}
function boxCard(box, index) {
const imageValue = box.image || '';
const preview = imageValue
? `<img class="admin-image-preview" src="${imageValue}" alt="${box.name || `Box ${index + 1}`} preview" />`
: '<div class="admin-image-placeholder">No picture</div>';
return `
<section class="admin-box-card" data-index="${index}" data-id="${box.id || `box-${index + 1}`}">
<div class="admin-box-title">
<h2>${box.name || `Box ${index + 1}`}</h2>
<span>${box.id || `box-${index + 1}`}</span>
</div>
${preview}
<label>
Box name
<input class="auth-input editor-name" type="text" value="${box.name || ''}" />
</label>
<label>
Price
<input class="auth-input editor-price" type="number" min="0" step="0.01" value="${Number(box.price || 0).toFixed(2)}" />
</label>
<label>
Picture URL or relative path
<input class="auth-input editor-image" type="text" placeholder="images/boxes/box-1.svg or https://..." value="${imageValue}" />
</label>
<label>
Description
<textarea class="auth-input editor-description" rows="4" placeholder="Describe this box">${box.description || ''}</textarea>
</label>
</section>
`;
}
function bindPreviewListeners() {
editorForm.querySelectorAll('.editor-image').forEach(input => {
input.addEventListener('input', () => {
const card = input.closest('.admin-box-card');
const oldPreview = card.querySelector('.admin-image-preview, .admin-image-placeholder');
const value = input.value.trim();
const replacement = document.createElement(value ? 'img' : 'div');
if (value) {
replacement.className = 'admin-image-preview';
replacement.src = value;
replacement.alt = `${card.querySelector('.editor-name').value || 'Box'} preview`;
} else {
replacement.className = 'admin-image-placeholder';
replacement.textContent = 'No picture';
}
oldPreview.replaceWith(replacement);
});
});
}
function renderBoxes(boxes) {
editorForm.innerHTML = boxes.map(boxCard).join('');
editorForm.style.display = 'grid';
editorActions.style.display = 'flex';
bindPreviewListeners();
}
async function loadBoxes() {
const code = editorCodeInput.value.trim();
localStorage.setItem(EDITOR_CODE_KEY, code);
setEditorMessage('Loading boxes...');
const response = await fetch(apiBase());
const data = await response.json();
if (!data.success) {
setEditorMessage(data.message || 'Could not load boxes.');
return;
}
renderBoxes(data.boxes);
setEditorMessage(`Boxes loaded. You can also edit <strong>${data.file}</strong> directly in the backend code.`);
}
function collectBoxes() {
return Array.from(editorForm.querySelectorAll('.admin-box-card')).map((card, index) => ({
id: card.dataset.id || `box-${index + 1}`,
name: card.querySelector('.editor-name').value.trim() || `Box ${index + 1}`,
price: Number(card.querySelector('.editor-price').value || 0),
image: card.querySelector('.editor-image').value.trim(),
description: card.querySelector('.editor-description').value.trim(),
}));
}
async function saveBoxes() {
const code = editorCodeInput.value.trim();
if (!code) {
setEditorMessage('Enter the editor code before saving.');
return;
}
localStorage.setItem(EDITOR_CODE_KEY, code);
setEditorMessage('Saving boxes...');
const response = await fetch(apiBase(), {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-editor-code': code,
},
body: JSON.stringify({ boxes: collectBoxes() }),
});
const data = await response.json();
if (data.success) {
renderBoxes(data.boxes);
setEditorMessage(`Saved. The storefront is now reading from <strong>${data.file}</strong>.`);
} else {
setEditorMessage(data.message || 'Save failed.');
}
}
loadButton.addEventListener('click', loadBoxes);
saveButton.addEventListener('click', saveBoxes);
if (editorCodeInput.value) {
loadBoxes();
}