mirror of
https://github.com/tavo-wasd-gh/conex-builder.git
synced 2025-06-06 11:43:29 -06:00
613 lines
22 KiB
JavaScript
613 lines
22 KiB
JavaScript
const EditorJSComponents = [
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/header@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/image@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/list@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/quote@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/code@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/table@latest",
|
|
"https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest",
|
|
];
|
|
|
|
let typingTimeout;
|
|
let hideTimeout;
|
|
let editor;
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const dialog = document.getElementById("dialog");
|
|
const overlay = document.getElementById("overlay");
|
|
const floatingButtons = document.getElementById("floatingButtons");
|
|
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(() => {
|
|
return loadScript("/editor.js");
|
|
}).then(() => {
|
|
loadEditorState();
|
|
}).catch(err => console.error("Error loading editor:", err));
|
|
|
|
loadScript("/paypal.js").catch(err => console.error(err));
|
|
|
|
initializeEventListeners();
|
|
});
|
|
|
|
function loadScript(src, async = true) {
|
|
return new Promise((resolve, reject) => {
|
|
const script = document.createElement('script');
|
|
script.src = src;
|
|
script.async = async;
|
|
script.onload = () => resolve();
|
|
script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
|
|
document.head.appendChild(script);
|
|
});
|
|
}
|
|
|
|
function loadEditorState() {
|
|
const savedData = localStorage.getItem('conex_data');
|
|
const holderElement = document.getElementById('editorjs');
|
|
holderElement.innerHTML = '';
|
|
|
|
if (savedData) {
|
|
const parsedData = JSON.parse(savedData);
|
|
console.log('Loaded parsedData:', parsedData);
|
|
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");
|
|
disclaimers.forEach((element) => {
|
|
element.style.display = "block";
|
|
});
|
|
|
|
initializeEditor(parsedData);
|
|
|
|
document.getElementById('continueEditingModeButton').style.display = "block";
|
|
fetch(`./lang/es.json`)
|
|
.then(response => response.json())
|
|
.then(translations => {
|
|
const translatedText = translations['continueEditingModeButton'];
|
|
const continueEditingModeButton = document.getElementById('continueEditingModeButton');
|
|
if (parsedData.title && translatedText) {
|
|
continueEditingModeButton.innerText = `${translatedText}: ${parsedData.title}`;
|
|
} else {
|
|
continueEditingModeButton.innerText = translatedText;
|
|
}
|
|
})
|
|
.catch(error => console.error('Error loading translation file:', error));
|
|
} else {
|
|
document.getElementById('title').innerText = '';
|
|
document.getElementById('slogan').value = '';
|
|
document.getElementById('banner').src = '/static/svg/banner.svg';
|
|
document.getElementById("continueEditingModeButton").style.display = "none";
|
|
const disclaimers = document.querySelectorAll(".localstorage-exists");
|
|
disclaimers.forEach((element) => {
|
|
element.style.display = "none";
|
|
});
|
|
|
|
initializeEditor();
|
|
}
|
|
}
|
|
|
|
function initializeEventListeners() {
|
|
// Prevent ENTER key in slogan element
|
|
document.getElementById('slogan').addEventListener('keydown', function(event) {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
|
|
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('slogan').addEventListener('change', saveEditorData);
|
|
|
|
// // Mode switching
|
|
document.getElementById('buyModeButton').addEventListener('click', openBuyModeDialog);
|
|
document.getElementById('editModeButton').addEventListener('click', openEditModeDialog);
|
|
|
|
document.getElementById("continueToBuyModeButton").addEventListener('click', async () => {
|
|
const button = document.getElementById("continueToBuyModeButton");
|
|
const directoryInput = document.getElementById("buyModeDirectoryInput");
|
|
const errorMessage = document.getElementById("checkdir-error-message");
|
|
const directory = sanitizeDirectoryTitle(directoryInput.value);
|
|
|
|
|
|
const originalBuyButtonHTML = button.innerHTML;
|
|
button.innerHTML = '<span class="loader"></span>';
|
|
button.disabled = true;
|
|
|
|
let timeout = setTimeout(() => {
|
|
button.innerHTML = originalBuyButtonHTML;
|
|
button.disabled = false;
|
|
errorMessage.style.display = "block";
|
|
errorMessage.innerHTML = `Revisar la disponibilidad del sitio tardó mucho tiempo, intentalo más tarde.`;
|
|
}, 10000);
|
|
|
|
try {
|
|
const exists = await checkDirectoryExists(directory);
|
|
|
|
clearTimeout(timeout);
|
|
|
|
if (exists) {
|
|
errorMessage.style.display = "block";
|
|
errorMessage.innerHTML = `El sitio https://conex.one/${directory} ya existe.`;
|
|
} else {
|
|
errorMessage.style.display = "none";
|
|
buyMode(directory);
|
|
}
|
|
} catch (error) {
|
|
clearTimeout(timeout);
|
|
errorMessage.style.display = "block";
|
|
errorMessage.innerHTML = `Error: Could not check the site. Please try again.`;
|
|
} finally {
|
|
button.innerHTML = originalBuyButtonHTML;
|
|
button.disabled = false;
|
|
}
|
|
});
|
|
|
|
document.getElementById('buyModeDirectoryInput').addEventListener('input', function() {
|
|
const input = this.value.trim();
|
|
const sanitizedDirectory = sanitizeDirectoryTitle(input);
|
|
const previewElement = document.getElementById('checkdir-preview');
|
|
|
|
previewElement.style.display = "block"
|
|
previewElement.innerHTML = `Su sitio se publicará en:<br><a href="#">https://conex.one/${sanitizedDirectory}</a>`;
|
|
});
|
|
|
|
document.getElementById("continueToEditModeButton").addEventListener('click', () =>
|
|
editMode(extractSitePath(document.getElementById("editModeDirectoryInput").value))
|
|
);
|
|
document.getElementById('continueEditingModeButton').addEventListener('click', continueMode);
|
|
|
|
document.getElementById('dashButton').addEventListener('click', dashboardMode);
|
|
document.getElementById('uploadBannerBtn').addEventListener('change', handleImageUpload);
|
|
|
|
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.');
|
|
}
|
|
});
|
|
}
|
|
|
|
function openDialog(content) {
|
|
dialog.style.display = "block";
|
|
content.style.display = "block";
|
|
overlay.style.display = "block";
|
|
floatingButtons.style.display = "none";
|
|
}
|
|
|
|
function closeDialog() {
|
|
checkoutDialog.style.display = "none";
|
|
editDialog.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').innerText.trim();
|
|
const dataToSave = {
|
|
banner: document.getElementById('banner').src || '/static/svg/banner.svg',
|
|
title: document.getElementById('title').innerText,
|
|
slogan: document.getElementById('slogan').value,
|
|
directory: sanitizeDirectoryTitle(titleValue)
|
|
};
|
|
editor.save().then((editor_data) => {
|
|
dataToSave.editor_data = editor_data;
|
|
localStorage.setItem('conex_data', JSON.stringify(dataToSave));
|
|
console.log('Editor data saved to localStorage');
|
|
}).catch((error) => {
|
|
console.error('Saving failed:', error);
|
|
});
|
|
}
|
|
|
|
function validateDirectory(directory) {
|
|
successMessageElement = document.getElementById('checkdir-success-message');
|
|
errorMessageElement = document.getElementById('checkdir-error-message');
|
|
successMessageElement.textContent = '';
|
|
errorMessageElement.textContent = '';
|
|
|
|
if (!validateDirectoryLength(directory)) {
|
|
successMessageElement.style.display = "none";
|
|
errorMessageElement.style.display = "block";
|
|
errorMessageElement.textContent = 'Directory name must be between 4 and 35 characters.';
|
|
return;
|
|
}
|
|
|
|
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 {
|
|
successMessageElement.style.display = "block";
|
|
errorMessageElement.style.display = "none";
|
|
successMessageElement.textContent = `Se publicará en https://conex.one/${directory}`;
|
|
}
|
|
})
|
|
.catch(() => {
|
|
successMessageElement.style.display = "none";
|
|
errorMessageElement.style.display = "block";
|
|
errorMessageElement.textContent = 'Error occurred while checking the directory.';
|
|
});
|
|
}
|
|
|
|
function sanitizeDirectoryTitle(title) {
|
|
return title
|
|
.toLowerCase()
|
|
.replace(/\s+/g, '-')
|
|
.normalize('NFD')
|
|
.replace(/[\u0300-\u036f]/g, '')
|
|
.replace(/[^a-z0-9\-]/g, '');
|
|
}
|
|
|
|
function validateDirectoryLength(directory) {
|
|
if (directory.length < 4 || directory.length > 35) {
|
|
showPopup('El título debe tener entre 4 y 35 caracteres', 'exists');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function checkDirectoryExists(directory) {
|
|
return fetch(`https://api.conex.one/api/directory/${encodeURIComponent(directory)}`)
|
|
.then(response => response.json())
|
|
.then(data => data.exists)
|
|
.catch(error => {
|
|
console.error('Error checking directory:', error);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function showPopup(message, status) {
|
|
const popup = document.querySelector('.status-popup');
|
|
|
|
if (hideTimeout) {
|
|
clearTimeout(hideTimeout);
|
|
}
|
|
|
|
const existingCloseButton = popup.querySelector('.close-popup');
|
|
if (existingCloseButton) {
|
|
existingCloseButton.remove();
|
|
}
|
|
|
|
const closeButton = document.createElement('span');
|
|
closeButton.classList.add('close-popup');
|
|
closeButton.innerHTML = '×';
|
|
closeButton.addEventListener('click', () => {
|
|
hidePopup(popup, status);
|
|
});
|
|
|
|
popup.innerHTML = message;
|
|
popup.appendChild(closeButton);
|
|
popup.classList.remove('exists', 'available');
|
|
popup.classList.add(status);
|
|
popup.classList.add('show');
|
|
|
|
hideTimeout = setTimeout(() => {
|
|
hidePopup(popup, status);
|
|
}, 5000);
|
|
}
|
|
|
|
function hidePopup(popup, status) {
|
|
if (!popup) {
|
|
return;
|
|
}
|
|
popup.classList.remove('show');
|
|
setTimeout(() => {
|
|
popup.classList.remove(status);
|
|
}, 100);
|
|
}
|
|
|
|
function handleImageUpload() {
|
|
const uploadButton = document.getElementById('uploadBannerBtn');
|
|
const imageIcon = document.querySelector('.tool-button img');
|
|
const loader = document.querySelector('.loader');
|
|
|
|
const savedData = localStorage.getItem('conex_data');
|
|
const parsedData = savedData ? JSON.parse(savedData) : null;
|
|
const directory = parsedData?.directory || "temp";
|
|
const file = event.target.files[0];
|
|
|
|
if (file) {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
formData.append('directory', directory);
|
|
|
|
uploadButton.disabled = true;
|
|
loader.style.display = 'inline-block';
|
|
imageIcon.style.display = 'none';
|
|
|
|
fetch('https://api.conex.one/api/upload', {
|
|
method: 'POST',
|
|
body: formData,
|
|
}).then(response => response.json()).then(data => {
|
|
if (data && data.file && data.file.url) {
|
|
document.getElementById('banner').src = data.file.url;
|
|
saveEditorData();
|
|
} else {
|
|
console.error('Error: Invalid response format', data);
|
|
}
|
|
}).catch(error => {
|
|
console.error('Error uploading the image:', error);
|
|
}).finally(() => {
|
|
uploadButton.disabled = false;
|
|
loader.style.display = 'none';
|
|
imageIcon.style.display = 'inline-block';
|
|
});
|
|
}
|
|
}
|
|
|
|
function loadLanguage(lang) {
|
|
fetch(`./lang/${lang}.json`)
|
|
.then(response => response.json())
|
|
.then(translations => {
|
|
document.querySelectorAll('[data-translate]').forEach(element => {
|
|
const translationKey = element.getAttribute('data-translate');
|
|
|
|
if (element.tagName.toLowerCase() === 'input' || element.tagName.toLowerCase() === 'textarea') {
|
|
element.placeholder = translations[translationKey];
|
|
} else {
|
|
element.innerText = translations[translationKey];
|
|
}
|
|
});
|
|
})
|
|
.catch(error => console.error('Error loading language file:', error));
|
|
}
|
|
|
|
function dashboardMode() {
|
|
loadEditorState();
|
|
const dashboard = document.getElementById('dashboard');
|
|
dashboard.style.display = 'flex';
|
|
dashboard.style.opacity = '0';
|
|
setTimeout(() => {
|
|
dashboard.style.transition = 'opacity 0.5s ease';
|
|
dashboard.style.opacity = '1';
|
|
}, 10);
|
|
}
|
|
|
|
function buyMode() {
|
|
localStorage.removeItem('conex_data');
|
|
title = document.getElementById('buyModeDirectoryInput').value.trim();
|
|
directory = sanitizeDirectoryTitle(title);
|
|
|
|
let tagsInput = document.getElementById('buyModeTagsInput').value.trim();
|
|
let tags = tagsInput
|
|
.split(/[\s,]+/)
|
|
.map(tag => tag.trim().toLowerCase().replace(/[^a-z0-9]/g, ''))
|
|
.filter(tag => tag.length > 0);
|
|
|
|
const tagsString = tags.join(' ');
|
|
|
|
const dataToSave = {
|
|
title: title,
|
|
directory: directory,
|
|
tags: tagsString
|
|
};
|
|
|
|
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";
|
|
document.getElementById("editButton").style.display = "none";
|
|
|
|
const dashboard = document.getElementById('dashboard');
|
|
dashboard.style.transition = 'opacity 0.5s ease';
|
|
dashboard.style.opacity = '0';
|
|
|
|
setTimeout(() => {
|
|
dashboard.style.display = 'none';
|
|
}, 500);
|
|
}
|
|
|
|
function continueMode() {
|
|
const savedData = localStorage.getItem('conex_data');
|
|
if (savedData) {
|
|
const parsedData = JSON.parse(savedData);
|
|
if (parsedData.directory) {
|
|
checkDirectoryExists(parsedData.directory).then(exists => {
|
|
if (exists) {
|
|
editMode(parsedData.directory);
|
|
} else {
|
|
continueBuyMode();
|
|
}
|
|
});
|
|
} else {
|
|
continueBuyMode();
|
|
}
|
|
} else {
|
|
buyMode();
|
|
}
|
|
}
|
|
|
|
function continueBuyMode() {
|
|
document.getElementById("buyButton").style.display = "block";
|
|
document.getElementById("editButton").style.display = "none";
|
|
const dashboard = document.getElementById('dashboard');
|
|
dashboard.style.transition = 'opacity 0.5s ease';
|
|
dashboard.style.opacity = '0';
|
|
|
|
setTimeout(() => {
|
|
dashboard.style.display = 'none';
|
|
}, 500);
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
function openEditModeDialog() {
|
|
overlay.style.display = "block";
|
|
dialog.style.display = "block";
|
|
editDialog.style.display = "block";
|
|
}
|
|
|
|
async function editMode(dir) {
|
|
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');
|
|
dashboard.style.transition = 'opacity 0.5s ease';
|
|
dashboard.style.opacity = '0';
|
|
|
|
setTimeout(() => {
|
|
dashboard.style.display = 'none';
|
|
}, 500);
|
|
}
|
|
|
|
async function fetchAndStoreData(directoryName) {
|
|
try {
|
|
const response = await fetch(`https://api.conex.one/api/fetch/${encodeURIComponent(directoryName)}`);
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch data for directory: ${directoryName}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
localStorage.setItem('conex_data', JSON.stringify(data));
|
|
console.log('Data fetched and stored in localStorage:', data);
|
|
|
|
loadEditorState();
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error fetching and storing data:', error);
|
|
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('https://api.conex.one/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('https://api.conex.one/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;
|
|
}
|