Skip to content

Commit

Permalink
feat(vee-validate): add i18n to zod schemas, refactor: forms and layout
Browse files Browse the repository at this point in the history
  • Loading branch information
mnenie committed Dec 24, 2024
1 parent 8fe26c1 commit 3997865
Show file tree
Hide file tree
Showing 43 changed files with 724 additions and 289 deletions.
4 changes: 1 addition & 3 deletions core/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
"@unhead/vue": "^1.9.14",
"@unocss/core": "0.65.1",
"@unocss/reset": "0.65.1",
"@vee-validate/i18n": "4.14.7",
"@vee-validate/rules": "4.14.7",
"@vee-validate/zod": "^4.13.1",
"@vitest/eslint-plugin": "^1.1.7",
"@vueuse/core": "^10.11.1",
"@vueuse/integrations": "^10.10.0",
Expand All @@ -38,6 +35,7 @@
"tailwind-merge": "2.5.5",
"universal-cookie": "^6.1.3",
"unocss": "0.65.1",
"unplugin-vue-router-extend": "0.1.15",
"vee-validate": "^4.13.1",
"vue": "^3.5.8",
"vue-data-ui": "^2.3.44",
Expand Down
2 changes: 1 addition & 1 deletion core/client/src/app/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const toasterTheme = computed<ToasterTheme>(() => {
<template>
<AppLayout>
<RouterView v-slot="{ Component }">
<KeepAlive :include="['sign-in', 'sign-up', 'confirm']">
<KeepAlive :include="['sign-in', 'sign-up']">
<component :is="Component" />
</KeepAlive>
</RouterView>
Expand Down
6 changes: 3 additions & 3 deletions core/client/src/app/providers/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export const router = createRouter({

router.beforeEach((to, from) => {
// Needs to add guard auth logic in router
// if (to.meta.requiresAuth === true) {
// return router.push('/auth/sign-in')
// }
if (to.meta.requiresAuth === true) {
return router.push({ name: 'sign-in' })
}
})

router.beforeEach(layoutResolverMiddleware)
Expand Down
9 changes: 3 additions & 6 deletions core/client/src/features/auth/common/ui/PrivacyPolicy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { useRoute } from 'vue-router/auto'
const { tm, locale } = useI18n()
const route = useRoute()
// @ts-expect-error tm types
const privacyItems = tm('authentication.privacy')
const privacyItems = tm('authentication.privacy') as string[]
const maxWidth = computed(() => {
return locale.value === 'ru-RU' ? '400px' : '320px'
Expand All @@ -28,8 +27,7 @@ const privacyChangingItem = computed(() =>
href="https://github.com/mnenie/jenda"
target="_blank"
rel="noopener noreferrer"
class="cursor-pointer underline underline-offset-4 duration-100 ease-in
hover:text-neutral-900 dark:hover:text-neutral-500"
class="form-text-underline dark:hover:text-neutral-500"
>
{{ privacyItems[2] }}
</a>
Expand All @@ -38,8 +36,7 @@ const privacyChangingItem = computed(() =>
href="https://github.com/mnenie/jenda"
target="_blank"
rel="noopener noreferrer"
class="cursor-pointer underline underline-offset-4 duration-100 ease-in
hover:text-neutral-900 dark:hover:text-neutral-500"
class="form-text-underline dark:hover:text-neutral-500"
>
{{ privacyItems[4] }}
</a>
Expand Down
80 changes: 40 additions & 40 deletions core/client/src/features/auth/sign-in/ui/SignInForm.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
<script setup lang="ts">
import { UiButton, UiInput } from '@/shared/ui'
import { z } from '@/shared/libs/vee-validate'
import {
UiButton,
UiFormField,
UiFormLabel,
UiFormMessage,
UiInput,
} from '@/shared/ui'
import { toTypedSchema } from '@vee-validate/zod'
import { createReusableTemplate } from '@vueuse/core'
import { useField, useForm } from 'vee-validate'
import { toast } from 'vue-sonner'
import { z } from 'zod'
const validationSchema = toTypedSchema(
z.object({
email: z
.string({ required_error: 'Email is a required field' })
.nonempty('Email is a required field')
.email('Email must be a valid'),
password: z
.string({ required_error: 'Password is a required field' })
.nonempty('Password is a required field')
.min(8, 'Password must be at least 8 characters'),
email: z.string().min(1).email(),
password: z.string().min(8),
}),
)
Expand All @@ -28,42 +29,41 @@ const onLogin = handleSubmit((values) => {
// on login event
toast.warning('Jenda in dev mode and temporarily unavailable')
})
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>

<template>
<DefineTemplate v-slot="{ $slots, field, error }">
<UiFormField v-auto-animate>
<UiFormLabel
:for="field"
>
{{ $t(`authentication.form.${field}`) }}
</UiFormLabel>
<component :is="$slots.default" />
<UiFormMessage v-if="error" :content="error" />
</UiFormField>
</DefineTemplate>
<form @submit.prevent="onLogin">
<div class="grid gap-6">
<div class="grid gap-4">
<div v-auto-animate class="form-field">
<label
class="form-label"
for="email"
>
{{ $t('authentication.form.email') }}
</label>
<UiInput id="email" v-model="email" placeholder="[email protected]" type="email" />
<span
v-if="errors.email"
class="text-xs text-red-500 !fw500"
>
{{ errors.email }}
</span>
</div>
<div v-auto-animate class="form-field">
<label
class="form-label"
for="password"
>
{{ $t('authentication.form.password') }}
</label>
<UiInput id="password" v-model="password" placeholder="user_password_example" type="password" />
<span
v-if="errors.password"
class="text-xs text-red-500 !fw500"
>
{{ errors.password }}
</span>
</div>
<ReuseTemplate field="email" :error="errors.email">
<UiInput
id="email"
v-model="email"
placeholder="[email protected]"
type="email"
/>
</ReuseTemplate>
<ReuseTemplate field="password" :error="errors.password">
<UiInput
id="password"
v-model="password"
placeholder="user_password_example"
type="password"
/>
</ReuseTemplate>
</div>
<div class="grid gap-2">
<UiButton type="submit">
Expand Down
17 changes: 6 additions & 11 deletions core/client/src/features/auth/sign-up/ui/ConfirmForm.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script setup lang="ts">
import { UiButton, UiPinInput, UiPinInputGroup, UiPinInputInput } from '@/shared/ui'
import { UiButton, UiFormField, UiFormMessage, UiPinInput, UiPinInputGroup, UiPinInputInput } from '@/shared/ui'
import { toTypedSchema } from '@vee-validate/zod'
import { useField, useForm } from 'vee-validate'
import { useRouter } from 'vue-router/auto'
import { toast } from 'vue-sonner'
import { z } from 'zod'
const formSchema = toTypedSchema(z.object({
pin: z.array(z.coerce.string()).length(5, { message: 'Invalid pin' }),
pin: z.array(z.coerce.string()).length(5),
}))
const { handleSubmit, setFieldValue, errors } = useForm({
Expand All @@ -32,7 +32,7 @@ function onResend() {

<template>
<form @submit.prevent="onConfirm">
<div v-auto-animate class="form-field">
<UiFormField v-auto-animate>
<UiPinInput
id="pin-input"
v-model:model-value="pin"
Expand All @@ -52,13 +52,8 @@ function onResend() {
/>
</UiPinInputGroup>
</UiPinInput>
<span
v-if="errors.pin"
class="text-xs text-red-500 !fw500"
>
{{ errors.pin }}
</span>
</div>
<UiFormMessage v-if="errors.pin" :content="errors.pin" />
</UiFormField>
<p class="text-sm text-neutral-400 mt-2">
{{ $t('authentication.form.otp') }}
</p>
Expand All @@ -71,7 +66,7 @@ function onResend() {
>
{{ $t('authentication.confirm.proposal') }}
<span
class="cursor-pointer underline underline-offset-4 duration-100 ease-in hover:text-neutral-900 dark:hover:text-neutral-400"
class="form-text-underline"
>
{{ $t('authentication.confirm.route') }}
</span>
Expand Down
84 changes: 43 additions & 41 deletions core/client/src/features/auth/sign-up/ui/SignUpForm.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
<script setup lang="ts">
import { UiButton, UiInput } from '@/shared/ui'
import { z } from '@/shared/libs/vee-validate'
import {
UiButton,
UiFormField,
UiFormLabel,
UiFormMessage,
UiInput,
} from '@/shared/ui'
import { toTypedSchema } from '@vee-validate/zod'
import { createReusableTemplate } from '@vueuse/core'
import { useField, useForm } from 'vee-validate'
import { useRouter } from 'vue-router/auto'
import { z } from 'zod'
import { toast } from 'vue-sonner'
const validationSchema = toTypedSchema(
z.object({
email: z
.string({ required_error: 'Email is a required field' })
.nonempty('Email is a required field')
.email('Email must be a valid'),
password: z
.string({ required_error: 'Password is a required field' })
.nonempty('Password is a required field')
.min(8, 'Password must be at least 8 characters'),
email: z.string().min(1).email(),
password: z.string().min(8),
}),
)
Expand All @@ -27,45 +29,45 @@ const { value: password } = useField<string>('password')
const router = useRouter()
const onRegistration = handleSubmit((values) => {
toast.warning('Jenda in dev mode and temporarily unavailable')
// on registration event
router.push({ name: 'confirm' })
})
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>

<template>
<DefineTemplate v-slot="{ $slots, field, error }">
<UiFormField v-auto-animate>
<UiFormLabel
:for="field"
>
{{ $t(`authentication.form.${field}`) }}
</UiFormLabel>
<component :is="$slots.default" />
<UiFormMessage v-if="error" :content="error" />
</UiFormField>
</DefineTemplate>
<form @submit.prevent="onRegistration">
<div class="grid gap-6">
<div class="grid gap-4">
<div v-auto-animate class="form-field">
<label
class="form-label"
for="email"
>
{{ $t('authentication.form.email') }}
</label>
<UiInput id="email" v-model="email" placeholder="[email protected]" type="email" />
<span
v-if="errors.email"
class="text-xs text-red-500 !fw500"
>
{{ errors.email }}
</span>
</div>
<div v-auto-animate class="form-field">
<label
class="form-label"
for="password"
>
{{ $t('authentication.form.password') }}
</label>
<UiInput id="password" v-model="password" placeholder="user_password_example" type="password" />
<span
v-if="errors.password"
class="text-xs text-red-500 !fw500"
>
{{ errors.password }}
</span>
</div>
<ReuseTemplate field="email" :error="errors.email">
<UiInput
id="email"
v-model="email"
placeholder="[email protected]"
type="email"
/>
</ReuseTemplate>
<ReuseTemplate field="password" :error="errors.password">
<UiInput
id="password"
v-model="password"
placeholder="user_password_example"
type="password"
/>
</ReuseTemplate>
</div>
<div class="grid gap-2">
<UiButton type="submit">
Expand All @@ -74,7 +76,7 @@ const onRegistration = handleSubmit((values) => {
<p class="text-sm text-center select-none text-neutral-500 dark:text-neutral-300">
{{ $t('authentication.registration.proposal') }}
<span
class="cursor-pointer underline underline-offset-4 duration-100 ease-in hover:text-neutral-900 dark:hover:text-neutral-400"
class="form-text-underline"
@click="router.push({ name: 'sign-in' })"
>
{{ $t('authentication.registration.route') }}
Expand Down
Loading

0 comments on commit 3997865

Please sign in to comment.