Skip to content

Commit

Permalink
feat(nuxt-auth): configurable auth components via app config
Browse files Browse the repository at this point in the history
  • Loading branch information
gravitano committed Feb 3, 2023
1 parent e96ffce commit bfa2de7
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 181 deletions.
120 changes: 120 additions & 0 deletions starter/nuxt-auth/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {string, boolean, ref as YupRef} from 'yup';

export default defineAppConfig({
auth: {
logo: true,
redirect: {
home: '/', // redirect to home page after login
},
login: {
logo: true,
head: {
title: 'Login',
},
title: 'Login',
description: 'Enter your username and password to login.',
usernameProps: {
label: 'Username',
placeholder: 'Username',
},
passwordProps: {
label: 'Password',
placeholder: 'Password',
},
rememberMe: {
enabled: true,
label: 'Remember Me',
},
submitText: 'Login',
submitProps: {
color: 'primary',
block: true,
},
forgotPasswordLinkText: 'Forgot Password?',
registerLinkText: 'Register',
registerText: "Don't have an account?",
loginWithText: 'Login with',
orText: 'or',
providerButtonColors: {
google: 'danger',
facebook: 'primary',
twitter: 'info',
github: 'dark',
} as Record<string, string>,
},
register: {
head: {
title: 'Register',
},
logo: true,
title: 'Register',
description: 'Enter your details to create your account.',
buttonText: 'Register',
buttonProps: {
color: 'primary',
block: true,
},
successMessage: 'Account created successfully.',
loginButtonText: 'Back to Login',
inputs: [
{
name: 'name',
label: 'Name',
placeholder: 'Name',
validation: string().required(),
},
{
name: 'email',
label: 'Email',
placeholder: 'Email',
type: 'email',
validation: string().email().required(),
},
{
name: 'password',
label: 'Password',
placeholder: 'Password',
type: 'password',
validation: string().required(),
},
{
name: 'password_confirmation',
label: 'Password Confirmation',
placeholder: 'Password Confirmation',
type: 'password',
validation: string()
.required()
.oneOf([YupRef('password')], 'Password does not match'),
},
{
name: 'agree_to_toc',
label: 'Agree to Terms and Conditions',
component: 'checkbox',
validation: boolean().required(),
},
],
},
forgotPassword: {
logo: true,
head: {
title: 'Forgot Password',
},
title: 'Forgot Password',
description: 'Enter your email address to reset your password.',
buttonText: 'Reset Password',
loginButtonText: 'Login',
successMessage: 'Password reset email sent.',
inputProps: {
name: 'email',
label: 'Email',
placeholder: 'Email',
type: 'email',
},
buttonProps: {
type: 'submit',
color: 'primary',
block: true,
},
},
},
});
59 changes: 22 additions & 37 deletions starter/nuxt-auth/components/auth/AuthForgotPassword.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,7 @@
import {useForm} from 'vee-validate';
import {object, string} from 'yup';
const props = withDefaults(
defineProps<{
title: string;
description: string;
buttonText: string;
loginButtonText: string;
successMessage: string;
inputProps: Record<string, any>;
buttonProps: Record<string, any>;
}>(),
{
title: 'Forgot Password',
description: 'Enter your email address to reset your password.',
buttonText: 'Reset Password',
loginButtonText: 'Login',
successMessage: 'Password reset email sent.',
inputProps: () => ({
name: 'email',
label: 'Email',
placeholder: 'Email',
type: 'email',
}),
buttonProps: () => ({
type: 'submit',
color: 'primary',
block: true,
}),
},
);
const appConfig = useAppConfig();
const loading = ref(false);
const error = ref();
Expand Down Expand Up @@ -62,28 +34,41 @@ const onSubmit = handleSubmit(async (values) => {
<template>
<div class="p-6 grid items-center justify-center">
<div class="md:w-[400px]">
<VLogo img-class="mb-6" />
<slot name="logo">
<VLogo
v-if="appConfig.auth.logo || appConfig.auth.forgotPassword.logo"
img-class="mb-6"
/>
</slot>
<div class="space-y-2 mb-4">
<h1 class="text-2xl font-semibold text-gray-900">
{{ title }}
{{ appConfig.auth.forgotPassword.title }}
</h1>
<p class="text-sm text-gray-700">
{{ description }}
{{ appConfig.auth.forgotPassword.description }}
</p>
</div>
<template v-if="success">
<VAlert color="success" solid class="mb-4">
{{ successMessage }}
{{ appConfig.auth.forgotPassword.successMessage }}
</VAlert>
<VBtn to="/auth/login" block>
{{ loginButtonText }}
{{ appConfig.auth.forgotPassword.loginButtonText }}
</VBtn>
</template>
<form v-else @submit="onSubmit">
<VAlert v-if="error" color="error" class="mb-4"> {{ error }} </VAlert>
<VInput wrapper-class="mb-4" name="email" v-bind="inputProps" />
<VBtn :loading="loading" type="submit" v-bind="buttonProps">
{{ buttonText }}
<VInput
wrapper-class="mb-4"
v-bind="appConfig.auth.forgotPassword.inputProps"
name="email"
/>
<VBtn
:loading="loading"
v-bind="appConfig.auth.forgotPassword.buttonProps"
type="submit"
>
{{ appConfig.auth.forgotPassword.buttonText }}
</VBtn>
</form>
</div>
Expand Down
100 changes: 34 additions & 66 deletions starter/nuxt-auth/components/auth/AuthLogin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,7 @@
import {useForm} from 'vee-validate';
import {object, string} from 'yup';
const props = withDefaults(
defineProps<{
redirect?: string;
title?: string;
description?: string;
usernameProps?: Record<string, any>;
passwordProps?: Record<string, any>;
rememberMe?: boolean;
rememberMeLabel?: string;
submitText?: string;
submitProps?: Record<string, any>;
forgotPasswordLinkText?: string;
registerLinkText?: string;
registerText?: string;
loginWithText?: string;
orText?: string;
providerButtonColors?: Record<string, string>;
}>(),
{
redirect: '/',
title: 'Login',
description: 'Enter your username and password to login.',
usernameProps: () => ({
label: 'Username',
placeholder: 'Username',
}),
passwordProps: () => ({
label: 'Password',
placeholder: 'Password',
}),
rememberMe: true,
rememberMeLabel: 'Remember Me',
submitText: 'Login',
submitProps: () => ({
color: 'primary',
block: true,
}),
forgotPasswordLinkText: 'Forgot Password?',
registerLinkText: 'Register',
registerText: "Don't have an account?",
loginWithText: 'Login with',
orText: 'or',
providerButtonColors: () => ({
google: 'danger',
facebook: 'primary',
twitter: 'info',
github: 'dark',
}),
},
);
const appConfig = useAppConfig();
const router = useRouter();
const route = useRoute();
Expand Down Expand Up @@ -83,55 +34,70 @@ const onSubmit = handleSubmit(async (values) => {
// get path name from callback url
const callbackUrl = new URL(String(route.query.callbackUrl)).pathname;
router.push(String(route.query.next || callbackUrl || props.redirect));
router.push(
String(route.query.next || callbackUrl || appConfig.auth.redirect.home),
);
});
</script>

<template>
<div class="p-6 grid items-center justify-center">
<form class="md:w-[400px]" @submit="onSubmit">
<VLogo img-class="mb-6" />
<slot name="logo">
<VLogo
v-if="appConfig.auth.logo || appConfig.auth.login.logo"
img-class="mb-6"
/>
</slot>
<div class="space-y-2 mb-4">
<h1 class="text-2xl font-semibold text-gray-900">
{{ title }}
{{ appConfig.auth.login.title }}
</h1>
<p class="text-sm text-gray-700">
{{ description }}
{{ appConfig.auth.login.description }}
</p>
</div>
<VAlert v-if="error" color="error" class="mb-4"> {{ error }} </VAlert>
<VInput wrapper-class="mb-4" name="username" v-bind="usernameProps" />
<VInput
wrapper-class="mb-4"
name="username"
v-bind="appConfig.auth.login.usernameProps"
/>
<VInput
wrapper-class="mb-4"
name="password"
type="password"
v-bind="passwordProps"
v-bind="appConfig.auth.login.passwordProps"
/>
<div class="mb-4 flex gap-4 justify-between">
<VCheckbox
v-if="rememberMe"
:label="rememberMeLabel"
v-if="appConfig.auth.login.rememberMe.enabled"
:label="appConfig.auth.login.rememberMe.label"
name="rememberMe"
/>
<VBtn to="/auth/forgot-password" color="primary" text flush>
{{ forgotPasswordLinkText }}
{{ appConfig.auth.login.forgotPasswordLinkText }}
</VBtn>
</div>
<VBtn :loading="status === 'loading'" type="submit" v-bind="submitProps">
{{ submitText }}
<VBtn
:loading="status === 'loading'"
type="submit"
v-bind="appConfig.auth.login.submitProps"
>
{{ appConfig.auth.login.submitText }}
</VBtn>

<p class="text-sm text-gray-700 text-center mt-5">
{{ registerText }}
{{ appConfig.auth.login.registerText }}
<VBtn to="/auth/register" color="primary" text flush>
{{ registerLinkText }}
{{ appConfig.auth.login.registerLinkText }}
</VBtn>
</p>

<div class="flex gap-4 items-center mt-5 mb-4">
<div class="border-t flex-1"></div>
<span class="text-sm text-gray-600">
{{ orText }}
{{ appConfig.auth.login.orText }}
</span>
<div class="border-t flex-1"></div>
</div>
Expand All @@ -140,10 +106,12 @@ const onSubmit = handleSubmit(async (values) => {
<VBtn
v-if="provider?.id !== 'credentials'"
block
:color="providerButtonColors[String(provider?.id)]"
:color="
appConfig.auth.login.providerButtonColors[String(provider?.id)]
"
@click="signIn(provider?.id)"
>
{{ loginWithText }} {{ provider?.name }}
{{ appConfig.auth.login.loginWithText }} {{ provider?.name }}
</VBtn>
</template>
</form>
Expand Down
Loading

0 comments on commit bfa2de7

Please sign in to comment.