129 lines
3.2 KiB
Vue
129 lines
3.2 KiB
Vue
<template>
|
|
<q-page class="flex flex-center">
|
|
<q-card class="signup-card">
|
|
<q-card-section>
|
|
<div class="text-h6">Sign Up</div>
|
|
</q-card-section>
|
|
|
|
<q-card-section>
|
|
<q-form @submit="onSubmit" class="q-gutter-md">
|
|
<q-input
|
|
v-model="name"
|
|
label="Full Name"
|
|
:rules="[(val) => !!val || 'Name is required']"
|
|
/>
|
|
|
|
<q-input
|
|
v-model="email"
|
|
label="Email"
|
|
type="email"
|
|
:rules="[(val) => !!val || 'Email is required', isValidEmail]"
|
|
/>
|
|
|
|
<q-input
|
|
v-model="password"
|
|
label="Password"
|
|
:type="isPwd ? 'password' : 'text'"
|
|
:rules="[
|
|
(val) => !!val || 'Password is required',
|
|
(val) => val.length >= 8 || 'Password must be at least 8 characters',
|
|
]"
|
|
>
|
|
<template v-slot:append>
|
|
<q-icon
|
|
:name="isPwd ? 'visibility_off' : 'visibility'"
|
|
class="cursor-pointer"
|
|
@click="isPwd = !isPwd"
|
|
/>
|
|
</template>
|
|
</q-input>
|
|
|
|
<q-input
|
|
v-model="confirmPassword"
|
|
label="Confirm Password"
|
|
:type="isPwd ? 'password' : 'text'"
|
|
:rules="[
|
|
(val) => !!val || 'Please confirm your password',
|
|
(val) => val === password || 'Passwords do not match',
|
|
]"
|
|
/>
|
|
|
|
<div>
|
|
<q-btn
|
|
label="Sign Up"
|
|
type="submit"
|
|
color="primary"
|
|
class="full-width"
|
|
:loading="loading"
|
|
/>
|
|
</div>
|
|
|
|
<div class="text-center q-mt-sm">
|
|
<router-link to="/login" class="text-primary"
|
|
>Already have an account? Login</router-link
|
|
>
|
|
</div>
|
|
</q-form>
|
|
</q-card-section>
|
|
</q-card>
|
|
</q-page>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useQuasar } from 'quasar';
|
|
import { useAuthStore } from 'stores/auth';
|
|
|
|
const $q = useQuasar();
|
|
const router = useRouter();
|
|
const authStore = useAuthStore();
|
|
|
|
const name = ref('');
|
|
const email = ref('');
|
|
const password = ref('');
|
|
const confirmPassword = ref('');
|
|
const isPwd = ref(true);
|
|
const loading = ref(false);
|
|
|
|
const isValidEmail = (val: string) => {
|
|
const emailPattern =
|
|
/^(?=[a-zA-Z0-9@._%+-]{6,254}$)[a-zA-Z0-9._%+-]{1,64}@(?:[a-zA-Z0-9-]{1,63}\.){1,8}[a-zA-Z]{2,63}$/;
|
|
return emailPattern.test(val) || 'Invalid email';
|
|
};
|
|
|
|
const onSubmit = async () => {
|
|
try {
|
|
loading.value = true;
|
|
await authStore.signup({
|
|
name: name.value,
|
|
email: email.value,
|
|
password: password.value,
|
|
});
|
|
|
|
$q.notify({
|
|
color: 'positive',
|
|
message: 'Account created successfully',
|
|
position: 'top',
|
|
});
|
|
await router.push('/login');
|
|
} catch (error: unknown) {
|
|
$q.notify({
|
|
color: 'negative',
|
|
message: error instanceof Error ? error.message : 'Signup failed',
|
|
position: 'top',
|
|
});
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.signup-card {
|
|
width: 100%;
|
|
max-width: 400px;
|
|
padding: 20px;
|
|
}
|
|
</style>
|