Files
continuum-app/apps/web/pages/login.vue
T
octoturge 4519c3ba50 Let testers sign in: an opt-in password form on the login page
The login page offered only a magic link, and the devstack's Supabase
cannot send email: POST /auth/v1/otp for an existing user answers
500 "Error sending magic link email". So nobody could sign in through
the page at all; the e2e browser run only got in by calling the Supabase
client directly.

NUXT_PUBLIC_PASSWORD_LOGIN=true now shows a password form beside the
magic-link one. It is off by default and the form says it is testing
only, so a build for real users never shows it unless someone sets the
flag on purpose.

Verified against the static build (nuxt generate, 5 routes, 524 KB): in
real Chrome the SPA loads, the form signs in, the app leaves /login and
the header shows the signed-in user, with no uncaught page errors.

Also: the Nitro build leaves apps/web/dist as a symlink to the output,
and the `dist/` ignore rule matches only directories, so it showed up as
untracked. The rule is now `dist`.
2026-10-29 10:12:19 +00:00

76 lines
2.0 KiB
Vue

<script setup lang="ts">
const email = ref("");
const sent = ref(false);
const error = ref<string | null>(null);
const client = useSupabaseClient();
const passwordLogin = useRuntimeConfig().public.passwordLogin;
const password = ref("");
async function signInWithPassword() {
error.value = null;
const { error: authError } = await client.auth.signInWithPassword({
email: email.value,
password: password.value,
});
if (authError) {
error.value = authError.message;
return;
}
// The Supabase module redirects away from /login once a session exists.
await navigateTo("/");
}
async function sendMagicLink() {
error.value = null;
const { error: authError } = await client.auth.signInWithOtp({ email: email.value });
if (authError) {
error.value = authError.message;
return;
}
sent.value = true;
}
</script>
<template>
<div class="login">
<h1>Sign in to Continuum</h1>
<form v-if="!sent" @submit.prevent="sendMagicLink">
<input v-model="email" type="email" placeholder="you@farm.com" required />
<button type="submit">Send magic link</button>
</form>
<p v-else>Check your inbox for a sign-in link.</p>
<form v-if="passwordLogin" class="login__password" @submit.prevent="signInWithPassword">
<p class="login__hint">Password sign-in is enabled for this build (testing only).</p>
<input v-model="email" type="email" placeholder="you@farm.com" required />
<input v-model="password" type="password" placeholder="password" required autocomplete="current-password" />
<button type="submit">Sign in</button>
</form>
<p v-if="error" class="login__error">{{ error }}</p>
</div>
</template>
<style scoped>
.login {
max-width: 320px;
margin: 4rem auto;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.login__password {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.login__hint {
font-size: 0.75rem;
opacity: 0.7;
}
.login__error {
color: #f2604c;
}
</style>