wire frontend email signup

This commit is contained in:
Yisroel Baum 2026-08-03 20:34:16 +03:00
parent e47535f91c
commit ed0d02959a
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
5 changed files with 297 additions and 24 deletions

View file

@ -13,17 +13,20 @@ const meResponseSchema = z.object({
user: authUserSchema,
})
const loginErrorResponseSchema = z.object({
const authErrorResponseSchema = z.object({
error: z.string(),
})
export type AuthUser = z.infer<typeof authUserSchema>
export type LoginFieldErrors = Partial<Record<'email' | 'password', string>>
export type SignupFieldErrors = Partial<Record<'email', string>>
export type ConfirmEmailFieldErrors = Partial<Record<'password' | 'passwordConfirmation', string>>
export const useAuthStore = defineStore('auth', () => {
const user = ref<AuthUser | null>(null)
const loading = ref(false)
const error = ref<string | null>(null)
const signupCompleted = ref(false)
const isAuthenticated = computed(() => user.value !== null)
async function fetchMe(): Promise<boolean> {
@ -85,7 +88,7 @@ export const useAuthStore = defineStore('auth', () => {
}
user.value = null
const errorResponse = loginErrorResponseSchema.safeParse(responseBody)
const errorResponse = authErrorResponseSchema.safeParse(responseBody)
error.value = errorResponse.success
? errorResponse.data.error
: 'Unable to log in. Please try again.'
@ -101,6 +104,76 @@ export const useAuthStore = defineStore('auth', () => {
}
}
async function signup(email: string): Promise<boolean> {
loading.value = true
error.value = null
signupCompleted.value = false
try {
const response = await fetch(`${API_BASE}/api/signup`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
})
if (response.status === 201) {
signupCompleted.value = true
return true
}
error.value = await responseError(response, 'Unable to sign up. Please try again.')
return false
} catch {
error.value = 'Unable to sign up. Please try again.'
return false
} finally {
loading.value = false
}
}
async function confirmEmail(token: string, password: string): Promise<boolean> {
loading.value = true
error.value = null
try {
const response = await fetch(`${API_BASE}/api/confirm-email`, {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ token, password }),
})
if (response.status === 200) {
const responseBody: unknown = await response.json()
user.value = meResponseSchema.parse(responseBody).user
signupCompleted.value = false
return true
}
user.value = null
error.value = await responseError(response, 'Unable to confirm your email. Please try again.')
return false
} catch {
user.value = null
error.value = 'Unable to confirm your email. Please try again.'
return false
} finally {
loading.value = false
}
}
async function logout(): Promise<void> {
try {
await fetch(`${API_BASE}/api/logout`, {
@ -119,9 +192,23 @@ export const useAuthStore = defineStore('auth', () => {
user,
loading,
error,
signupCompleted,
isAuthenticated,
fetchMe,
login,
signup,
confirmEmail,
logout,
}
})
async function responseError(response: Response, fallback: string): Promise<string> {
try {
const responseBody: unknown = await response.json()
const parsedError = authErrorResponseSchema.safeParse(responseBody)
return parsedError.success ? parsedError.data.error : fallback
} catch {
return fallback
}
}