(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]); } } }); })();