From 6b221cccd58710682c99db7afbc29322da042880 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 31 Oct 2023 10:44:25 +0700 Subject: - Add redirect after activation - Add register form validation --- src-migrate/common/stores/useRegisterStore.ts | 28 +++++- src-migrate/common/types/auth.ts | 10 +-- src-migrate/common/validations/auth.ts | 13 +++ .../account-activation/components/FormEmail.tsx | 3 +- .../account-activation/components/FormOTP.tsx | 12 +-- .../account-activation/components/FormToken.tsx | 19 ++--- src-migrate/modules/register/components/Form.tsx | 19 ++++- src/lib/auth/components/LoginDesktop.jsx | 82 ++++++++++-------- src/lib/auth/components/LoginMobile.jsx | 99 +++++++++++++--------- src/styles/globals.css | 6 +- 10 files changed, 186 insertions(+), 105 deletions(-) create mode 100644 src-migrate/common/validations/auth.ts diff --git a/src-migrate/common/stores/useRegisterStore.ts b/src-migrate/common/stores/useRegisterStore.ts index 725bbfda..d6c7db2a 100644 --- a/src-migrate/common/stores/useRegisterStore.ts +++ b/src-migrate/common/stores/useRegisterStore.ts @@ -1,8 +1,13 @@ import { create } from 'zustand'; import { RegisterProps } from '../types/auth'; +import { registerSchema } from '../validations/auth'; +import { ValidationError } from 'yup'; type State = { form: RegisterProps; + errors: { + [key in keyof RegisterProps]?: string; + }; isValid: boolean; isCheckedTNC: boolean; isOpenTNC: boolean; @@ -15,9 +20,10 @@ type Action = { toggleCheckTNC: () => void; openTNC: () => void; closeTNC: () => void; + validate: () => void; }; -export const useRegisterStore = create((set) => ({ +export const useRegisterStore = create((set, get) => ({ form: { company: '', name: '', @@ -25,6 +31,26 @@ export const useRegisterStore = create((set) => ({ password: '', phone: '', }, + errors: {}, + validate: () => + registerSchema + .validate(get().form, { abortEarly: false }) + .then(() => { + set({ + errors: {}, + isValid: false, + }); + }) + .catch((err: ValidationError) => { + const validationErrors: State['errors'] = {}; + err.inner.forEach( + (e) => (validationErrors[e.path as keyof RegisterProps] = e.message) + ); + set({ + errors: validationErrors, + isValid: false, + }); + }), isValid: false, isCheckedTNC: false, isOpenTNC: false, diff --git a/src-migrate/common/types/auth.ts b/src-migrate/common/types/auth.ts index ca7b562a..5909584a 100644 --- a/src-migrate/common/types/auth.ts +++ b/src-migrate/common/types/auth.ts @@ -1,4 +1,6 @@ +import { registerSchema } from '../validations/auth'; import { OdooApiProps } from './odoo'; +import * as yup from 'yup'; export type AuthProps = { id: number; @@ -17,13 +19,7 @@ export type AuthProps = { export type AuthApiProps = OdooApiProps & { result: AuthProps }; -export type RegisterProps = { - name: string; - email: string; - password: string; - company: string; - phone: string; -}; +export type RegisterProps = yup.InferType; export type RegisterResApiProps = { register: boolean; diff --git a/src-migrate/common/validations/auth.ts b/src-migrate/common/validations/auth.ts new file mode 100644 index 00000000..94b40849 --- /dev/null +++ b/src-migrate/common/validations/auth.ts @@ -0,0 +1,13 @@ +import { object, string } from 'yup'; + +export const registerSchema = object({ + name: string().required('Nama harus diisi'), + email: string() + .email('Email harus menggunakan format example@mail.com') + .required('Email harus diisi'), + password: string() + .min(6, 'Password minimal 6 karakter') + .required('Password harus diisi'), + company: string().optional(), + phone: string().required('Nomor telepon harus diisi'), +}); diff --git a/src-migrate/modules/account-activation/components/FormEmail.tsx b/src-migrate/modules/account-activation/components/FormEmail.tsx index cd917bc9..ec300ba4 100644 --- a/src-migrate/modules/account-activation/components/FormEmail.tsx +++ b/src-migrate/modules/account-activation/components/FormEmail.tsx @@ -43,7 +43,8 @@ const FormEmail = () => { if (mutation.data?.activation_request === true) { const urlParams = new URLSearchParams({ activation: 'otp', - email + email, + redirect: (router.query?.redirect || '/') as string }) router.push(`${router.route}?${urlParams}`) } diff --git a/src-migrate/modules/account-activation/components/FormOTP.tsx b/src-migrate/modules/account-activation/components/FormOTP.tsx index a4775d61..47c69329 100644 --- a/src-migrate/modules/account-activation/components/FormOTP.tsx +++ b/src-migrate/modules/account-activation/components/FormOTP.tsx @@ -54,8 +54,9 @@ const FormOTP = () => { useEffect(() => { if (mutationActivation.data?.user) { setAuth(mutationActivation.data.user) + router.push((query?.redirect || '/') as string) } - }, [mutationActivation.data]) + }, [mutationActivation.data, router, query.redirect]) return ( @@ -78,10 +79,6 @@ const FormOTP = () => { Mohon maaf kode OTP yand anda masukan salah ) } - - {mutationActivation.data?.activation && ( - Akun anda berhasil diaktifkan, selamat berbelanja di Indoteknik. - )} {!mutationActivation.data?.activation && ( @@ -108,11 +105,6 @@ const FormOTP = () => { )} - {mutationActivation.data?.activation && ( - Kembali ke halaman utama - )} - - diff --git a/src-migrate/modules/account-activation/components/FormToken.tsx b/src-migrate/modules/account-activation/components/FormToken.tsx index a1525fe6..b68b244f 100644 --- a/src-migrate/modules/account-activation/components/FormToken.tsx +++ b/src-migrate/modules/account-activation/components/FormToken.tsx @@ -10,7 +10,8 @@ import { activationUserToken } from "~/services/auth" import { setAuth } from "~/common/libs/auth" const FormToken = () => { - const { query } = useRouter() + const router = useRouter() + const { query } = router const [active, setActive] = useState(false) const mutation = useMutation({ @@ -28,8 +29,9 @@ const FormToken = () => { useEffect(() => { if (mutation.data?.user) { setAuth(mutation.data.user) + router.push((query?.redirect || '/') as string) } - }, [mutation.data]) + }, [mutation.data, router, query.redirect]) return ( @@ -41,7 +43,7 @@ const FormToken = () => { )} - {!mutation.isLoading && ( + {!mutation.isLoading && !mutation.data?.activation && ( { > - Aktivasi akun {mutation.data?.activation ? 'berhasil' : 'gagal'} + Aktivasi akun gagal - {mutation.data?.activation && ( - <> - Akun anda berhasil diaktifkan, selamat berbelanja di Indoteknik. - Kembali ke halaman utama - - )} - - {!mutation.data?.activation && mutation.data?.reason === 'INVALID_TOKEN' && ( + {mutation.data?.reason === 'INVALID_TOKEN' && ( <> Token sudah kadaluwarsa, silahkan coba kembali. Aktivasi Akun diff --git a/src-migrate/modules/register/components/Form.tsx b/src-migrate/modules/register/components/Form.tsx index 3227a549..5b51d6f4 100644 --- a/src-migrate/modules/register/components/Form.tsx +++ b/src-migrate/modules/register/components/Form.tsx @@ -8,6 +8,7 @@ import FormCaptcha from "./FormCaptcha"; import { useRouter } from "next/router"; import { UseToastOptions, useToast } from "@chakra-ui/react"; import Link from "next/link"; +import { registerSchema } from "~/common/validations/auth"; const Form = () => { const { @@ -15,7 +16,9 @@ const Form = () => { isValid, isCheckedTNC, isValidCaptcha, + errors, updateForm, + validate, } = useRegisterStore() const router = useRouter() const toast = useToast() @@ -23,6 +26,7 @@ const Form = () => { const handleInputChange = (event: ChangeEvent) => { const { name, value } = event.target; updateForm(name, value) + validate() } const mutation = useMutation({ @@ -37,7 +41,8 @@ const Form = () => { if (response?.register === true) { const urlParams = new URLSearchParams({ activation: 'otp', - email: form.email + email: form.email, + redirect: (router.query?.next || '/') as string }) router.push(`${router.route}?${urlParams}`) } @@ -97,7 +102,10 @@ const Form = () => { placeholder='Masukan nama lengkap anda' value={form.name} onChange={handleInputChange} + aria-invalid={!!errors.name} /> + + {!!errors.name && {errors.name}}
@@ -111,7 +119,10 @@ const Form = () => { placeholder='08xxxxxxxx' value={form.phone} onChange={handleInputChange} + aria-invalid={!!errors.phone} /> + + {!!errors.phone && {errors.phone}}
@@ -126,7 +137,10 @@ const Form = () => { value={form.email} onChange={handleInputChange} autoComplete="username" + aria-invalid={!!errors.email} /> + + {!!errors.email && {errors.email}}
@@ -140,7 +154,10 @@ const Form = () => { value={form.password} onChange={handleInputChange} autoComplete="current-password" + aria-invalid={!!errors.password} /> + + {!!errors.password && {errors.password}}
diff --git a/src/lib/auth/components/LoginDesktop.jsx b/src/lib/auth/components/LoginDesktop.jsx index d22da6f8..1333db14 100644 --- a/src/lib/auth/components/LoginDesktop.jsx +++ b/src/lib/auth/components/LoginDesktop.jsx @@ -1,46 +1,54 @@ -import DesktopView from '@/core/components/views/DesktopView' -import useLogin from '../hooks/useLogin' -import Link from '@/core/components/elements/Link/Link' -import PageContent from '@/lib/content/components/PageContent' -import Alert from '@/core/components/elements/Alert/Alert' -import { useSession, signIn, SignOut } from 'next-auth/react' -import Image from 'next/image' -import { useRouter } from 'next/router' -import { useContext, useEffect, useState } from 'react' -import { getAuth, setAuth } from '@/core/utils/auth' -import { setCookie } from 'cookies-next' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import Spinner from '@/core/components/elements/Spinner/Spinner' -import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner' -import odooApi from '@/core/api/odooApi' +import DesktopView from '@/core/components/views/DesktopView'; +import useLogin from '../hooks/useLogin'; +import Link from '@/core/components/elements/Link/Link'; +import PageContent from '@/lib/content/components/PageContent'; +import Alert from '@/core/components/elements/Alert/Alert'; +import { useSession, signIn, SignOut } from 'next-auth/react'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'; const LoginDesktop = () => { - const { handleSubmit, handleChangeInput, isLoading, isValid, alert, emailRef, passwordRef, handleGoogleSubmit } = - useLogin() + const { + handleSubmit, + handleChangeInput, + isLoading, + isValid, + alert, + emailRef, + passwordRef, + handleGoogleSubmit, + } = useLogin(); - const router = useRouter() - const [query, setQuery] = useState(router?.query?.next || '/') - const { data: session } = useSession() + const router = useRouter(); + const [query, setQuery] = useState(router?.query?.next || '/'); + const { data: session } = useSession(); const handleGoogle = async () => { - const url = query != '/' ? '/login?source=google&next=' + query : '/login?source=google' - await signIn('google', { callbackUrl: url }) - } + const url = + query != '/' + ? '/login?source=google&next=' + query + : '/login?source=google'; + await signIn('google', { callbackUrl: url }); + }; useEffect(() => { if (session) { - handleGoogleSubmit(session) + handleGoogleSubmit(session); } - }, [session]) + }, [session]); if (router.query.source) { return ( -
Mohon Tunggu
+
+ Mohon Tunggu +
- ) + ); } return ( @@ -48,7 +56,9 @@ const LoginDesktop = () => {
-

Selamat Datang di Indoteknik

+

+ Selamat Datang di Indoteknik +

Masuk ke akun kamu untuk mulai transaksi!

@@ -59,7 +69,10 @@ const LoginDesktop = () => { )} -
+
{
Belum punya akun Indoteknik?{' '} - + Daftar akun baru
@@ -129,7 +145,7 @@ const LoginDesktop = () => {
- ) -} + ); +}; -export default LoginDesktop +export default LoginDesktop; diff --git a/src/lib/auth/components/LoginMobile.jsx b/src/lib/auth/components/LoginMobile.jsx index 6e1831d4..58ae4e6e 100644 --- a/src/lib/auth/components/LoginMobile.jsx +++ b/src/lib/auth/components/LoginMobile.jsx @@ -1,19 +1,17 @@ -import Image from 'next/image' -import IndoteknikLogo from '@/images/logo.png' -import Link from '@/core/components/elements/Link/Link' -import Alert from '@/core/components/elements/Alert/Alert' -import MobileView from '@/core/components/views/MobileView' -import useLogin from '../hooks/useLogin' +import Image from 'next/image'; +import IndoteknikLogo from '@/images/logo.png'; +import Link from '@/core/components/elements/Link/Link'; +import Alert from '@/core/components/elements/Alert/Alert'; +import MobileView from '@/core/components/views/MobileView'; +import useLogin from '../hooks/useLogin'; -import { useSession, signIn, SignOut } from 'next-auth/react' -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import { setCookie } from 'cookies-next' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner' -import odooApi from '@/core/api/odooApi' -import { getAuth } from '@/core/utils/auth' -import PageContent from '@/lib/content/components/PageContent' +import { useSession, signIn, SignOut } from 'next-auth/react'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'; +import { getAuth } from '@/core/utils/auth'; +import PageContent from '@/lib/content/components/PageContent'; const LoginMobile = () => { const { @@ -24,43 +22,55 @@ const LoginMobile = () => { alert, emailRef, passwordRef, - handleGoogleSubmit - } = useLogin() + handleGoogleSubmit, + } = useLogin(); - const router = useRouter() - const [query, setQuery] = useState(router?.query?.next || '/') - const { data: session } = useSession() - const auth = getAuth() + const router = useRouter(); + const [query, setQuery] = useState(router?.query?.next || '/'); + const { data: session } = useSession(); + const auth = getAuth(); const handleGoogle = async () => { - const url = query != '/' ? '/login?source=google&next=' + query : '/login?source=google' - await signIn('google', { callbackUrl: url }) - } + const url = + query != '/' + ? '/login?source=google&next=' + query + : '/login?source=google'; + await signIn('google', { callbackUrl: url }); + }; useEffect(() => { if (session) { - handleGoogleSubmit(session) + handleGoogleSubmit(session); } - }, [session]) + }, [session]); if (router.query.source) { return ( -
Mohon Tunggu
+
+ Mohon Tunggu +
- ) + ); } return (
- Logo Indoteknik + Logo Indoteknik

Mulai Belanja Sekarang

-

Masuk ke akun kamu untuk belanja

+

+ Masuk ke akun kamu untuk belanja +

{alert && ( @@ -68,7 +78,10 @@ const LoginMobile = () => { )} - +
{ placeholder='••••••••••••' />
- @@ -123,16 +140,20 @@ const LoginMobile = () => {
Belum punya akun Indoteknik?{' '} - + Daftar
- {/*
- -
*/} + +
+ +
- ) -} + ); +}; -export default LoginMobile +export default LoginMobile; diff --git a/src/styles/globals.css b/src/styles/globals.css index ea20b247..bf9fec10 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -107,7 +107,7 @@ button { disabled:bg-gray_r-5; } - .form-input[aria-invalid] { + .form-input[aria-invalid="true"] { @apply border-danger-500 focus:border-danger-500; } @@ -116,6 +116,10 @@ button { @apply py-2; } + .form-msg-danger { + @apply text-danger-600 mt-2 block; + } + .btn-yellow, .btn-light, .btn-red, -- cgit v1.2.3