diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2023-11-21 06:10:12 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2023-11-21 06:10:12 +0000 |
| commit | 0fc062268c71d53f8777c358b31e2a540d60d404 (patch) | |
| tree | 0183a00dcfb14583c7dfa80da082c21630afe375 /src-migrate/modules/account-activation | |
| parent | 6ebe202147269100cd63ef125e877e8f693a27a1 (diff) | |
| parent | 6a6ce21e5a552b0dc6cd541710a87fd0a0fd9d20 (diff) | |
Merged in refactor/all (pull request #116)
Refactor/all
Diffstat (limited to 'src-migrate/modules/account-activation')
4 files changed, 313 insertions, 0 deletions
diff --git a/src-migrate/modules/account-activation/components/FormEmail.tsx b/src-migrate/modules/account-activation/components/FormEmail.tsx new file mode 100644 index 00000000..ec300ba4 --- /dev/null +++ b/src-migrate/modules/account-activation/components/FormEmail.tsx @@ -0,0 +1,97 @@ +import { Alert, AlertIcon } from "@chakra-ui/react" +import Link from "next/link" +import { useRouter } from "next/router" +import { ChangeEvent, useEffect, useState } from "react" +import { useMutation } from "react-query" +import Modal from "~/common/components/elements/Modal" +import { useRegisterStore } from "~/common/stores/useRegisterStore" +import { ActivationReqProps } from "~/common/types/auth" +import { activationReq } from "~/services/auth" + +const FormEmail = () => { + const router = useRouter() + const { query } = router + const [active, setActive] = useState<boolean>(false) + const [isBtnDisabled, setIsBtnDisabled] = useState<boolean>(true) + const [email, setEmail] = useState<string>('') + + const { form } = useRegisterStore() + + useEffect(() => { + if (form) setEmail(form?.email) + }, [form]) + + useEffect(() => { + setIsBtnDisabled(email === '') + }, [email]) + + useEffect(() => { + setActive(query?.activation === 'email') + }, [query.activation]) + + const mutation = useMutation({ + mutationFn: (data: ActivationReqProps) => activationReq(data) + }) + + const handleSubmit = (e: ChangeEvent<HTMLFormElement>) => { + e.preventDefault() + mutation.data = undefined + mutation.mutate({ email }) + } + + useEffect(() => { + if (mutation.data?.activation_request === true) { + const urlParams = new URLSearchParams({ + activation: 'otp', + email, + redirect: (router.query?.redirect || '/') as string + }) + router.push(`${router.route}?${urlParams}`) + } + }, [mutation.data?.activation_request, router, email]) + + return ( + <Modal active={active} mode="desktop" close={() => router.push(router.route)} title="Aktivasi Akun"> + <form onSubmit={handleSubmit} className="py-3 flex flex-col items-center gap-y-4"> + { + mutation.data !== undefined && + !mutation.data?.activation_request && + ( + <Alert status="warning"> + <AlertIcon /> + {mutation.data?.reason === 'ACTIVE' && 'Akun sudah aktif.'} + {mutation.data?.reason === 'NOT_FOUND' && 'Akun tidak ditemukan.'} + + {mutation.data?.reason === 'ACTIVE' && ( + <Link href="/login" className="ml-1 text-yellow-700 underline">Klik untuk masuk akun anda</Link> + )} + + {mutation.data?.reason === 'NOT_FOUND' && ( + <Link href="/register" className="ml-1 text-yellow-700 underline">Klik untuk daftar akun baru</Link> + )} + </Alert> + ) + } + + <input + type="text" + className="form-input w-full" + placeholder="Masukan alamat email anda" + autoComplete="email" + value={email} + onChange={(e) => setEmail(e.target.value)} + autoFocus + /> + <button + type="submit" + className="btn-yellow w-full" + disabled={isBtnDisabled || mutation.isLoading} + > + {mutation.isLoading ? 'Loading...' : 'Kirim Aktivasi'} + </button> + </form> + </Modal> + ) +} + +export default FormEmail
\ No newline at end of file diff --git a/src-migrate/modules/account-activation/components/FormOTP.tsx b/src-migrate/modules/account-activation/components/FormOTP.tsx new file mode 100644 index 00000000..6815a088 --- /dev/null +++ b/src-migrate/modules/account-activation/components/FormOTP.tsx @@ -0,0 +1,125 @@ +import { Button, HStack, PinInput, PinInputField, Spinner } from "@chakra-ui/react" +import { useRouter } from "next/router" +import { useEffect, useState } from "react" +import { useMutation } from "react-query" +import { useCountdown } from "usehooks-ts" +import Modal from '~/common/components/elements/Modal' +import { setAuth } from "~/common/libs/auth" +import { ActivationOtpProps, ActivationReqProps } from "~/common/types/auth" +import { activationReq, activationUserOTP } from "~/services/auth" + +const FormOTP = () => { + const router = useRouter() + const { query } = router + const [active, setActive] = useState<boolean>(false) + const [email, setEmail] = useState<string>('') + const [otp, setOtp] = useState<string>('') + const [count, { startCountdown, resetCountdown }] = useCountdown({ + countStart: 60 * 1, + intervalMs: 1000, + }) + + useEffect(() => { + setEmail((query?.email || '') as string) + }, [query?.email]) + + useEffect(() => { + setActive(query?.activation === 'otp') + }, [query.activation]) + + useEffect(() => { + !!active && startCountdown() + }, [active, startCountdown]) + + const mutationActivationReq = useMutation({ + mutationFn: (data: ActivationReqProps) => activationReq(data), + onSuccess: () => { + resetCountdown() + startCountdown() + } + }) + + const mutationActivation = useMutation({ + mutationFn: (data: ActivationOtpProps) => activationUserOTP(data) + }) + + useEffect(() => { + if (otp.length === 4 && !mutationActivation.data?.activation) { + mutationActivation.mutate({ email, otp }) + } + //eslint-disable-next-line + }, [otp]) + + useEffect(() => { + if (mutationActivation.data?.user) { + setAuth(mutationActivation.data.user) + router.push((query?.redirect || '/') as string) + } + }, [mutationActivation.data, router, query.redirect]) + + return ( + <Modal active={active} className="w-10/12 md:w-fit px-10" close={() => setActive(false)} mode="desktop"> + <div className="pb-8 flex flex-col items-center"> + <div className="text-title-sm font-medium mb-4">Masukan Kode OTP</div> + <HStack> + <PinInput size='lg' otp onChange={(val) => setOtp(val)}> + <PinInputField autoFocus /> + <PinInputField /> + <PinInputField /> + <PinInputField /> + </PinInput> + </HStack> + <div className="mt-4 text-center"> + {mutationActivation.isLoading && <Spinner size='sm' />} + + {!mutationActivation.isLoading && + mutationActivation.data?.reason === 'INVALID_OTP' && + ( + <span className="text-red-700">Mohon maaf kode OTP yand anda masukan salah</span> + ) + } + </div> + + {!mutationActivation.data?.activation && ( + <div className="mt-4 text-center text-gray-700"> + Kode verifikasi telah dikirimkan ke alamat email <span className="font-medium">{email}</span>. Silakan periksa kotak masuk atau folder spam. + </div> + )} + + <div className="mt-4 flex flex-col items-center"> + {!mutationActivation.data?.activation && ( + <> + {count > 0 && timeFormat(count)} + + {!mutationActivation.data?.activation && count == 0 && ( + <> + <div className="mb-3">Belum menerima kode apapun?</div> + + <Button + onClick={() => mutationActivationReq.mutate({ email })} + disabled={mutationActivationReq.isLoading} + > + {mutationActivationReq.isLoading ? <Spinner size='sm' /> : 'Kirim Ulang'} + </Button> + </> + )} + </> + )} + + </div> + </div> + </Modal> + ) +} + +const timeFormat = (time: number): string => { + const minute = Math.floor(time / 60); + const second = time % 60; + + const minuteFormat = minute < 10 ? `0${minute}` : `${minute}` + const secondFormat = second < 10 ? `0${second}` : `${second}` + + return `${minuteFormat}:${secondFormat}` +} + +export default FormOTP
\ No newline at end of file diff --git a/src-migrate/modules/account-activation/components/FormToken.tsx b/src-migrate/modules/account-activation/components/FormToken.tsx new file mode 100644 index 00000000..b68b244f --- /dev/null +++ b/src-migrate/modules/account-activation/components/FormToken.tsx @@ -0,0 +1,75 @@ +import { Alert, AlertDescription, AlertIcon, AlertTitle, Spinner } from "@chakra-ui/react" +import { useRouter } from "next/router" +import { useEffect, useState } from "react" +import Link from "next/link" +import { useMutation } from "react-query" + +import Modal from "~/common/components/elements/Modal" +import { ActivationTokenProps } from "~/common/types/auth" +import { activationUserToken } from "~/services/auth" +import { setAuth } from "~/common/libs/auth" + +const FormToken = () => { + const router = useRouter() + const { query } = router + const [active, setActive] = useState<boolean>(false) + + const mutation = useMutation({ + mutationFn: (data: ActivationTokenProps) => activationUserToken(data), + }) + + useEffect(() => { + if (query?.activation === 'token' && typeof query?.token === 'string') { + mutation.mutate({ token: query.token }) + setActive(true) + } + //eslint-disable-next-line + }, [query.activation, query.token]) + + useEffect(() => { + if (mutation.data?.user) { + setAuth(mutation.data.user) + router.push((query?.redirect || '/') as string) + } + }, [mutation.data, router, query.redirect]) + + return ( + <Modal active={active} mode="desktop"> + <div className="pb-6 flex flex-col items-center gap-y-6"> + {mutation.isLoading && ( + <> + <Spinner size='lg' borderWidth='3px' /> + <div className="text-h-sm">Mohon tunggu sedang memverifikasi akun</div> + </> + )} + + {!mutation.isLoading && !mutation.data?.activation && ( + <Alert + status={mutation.data?.activation ? 'success' : 'error'} + flexDirection="column" + alignItems="center" + justifyContent="center" + textAlign="center" + height="200px" + bg="transparent" + > + <AlertIcon boxSize="40px" mr={0} /> + <AlertTitle className="mt-4 mb-1 text-h-sm"> + Aktivasi akun gagal + </AlertTitle> + <AlertDescription maxWidth="sm"> + {mutation.data?.reason === 'INVALID_TOKEN' && ( + <> + Token sudah kadaluwarsa, silahkan coba kembali. + <Link href='/register?activation=email' className="block mt-8 text-red-700 underline">Aktivasi Akun</Link> + </> + )} + </AlertDescription> + </Alert> + )} + </div> + </Modal> + ) +} + +export default FormToken
\ No newline at end of file diff --git a/src-migrate/modules/account-activation/index.tsx b/src-migrate/modules/account-activation/index.tsx new file mode 100644 index 00000000..97c96953 --- /dev/null +++ b/src-migrate/modules/account-activation/index.tsx @@ -0,0 +1,16 @@ +import { useRouter } from "next/router" +import FormToken from "./components/FormToken" +import FormEmail from "./components/FormEmail" +import FormOTP from "./components/FormOTP" + +const AccountActivation = () => { + return ( + <> + <FormEmail /> + <FormToken /> + <FormOTP /> + </> + ) +} + +export default AccountActivation
\ No newline at end of file |
