summaryrefslogtreecommitdiff
path: root/src-migrate/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate/modules')
-rw-r--r--src-migrate/modules/account-activation/components/FormEmail.tsx91
-rw-r--r--src-migrate/modules/account-activation/components/FormOTP.tsx112
-rw-r--r--src-migrate/modules/account-activation/components/FormToken.tsx24
-rw-r--r--src-migrate/modules/account-activation/index.tsx4
-rw-r--r--src-migrate/modules/register/components/Form.tsx35
-rw-r--r--src-migrate/modules/register/index.tsx7
6 files changed, 251 insertions, 22 deletions
diff --git a/src-migrate/modules/account-activation/components/FormEmail.tsx b/src-migrate/modules/account-activation/components/FormEmail.tsx
index f16ab93f..cd917bc9 100644
--- a/src-migrate/modules/account-activation/components/FormEmail.tsx
+++ b/src-migrate/modules/account-activation/components/FormEmail.tsx
@@ -1,6 +1,95 @@
+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
+ })
+ router.push(`${router.route}?${urlParams}`)
+ }
+ }, [mutation.data?.activation_request, router, email])
+
return (
- <div>FormEmail</div>
+ <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>
)
}
diff --git a/src-migrate/modules/account-activation/components/FormOTP.tsx b/src-migrate/modules/account-activation/components/FormOTP.tsx
index 24e9e7f6..e38fa8fe 100644
--- a/src-migrate/modules/account-activation/components/FormOTP.tsx
+++ b/src-migrate/modules/account-activation/components/FormOTP.tsx
@@ -1,23 +1,127 @@
-import { HStack, PinInput, PinInputField } from "@chakra-ui/react"
+import { HStack, PinInput, PinInputField, Spinner } from "@chakra-ui/react"
+import Link from "next/link"
+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 { 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 * 3,
+ 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])
+
+ // TODO: Save user to local storage
+
return (
- <Modal active={false} className="w-10/12 md:w-fit px-10" mode="desktop">
+ <Modal active={active} className="w-10/12 md:w-fit px-10" 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>
+ <PinInput size='lg' otp onChange={(val) => setOtp(val)}>
<PinInputField autoFocus />
<PinInputField />
<PinInputField />
<PinInputField />
</PinInput>
</HStack>
- <div className="mt-4">Kode OTP dikirimkan ke email anda</div>
+ <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>
+ )
+ }
+
+ {mutationActivation.data?.activation && (
+ <span className="text-success-700">Akun anda berhasil diaktifkan, selamat berbelanja di Indoteknik.</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">
+ {!mutationActivation.data?.activation && (
+ <>
+ {count > 0 && timeFormat(count)}
+
+ {!mutationActivation.data?.activation && count == 0 && (
+ <button
+ className="text-red-700 underline"
+ type="button"
+ onClick={() => mutationActivationReq.mutate({ email })}
+ disabled={mutationActivationReq.isLoading}
+ >
+ {mutationActivationReq.isLoading ? <Spinner size='sm' /> : 'Kirim Ulang'}
+ </button>
+ )}
+ </>
+ )}
+
+ {mutationActivation.data?.activation && (
+ <Link href='/' className="text-success-700 underline">Kembali ke halaman utama</Link>
+ )}
+
+
+ </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
index 041fbae8..6af24413 100644
--- a/src-migrate/modules/account-activation/components/FormToken.tsx
+++ b/src-migrate/modules/account-activation/components/FormToken.tsx
@@ -8,22 +8,12 @@ import Modal from "~/common/components/elements/Modal"
import { ActivationTokenProps } from "~/common/types/auth"
import { activationUserToken } from "~/services/auth"
-type StatusProps = "success" | "error" | "loading";
-
const FormToken = () => {
const { query } = useRouter()
- const [status, setStatus] = useState<StatusProps>("loading")
const [active, setActive] = useState<boolean>(false)
const mutation = useMutation({
mutationFn: (data: ActivationTokenProps) => activationUserToken(data),
- onSuccess: (data) => {
- if (data.activation === true) {
- setStatus("success")
- } else {
- setStatus("error")
- }
- }
})
useEffect(() => {
@@ -34,19 +24,21 @@ const FormToken = () => {
//eslint-disable-next-line
}, [query.activation, query.token])
+ // TODO: Save user to local storage
+
return (
<Modal active={active} mode="desktop">
<div className="pb-6 flex flex-col items-center gap-y-6">
- {status === 'loading' && (
+ {mutation.isLoading && (
<>
<Spinner size='lg' borderWidth='3px' />
<div className="text-h-sm">Mohon tunggu sedang memverifikasi akun</div>
</>
)}
- {status !== 'loading' && (
+ {!mutation.isLoading && (
<Alert
- status={status}
+ status={mutation.data?.activation ? 'success' : 'error'}
flexDirection="column"
alignItems="center"
justifyContent="center"
@@ -56,17 +48,17 @@ const FormToken = () => {
>
<AlertIcon boxSize="40px" mr={0} />
<AlertTitle className="mt-4 mb-1 text-h-sm">
- Aktivasi akun {status === 'success' ? 'berhasil' : 'gagal'}
+ Aktivasi akun {mutation.data?.activation ? 'berhasil' : 'gagal'}
</AlertTitle>
<AlertDescription maxWidth="sm">
- {status === 'success' && (
+ {mutation.data?.activation && (
<>
Akun anda berhasil diaktifkan, selamat berbelanja di Indoteknik.
<Link href='/' className="block mt-8 text-success-700 underline">Kembali ke halaman utama</Link>
</>
)}
- {status === 'error' && mutation.data?.reason === 'INVALID_TOKEN' && (
+ {!mutation.data?.activation && 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>
diff --git a/src-migrate/modules/account-activation/index.tsx b/src-migrate/modules/account-activation/index.tsx
index edcc6652..97c96953 100644
--- a/src-migrate/modules/account-activation/index.tsx
+++ b/src-migrate/modules/account-activation/index.tsx
@@ -1,10 +1,14 @@
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 />
</>
)
}
diff --git a/src-migrate/modules/register/components/Form.tsx b/src-migrate/modules/register/components/Form.tsx
index fc1567ab..3227a549 100644
--- a/src-migrate/modules/register/components/Form.tsx
+++ b/src-migrate/modules/register/components/Form.tsx
@@ -1,10 +1,13 @@
-import { ChangeEvent } from "react";
+import { ChangeEvent, useEffect } from "react";
import { useMutation } from "react-query";
import { useRegisterStore } from "~/common/stores/useRegisterStore";
import { RegisterProps } from "~/common/types/auth";
import { registerUser } from "~/services/auth";
import TermCondition from "./TermCondition";
import FormCaptcha from "./FormCaptcha";
+import { useRouter } from "next/router";
+import { UseToastOptions, useToast } from "@chakra-ui/react";
+import Link from "next/link";
const Form = () => {
const {
@@ -14,6 +17,8 @@ const Form = () => {
isValidCaptcha,
updateForm,
} = useRegisterStore()
+ const router = useRouter()
+ const toast = useToast()
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
@@ -30,7 +35,35 @@ const Form = () => {
const response = await mutation.mutateAsync(form)
if (response?.register === true) {
+ const urlParams = new URLSearchParams({
+ activation: 'otp',
+ email: form.email
+ })
+ router.push(`${router.route}?${urlParams}`)
+ }
+
+ const toastProps: UseToastOptions = {
+ duration: 5000,
+ isClosable: true
+ }
+ switch (response?.reason) {
+ case 'EMAIL_USED':
+ toast({
+ ...toastProps,
+ title: 'Email sudah digunakan',
+ status: 'warning'
+ })
+ break;
+ case 'NOT_ACTIVE':
+ const activationUrl = `${router.route}?activation=email`
+ toast({
+ ...toastProps,
+ title: 'Akun belum aktif',
+ description: <>Akun sudah terdaftar namun belum aktif. <Link href={activationUrl} className="underline">Klik untuk aktivasi akun</Link></>,
+ status: 'warning'
+ })
+ break
}
}
diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx
index 6325ee09..00931284 100644
--- a/src-migrate/modules/register/index.tsx
+++ b/src-migrate/modules/register/index.tsx
@@ -32,6 +32,13 @@ const Register = () => {
Masuk
</Link>
</div>
+
+ <div className='text-gray_r-11 mt-4 text-center md:text-left'>
+ Akun anda belum aktif?{' '}
+ <Link href='/register?activation=email' className='inline font-medium text-danger-500'>
+ Aktivasi
+ </Link>
+ </div>
</section>
<section className="my-10 md:my-0">