573 lines
26 KiB
JavaScript
573 lines
26 KiB
JavaScript
(function () {
|
|
var supported = ["en", "it", "fr", "de", "es"];
|
|
var fallback = "en";
|
|
var aliases = {
|
|
"en-us": "en",
|
|
"de-ch": "de",
|
|
"fr-ch": "fr"
|
|
};
|
|
|
|
var translations = {
|
|
en: {
|
|
pageTitle: "Bag Exchange | Swap bags and handbags",
|
|
languageLabel: "Language",
|
|
badge: "community beta",
|
|
heroTitle: "Give your bags a new life.",
|
|
heroDesc: "Swap bags and handbags in a simple, safe, and sustainable way. Upload your item, find real matches, and refresh your style without buying new every time.",
|
|
ctaPrimary: "Start swapping",
|
|
ctaLogin: "Login",
|
|
ctaLogout: "Logout",
|
|
ctaSecondary: "See how it works",
|
|
ctaRegister: "Create account",
|
|
howTitle: "How it works in 3 steps",
|
|
step1: "1. List your bag with photos and condition",
|
|
step2: "2. Receive offers from people with similar taste",
|
|
step3: "3. Confirm the swap through chat and tracked shipping",
|
|
card1Title: "Verified profiles only",
|
|
card1Desc: "We reduce risk with account verification, feedback, and transparent swap history.",
|
|
card2Title: "Save and add value",
|
|
card2Desc: "A smart way to renew your wardrobe while avoiding waste and unnecessary spending.",
|
|
card3Title: "Circular style",
|
|
card3Desc: "From daily bags to elegant clutches: every piece can find a new owner.",
|
|
communityTitle: "Videochat and grow your profile",
|
|
communityDesc: "You can videochat with people interested in your items or simply exchange opinions and advice. You can aspire to become a fashion bag influencer.",
|
|
footer: "© 2026 Bag Exchange · Bag and handbag exchange between individuals",
|
|
modalTitle: "How to prepare your exchange",
|
|
modalStep1: "Create a photo gallery of your bag.",
|
|
modalStep2: "Describe the product.",
|
|
modalStep3: "Add your exchange conditions.",
|
|
subscribeTitle: "We are building Bag Exchange.",
|
|
subscribeDesc: "Enter your email to stay updated.",
|
|
subscribePlaceholder: "Your email",
|
|
subscribeCta: "Keep me updated",
|
|
subscribeThanks: "Thank you. We will keep you updated.",
|
|
subscribeInvalidEmail: "Please enter a valid email address.",
|
|
subscribeError: "Something went wrong. Please try again.",
|
|
registerTitle: "Create your account",
|
|
registerDesc: "Register to start exchanging bags and join the community.",
|
|
registerEmailPlaceholder: "Your email",
|
|
registerPasswordPlaceholder: "Password",
|
|
registerConfirmPlaceholder: "Confirm password",
|
|
registerCta: "Create account",
|
|
registerThanks: "Registration completed. You can now log in when the auth area is live.",
|
|
registerInvalidEmail: "Please enter a valid email address.",
|
|
registerPasswordMismatch: "Passwords do not match.",
|
|
registerWeakPassword: "Use at least 8 characters with letters and numbers.",
|
|
registerEmailExists: "This email is already registered.",
|
|
registerError: "Unable to complete registration. Please try again.",
|
|
loginTitle: "Access your account",
|
|
loginDesc: "Log in to continue your exchange journey.",
|
|
loginEmailPlaceholder: "Your email",
|
|
loginPasswordPlaceholder: "Password",
|
|
loginCta: "Log in",
|
|
loginForgotLink: "Forgot your password?",
|
|
loginSuccess: "Login successful.",
|
|
loginInvalid: "Invalid email or password.",
|
|
loginNotVerified: "Email not verified. Check your inbox for the verification link.",
|
|
loginError: "Unable to log in. Please try again.",
|
|
authStatusGuest: "Not logged in.",
|
|
authStatusUserPrefix: "Logged in as:"
|
|
},
|
|
it: {
|
|
pageTitle: "Bag Exchange | Scambia borse e borsette",
|
|
languageLabel: "Lingua",
|
|
badge: "community beta",
|
|
heroTitle: "Dai nuova vita alle tue borse.",
|
|
heroDesc: "Scambia borse e borsette in modo semplice, sicuro e sostenibile. Carica il tuo articolo, trova match reali e rinnova il tuo stile senza comprare ogni volta da zero.",
|
|
ctaPrimary: "Inizia a scambiare",
|
|
ctaLogin: "Login",
|
|
ctaLogout: "Logout",
|
|
ctaSecondary: "Guarda come funziona",
|
|
ctaRegister: "Crea account",
|
|
howTitle: "Come funziona in 3 step",
|
|
step1: "1. Pubblica la tua borsa con foto e condizioni",
|
|
step2: "2. Ricevi proposte da persone con gusti simili",
|
|
step3: "3. Conferma lo scambio con chat e spedizione tracciata",
|
|
card1Title: "Solo profili verificati",
|
|
card1Desc: "Riduciamo i rischi grazie a verifica account, feedback e storico scambi trasparente.",
|
|
card2Title: "Risparmia e valorizza",
|
|
card2Desc: "Un modo intelligente per rinnovare il guardaroba evitando sprechi e spese inutili.",
|
|
card3Title: "Stile circolare",
|
|
card3Desc: "Dalle borse da giorno alle pochette eleganti: ogni pezzo trova una nuova proprietaria.",
|
|
communityTitle: "Videochat e crescita del tuo profilo",
|
|
communityDesc: "Hai la possibilita di videochattare con gli interessati ai tuoi prodotti o semplicemente per scambiarsi opinioni e consigli. Puoi aspirare a diventare una fashion bag influencer.",
|
|
footer: "© 2026 Bag Exchange · Scambio borse e borsette tra privati",
|
|
modalTitle: "Come preparare il tuo scambio",
|
|
modalStep1: "Crea una galleria di foto della tua borsa.",
|
|
modalStep2: "Descrivi il prodotto.",
|
|
modalStep3: "Inserisci le condizioni di scambio.",
|
|
subscribeTitle: "Stiamo sviluppando Bag Exchange.",
|
|
subscribeDesc: "Inserisci la tua email per rimanere aggiornato.",
|
|
subscribePlaceholder: "La tua email",
|
|
subscribeCta: "Tienimi aggiornato",
|
|
subscribeThanks: "Grazie. Ti terremo aggiornato.",
|
|
subscribeInvalidEmail: "Inserisci un indirizzo email valido.",
|
|
subscribeError: "Si e verificato un errore. Riprova.",
|
|
registerTitle: "Crea il tuo account",
|
|
registerDesc: "Registrati per iniziare a scambiare borse ed entrare nella community.",
|
|
registerEmailPlaceholder: "La tua email",
|
|
registerPasswordPlaceholder: "Password",
|
|
registerConfirmPlaceholder: "Conferma password",
|
|
registerCta: "Crea account",
|
|
registerThanks: "Registrazione completata. Potrai fare login quando l'area auth sara disponibile.",
|
|
registerInvalidEmail: "Inserisci un indirizzo email valido.",
|
|
registerPasswordMismatch: "Le password non coincidono.",
|
|
registerWeakPassword: "Usa almeno 8 caratteri con lettere e numeri.",
|
|
registerEmailExists: "Questa email e gia registrata.",
|
|
registerError: "Impossibile completare la registrazione. Riprova.",
|
|
loginTitle: "Accedi al tuo account",
|
|
loginDesc: "Effettua il login per continuare il tuo percorso di scambio.",
|
|
loginEmailPlaceholder: "La tua email",
|
|
loginPasswordPlaceholder: "Password",
|
|
loginCta: "Accedi",
|
|
loginForgotLink: "Hai dimenticato la password?",
|
|
loginSuccess: "Login effettuato con successo.",
|
|
loginInvalid: "Email o password non validi.",
|
|
loginNotVerified: "Email non verificata. Controlla la tua casella per il link di verifica.",
|
|
loginError: "Impossibile effettuare il login. Riprova.",
|
|
authStatusGuest: "Non autenticato.",
|
|
authStatusUserPrefix: "Connesso come:"
|
|
},
|
|
fr: {
|
|
pageTitle: "Bag Exchange | Echange de sacs et pochettes",
|
|
languageLabel: "Langue",
|
|
badge: "communaute beta",
|
|
heroTitle: "Donnez une nouvelle vie a vos sacs.",
|
|
heroDesc: "Echangez sacs et pochettes de facon simple, sure et durable. Publiez votre article, trouvez de vrais matchs et renouvelez votre style sans acheter neuf a chaque fois.",
|
|
ctaPrimary: "Commencer l'echange",
|
|
ctaLogin: "Connexion",
|
|
ctaLogout: "Deconnexion",
|
|
ctaSecondary: "Voir comment ca marche",
|
|
ctaRegister: "Creer un compte",
|
|
howTitle: "Comment ca marche en 3 etapes",
|
|
step1: "1. Publiez votre sac avec photos et etat",
|
|
step2: "2. Recevez des propositions de personnes au style proche",
|
|
step3: "3. Confirmez l'echange via chat et livraison suivie",
|
|
card1Title: "Profils verifies uniquement",
|
|
card1Desc: "Nous reduisons les risques avec verification des comptes, avis et historique d'echange transparent.",
|
|
card2Title: "Economisez et valorisez",
|
|
card2Desc: "Une facon intelligente de renouveler votre dressing en evitant le gaspillage et les depenses inutiles.",
|
|
card3Title: "Style circulaire",
|
|
card3Desc: "Du sac quotidien a la pochette elegante: chaque piece peut trouver une nouvelle proprietaire.",
|
|
communityTitle: "Videochat et visibilite mode",
|
|
communityDesc: "Vous pouvez faire une videochat avec les personnes interessees par vos articles ou simplement echanger des avis et des conseils. Vous pouvez aspirer a devenir une influenceuse mode des sacs.",
|
|
footer: "© 2026 Bag Exchange · Echange de sacs et pochettes entre particuliers",
|
|
modalTitle: "Comment preparer votre echange",
|
|
modalStep1: "Creez une galerie photo de votre sac.",
|
|
modalStep2: "Decrivez le produit.",
|
|
modalStep3: "Ajoutez vos conditions d'echange.",
|
|
subscribeTitle: "Nous developpons Bag Exchange.",
|
|
subscribeDesc: "Entrez votre email pour rester informe.",
|
|
subscribePlaceholder: "Votre email",
|
|
subscribeCta: "Me tenir informe",
|
|
subscribeThanks: "Merci. Nous vous tiendrons informe.",
|
|
subscribeInvalidEmail: "Veuillez entrer une adresse email valide.",
|
|
subscribeError: "Une erreur est survenue. Veuillez reessayer.",
|
|
registerTitle: "Creez votre compte",
|
|
registerDesc: "Inscrivez-vous pour commencer les echanges et rejoindre la communaute.",
|
|
registerEmailPlaceholder: "Votre email",
|
|
registerPasswordPlaceholder: "Mot de passe",
|
|
registerConfirmPlaceholder: "Confirmer le mot de passe",
|
|
registerCta: "Creer un compte",
|
|
registerThanks: "Inscription terminee. Vous pourrez vous connecter quand l'espace auth sera disponible.",
|
|
registerInvalidEmail: "Veuillez entrer une adresse email valide.",
|
|
registerPasswordMismatch: "Les mots de passe ne correspondent pas.",
|
|
registerWeakPassword: "Utilisez au moins 8 caracteres avec lettres et chiffres.",
|
|
registerEmailExists: "Cet email est deja enregistre.",
|
|
registerError: "Impossible de finaliser l'inscription. Veuillez reessayer.",
|
|
loginTitle: "Accedez a votre compte",
|
|
loginDesc: "Connectez-vous pour poursuivre votre parcours d'echange.",
|
|
loginEmailPlaceholder: "Votre email",
|
|
loginPasswordPlaceholder: "Mot de passe",
|
|
loginCta: "Connexion",
|
|
loginForgotLink: "Mot de passe oublie ?",
|
|
loginSuccess: "Connexion reussie.",
|
|
loginInvalid: "Email ou mot de passe invalide.",
|
|
loginNotVerified: "Email non verifiee. Verifiez votre boite de reception pour le lien de verification.",
|
|
loginError: "Impossible de se connecter. Veuillez reessayer.",
|
|
authStatusGuest: "Non connecte.",
|
|
authStatusUserPrefix: "Connecte en tant que :"
|
|
},
|
|
de: {
|
|
pageTitle: "Bag Exchange | Tausche Taschen und Handtaschen",
|
|
languageLabel: "Sprache",
|
|
badge: "community beta",
|
|
heroTitle: "Gib deinen Taschen ein neues Leben.",
|
|
heroDesc: "Tausche Taschen und Handtaschen einfach, sicher und nachhaltig. Lade dein Teil hoch, finde echte Matches und erneuere deinen Stil ohne standig neu zu kaufen.",
|
|
ctaPrimary: "Jetzt tauschen",
|
|
ctaLogin: "Login",
|
|
ctaLogout: "Logout",
|
|
ctaSecondary: "So funktioniert es",
|
|
ctaRegister: "Konto erstellen",
|
|
howTitle: "So funktioniert es in 3 Schritten",
|
|
step1: "1. Stelle deine Tasche mit Fotos und Zustand ein",
|
|
step2: "2. Erhalte Angebote von Menschen mit ahnlichem Geschmack",
|
|
step3: "3. Bestatige den Tausch per Chat und Sendungsverfolgung",
|
|
card1Title: "Nur verifizierte Profile",
|
|
card1Desc: "Wir reduzieren Risiken durch Kontoverifizierung, Bewertungen und transparente Tauschhistorie.",
|
|
card2Title: "Spare und schaffe Wert",
|
|
card2Desc: "Eine smarte Art, deine Garderobe zu erneuern und gleichzeitig Verschwendung und unnotige Ausgaben zu vermeiden.",
|
|
card3Title: "Kreislauf-Stil",
|
|
card3Desc: "Von Alltagstaschen bis zur eleganten Clutch: Jedes Stuck kann eine neue Besitzerin finden.",
|
|
communityTitle: "Videochat und Profilaufbau",
|
|
communityDesc: "Du kannst per Videochat mit Interessierten an deinen Produkten sprechen oder einfach Meinungen und Tipps austauschen. Du kannst darauf hinarbeiten, Fashion-Bag-Influencerin zu werden.",
|
|
footer: "© 2026 Bag Exchange · Taschen- und Handtaschentausch zwischen Privatpersonen",
|
|
modalTitle: "So bereitest du deinen Tausch vor",
|
|
modalStep1: "Erstelle eine Fotogalerie deiner Tasche.",
|
|
modalStep2: "Beschreibe das Produkt.",
|
|
modalStep3: "Hinterlege die Tauschbedingungen.",
|
|
subscribeTitle: "Wir entwickeln Bag Exchange.",
|
|
subscribeDesc: "Gib deine E-Mail ein, um auf dem Laufenden zu bleiben.",
|
|
subscribePlaceholder: "Deine E-Mail",
|
|
subscribeCta: "Auf dem Laufenden halten",
|
|
subscribeThanks: "Danke. Wir halten dich auf dem Laufenden.",
|
|
subscribeInvalidEmail: "Bitte gib eine gueltige E-Mail-Adresse ein.",
|
|
subscribeError: "Etwas ist schiefgelaufen. Bitte versuche es erneut.",
|
|
registerTitle: "Erstelle dein Konto",
|
|
registerDesc: "Registriere dich, um mit dem Tauschen zu starten und der Community beizutreten.",
|
|
registerEmailPlaceholder: "Deine E-Mail",
|
|
registerPasswordPlaceholder: "Passwort",
|
|
registerConfirmPlaceholder: "Passwort bestaetigen",
|
|
registerCta: "Konto erstellen",
|
|
registerThanks: "Registrierung abgeschlossen. Du kannst dich einloggen, sobald der Auth-Bereich live ist.",
|
|
registerInvalidEmail: "Bitte gib eine gueltige E-Mail-Adresse ein.",
|
|
registerPasswordMismatch: "Die Passwoerter stimmen nicht ueberein.",
|
|
registerWeakPassword: "Mindestens 8 Zeichen mit Buchstaben und Zahlen verwenden.",
|
|
registerEmailExists: "Diese E-Mail ist bereits registriert.",
|
|
registerError: "Registrierung konnte nicht abgeschlossen werden. Bitte erneut versuchen.",
|
|
loginTitle: "Zugang zu deinem Konto",
|
|
loginDesc: "Melde dich an, um deine Austauschreise fortzusetzen.",
|
|
loginEmailPlaceholder: "Deine E-Mail",
|
|
loginPasswordPlaceholder: "Passwort",
|
|
loginCta: "Anmelden",
|
|
loginForgotLink: "Passwort vergessen?",
|
|
loginSuccess: "Login erfolgreich.",
|
|
loginInvalid: "Ungueltige E-Mail oder Passwort.",
|
|
loginNotVerified: "E-Mail nicht verifiziert. Bitte pruefe dein Postfach auf den Verifizierungslink.",
|
|
loginError: "Anmeldung nicht moeglich. Bitte erneut versuchen.",
|
|
authStatusGuest: "Nicht angemeldet.",
|
|
authStatusUserPrefix: "Angemeldet als:"
|
|
},
|
|
es: {
|
|
pageTitle: "Bag Exchange | Intercambio de bolsos y carteras",
|
|
languageLabel: "Idioma",
|
|
badge: "comunidad beta",
|
|
heroTitle: "Dale nueva vida a tus bolsos.",
|
|
heroDesc: "Intercambia bolsos y carteras de forma simple, segura y sostenible. Sube tu articulo, encuentra matches reales y renueva tu estilo sin comprar nuevo cada vez.",
|
|
ctaPrimary: "Empezar a intercambiar",
|
|
ctaLogin: "Iniciar sesion",
|
|
ctaLogout: "Cerrar sesion",
|
|
ctaSecondary: "Ver como funciona",
|
|
ctaRegister: "Crear cuenta",
|
|
howTitle: "Como funciona en 3 pasos",
|
|
step1: "1. Publica tu bolso con fotos y estado",
|
|
step2: "2. Recibe propuestas de personas con gustos similares",
|
|
step3: "3. Confirma el intercambio con chat y envio con seguimiento",
|
|
card1Title: "Solo perfiles verificados",
|
|
card1Desc: "Reducimos riesgos con verificacion de cuenta, valoraciones e historial de intercambios transparente.",
|
|
card2Title: "Ahorra y revaloriza",
|
|
card2Desc: "Una forma inteligente de renovar tu armario evitando desperdicios y gastos innecesarios.",
|
|
card3Title: "Estilo circular",
|
|
card3Desc: "Desde bolsos de diario hasta clutch elegante: cada pieza puede encontrar nueva duena.",
|
|
communityTitle: "Videochat y crecimiento de perfil",
|
|
communityDesc: "Puedes hacer videochat con personas interesadas en tus productos o simplemente intercambiar opiniones y consejos. Puedes aspirar a convertirte en una influencer de bolsos de moda.",
|
|
footer: "© 2026 Bag Exchange · Intercambio de bolsos y carteras entre particulares",
|
|
modalTitle: "Como preparar tu intercambio",
|
|
modalStep1: "Crea una galeria de fotos de tu bolso.",
|
|
modalStep2: "Describe el producto.",
|
|
modalStep3: "Indica las condiciones de intercambio.",
|
|
subscribeTitle: "Estamos desarrollando Bag Exchange.",
|
|
subscribeDesc: "Ingresa tu email para mantenerte al dia.",
|
|
subscribePlaceholder: "Tu email",
|
|
subscribeCta: "Mantenerme informado",
|
|
subscribeThanks: "Gracias. Te mantendremos informado.",
|
|
subscribeInvalidEmail: "Introduce un correo electronico valido.",
|
|
subscribeError: "Algo salio mal. Intentalo de nuevo.",
|
|
registerTitle: "Crea tu cuenta",
|
|
registerDesc: "Registrate para empezar a intercambiar y unirte a la comunidad.",
|
|
registerEmailPlaceholder: "Tu email",
|
|
registerPasswordPlaceholder: "Contrasena",
|
|
registerConfirmPlaceholder: "Confirmar contrasena",
|
|
registerCta: "Crear cuenta",
|
|
registerThanks: "Registro completado. Podras iniciar sesion cuando el area auth este disponible.",
|
|
registerInvalidEmail: "Introduce un correo electronico valido.",
|
|
registerPasswordMismatch: "Las contrasenas no coinciden.",
|
|
registerWeakPassword: "Usa al menos 8 caracteres con letras y numeros.",
|
|
registerEmailExists: "Este email ya esta registrado.",
|
|
registerError: "No se pudo completar el registro. Intentalo de nuevo.",
|
|
loginTitle: "Accede a tu cuenta",
|
|
loginDesc: "Inicia sesion para continuar tu recorrido de intercambio.",
|
|
loginEmailPlaceholder: "Tu email",
|
|
loginPasswordPlaceholder: "Contrasena",
|
|
loginCta: "Iniciar sesion",
|
|
loginForgotLink: "Has olvidado tu contrasena?",
|
|
loginSuccess: "Sesion iniciada correctamente.",
|
|
loginInvalid: "Email o contrasena no validos.",
|
|
loginNotVerified: "Email no verificado. Revisa tu bandeja de entrada para el enlace de verificacion.",
|
|
loginError: "No se pudo iniciar sesion. Intentalo de nuevo.",
|
|
authStatusGuest: "No autenticado.",
|
|
authStatusUserPrefix: "Conectado como:"
|
|
}
|
|
};
|
|
var currentLanguage = fallback;
|
|
var currentAuthEmail = "";
|
|
|
|
function normalizeLanguage(lang) {
|
|
if (!lang) return fallback;
|
|
var normalized = String(lang).toLowerCase().replace("_", "-");
|
|
if (aliases[normalized]) return aliases[normalized];
|
|
var base = normalized.split("-")[0];
|
|
if (supported.indexOf(base) !== -1) return base;
|
|
return fallback;
|
|
}
|
|
|
|
function getInitialLanguage() {
|
|
var params = new URLSearchParams(window.location.search);
|
|
var queryLang = params.get("lang");
|
|
if (queryLang) return normalizeLanguage(queryLang);
|
|
|
|
var saved = window.localStorage.getItem("preferredLang");
|
|
if (saved) return normalizeLanguage(saved);
|
|
|
|
var browserLang = navigator.language || (navigator.languages && navigator.languages[0]) || fallback;
|
|
return normalizeLanguage(browserLang);
|
|
}
|
|
|
|
function applyLanguage(lang) {
|
|
var active = translations[lang] || translations[fallback];
|
|
currentLanguage = lang;
|
|
|
|
document.documentElement.lang = lang;
|
|
document.title = active.pageTitle;
|
|
|
|
var nodes = document.querySelectorAll("[data-i18n]");
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
var key = nodes[i].getAttribute("data-i18n");
|
|
if (active[key]) nodes[i].textContent = active[key];
|
|
}
|
|
|
|
var placeholders = document.querySelectorAll("[data-i18n-placeholder]");
|
|
for (var j = 0; j < placeholders.length; j++) {
|
|
var placeholderKey = placeholders[j].getAttribute("data-i18n-placeholder");
|
|
if (active[placeholderKey]) placeholders[j].setAttribute("placeholder", active[placeholderKey]);
|
|
}
|
|
|
|
var selector = document.getElementById("language-select");
|
|
if (selector) selector.value = lang;
|
|
|
|
var authStatusNode = document.getElementById("auth-status");
|
|
if (authStatusNode) {
|
|
if (currentAuthEmail) {
|
|
authStatusNode.textContent = currentAuthEmail;
|
|
authStatusNode.classList.remove("is-hidden");
|
|
} else {
|
|
authStatusNode.textContent = "";
|
|
authStatusNode.classList.add("is-hidden");
|
|
}
|
|
}
|
|
|
|
var url = new URL(window.location.href);
|
|
url.searchParams.set("lang", lang);
|
|
window.history.replaceState({}, "", url.toString());
|
|
}
|
|
|
|
var initialLanguage = getInitialLanguage();
|
|
applyLanguage(initialLanguage);
|
|
|
|
var select = document.getElementById("language-select");
|
|
if (select) {
|
|
select.addEventListener("change", function (event) {
|
|
var chosen = normalizeLanguage(event.target.value);
|
|
window.localStorage.setItem("preferredLang", chosen);
|
|
applyLanguage(chosen);
|
|
});
|
|
}
|
|
|
|
function closeModal(modal) {
|
|
if (!modal) return;
|
|
modal.classList.remove("is-open");
|
|
modal.setAttribute("aria-hidden", "true");
|
|
}
|
|
|
|
function openModal(modal) {
|
|
if (!modal) return;
|
|
modal.classList.add("is-open");
|
|
modal.setAttribute("aria-hidden", "false");
|
|
}
|
|
|
|
function bindModal(openButtonId, modalId, closeButtonId) {
|
|
var modal = document.getElementById(modalId);
|
|
var openButton = document.getElementById(openButtonId);
|
|
var closeButton = document.getElementById(closeButtonId);
|
|
if (!modal || !openButton || !closeButton) return null;
|
|
|
|
openButton.addEventListener("click", function () {
|
|
openModal(modal);
|
|
});
|
|
|
|
closeButton.addEventListener("click", function () {
|
|
closeModal(modal);
|
|
});
|
|
|
|
modal.addEventListener("click", function (event) {
|
|
if (event.target === modal) {
|
|
closeModal(modal);
|
|
}
|
|
});
|
|
|
|
return modal;
|
|
}
|
|
|
|
var modals = [];
|
|
var subscribeModal = bindModal("start-swapping-btn", "subscribe-modal", "subscribe-close-btn");
|
|
if (subscribeModal) modals.push(subscribeModal);
|
|
|
|
var subscribeForm = document.getElementById("subscribe-form");
|
|
var subscribeEmailInput = document.getElementById("subscribe-email");
|
|
var subscribeSubmitButton = document.getElementById("subscribe-submit-btn");
|
|
var subscribeFeedback = document.getElementById("subscribe-feedback");
|
|
var subscribeError = document.getElementById("subscribe-error");
|
|
var loginButton = document.getElementById("login-btn");
|
|
var registerButton = document.getElementById("register-btn");
|
|
var logoutButton = document.getElementById("logout-btn");
|
|
|
|
function getActiveTranslation(key) {
|
|
var active = translations[currentLanguage] || translations[fallback];
|
|
return active[key] || "";
|
|
}
|
|
|
|
function setSubscribeState(subscribed) {
|
|
if (!subscribeForm || !subscribeFeedback) return;
|
|
subscribeForm.classList.toggle("is-hidden", subscribed);
|
|
subscribeFeedback.classList.toggle("is-hidden", !subscribed);
|
|
if (subscribed && subscribeError) {
|
|
subscribeError.classList.add("is-hidden");
|
|
subscribeError.textContent = "";
|
|
}
|
|
}
|
|
|
|
function setSubscribeError(message) {
|
|
if (!subscribeError) return;
|
|
subscribeError.textContent = message;
|
|
subscribeError.classList.remove("is-hidden");
|
|
}
|
|
|
|
function setAuthStatus(email) {
|
|
currentAuthEmail = email || "";
|
|
var authStatusNode = document.getElementById("auth-status");
|
|
if (!authStatusNode) return;
|
|
if (currentAuthEmail) {
|
|
authStatusNode.textContent = currentAuthEmail;
|
|
authStatusNode.classList.remove("is-hidden");
|
|
if (loginButton) loginButton.classList.add("is-hidden");
|
|
if (registerButton) registerButton.classList.add("is-hidden");
|
|
if (logoutButton) logoutButton.classList.remove("is-hidden");
|
|
} else {
|
|
authStatusNode.textContent = "";
|
|
authStatusNode.classList.add("is-hidden");
|
|
if (loginButton) loginButton.classList.remove("is-hidden");
|
|
if (registerButton) registerButton.classList.remove("is-hidden");
|
|
if (logoutButton) logoutButton.classList.add("is-hidden");
|
|
}
|
|
}
|
|
|
|
async function refreshAuthStatus() {
|
|
try {
|
|
var response = await fetch("/api/auth/me", { method: "GET" });
|
|
if (!response.ok) {
|
|
setAuthStatus("");
|
|
return;
|
|
}
|
|
var payload = await response.json();
|
|
if (payload && payload.authenticated && payload.email) {
|
|
setAuthStatus(payload.email);
|
|
} else {
|
|
setAuthStatus("");
|
|
}
|
|
} catch (error) {
|
|
setAuthStatus("");
|
|
}
|
|
}
|
|
|
|
function collectBrowserData() {
|
|
return {
|
|
userAgent: navigator.userAgent || "",
|
|
language: navigator.language || "",
|
|
languages: navigator.languages || [],
|
|
platform: navigator.platform || "",
|
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "",
|
|
screen: {
|
|
width: window.screen && window.screen.width ? window.screen.width : 0,
|
|
height: window.screen && window.screen.height ? window.screen.height : 0
|
|
}
|
|
};
|
|
}
|
|
|
|
if (subscribeForm) {
|
|
subscribeForm.addEventListener("submit", async function (event) {
|
|
event.preventDefault();
|
|
if (!subscribeEmailInput) return;
|
|
|
|
var email = subscribeEmailInput.value.trim();
|
|
if (!email || !subscribeEmailInput.checkValidity()) {
|
|
setSubscribeError(getActiveTranslation("subscribeInvalidEmail"));
|
|
return;
|
|
}
|
|
|
|
if (subscribeError) {
|
|
subscribeError.classList.add("is-hidden");
|
|
subscribeError.textContent = "";
|
|
}
|
|
|
|
if (subscribeSubmitButton) subscribeSubmitButton.disabled = true;
|
|
|
|
try {
|
|
var response = await fetch("/api/subscribe", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
email: email,
|
|
browserData: collectBrowserData()
|
|
})
|
|
});
|
|
|
|
if (response.ok || response.status === 409) {
|
|
setSubscribeState(true);
|
|
subscribeForm.reset();
|
|
if (subscribeFeedback) {
|
|
subscribeFeedback.textContent = getActiveTranslation("subscribeThanks");
|
|
}
|
|
} else if (response.status === 400) {
|
|
setSubscribeError(getActiveTranslation("subscribeInvalidEmail"));
|
|
} else {
|
|
setSubscribeError(getActiveTranslation("subscribeError"));
|
|
}
|
|
} catch (error) {
|
|
setSubscribeError(getActiveTranslation("subscribeError"));
|
|
} finally {
|
|
if (subscribeSubmitButton) subscribeSubmitButton.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (logoutButton) {
|
|
logoutButton.addEventListener("click", async function () {
|
|
try {
|
|
await fetch("/api/auth/logout", { method: "POST" });
|
|
} catch (error) {
|
|
}
|
|
setAuthStatus("");
|
|
});
|
|
}
|
|
|
|
refreshAuthStatus();
|
|
|
|
document.addEventListener("keydown", function (event) {
|
|
if (event.key === "Escape") {
|
|
for (var i = 0; i < modals.length; i++) {
|
|
closeModal(modals[i]);
|
|
}
|
|
}
|
|
});
|
|
})();
|