mediahub-fe/components/partials/auth/login-form.tsx

671 lines
21 KiB
TypeScript
Raw Normal View History

2024-11-26 03:09:48 +00:00
"use client";
import React, { useEffect, useState } from "react";
2024-11-26 03:09:48 +00:00
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import Cookies from "js-cookie";
2024-11-26 03:09:48 +00:00
import { Icon } from "@/components/ui/icon";
import { useForm, SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
2024-11-26 03:09:48 +00:00
import { z } from "zod";
import { cn, getCookiesDecrypt, setCookiesEncrypt } from "@/lib/utils";
import { Eye, EyeOff, Loader2 } from "lucide-react";
2025-04-07 16:37:19 +00:00
import {
getProfile,
login,
postEmailValidation,
postSetupEmail,
requestOTP,
verifyOTPByUsername,
2025-04-07 16:37:19 +00:00
} from "@/service/auth";
import { toast } from "sonner";
2025-01-15 15:59:19 +00:00
import { useRouter } from "@/components/navigation";
import { warning } from "@/lib/swal";
2025-01-15 15:59:19 +00:00
import { Link } from "@/i18n/routing";
2025-02-05 02:45:29 +00:00
import { useTranslations } from "next-intl";
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from "@/components/ui/input-otp";
import { error, loading } from "@/config/swal";
import { data } from "jquery";
import {
Dialog,
DialogContent,
DialogFooter,
DialogTrigger,
} from "@/components/ui/dialog";
import { getUserNotifications, listRole } from "@/service/landing/landing";
2024-11-26 03:09:48 +00:00
// Schema validasi menggunakan zod
2024-11-26 03:09:48 +00:00
const schema = z.object({
username: z.string().min(1, { message: "Judul diperlukan" }),
2025-02-11 06:53:55 +00:00
password: z
.string()
.min(4, { message: "Password must be at least 4 characters." }),
2024-11-26 03:09:48 +00:00
});
// Tipe untuk form values
type LoginFormValues = {
username: string;
password: string;
};
2024-11-26 03:09:48 +00:00
const LoginForm = () => {
const [isPending, startTransition] = React.useTransition();
const router = useRouter();
const [passwordType, setPasswordType] = React.useState("password");
2025-02-05 02:45:29 +00:00
const t = useTranslations("LandingPage");
2024-11-26 03:09:48 +00:00
2025-04-07 16:37:19 +00:00
const [step, setStep] = useState<number>(1);
const [otpValue, setOtpValue] = useState("");
const [userIdentity] = useState();
const [email, setEmail] = useState();
const [category, setCategory] = useState("5");
const roleId = getCookiesDecrypt("urie");
2025-04-07 16:37:19 +00:00
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [oldEmail, setOldEmail] = useState("");
const [oldEmailValidate, setOldEmailValidate] = useState("");
const [role, setRole] = useState<any>();
const [menuActive, setMenuActive] = useState<string>();
const [notifications, setNotifications] = useState([]);
const [notificationsUpdate, setNotificationsUpdate] = useState([]);
2025-04-07 16:37:19 +00:00
const [newEmail, setNewEmail] = useState("");
const [newEmailValidate, setNewEmailValidate] = useState("");
const [otpValidate, setOtpValidate] = useState("");
const [showPassword, setShowPassword] = useState(false);
2024-11-26 03:09:48 +00:00
const togglePasswordType = () => {
2025-02-11 06:53:55 +00:00
setPasswordType((prevType) =>
prevType === "password" ? "text" : "password"
);
2024-11-26 03:09:48 +00:00
};
2024-11-26 03:09:48 +00:00
const {
register,
handleSubmit,
getValues,
2024-11-26 03:09:48 +00:00
formState: { errors },
} = useForm<LoginFormValues>({
2024-11-26 03:09:48 +00:00
resolver: zodResolver(schema),
mode: "all",
});
const handleTypeOTP = (event: React.KeyboardEvent<HTMLInputElement>) => {
const { key } = event;
const target = event.currentTarget;
if (key === "Enter") {
event.preventDefault();
const inputs = Array.from(target.form?.querySelectorAll("input") || []);
const currentIndex = inputs.indexOf(target);
const nextInput = inputs[currentIndex + 1] as HTMLElement | undefined;
if (nextInput) {
nextInput.focus();
}
}
};
const onSubmit: SubmitHandler<LoginFormValues> = async (data) => {
2024-12-10 07:24:50 +00:00
try {
2025-01-01 17:48:57 +00:00
const response = await login({
2024-12-10 07:24:50 +00:00
...data,
grantType: "password",
clientId: "mediahub-app",
2024-12-10 07:24:50 +00:00
});
console.log("LOGIN: ", response);
2025-01-01 17:48:57 +00:00
if (response?.error) {
2024-12-10 07:24:50 +00:00
toast.error("Username / Password Tidak Sesuai");
} else {
2025-01-05 00:44:55 +00:00
const { access_token } = response?.data;
const { refresh_token } = response?.data;
2024-12-10 07:24:50 +00:00
const dateTime = new Date();
const newTime = dateTime.getTime() + 10 * 60 * 1000;
Cookies.set("access_token", access_token, {
expires: 1,
});
Cookies.set("refresh_token", refresh_token, {
expires: 1,
});
Cookies.set("time_refresh", new Date(newTime).toISOString(), {
expires: 1,
});
2024-11-26 03:09:48 +00:00
2024-12-10 07:24:50 +00:00
Cookies.set("is_first_login", String(true), {
secure: true,
sameSite: "strict",
});
const profile = await getProfile(access_token);
console.log("PROFILE : ", profile?.data?.data);
2025-02-11 06:53:55 +00:00
if (
2025-06-11 04:44:17 +00:00
profile?.data?.data?.isInternational == true ||
2025-02-11 06:53:55 +00:00
profile?.data?.data?.isActive == false ||
profile?.data?.data?.isDelete == true
) {
2024-12-10 07:24:50 +00:00
Object.keys(Cookies.get()).forEach((cookieName) => {
Cookies.remove(cookieName);
});
2025-02-11 06:53:55 +00:00
warning(
"Akun Anda tidak dapat digunakan untuk masuk ke MediaHub Polri",
"/auth/login"
);
2024-12-10 07:24:50 +00:00
} else {
2025-01-01 17:48:57 +00:00
Cookies.set("home_path", profile?.data?.data?.homePath, {
expires: 1,
});
2025-02-11 06:53:55 +00:00
Cookies.set(
"profile_picture",
profile?.data?.data?.profilePictureUrl,
{
expires: 1,
}
);
2025-01-01 17:48:57 +00:00
Cookies.set("state", profile?.data?.data?.userLevel?.name, {
expires: 1,
});
Cookies.set(
"state-prov",
profile.data?.data?.userLevel?.province?.provName,
{
expires: 1,
}
);
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("uie", profile?.data?.data?.id, {
expires: 1,
});
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("urie", profile?.data?.data?.roleId, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("urne", profile?.data?.data?.role?.name, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("ulie", profile?.data?.data?.userLevel?.id, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-02-11 06:53:55 +00:00
setCookiesEncrypt(
"uplie",
profile?.data?.data?.userLevel?.parentLevelId,
{
expires: 1,
}
);
setCookiesEncrypt(
"ulne",
profile?.data?.data?.userLevel?.levelNumber,
{
expires: 1,
}
);
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("ufne", profile?.data?.data?.fullname, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("ulnae", profile?.data?.data?.userLevel?.name, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-01-01 17:48:57 +00:00
setCookiesEncrypt("uinse", profile?.data?.data?.instituteId, {
2024-12-10 07:24:50 +00:00
expires: 1,
});
2025-02-11 06:53:55 +00:00
console.log("ssaddd", profile?.data?.data?.roleId);
if (
2025-01-01 17:48:57 +00:00
Number(profile?.data?.data?.roleId) == 2 ||
Number(profile?.data?.data?.roleId) == 3 ||
Number(profile?.data?.data?.roleId) == 4 ||
Number(profile?.data?.data?.roleId) == 9 ||
Number(profile?.data?.data?.roleId) == 10 ||
Number(profile?.data?.data?.roleId) == 11 ||
2025-02-11 06:53:55 +00:00
Number(profile?.data?.data?.roleId) == 12 ||
2025-03-03 02:46:53 +00:00
Number(profile?.data?.data?.roleId) == 18 ||
Number(profile?.data?.data?.roleId) == 19
) {
2025-06-09 02:01:46 +00:00
if (profile?.data?.data?.roleId === 18) {
2025-06-08 15:41:06 +00:00
window.location.href = "/in/dashboard/executive-data";
2025-02-11 06:53:55 +00:00
// router.push('/admin/dashboard');
Cookies.set("status", "login", {
expires: 1,
});
2025-06-09 02:01:46 +00:00
} else if (profile?.data?.data?.roleId === 2) {
window.location.href = "/in/dashboard/executive";
Cookies.set("status", "login", {
expires: 1,
});
2025-02-11 06:53:55 +00:00
} else if (
2025-04-29 03:47:41 +00:00
profile?.data?.data?.userLevel?.id == 794 ||
2025-02-11 06:53:55 +00:00
profile?.data?.data?.userLevel?.parentLevelId == 761
) {
2025-04-29 03:47:41 +00:00
window.location.href = "/in/dashboard";
2024-12-10 07:24:50 +00:00
Cookies.set("status", "login", {
expires: 1,
});
} else {
window.location.href = "/in/dashboard";
2024-12-10 07:24:50 +00:00
// router.push('/admin/dashboard');
Cookies.set("status", "login", {
expires: 1,
});
}
2024-12-10 07:24:50 +00:00
} else {
2024-12-30 16:00:25 +00:00
window.location.href = "/";
2024-12-10 07:24:50 +00:00
Cookies.set("status", "login", {
expires: 1,
});
}
2024-11-26 03:09:48 +00:00
}
}
2024-12-10 07:24:50 +00:00
} catch (err: any) {
toast.error(err.message || "An unexpected error occurred.");
}
// startTransition( () => {
// });
2024-11-26 03:09:48 +00:00
};
2025-04-07 16:37:19 +00:00
const handleEmailValidation = async () => {
const data = getValues();
2025-04-07 16:37:19 +00:00
// loading();
2025-04-07 16:37:19 +00:00
const response = await postEmailValidation(data);
if (response?.error) {
error(response?.message);
2025-04-07 16:37:19 +00:00
return false;
}
const msg = response?.data?.message;
2025-06-11 04:44:17 +00:00
// onSubmit(data);
2025-06-11 04:44:17 +00:00
if (msg == "Continue to setup email") {
setStep(2);
} else if (msg == "Email is valid and OTP has been sent") {
setStep(3);
} else if (msg == "Username & password valid") {
onSubmit(data);
} else {
error("Username / password incorrect");
}
2025-04-29 17:16:33 +00:00
// else {
// setStep(1);
// }
2025-04-07 16:37:19 +00:00
};
const handleSetupEmail = async () => {
const values = getValues();
2025-04-07 16:37:19 +00:00
const data = {
username: values.username,
password: values.password,
2025-04-07 16:37:19 +00:00
oldEmail: oldEmail,
newEmail: newEmail,
};
// loading();
2025-04-07 16:37:19 +00:00
const response = await postSetupEmail(data);
// close();
if (response?.error) {
2025-04-07 16:37:19 +00:00
error(response.message);
return false;
}
const msg = response?.data?.message;
2025-04-07 16:37:19 +00:00
if (msg == "Email is valid and OTP has been sent") {
setStep(3);
} else if (msg == "The old email is not same") {
error("Email is invalid");
}
};
const checkEmail = (state: any, e: any) => {
const regEmail =
/^(([^\s"(),.:;<>@[\\\]]+(\.[^\s"(),.:;<>@[\\\]]+)*)|(".+"))@((\[(?:\d{1,3}\.){3}\d{1,3}])|(([\dA-Za-z\-]+\.)+[A-Za-z]{2,}))$/;
if (regEmail.test(e)) {
if (state == "old") {
setOldEmailValidate("");
setOldEmail(e);
} else {
setNewEmailValidate("");
setNewEmail(e);
}
} else {
if (state == "old") {
setOldEmailValidate("Email tidak valid");
setOldEmail("");
} else {
setNewEmailValidate("Email tidak valid");
setNewEmail("");
}
}
};
const handleLoginOTP = async () => {
// const otp = `${otp1}${otp2}${otp3}${otp4}${otp5}${otp6}`;
const values = getValues();
if (otpValue.length === 6) {
loading();
const response = await verifyOTPByUsername(values.username, otpValue);
if (response?.error) {
error(response.message);
return false;
}
close();
if (response?.message === "success") {
onSubmit(values);
} else {
setOtpValidate("Kode OTP Tidak Valid");
}
}
};
let menu = "";
useEffect(() => {
async function initState() {
setMenuActive(menu);
const res = await listRole();
setRole(res?.data?.data);
}
async function getNotif() {
if (roleId != undefined) {
const response = await getUserNotifications(0, 2);
setNotifications(response?.data?.data?.content);
console.log("respon:", response);
}
}
async function getNotifUpdate() {
if (roleId != undefined) {
const response = await getUserNotifications(0, 3);
setNotificationsUpdate(response?.data?.data?.content);
console.log("Notiffff:", response);
}
}
initState();
getNotif();
getNotifUpdate();
}, []);
2024-11-26 03:09:48 +00:00
return (
<>
{step !== 3 && (
<form
onSubmit={handleSubmit(onSubmit)}
className="mt-5 2xl:mt-7 space-y-4"
>
{step === 1 && (
<>
<div className="text-left 2xl:mb-10 mb-4 mt-10">
<h4 className="font-semibold text-3xl text-left">
{t("logInPlease")}
</h4>
<div className="text-default-500 text-base">
{t("acc")}
<Dialog>
<DialogTrigger asChild>
<span className="w-full lg:w-fit px-2 h-8 text-red-500 hover:cursor-pointer">
{t("register")}
</span>
</DialogTrigger>
<DialogContent size="sm" className="sm:max-w-[425px]">
<div className="flex flex-col w-full gap-1">
<p className="text-lg font-semibold text-center">
{t("categoryReg")}
</p>
<p className="text-base text-center">
{t("selectOne")}
</p>
</div>
<div>
{role?.map((row: any) => (
<div key={row.id}>
<input
type="radio"
id={`category${row.id}`}
name="category"
className=""
value={row.id}
checked={category == `${row.id}`}
onChange={(event) =>
setCategory(event.target.value)
}
/>
<label
className="ml-2"
htmlFor={`category${row.id}`}
>
{row.name}
</label>
</div>
))}
</div>
<div className="border-b-2 border-black"></div>
<DialogFooter>
<Link
href={`/auth/registration?category=${category}`}
className="flex justify-center bg-red-500 px-4 py-1 rounded-md border border-black text-white"
type="submit"
>
{t("next")}{" "}
</Link>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="username"
className="font-medium text-default-600"
>
Username
</Label>
<Input
size="lg"
disabled={isPending}
{...register("username")}
id="username"
type="text"
className={cn("", {
"border-destructive": errors.username,
})}
/>
{errors.username?.message && (
<div className="text-destructive mt-2 text-sm">
{errors.username.message}
</div>
)}
</div>
2024-11-26 03:09:48 +00:00
<div className="mt-3.5 space-y-2">
<Label
htmlFor="password"
className="font-medium text-default-600"
>
{t("password")}
</Label>
<div className="relative">
<Input
size="lg"
disabled={isPending}
{...register("password")}
id="password"
type={showPassword ? "text" : "password"}
className="peer pr-10"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-default-500 hover:text-default-700"
tabIndex={-1}
>
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
{errors.password?.message && (
<div className="text-destructive mt-2 text-sm">
{errors.password.message}
</div>
)}
</div>
<div className="flex justify-between">
<div className="flex gap-2 items-center">
<Checkbox id="checkbox" defaultChecked />
<Label htmlFor="checkbox">{t("rememberMe")}</Label>
</div>
<Link
href="/auth/forgot-password"
className="text-sm text-default-800 dark:text-default-400 leading-6 font-medium"
>
{t("forgotPass")}
</Link>
</div>
<Button
2025-06-24 08:19:46 +00:00
type="submit"
fullWidth
2025-06-24 08:19:46 +00:00
// onClick={handleEmailValidation}
// disabled={isPending}
>
Selanjutnya
</Button>
</>
)}
{step === 2 && (
<>
<div className="text-left 2xl:mb-10 mb-4">
<h4 className="font-semibold text-3xl text-left">
Anda perlu memasukkan email baru untuk bisa Login.
</h4>
</div>
<div className="flex flex-col justify-center mb-6">
<div className="space-y-2">
<Label
htmlFor="username"
className="font-medium text-default-600"
>
Email Lama <span className="text-red-500">*</span>
</Label>
<Input
size="lg"
disabled={isPending}
onChange={(e) => checkEmail("old", e.target.value)}
id="oldEmail"
type="email"
className={cn("", {
"border-destructive": errors.username,
})}
/>
<p className="invalid-feedback-custom">{oldEmailValidate}</p>
{errors.username?.message && (
<div className="text-destructive mt-2 text-sm">
{errors.username.message}
</div>
)}
2025-04-07 16:37:19 +00:00
</div>
<div className="space-y-2">
<Label
htmlFor="username"
className="font-medium text-default-600"
>
Email Baru <span className="text-red-500">*</span>
</Label>
<Input
size="lg"
disabled={isPending}
onChange={(e) => checkEmail("new", e.target.value)}
id="newEmail"
type="email"
className={cn("", {
"border-destructive": errors.username,
})}
/>
<p className="invalid-feedback-custom">{newEmailValidate}</p>
{errors.username?.message && (
<div className="text-destructive mt-2 text-sm">
{errors.username.message}
</div>
)}
2025-04-07 16:37:19 +00:00
</div>
</div>
<Button
fullWidth
className="bg-red-500"
onClick={handleSetupEmail}
type="button"
>
Simpan
</Button>
</>
)}
</form>
)}
{step === 3 && (
<div className="mt-10 space-y-6">
<div className="text-left 2xl:mb-10 mb-4 mt-10">
<h4 className="font-semibold text-3xl text-left">
{t("pleaseEnterOtp")}
</h4>
</div>
<div className="flex justify-center mb-6">
<InputOTP
maxLength={6}
onChange={(val: string) => setOtpValue(val)}
>
<InputOTPGroup>
<InputOTPSlot index={0} onKeyDown={handleTypeOTP} />
<InputOTPSlot index={1} onKeyDown={handleTypeOTP} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={2} onKeyDown={handleTypeOTP} />
<InputOTPSlot index={3} onKeyDown={handleTypeOTP} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={4} onKeyDown={handleTypeOTP} />
<InputOTPSlot index={5} onKeyDown={handleTypeOTP} />
</InputOTPGroup>
</InputOTP>
</div>
{otpValidate && (
<p className="invalid-feedback-custom text-center">
<b>{otpValidate}</b>
</p>
)}
<Button
fullWidth
className="bg-red-500"
type="button"
onClick={handleLoginOTP}
disabled={otpValue.length !== 6}
>
2025-04-16 06:28:10 +00:00
{t("signIn")}
</Button>
</div>
)}
</>
2024-11-26 03:09:48 +00:00
);
};
2024-11-26 03:09:48 +00:00
export default LoginForm;