From 5e996f791ed1b32433d948d8e25be4b0a472cdc8 Mon Sep 17 00:00:00 2001 From: Kroonk Date: Wed, 20 May 2026 17:25:15 +0200 Subject: [PATCH] Fix auth modal feedback and production deploy config --- Dockerfile | 2 +- client/src/components/auth/AuthModal.tsx | 109 +++++++++++------------ client/src/lib/auth.ts | 30 +++++-- docker-compose.yml | 2 +- 4 files changed, 77 insertions(+), 66 deletions(-) diff --git a/Dockerfile b/Dockerfile index 66b710c..52b3887 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ WORKDIR /opt/michess/ COPY . . RUN corepack enable && \ - corepack prepare pnpm@latest --activate && \ + corepack prepare pnpm@9.15.9 --activate && \ pnpm config set store-dir /opt/michess/.pnpm-store && \ pnpm install --no-frozen-lockfile diff --git a/client/src/components/auth/AuthModal.tsx b/client/src/components/auth/AuthModal.tsx index 6b64c94..5b8df13 100644 --- a/client/src/components/auth/AuthModal.tsx +++ b/client/src/components/auth/AuthModal.tsx @@ -16,69 +16,68 @@ export default function AuthModal() { const [buttonLoading, setButtonLoading] = useState(false); const modalToggleRef = useRef(null); + function closeModal() { + if (modalToggleRef.current?.checked) { + modalToggleRef.current.checked = false; + } + } + async function submitAuth(e: FormEvent) { e.preventDefault(); const target = e.target as HTMLFormElement; - if (activeTab === "guest") { - const guestName = target.elements.namedItem("guestName") as HTMLInputElement; - if (!guestName || !guestName.value) return; + setServerMessage(null); + setButtonLoading(true); - setButtonLoading(true); - const user = await setGuestSession(guestName.value); - if (user) { - session?.setUser(user); - if (modalToggleRef.current?.checked) { - modalToggleRef.current.checked = false; - } - } - guestName.value = ""; - } else if (activeTab === "login") { - const loginName = target.elements.namedItem("loginName") as HTMLInputElement; - const loginPassword = target.elements.namedItem("loginPassword") as HTMLInputElement; - if (!loginName || !loginName.value || !loginPassword || !loginPassword.value) return; - - setButtonLoading(true); - const user = await login(loginName.value, loginPassword.value); - if (typeof user === "string") { - setServerMessage(user); - } else if (user?.id) { - session?.setUser(user); - if (serverMessage) { - setServerMessage(null); - } - if (modalToggleRef.current?.checked) { - modalToggleRef.current.checked = false; - } - } - } else if (activeTab === "register") { - const registerName = target.elements.namedItem("registerName") as HTMLInputElement; - const registerEmail = target.elements.namedItem("registerEmail") as HTMLInputElement; - const registerPassword = target.elements.namedItem("registerPassword") as HTMLInputElement; - if (!registerName || !registerName.value || !registerPassword || !registerPassword.value) { - return; - } - - setButtonLoading(true); - const user = await register( - registerName.value, - registerPassword.value, - registerEmail.value || undefined - ); - - if (typeof user === "string") { - setServerMessage(user); - } else if (user?.id) { - session?.setUser(user); - if (serverMessage) { - setServerMessage(null); - } - if (modalToggleRef.current?.checked) { - modalToggleRef.current.checked = false; + try { + if (activeTab === "guest") { + const guestName = target.elements.namedItem("guestName") as HTMLInputElement; + if (!guestName || !guestName.value) return; + + const user = await setGuestSession(guestName.value); + if (typeof user === "string") { + setServerMessage(user); + } else if (user?.id) { + session?.setUser(user); + closeModal(); + guestName.value = ""; + } + } else if (activeTab === "login") { + const loginName = target.elements.namedItem("loginName") as HTMLInputElement; + const loginPassword = target.elements.namedItem("loginPassword") as HTMLInputElement; + if (!loginName || !loginName.value || !loginPassword || !loginPassword.value) return; + + const user = await login(loginName.value, loginPassword.value); + if (typeof user === "string") { + setServerMessage(user); + } else if (user?.id) { + session?.setUser(user); + closeModal(); + } + } else if (activeTab === "register") { + const registerName = target.elements.namedItem("registerName") as HTMLInputElement; + const registerEmail = target.elements.namedItem("registerEmail") as HTMLInputElement; + const registerPassword = target.elements.namedItem("registerPassword") as HTMLInputElement; + if (!registerName || !registerName.value || !registerPassword || !registerPassword.value) { + return; + } + + const user = await register( + registerName.value, + registerPassword.value, + registerEmail.value || undefined + ); + + if (typeof user === "string") { + setServerMessage(user); + } else if (user?.id) { + session?.setUser(user); + closeModal(); } } + } finally { + setButtonLoading(false); } - setButtonLoading(false); } useEffect(() => { diff --git a/client/src/lib/auth.ts b/client/src/lib/auth.ts index de65bd9..28b15ca 100644 --- a/client/src/lib/auth.ts +++ b/client/src/lib/auth.ts @@ -1,6 +1,19 @@ import { API_URL } from "@/config"; import type { User } from "@michess/types"; +const readErrorMessage = async (res: Response, fallback: string) => { + try { + const body = await res.json(); + if (typeof body?.message === "string") { + return body.message; + } + } catch (err) { + // Response did not include a JSON error body. + } + + return fallback; +}; + export const fetchSession = async () => { try { const res = await fetch(`${API_URL}/v1/auth`, { @@ -30,8 +43,10 @@ export const setGuestSession = async (name: string) => { const user: User = await res.json(); return user; } + return await readErrorMessage(res, "Could not start guest session."); } catch (err) { console.error(err); + return "Could not reach the server. Please try again."; } }; @@ -48,12 +63,11 @@ export const register = async (name: string, password: string, email?: string) = if (res.status === 201) { const user: User = await res.json(); return user; - } else if (res.status === 409) { - const { message } = await res.json(); - return message as string; } + return await readErrorMessage(res, "Registration failed. Please try again."); } catch (err) { console.error(err); + return "Could not reach the server. Please try again."; } }; @@ -70,12 +84,11 @@ export const login = async (name: string, password: string) => { if (res.status === 200) { const user: User = await res.json(); return user; - } else if (res.status === 404 || res.status === 401) { - const { message } = await res.json(); - return message as string; } + return await readErrorMessage(res, "Login failed. Please try again."); } catch (err) { console.error(err); + return "Could not reach the server. Please try again."; } }; @@ -107,11 +120,10 @@ export const updateUser = async (name?: string, email?: string, password?: strin if (res.status === 200) { const user: User = await res.json(); return user; - } else if (res.status === 409) { - const { message } = await res.json(); - return message as string; } + return await readErrorMessage(res, "Could not update settings. Please try again."); } catch (err) { console.error(err); + return "Could not reach the server. Please try again."; } }; diff --git a/docker-compose.yml b/docker-compose.yml index e350a5c..0a9f3aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: PGPASSWORD: ${POSTGRES_PASSWORD:-changeme} PORT: 3001 SESSION_SECRET: ${SESSION_SECRET:-change-this-secret-in-production} - CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000} + CORS_ORIGIN: ${CORS_ORIGIN:-https://michess.mischlabs.de} ADMIN_EMAIL: ${ADMIN_EMAIL:-} APP_DIR: /opt/michess ports: