diff options
Diffstat (limited to 'src/modules/login')
| -rw-r--r-- | src/modules/login/components/Form.tsx | 81 | ||||
| -rw-r--r-- | src/modules/login/index.tsx | 20 | ||||
| -rw-r--r-- | src/modules/login/login.module.css | 15 |
3 files changed, 116 insertions, 0 deletions
diff --git a/src/modules/login/components/Form.tsx b/src/modules/login/components/Form.tsx new file mode 100644 index 0000000..941dab3 --- /dev/null +++ b/src/modules/login/components/Form.tsx @@ -0,0 +1,81 @@ +"use client"; +import toast from "@/common/libs/toast"; +import { useLoginStore } from "@/common/stores/useLoginStore" +import { Button, Input, Spinner } from "@nextui-org/react" +import { useMutation } from "@tanstack/react-query"; +import { useRouter } from "next/navigation"; +import { useMemo } from "react"; + +const Form = () => { + const { form, updateForm } = useLoginStore() + const router = useRouter() + + const errorMessage = { + 401: 'Username atau password tidak sesuai', + 404: 'Akun dengan username tersebut tidak ditemukan' + } + + const mutation = useMutation({ + mutationKey: ['login'], + mutationFn: async (data: typeof form) => await fetch("/api/auth/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }), + onError() { + toast('Mohon maaf terjadi kesalahan') + }, + async onSuccess(data) { + if (data.status !== 200) { + return toast(errorMessage[data.status as keyof typeof errorMessage]) + } + router.push('/') + }, + }) + + const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { + updateForm(e.target.name, e.target.value) + } + + const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { + e.preventDefault() + mutation.mutate(form) + } + + const isValid = useMemo(() => { + return form.username && form.password + }, [form]) + + return ( + <form className="grid grid-cols-1 gap-y-4" onSubmit={handleSubmit}> + <Input + isRequired + type="text" + label="Nama Pengguna" + name="username" + onChange={handleInputChange} + autoFocus + /> + <Input + isRequired + type="password" + label="Kata Sandi" + name="password" + onChange={handleInputChange} + /> + <Button + variant="solid" + color="primary" + isDisabled={!isValid || mutation.isPending} + className="mt-2" + type="submit" + > + {mutation.isPending ? <Spinner color="white" size="sm" /> : 'Masuk'} + </Button> + </form> + ) +} + +export default Form
\ No newline at end of file diff --git a/src/modules/login/index.tsx b/src/modules/login/index.tsx new file mode 100644 index 0000000..7247af4 --- /dev/null +++ b/src/modules/login/index.tsx @@ -0,0 +1,20 @@ +import { Spacer } from "@nextui-org/react" +import Form from "./components/Form" +import styles from "./login.module.css" + +const Login = () => { + return ( + <div className={styles.wrapper}> + <div className={styles.header}> + <h1 className={styles.title}>Stock Opname</h1> + <Spacer y={1} /> + <h2 className={styles.subtitle}>Masuk terlebih dahulu untuk melanjutkan</h2> + </div> + + <Spacer y={10} /> + <Form /> + </div> + ) +} + +export default Login
\ No newline at end of file diff --git a/src/modules/login/login.module.css b/src/modules/login/login.module.css new file mode 100644 index 0000000..99575d5 --- /dev/null +++ b/src/modules/login/login.module.css @@ -0,0 +1,15 @@ +.wrapper { + @apply pt-20 px-6; +} + +.header { + @apply text-center; +} + +.title { + @apply text-2xl text-blue-600 font-semibold; +} + +.subtitle { + @apply font-medium text-neutral-600; +} |
