From d1dc1b4bf01444aa6827fb56191d43728ec55f81 Mon Sep 17 00:00:00 2001 From: creations Date: Wed, 19 Mar 2025 19:59:43 -0400 Subject: [PATCH] update css and authform - stealtech, add register js and fix register backend --- public/css/auth.css | 214 ++++++++++++++++---------------- public/js/auth.js | 59 +++++++++ src/routes/api/auth/register.ts | 6 +- src/views/partials/authForm.ejs | 93 ++++++++------ 4 files changed, 225 insertions(+), 147 deletions(-) diff --git a/public/css/auth.css b/public/css/auth.css index bfb37f7..05743b2 100644 --- a/public/css/auth.css +++ b/public/css/auth.css @@ -1,190 +1,194 @@ .container { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - height: 100vh; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 100vh; } .content { - border: 1px solid var(--border); - background-color: var(--background-secondary); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 2rem; - width: clamp(200px, 50%, 300px); + border: 1px solid var(--border); + background-color: var(--background-secondary); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + width: clamp(200px, 50%, 300px); } .content form { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .auth-container { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - min-height: 100vh; - background: linear-gradient(135deg, rgba(31 30 30 / 90%) 0%, rgba(45 45 45 / 90%) 100%); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 100vh; + background: linear-gradient(135deg, rgba(31 30 30 / 90%) 0%, rgba(45 45 45 / 90%) 100%); } .auth-logo { - margin-bottom: 2rem; - text-align: center; + text-align: center; + margin-bottom: 2rem; } .auth-logo h1 { - font-size: 2.5rem; - font-weight: bold; - color: var(--text); - margin: 0; + font-size: 2.5rem; + margin-bottom: 0.5rem; + color: var(--accent); } .auth-logo p { - color: var(--text-secondary); - margin-top: 0.5rem; + color: var(--text-secondary); + margin-top: 0.5rem; } .auth-card { - width: 100%; - max-width: 400px; - border-radius: 8px; - box-shadow: var(--card-shadow); - background-color: var(--background-secondary); - overflow: hidden; - animation: fade-in 0.5s ease; + background-color: var(--background-secondary); + border-radius: 8px; + box-shadow: var(--card-shadow); + width: 100%; + max-width: 400px; + overflow: hidden; + animation: fade-in 0.5s ease; } .auth-header { - padding: 1.5rem; - background-color: rgba(0 0 0 / 10%); - text-align: center; + padding: 1.5rem; + text-align: center; + border-bottom: 1px solid var(--border); + background-color: rgba(0 0 0 / 10%); } .auth-header h2 { - margin: 0; - color: var(--text); - font-size: 1.5rem; + margin: 0; + font-size: 1.5rem; + color: var(--text); } .auth-form { - padding: 1.5rem; + padding: 1.5rem; } .auth-form form { - display: flex; - flex-direction: column; - width: 100%; + display: flex; + flex-direction: column; + width: 100%; } .auth-toggle { - text-align: center; - margin-top: 1.5rem; + text-align: center; + margin-top: 1.5rem; + font-size: 0.9rem; + color: var(--text-secondary); } .form-footer { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.9rem; + margin-top: 1rem; } .form-footer a { - color: var(--accent); - text-decoration: none; - font-size: 0.9rem; + color: var(--accent); + text-decoration: none; } .form-footer a:hover { - text-decoration: underline; + text-decoration: underline; } .form-footer label { - display: flex; - align-items: center; - gap: 0.25rem; - white-space: nowrap; + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + white-space: nowrap; } .auth-form button { - margin-top: 1rem; - width: 100%; + margin-top: 0.5rem; + width: 100%; } .password-group { - position: relative; - width: 100%; + position: relative; + width: 100%; } .password-wrapper { - position: relative; - width: 100%; + position: relative; + width: 100%; } .password-wrapper input { - width: 100%; - padding-right: 2rem; + width: 100%; + padding-right: 2rem; } .toggle-password { - position: absolute; - right: 10px; - top: 50%; - transform: translateY(-50%); - cursor: pointer; - width: 20px; - height: 20px; - fill: var(--text-secondary); - transition: fill 0.2s; + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + width: 20px; + height: 20px; + fill: var(--text-secondary); + transition: fill 0.2s ease; } .toggle-password:hover { - fill: var(--accent); + fill: var(--text); } .error-message { - color: var(--error); - background-color: rgb(237 66 69 / 10%); - border-left: 4px solid var(--error); - padding: 0.75rem; - margin-bottom: 1rem; - border-radius: 4px; - display: none; + color: var(--error); + background-color: rgb(237 66 69 / 10%); + padding: 0.75rem; + margin-bottom: 1.5rem; + border-radius: 4px; + display: none; + font-size: 0.9rem; + text-align: center; } @keyframes fade-in { - from { - opacity: 0; - transform: translateY(-20px); - } + from { + opacity: 0; + transform: translateY(-20px); + } - to { - opacity: 1; - transform: translateY(0); - } + to { + opacity: 1; + transform: translateY(0); + } } .auth-link { - color: #57f287; - text-decoration: none; - font-weight: bold; + color: var(--accent); + text-decoration: none; + font-weight: bold; } .auth-link:hover { - text-decoration: underline; + text-decoration: underline; } @media (width <= 480px) { - .auth-card { - max-width: 100%; - } + .auth-card { + max-width: 100%; + } - .auth-logo h1 { - font-size: 2rem; - } + .auth-logo h1 { + font-size: 2rem; + } } diff --git a/public/js/auth.js b/public/js/auth.js index 5f81984..e66989f 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -1,4 +1,5 @@ const loginForm = document.getElementById("login-form"); +const registerForm = document.getElementById("register-form"); const errorMessage = document.getElementById("error-message"); const rememberMe = document.getElementById("remember-me"); const emailInput = document.getElementById("email"); @@ -58,6 +59,64 @@ if (loginForm) { } } }); +} else if (registerForm) { + registerForm.addEventListener("submit", async (e) => { + e.preventDefault(); + + const email = emailInput?.value.trim(); + const username = document.getElementById("username")?.value.trim(); + const password = document.getElementById("password")?.value.trim(); + const inviteCode = document.getElementById("invite-code")?.value.trim(); + + if (!email || !password) { + if (errorMessage) { + errorMessage.style.display = "block"; + errorMessage.textContent = "Please enter email, password."; + } + return; + } + + try { + const response = await fetch("/api/auth/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + credentials: "same-origin", + body: JSON.stringify({ + username, + email, + password, + invite: inviteCode, + }), + }); + + const data = await response.json(); + + if (data.success) { + window.location.href = "/"; + } else { + if (errorMessage) { + errorMessage.style.display = "block"; + + if (Array.isArray(data.errors)) { + errorMessage.innerHTML = data.errors + .map((err) => `

${err}

`) + .join(""); + } else { + errorMessage.textContent = + data.error || + "An error occurred. Please try again."; + } + } + } + } catch (error) { + console.error("Register error:", error); + if (errorMessage) { + errorMessage.style.display = "block"; + errorMessage.textContent = + "An error occurred. Please try again."; + } + } + }); } const passwordInput = document.getElementById("password"); diff --git a/src/routes/api/auth/register.ts b/src/routes/api/auth/register.ts index edaf1dc..185131d 100644 --- a/src/routes/api/auth/register.ts +++ b/src/routes/api/auth/register.ts @@ -73,9 +73,13 @@ async function handler( ?.count, ) === 0; + let inviteValid: boolean = true; if (!firstUser && invite) { const inviteValidation: { valid: boolean; error?: string } = isValidInvite(invite); + + inviteValid = inviteValidation.valid; + if (!inviteValidation.valid && inviteValidation.error) { errors.push(inviteValidation.error); } @@ -103,7 +107,7 @@ async function handler( errors.push("Username or email already exists"); } - if (invite && !firstUser) { + if (invite && inviteValid && !firstUser) { [inviteData] = await reservation`SELECT * FROM invites WHERE id = ${invite};`; diff --git a/src/views/partials/authForm.ejs b/src/views/partials/authForm.ejs index d0f7072..9f8a477 100644 --- a/src/views/partials/authForm.ejs +++ b/src/views/partials/authForm.ejs @@ -1,49 +1,60 @@
-
- <%= pageType === "register" ? "Registration failed. Please try again." : "Invalid email or password. Please try again." %> -
+
+ <%= pageType==="register" ? "Registration failed. Please try again." + : "Invalid email or password. Please try again." %> +
-
" class="form"> - <% if (pageType === "register") { %> -
- - -
- <% } %> + " class="form"> + <% if (pageType==="register") { %> +
+ + +
-
- - -
+ <% if (requires_invite === true) { %> +
+ + +
+ <% } %> + <% } %> -
- -
- - - - -
-
+
+ + +
- <% if (pageType !== "register") { %> - - <% } %> +
+ +
+ + + + +
+
- -
+ <% if (pageType !=="register" ) { %> + + <% } %> -
-

- <%= pageType === "register" ? "Already have an account?" : "Don't have an account?" %> - - <%= pageType === "register" ? "Login" : "Register" %> - -

-
+ + + +
+

+ <%= pageType==="register" ? "Already have an account?" : "Don't have an account?" %> + + <%= pageType==="register" ? "Login" : "Register" %> + +

+