mirror of
https://github.com/tavo-wasd-gh/conex-builder.git
synced 2025-06-06 11:43:29 -06:00
extra field in update handler, frontend refactor
This commit is contained in:
parent
b9d1620646
commit
57c7c15ec5
6 changed files with 312 additions and 62 deletions
237
public/client.js
237
public/client.js
|
@ -21,9 +21,12 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
const checkoutDialog = document.getElementById("checkoutDialog");
|
||||
const editDialog = document.getElementById("editDialog");
|
||||
const buyDialog = document.getElementById("buyDialog");
|
||||
const updateContentDialog = document.getElementById("updateContentDialog");
|
||||
|
||||
checkoutDialog.style.display = "none";
|
||||
editDialog.style.display = "none";
|
||||
buyDialog.style.display = "none";
|
||||
updateContentDialog.style.display = "none";
|
||||
loadLanguage('es');
|
||||
|
||||
Promise.all(EditorJSComponents.map(src => loadScript(src))).then(() => {
|
||||
|
@ -58,7 +61,7 @@ function loadEditorState() {
|
|||
if (savedData) {
|
||||
const parsedData = JSON.parse(savedData);
|
||||
console.log('Loaded parsedData:', parsedData);
|
||||
document.getElementById('title').value = parsedData.title || '';
|
||||
document.getElementById('title').innerText = parsedData.title || '';
|
||||
document.getElementById('slogan').value = parsedData.slogan || '';
|
||||
document.getElementById('banner').src = parsedData.banner || '/static/svg/banner.svg';
|
||||
const disclaimers = document.querySelectorAll(".localstorage-exists");
|
||||
|
@ -82,7 +85,7 @@ function loadEditorState() {
|
|||
})
|
||||
.catch(error => console.error('Error loading translation file:', error));
|
||||
} else {
|
||||
document.getElementById('title').value = '';
|
||||
document.getElementById('title').innerText = '';
|
||||
document.getElementById('slogan').value = '';
|
||||
document.getElementById('banner').src = '/static/svg/banner.svg';
|
||||
document.getElementById("continueEditingModeButton").style.display = "none";
|
||||
|
@ -104,28 +107,73 @@ function initializeEventListeners() {
|
|||
});
|
||||
|
||||
document.getElementById("buyButton").addEventListener("click", () => openDialog(checkoutDialog));
|
||||
document.getElementById("editButton").addEventListener("click", () => openDialog(updateContentDialog));
|
||||
document.getElementById("closeDialogButton").addEventListener("click", () => closeDialog());
|
||||
|
||||
// // Editor save
|
||||
document.getElementById('title').addEventListener('change', saveEditorData);
|
||||
// document.getElementById('title').addEventListener('change', saveEditorData);
|
||||
document.getElementById('slogan').addEventListener('change', saveEditorData);
|
||||
|
||||
// // Mode switching
|
||||
// document.getElementById('buyModeButton').addEventListener('click', openBuyModeDialog);
|
||||
document.getElementById('buyModeButton').addEventListener('click', buyMode);
|
||||
document.getElementById('buyModeButton').addEventListener('click', openBuyModeDialog);
|
||||
document.getElementById('editModeButton').addEventListener('click', openEditModeDialog);
|
||||
document.getElementById("continueToBuyModeButton").addEventListener('click', async () => {
|
||||
const directory = sanitizeDirectoryTitle(document.getElementById("buyModeDirectoryInput").value);
|
||||
const exists = await checkDirectoryExists(directory);
|
||||
if (exists) {
|
||||
document.getElementById("checkdir-error-message").style.display = "block";
|
||||
document.getElementById("checkdir-error-message").innerHTML = `El sitio https://conex.one/${directory} ya existe.`;
|
||||
} else {
|
||||
document.getElementById("checkdir-error-message").style.display = "none";
|
||||
buyMode(directory);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("continueToEditModeButton").addEventListener('click', () =>
|
||||
editMode(document.getElementById("editModeDirectoryInput").value)
|
||||
editMode(extractSitePath(document.getElementById("editModeDirectoryInput").value))
|
||||
);
|
||||
document.getElementById('continueEditingModeButton').addEventListener('click', continueMode);
|
||||
|
||||
document.getElementById('dashButton').addEventListener('click', dashboardMode);
|
||||
document.getElementById('uploadBannerBtn').addEventListener('change', handleImageUpload);
|
||||
|
||||
const titleElement = document.getElementById('title');
|
||||
if (titleElement) {
|
||||
setupDirectoryInput(titleElement);
|
||||
}
|
||||
document.getElementById('requestChangesButton').addEventListener('click', async () => {
|
||||
const button = document.getElementById('requestChangesButton');
|
||||
button.disabled = true;
|
||||
button.classList.add('disabled');
|
||||
|
||||
await updateSiteRequest();
|
||||
|
||||
setTimeout(() => {
|
||||
button.disabled = false;
|
||||
button.classList.remove('disabled');
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
document.getElementById('confirmChangesButton').addEventListener('click', function() {
|
||||
successElement = document.getElementById('update-success-message');
|
||||
errorElement = document.getElementById('update-error-message');
|
||||
|
||||
const codeInput = document.getElementById('updateContentCodeInput').value;
|
||||
if (codeInput.length === 6 && !isNaN(codeInput)) {
|
||||
document.getElementById('updateContentCodeInput').value = '';
|
||||
errorElement.style.display = "none"
|
||||
updateSiteConfirm(codeInput);
|
||||
} else {
|
||||
successElement.style.display = "none"
|
||||
errorElement.style.display = "block"
|
||||
errorElement.innerHTML = "El código es un pin numérico de 6 dígitos.";
|
||||
console.error('Invalid code. Please enter a 6-digit number.');
|
||||
}
|
||||
});
|
||||
|
||||
const titleElement = document.getElementById('buyModeDirectoryInput');
|
||||
titleElement.addEventListener('input', debounce(function() {
|
||||
const directory = titleElement.value.trim();
|
||||
if (directory.length > 0) {
|
||||
validateDirectory(directory);
|
||||
}
|
||||
}, 500)); // 500ms debounce
|
||||
}
|
||||
|
||||
function openDialog(content) {
|
||||
|
@ -135,21 +183,31 @@ function openDialog(content) {
|
|||
floatingButtons.style.display = "none";
|
||||
}
|
||||
|
||||
function debounce(func, delay) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), delay);
|
||||
};
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
checkoutDialog.style.display = "none";
|
||||
editDialog.style.display = "none";
|
||||
// buyDialog.style.display = "none";
|
||||
buyDialog.style.display = "none";
|
||||
updateContentDialog.style.display = "none";
|
||||
dialog.style.display = "none";
|
||||
overlay.style.display = "none";
|
||||
floatingButtons.style.display = "flex";
|
||||
document.getElementById('checkout-error-message').style.display = "none";
|
||||
document.getElementById('update-error-message').style.display = "none";
|
||||
}
|
||||
|
||||
function saveEditorData() {
|
||||
const titleValue = document.getElementById('title').value.trim();
|
||||
const titleValue = document.getElementById('title').innerText.trim();
|
||||
const dataToSave = {
|
||||
banner: document.getElementById('banner').src || '/static/svg/banner.svg',
|
||||
title: document.getElementById('title').value,
|
||||
title: document.getElementById('title').innerText,
|
||||
slogan: document.getElementById('slogan').value,
|
||||
directory: sanitizeDirectoryTitle(titleValue)
|
||||
};
|
||||
|
@ -162,21 +220,37 @@ function saveEditorData() {
|
|||
});
|
||||
}
|
||||
|
||||
function setupDirectoryInput(inputElement, debounceTime = 500) {
|
||||
inputElement.addEventListener('input', () => {
|
||||
clearTimeout(typingTimeout);
|
||||
function validateDirectory(directory) {
|
||||
successMessageElement = document.getElementById('checkdir-success-message');
|
||||
errorMessageElement = document.getElementById('checkdir-error-message');
|
||||
successMessageElement.textContent = '';
|
||||
errorMessageElement.textContent = '';
|
||||
|
||||
typingTimeout = setTimeout(() => {
|
||||
const inputValue = inputElement.value.trim();
|
||||
if (!validateDirectoryLength(directory)) {
|
||||
successMessageElement.style.display = "none";
|
||||
errorMessageElement.style.display = "block";
|
||||
errorMessageElement.textContent = 'Directory name must be between 4 and 35 characters.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputValue.length > 0) {
|
||||
const sanitizedValue = sanitizeDirectoryTitle(inputValue); // Sanitize the input value
|
||||
checkDirectory(sanitizedValue);
|
||||
directory = sanitizeDirectoryTitle(directory)
|
||||
checkDirectoryExists(directory)
|
||||
.then(exists => {
|
||||
if (exists) {
|
||||
successMessageElement.style.display = "none";
|
||||
errorMessageElement.style.display = "block";
|
||||
errorMessageElement.textContent = `El sitio https://conex.one/${directory} ya existe.`;
|
||||
} else {
|
||||
hidePopup();
|
||||
successMessageElement.style.display = "block";
|
||||
errorMessageElement.style.display = "none";
|
||||
successMessageElement.textContent = `Se publicará en https://conex.one/${directory}`;
|
||||
}
|
||||
}, debounceTime);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
successMessageElement.style.display = "none";
|
||||
errorMessageElement.style.display = "block";
|
||||
errorMessageElement.textContent = 'Error occurred while checking the directory.';
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeDirectoryTitle(title) {
|
||||
|
@ -188,11 +262,6 @@ function sanitizeDirectoryTitle(title) {
|
|||
.replace(/[^a-z0-9\-]/g, '');
|
||||
}
|
||||
|
||||
function checkDirectory(directory) {
|
||||
if (!validateDirectoryLength(directory)) return;
|
||||
fetchDirectoryStatus(directory, 'exists', 'available', 'El sitio web ya existe', 'Se publicará en');
|
||||
}
|
||||
|
||||
function validateDirectoryLength(directory) {
|
||||
if (directory.length < 4 || directory.length > 35) {
|
||||
showPopup('El título debe tener entre 4 y 35 caracteres', 'exists');
|
||||
|
@ -201,14 +270,6 @@ function validateDirectoryLength(directory) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function fetchDirectoryStatus(directory, failureStatus, successStatus, failureMessage, successMessage) {
|
||||
checkDirectoryExists(directory).then(exists => {
|
||||
const message = exists ? `${failureMessage} conex.one/${directory}` : `${successMessage} conex.one/${directory}`;
|
||||
const status = exists ? failureStatus : successStatus;
|
||||
showPopup(message, status);
|
||||
});
|
||||
}
|
||||
|
||||
function checkDirectoryExists(directory) {
|
||||
return fetch(`/api/directory/${encodeURIComponent(directory)}`)
|
||||
.then(response => response.json())
|
||||
|
@ -331,8 +392,14 @@ function dashboardMode() {
|
|||
|
||||
function buyMode() {
|
||||
localStorage.removeItem('conex_data');
|
||||
const dataToSave = {
|
||||
title: document.getElementById('buyModeDirectoryInput').value.trim(),
|
||||
};
|
||||
localStorage.setItem('conex_data', JSON.stringify(dataToSave));
|
||||
loadEditorState();
|
||||
|
||||
closeDialog();
|
||||
|
||||
document.getElementById('checkout-success-message').style.display = "none";
|
||||
document.querySelector("#paypal-button-container").style.display = "block";
|
||||
document.getElementById("buyButton").style.display = "block";
|
||||
|
@ -380,6 +447,8 @@ function continueBuyMode() {
|
|||
}
|
||||
|
||||
function openBuyModeDialog() {
|
||||
document.getElementById("checkdir-error-message").style.display = "none";
|
||||
document.getElementById("checkdir-success-message").style.display = "none";
|
||||
overlay.style.display = "block";
|
||||
dialog.style.display = "block";
|
||||
buyDialog.style.display = "block";
|
||||
|
@ -392,13 +461,23 @@ function openEditModeDialog() {
|
|||
}
|
||||
|
||||
async function editMode(dir) {
|
||||
closeDialog();
|
||||
const success = await fetchAndStoreData(dir);
|
||||
if (!success) {
|
||||
console.error("Data could not be loaded, aborting UI changes");
|
||||
return;
|
||||
const errorMessageElement = document.getElementById('edit-error-message');
|
||||
const conexData = JSON.parse(localStorage.getItem('conex_data'));
|
||||
|
||||
if (conexData?.directory === dir) {
|
||||
console.log("Directory already loaded, skipping fetch.");
|
||||
} else {
|
||||
const success = await fetchAndStoreData(dir);
|
||||
if (!success) {
|
||||
errorMessageElement.innerHTML = "No se pudo cargar el sitio, asegúrate que estás digitando el enlace correcto.";
|
||||
errorMessageElement.style.display = "block";
|
||||
console.error("Data could not be loaded, aborting UI changes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog();
|
||||
errorMessageElement.style.display = "none";
|
||||
document.getElementById("buyButton").style.display = "none";
|
||||
document.getElementById("editButton").style.display = "block";
|
||||
const dashboard = document.getElementById('dashboard');
|
||||
|
@ -428,3 +507,77 @@ async function fetchAndStoreData(directoryName) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function updateSiteRequest() {
|
||||
const conexData = JSON.parse(localStorage.getItem('conex_data'));
|
||||
const directory = conexData?.directory;
|
||||
successElement = document.getElementById('update-success-message');
|
||||
errorElement = document.getElementById('update-error-message');
|
||||
|
||||
fetch('/api/update', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ directory: directory })
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
successElement.style.display = "block"
|
||||
errorElement.style.display = "none"
|
||||
successElement.innerHTML = "Se envió el código de autenticación de 6 dígitos a su correo electrónico.";
|
||||
} else {
|
||||
successElement.style.display = "none"
|
||||
errorElement.style.display = "block"
|
||||
errorElement.innerHTML = "Error enviando el código de confirmación a su correo, recuerde que puede solicitar el código solamente una vez cada minuto.";
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateSiteConfirm(code) {
|
||||
const conexData = JSON.parse(localStorage.getItem('conex_data'));
|
||||
const directory = conexData?.directory;
|
||||
const editorData = conexData?.editor_data;
|
||||
const slogan = conexData?.slogan;
|
||||
|
||||
successElement = document.getElementById('update-success-message');
|
||||
errorElement = document.getElementById('update-error-message');
|
||||
|
||||
if (!directory || !editorData) {
|
||||
console.error('Directory or editor_data not found in localStorage');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/api/confirm', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
directory: directory,
|
||||
auth_code: code,
|
||||
slogan: slogan,
|
||||
editor_data: editorData
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
successElement.style.display = "block"
|
||||
errorElement.style.display = "none"
|
||||
successElement.innerHTML = "Se actualizó correctamente la información de su sitio, los cambios deberían verse reflejados en menos de 24 horas.";
|
||||
} else {
|
||||
successElement.style.display = "none"
|
||||
errorElement.style.display = "block"
|
||||
errorElement.innerHTML = "Error actualizando su sitio, por favor vuelva a intentarlo más tarde.";
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function extractSitePath(url) {
|
||||
if (!url.includes("conex.one")) {
|
||||
return url;
|
||||
}
|
||||
const cleanUrl = url.replace(/^(https?:\/\/)?(www\.)?/, '').replace(/#.*$/, '');
|
||||
const match = cleanUrl.match(/^conex\.one\/([^\/?#]+)\/?/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="/static/css/editorjs-dark.css">
|
||||
</head>
|
||||
<div id="status-popup" class="status-popup">
|
||||
<span class="close-popup" onclick="hidePopup()">×</span>
|
||||
<span id="status-message"></span>
|
||||
</div>
|
||||
<div id="overlay"></div>
|
||||
<div id="dashboard">
|
||||
<div class="wave"></div>
|
||||
|
@ -45,13 +41,21 @@
|
|||
</div>
|
||||
<img id="banner" src="/static/svg/banner.svg" class="banner-image"/>
|
||||
<div class="desc">
|
||||
<input type="text" id="title" maxlength="35" class="input-title" data-translate="sampleTitle" placeholder="" >
|
||||
<h1 id="title" class="input-title"></h1>
|
||||
<textarea type="text" id="slogan" maxlength="100" class="input-slogan" data-translate="sampleSlogan" placeholder=""></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<body>
|
||||
<div id="editorjs"></div>
|
||||
</body>
|
||||
<footer class="footer">
|
||||
<div class="footer-content">
|
||||
<ul class="footer-links">
|
||||
<li><a href="#contact">Contactar con soporte</a></li>
|
||||
</ul>
|
||||
<p data-translate="footer"></p>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="floating-buttons-container" id="floatingButtons">
|
||||
<button class="floating-button" id="buyButton">
|
||||
<img src="/static/svg/check.svg">
|
||||
|
@ -86,9 +90,29 @@
|
|||
<div class="message error-message" id="checkout-error-message"></div>
|
||||
<div id="paypal-button-container"></div>
|
||||
</div>
|
||||
<div id="buyDialog">
|
||||
<h2 data-translate="buyDialogHeader"></h2>
|
||||
<p data-translate="buyDialogParagraph"></p>
|
||||
<div class="message success-message" id="checkdir-success-message"></div>
|
||||
<div class="message error-message" id="checkdir-error-message"></div>
|
||||
<input class="input-dialog" type="text" id="buyModeDirectoryInput" maxlength="35" placeholder="Mi Sitio"><br>
|
||||
<button id="continueToBuyModeButton" class="right">
|
||||
<span data-translate="continueToBuyModeButton"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="updateContentDialog">
|
||||
<h2 data-translate="updateContentDialogHeader"></h2>
|
||||
<p data-translate="updateContentDialogParagraph"></p>
|
||||
<div class="message success-message" id="update-success-message"></div>
|
||||
<div class="message error-message" id="update-error-message"></div>
|
||||
<input data-translate="tempCodePlaceholder" class="input-dialog" type="number" id="updateContentCodeInput" min="0" max="999999" placeholder=""><br>
|
||||
<button data-translate="requestChangesButton" id="requestChangesButton"></button>
|
||||
<button data-translate="confirmChangesButton" id="confirmChangesButton"></button>
|
||||
</div>
|
||||
<div id="editDialog">
|
||||
<h2 data-translate="editDialogHeader"></h2>
|
||||
<p data-translate="editDialogParagraph"></p>
|
||||
<div class="message error-message" id="edit-error-message"></div>
|
||||
<input class="input-dialog" type="text" id="editModeDirectoryInput" name="title" maxlength="35" placeholder="https://conex.one/mi-sitio"><br>
|
||||
<button id="continueToEditModeButton" class="right">
|
||||
<span data-translate="continueToEditModeButton"></span>
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
"editModeButton": "Editar sitio existente",
|
||||
"editModeButtonDisclaimer": "Limpiará el progreso actual para cargar un sitio existente",
|
||||
"continueEditingModeButton": "Continuar editando",
|
||||
"buyDialogHeader": "Diseñar un nuevo sitio web",
|
||||
"buyDialogParagraph": "Ingresa el nombre del sitio y revisa el enlace en el que se publicará una vez adquirido.",
|
||||
"updateContentDialogHeader": "Actualizar mi sitio",
|
||||
"updateContentDialogParagraph": "Para actualizar el sitio web, requerimos confirmar que el sitio es suyo. Para esto, enviaremos un correo electrónico a la cuenta de correo con la que compró este sitio web, con un código temporal de 6 dígitos que expirará en 5 minutos luego de ser enviado. Por favor, presione el botón para enviar el código y luego compruebe su identidad digitándolo en la casilla.",
|
||||
"tempCodePlaceholder": "Código de 6 dígitos enviado a su correo",
|
||||
"requestChangesButton": "Enviar correo con el pin",
|
||||
"confirmChangesButton": "Verificar pin y actualizar sitio",
|
||||
"continueToBuyModeButton": "Empezar a diseñar",
|
||||
"editDialogHeader": "Editar un sitio existente",
|
||||
"editDialogParagraph": "El sitio ya debe estar registrado en conex.one para poder cargarlo localmente.",
|
||||
"continueToEditModeButton": "Editar este sitio",
|
||||
|
@ -18,7 +26,7 @@
|
|||
"supportEmail": "Correo electrónico: soporte@conex.one",
|
||||
"supportPhone": "",
|
||||
"supportSchedule": "Horario de atención: L-V: 9:00 a.m. - 6:00 p.m.",
|
||||
"sampleTitle": "[Título de ejemplo]",
|
||||
"sampleTitle": "Mi Sitio",
|
||||
"sampleSlogan": "[Slogan o breve descripción]",
|
||||
"sampleHeader": "Acerca de [Empres]",
|
||||
"sampleParagraph": "En [Nombre de Tu Empresa], nos dedicamos a ofrecer [tu servicio/producto] de la más alta calidad con un servicio al cliente excepcional. Nuestro equipo de expertos se asegura de que cada aspecto de tu experiencia sea manejado con profesionalismo y cuidado.",
|
||||
|
@ -33,5 +41,6 @@
|
|||
"sampleTable23": "1000",
|
||||
"sampleTable31": "Laminado",
|
||||
"sampleTable32": "Breve descripción",
|
||||
"sampleTable33": "2000"
|
||||
"sampleTable33": "2000",
|
||||
"footer": "Copyright (C) 2024 Conex"
|
||||
}
|
||||
|
|
|
@ -262,7 +262,7 @@ a {
|
|||
|
||||
#continueEditingModeButton {
|
||||
display: none;
|
||||
background-image: linear-gradient(45deg, #4a3b72, #4a3b72);
|
||||
background-image: linear-gradient(45deg, #4a3b72, #8a6cdf);
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
|
@ -352,18 +352,14 @@ a {
|
|||
|
||||
#dialog button {
|
||||
margin: 0.5em 0.5em 0 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#dialog button {
|
||||
padding: 0.5em;
|
||||
color: var(--unemph-color);
|
||||
background: var(--background-color);
|
||||
border: 1px solid var(--hover-border);
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
right: 1.3em;
|
||||
bottom: 1.5em;
|
||||
}
|
||||
|
||||
#dialog button:hover {
|
||||
|
@ -382,6 +378,15 @@ a {
|
|||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#requestChangesButton,
|
||||
#confirmChangesButton {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
#requestChangesButton {
|
||||
left: 1.78em;
|
||||
}
|
||||
|
||||
.input-dialog {
|
||||
color: var(--color);
|
||||
border-width: 0;
|
||||
|
@ -472,3 +477,47 @@ a {
|
|||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background-color: var(--hover-background);
|
||||
color: var(--unemph-color);
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: var(--hover-background);
|
||||
color: var(--unemph-color);
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
margin: 0.5em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
|
||||
.footer-links li {
|
||||
display: inline;
|
||||
margin: 1em 1em;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
font-size: 0.9em;
|
||||
color: var(--hyper-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
24
server/db.go
24
server/db.go
|
@ -119,10 +119,12 @@ func RegisterSitePayment(db *sql.DB, capture Capture, cart ConexData) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func UpdateSite(db *sql.DB, pkey int, editorData json.RawMessage) error {
|
||||
func UpdateSite(db *sql.DB, pkey int, editorData json.RawMessage, slogan string) error {
|
||||
if _, err := db.Exec(`
|
||||
UPDATE sites SET raw = $1 WHERE id = $2
|
||||
`, editorData, pkey); err != nil {
|
||||
UPDATE sites
|
||||
SET raw = $1, slogan = $2, status = 'diff'
|
||||
WHERE id = $3
|
||||
`, editorData, slogan, pkey); err != nil {
|
||||
return fmt.Errorf("%s: %v", errDBUpdateRaw, err)
|
||||
}
|
||||
|
||||
|
@ -130,15 +132,27 @@ func UpdateSite(db *sql.DB, pkey int, editorData json.RawMessage) error {
|
|||
}
|
||||
|
||||
func UpdateSiteAuth(db *sql.DB, folder string, code string) (string, error) {
|
||||
valid := time.Now().Add(5 * time.Minute)
|
||||
var valid sql.NullTime
|
||||
if err := db.QueryRow(`
|
||||
SELECT valid
|
||||
FROM sites
|
||||
WHERE folder = $1
|
||||
`, folder).Scan(&valid); err != nil {
|
||||
return "", fmt.Errorf("error fetching valid timestamp: %v", err)
|
||||
}
|
||||
|
||||
if valid.Valid && valid.Time.After(time.Now().Add(4*time.Minute)) {
|
||||
return "", fmt.Errorf("valid timestamp is still active, cannot update")
|
||||
}
|
||||
|
||||
newValid := time.Now().Add(5 * time.Minute)
|
||||
var email string
|
||||
if err := db.QueryRow(`
|
||||
UPDATE sites
|
||||
SET auth = $1, valid = $2
|
||||
WHERE folder = $3
|
||||
RETURNING email;
|
||||
`, code, valid, folder).Scan(&email); err != nil {
|
||||
`, code, newValid, folder).Scan(&email); err != nil {
|
||||
return "", fmt.Errorf("%s: %v", errDBUpdateSiteAuth, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -284,6 +284,7 @@ func ConfirmChangesHandler(db *sql.DB) http.HandlerFunc {
|
|||
Directory string `json:"directory"`
|
||||
Code string `json:"auth_code"`
|
||||
EditorData json.RawMessage `json:"editor_data"`
|
||||
Slogan string `json:"slogan"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&cart); err != nil {
|
||||
httpErrorAndLog(w, err, errReadBody, errClientNotice)
|
||||
|
@ -296,7 +297,7 @@ func ConfirmChangesHandler(db *sql.DB) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
if err := UpdateSite(db, pkey, cart.EditorData); err != nil {
|
||||
if err := UpdateSite(db, pkey, cart.EditorData, cart.Slogan); err != nil {
|
||||
httpErrorAndLog(w, err, errUpdateSite, errClientNotice)
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue