mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
feat: add clerk auth support with convex (#548)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import z from 'zod'
|
||||
const {$authClient} = useNuxtApp()
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
|
||||
const emit = defineEmits(['switchToSignUp'])
|
||||
|
||||
const toast = useToast()
|
||||
const loading = ref(false)
|
||||
|
||||
const schema = z.object({
|
||||
email: z.email('Invalid email address'),
|
||||
password: z.string().min(8, 'Password must be at least 8 characters'),
|
||||
})
|
||||
|
||||
type Schema = z.output<typeof schema>
|
||||
|
||||
const state = reactive({
|
||||
email: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
async function onSubmit (event: FormSubmitEvent<Schema>) {
|
||||
loading.value = true
|
||||
try {
|
||||
await $authClient.signIn.email(
|
||||
{
|
||||
email: event.data.email,
|
||||
password: event.data.password,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.add({ title: 'Sign in successful' })
|
||||
navigateTo('/dashboard', { replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.add({ title: 'Sign in failed', description: error.error.message })
|
||||
},
|
||||
},
|
||||
)
|
||||
} catch (error: any) {
|
||||
toast.add({ title: 'An unexpected error occurred', description: error.message || 'Please try again.' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mx-auto w-full mt-10 max-w-md p-6">
|
||||
<h1 class="mb-6 text-center text-3xl font-bold">Welcome Back</h1>
|
||||
|
||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UFormField label="Email" name="email">
|
||||
<UInput v-model="state.email" type="email" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UButton type="submit" block :loading="loading">
|
||||
Sign In
|
||||
</UButton>
|
||||
</UForm>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
<UButton
|
||||
variant="link"
|
||||
@click="$emit('switchToSignUp')"
|
||||
class="text-primary hover:text-primary-dark"
|
||||
>
|
||||
Need an account? Sign Up
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import z from 'zod'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
const {$authClient} = useNuxtApp()
|
||||
|
||||
const emit = defineEmits(['switchToSignIn'])
|
||||
|
||||
const toast = useToast()
|
||||
const loading = ref(false)
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(2, 'Name must be at least 2 characters'),
|
||||
email: z.email('Invalid email address'),
|
||||
password: z.string().min(8, 'Password must be at least 8 characters'),
|
||||
})
|
||||
|
||||
type Schema = z.output<typeof schema>
|
||||
|
||||
const state = reactive({
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
async function onSubmit (event: FormSubmitEvent<Schema>) {
|
||||
loading.value = true
|
||||
try {
|
||||
await $authClient.signUp.email(
|
||||
{
|
||||
name: event.data.name,
|
||||
email: event.data.email,
|
||||
password: event.data.password,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.add({ title: 'Sign up successful' })
|
||||
navigateTo('/dashboard', { replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.add({ title: 'Sign up failed', description: error.error.message })
|
||||
},
|
||||
},
|
||||
)
|
||||
} catch (error: any) {
|
||||
toast.add({ title: 'An unexpected error occurred', description: error.message || 'Please try again.' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mx-auto w-full mt-10 max-w-md p-6">
|
||||
<h1 class="mb-6 text-center text-3xl font-bold">Create Account</h1>
|
||||
|
||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UFormField label="Name" name="name">
|
||||
<UInput v-model="state.name" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Email" name="email">
|
||||
<UInput v-model="state.email" type="email" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UButton type="submit" block :loading="loading">
|
||||
Sign Up
|
||||
</UButton>
|
||||
</UForm>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
<UButton
|
||||
variant="link"
|
||||
@click="$emit('switchToSignIn')"
|
||||
class="text-primary hover:text-primary-dark"
|
||||
>
|
||||
Already have an account? Sign In
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const {$authClient} = useNuxtApp()
|
||||
const session = $authClient.useSession()
|
||||
const toast = useToast()
|
||||
|
||||
const handleSignOut = async () => {
|
||||
try {
|
||||
await $authClient.signOut({
|
||||
fetchOptions: {
|
||||
onSuccess: async () => {
|
||||
toast.add({ title: 'Signed out successfully' })
|
||||
await navigateTo('/', { replace: true, external: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.add({ title: 'Sign out failed', description: error?.error?.message || 'Unknown error'})
|
||||
}
|
||||
},
|
||||
})
|
||||
} catch (error: any) {
|
||||
toast.add({ title: 'An unexpected error occurred during sign out', description: error.message || 'Please try again.'})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<USkeleton v-if="session.isPending" class="h-9 w-24" />
|
||||
|
||||
<UButton v-else-if="!session.data" variant="outline" to="/login">
|
||||
Sign In
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-else
|
||||
variant="solid"
|
||||
icon="i-lucide-log-out"
|
||||
label="Sign out"
|
||||
@click="handleSignOut()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user