feat:login OTP, fix performance polda,polres,fix sidebar polda, satker

This commit is contained in:
Anang Yusman 2025-04-09 14:55:30 +08:00
parent 142a420366
commit aff407f3ce
9 changed files with 231 additions and 202 deletions

View File

@ -194,10 +194,7 @@ const options = {
const SurveyFormModal = ({ onClose }: { onClose: () => void }) => {
useEffect(() => {
// Lock body scroll when modal is open
document.body.style.overflow = "hidden";
// Clean up when modal closes
return () => {
document.body.style.overflow = "";
};
@ -359,7 +356,7 @@ const SurveyFormModal = ({ onClose }: { onClose: () => void }) => {
);
};
const ONE_HOUR = 60 * 60 * 1000;
const FIVE_MINUTES = 5 * 60 * 1000;
const Hero: React.FC = () => {
const router = useRouter();
@ -394,7 +391,7 @@ const Hero: React.FC = () => {
const now = new Date().getTime();
if (roleId && (!lastShown || now - parseInt(lastShown) > ONE_HOUR)) {
if (roleId && (!lastShown || now - parseInt(lastShown) > FIVE_MINUTES)) {
setShowSurveyModal(true);
Cookies.set("surveyLastShown", now.toString(), { expires: 1 });
}

View File

@ -17,6 +17,7 @@ import {
postEmailValidation,
postSetupEmail,
requestOTP,
verifyOTPByUsername,
} from "@/service/auth";
import { toast } from "sonner";
import { useRouter } from "@/components/navigation";
@ -30,6 +31,7 @@ import {
InputOTPSlot,
} from "@/components/ui/input-otp";
import { error, loading } from "@/config/swal";
import { data } from "jquery";
// Schema validasi menggunakan zod
const schema = z.object({
@ -57,22 +59,13 @@ const LoginForm = () => {
const [email, setEmail] = useState();
const [category, setCategory] = useState("5");
// const handleSignInClick = () => {
// handleSendOTP();
// setIsOtpStep(true);
// };
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [oldEmail, setOldEmail] = useState("");
const [oldEmailValidate, setOldEmailValidate] = useState("");
const [newEmail, setNewEmail] = useState("");
const [newEmailValidate, setNewEmailValidate] = useState("");
// const handleSignInClick = () => {
// handleSendOTP();
// setIsOtpStep(true);
// };
const [otpValidate, setOtpValidate] = useState("");
const [otp1, setOtp1] = useState();
const [otp2, setOtp2] = useState();
@ -90,6 +83,7 @@ const LoginForm = () => {
const {
register,
handleSubmit,
getValues,
formState: { errors },
} = useForm<LoginFormValues>({
resolver: zodResolver(schema),
@ -103,37 +97,8 @@ const LoginForm = () => {
event.preventDefault();
};
// const handleNextStep = () => {
// setIsOtpStep(true);
// };
const handleSendOTP = async () => {
console.log(userIdentity, email);
console.log("UMUM");
if (email != "") {
const data = {
memberIdentity: null,
email: "",
category,
};
// loading();
const response = await requestOTP(data);
if (response.error) {
error(response.message);
return false;
}
close();
}
};
// Fungsi submit form
const onSubmit: SubmitHandler<LoginFormValues> = async (data) => {
try {
// const response = null;
const response = await login({
...data,
grantType: "password",
@ -193,6 +158,13 @@ const LoginForm = () => {
Cookies.set("state", profile?.data?.data?.userLevel?.name, {
expires: 1,
});
Cookies.set(
"state-prov",
profile.data?.data?.userLevel?.province?.provName,
{
expires: 1,
}
);
setCookiesEncrypt("uie", profile?.data?.data?.id, {
expires: 1,
});
@ -278,19 +250,16 @@ const LoginForm = () => {
};
const handleEmailValidation = async () => {
const data = {
username: username,
password: password,
};
const data = getValues();
loading();
// loading();
const response = await postEmailValidation(data);
close();
if (response.error) {
error(response.message);
if (response?.error) {
error(response?.message);
return false;
}
const msg = response.data?.message;
const msg = response?.data?.message;
if (msg == "Continue to setup email") {
setStep(2);
} else if (msg == "Email is valid and OTP has been sent") {
@ -298,26 +267,27 @@ const LoginForm = () => {
} else if (msg == "Username & password valid") {
onSubmit(data);
} else {
error("Username / password incorrect");
setStep(2);
}
};
const handleSetupEmail = async () => {
const values = getValues();
const data = {
username: username,
password: password,
username: values.username,
password: values.password,
oldEmail: oldEmail,
newEmail: newEmail,
};
loading();
// loading();
const response = await postSetupEmail(data);
close();
if (response.error) {
// close();
if (response?.error) {
error(response.message);
return false;
}
const msg = response.data?.message;
const msg = response?.data?.message;
if (msg == "Email is valid and OTP has been sent") {
setStep(3);
} else if (msg == "The old email is not same") {
@ -325,6 +295,52 @@ const LoginForm = () => {
}
};
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");
}
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="mt-5 2xl:mt-7 space-y-4">
{step === 1 ? (
@ -391,7 +407,7 @@ const LoginForm = () => {
</Link>
</div>
<Button
type="submit"
type="button"
fullWidth
onClick={handleEmailValidation}
disabled={isPending}
@ -417,13 +433,14 @@ const LoginForm = () => {
<Input
size="lg"
disabled={isPending}
onChange={(e) => setOldEmail(e.target.value)}
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}
@ -440,13 +457,14 @@ const LoginForm = () => {
<Input
size="lg"
disabled={isPending}
onChange={(e) => setNewEmail(e.target.value)}
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}
@ -454,8 +472,13 @@ const LoginForm = () => {
)}
</div>
</div>
<Button fullWidth className="bg-red-500">
Sign in
<Button
fullWidth
className="bg-red-500"
onClick={handleSetupEmail}
type="submit"
>
Simpan
</Button>
</>
) : (
@ -466,49 +489,37 @@ const LoginForm = () => {
</h4>
</div>
<div className="flex justify-center mb-6">
<InputOTP maxLength={6} onChange={(e) => setOtpValue(e)}>
<InputOTP
maxLength={6}
onChange={(val: string) => setOtpValue(val)}
>
<InputOTPGroup>
<InputOTPSlot
index={0}
onChange={(e: any) => setOtp1(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot
index={1}
onChange={(e: any) => setOtp2(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot index={0} onKeyUp={handleTypeOTP} />
<InputOTPSlot index={1} onKeyUp={handleTypeOTP} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot
index={2}
onChange={(e: any) => setOtp3(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot
index={3}
onChange={(e: any) => setOtp4(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot index={2} onKeyUp={handleTypeOTP} />
<InputOTPSlot index={3} onKeyUp={handleTypeOTP} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot
index={4}
onChange={(e: any) => setOtp5(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot
index={5}
onChange={(e: any) => setOtp6(e.target.value)}
onKeyUp={handleTypeOTP}
/>
<InputOTPSlot index={4} onKeyUp={handleTypeOTP} />
<InputOTPSlot index={5} onKeyUp={handleTypeOTP} />
</InputOTPGroup>
</InputOTP>
<p className="invalid-feedback-custom text-center">
<b>{otpValidate}</b>
</p>
</div>
<Button fullWidth className="bg-red-500">
Sign in
<Button
fullWidth
className="bg-red-500"
type="button"
onClick={handleLoginOTP}
disabled={otpValue.length !== 6}
>
Verifikasi OTP & Masuk
</Button>
</>
)}

View File

@ -33,8 +33,8 @@ export default function PerformancePoldaViz() {
levelName == "MABES POLRI"
? isInternational[0]
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-ranking-polda?"
: `views/2023_09_db-ranking-polda_rev100/db-ranking-13?`;
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-top10?"
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?polda-selected=${poldaState}&`;
const param = ":embed=yes&:toolbar=yes&:iframeSizedToWindow=true";

View File

@ -27,7 +27,7 @@ export default function PerformancePolresViz() {
? isInternational[0]
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-top10?"
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?polda-selected=${provState}&`;
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?polda-selected=${poldaState}&`;
const param = ":embed=yes&:toolbar=yes&:iframeSizedToWindow=true";
@ -59,9 +59,7 @@ export default function PerformancePolresViz() {
<div className="flex flex-col gap-2 bg-white rounded-lg p-3">
<p className="text-lg">
<b>
{isInternational[0]
? "POLRES PERFORMANCE"
: "POLFORMANCE POLRES"}
{isInternational[0] ? "POLRES PERFORMANCE" : "POLFORMANCE POLRES"}
</b>
</p>
<div className="my-5">

View File

@ -3001,20 +3001,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
},
],
},
// {
// groupLabel: "",
// id: "agenda-setting",
// menus: [
// {
// id: "agenda-setting",
// href: "/contributor/agenda-setting",
// label: t("agenda-setting"),
// active: pathname.includes("/agenda-setting"),
// icon: "iconoir:journal-page",
// submenus: [],
// },
// ],
// },
{
groupLabel: "",
id: "management-user",
@ -3057,6 +3044,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
},
],
},
// {
// groupLabel: "",
// id: "agenda-setting",
// menus: [
// {
// id: "agenda-setting",
// href: "/contributor/agenda-setting",
// label: t("agenda-setting"),
// active: pathname.includes("/agenda-setting"),
// icon: "iconoir:journal-page",
// submenus: [],
// },
// ],
// },
{
groupLabel: "",
id: "performance-polda",
@ -3352,20 +3353,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
},
],
},
// {
// groupLabel: "",
// id: "agenda-setting",
// menus: [
// {
// id: "agenda-setting",
// href: "/contributor/agenda-setting",
// label: t("agenda-setting"),
// active: pathname.includes("/agenda-setting"),
// icon: "iconoir:journal-page",
// submenus: [],
// },
// ],
// },
{
groupLabel: "",
id: "agenda-setting",
menus: [
{
id: "agenda-setting",
href: "/contributor/agenda-setting",
label: t("agenda-setting"),
active: pathname.includes("/agenda-setting"),
icon: "iconoir:journal-page",
submenus: [],
},
],
},
{
groupLabel: "",
id: "performance-polres",
@ -3437,70 +3438,70 @@ export function getMenuList(pathname: string, t: any): Group[] {
},
],
},
{
groupLabel: "",
id: "settings",
menus: [
{
id: "settings",
href: "/admin/settings",
label: t("settings"),
active: pathname.includes("/settinng"),
icon: "material-symbols:settings",
submenus: [
{
href: "/admin/settings/category",
label: t("category"),
active: pathname === "/admin/settings/category",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/settings/tag",
label: "Tag",
active: pathname === "/admin/settings/tag",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/settings/banner",
label: "Banner",
active: pathname === "/admin/settings/banner",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/settings/feedback",
label: "Feedback",
active: pathname === "/admin/settings/feedback",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/settings/faq",
label: "FAQ",
active: pathname === "/admin/settings/faq",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "https://nat-mediahub.polri.go.id/",
label: "Mediahub 2022",
active: pathname === "/admin/settings/mediahub-2022",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/settings/privacy",
label: t("privacy"),
active: pathname === "/admin/settings/privacy",
icon: "heroicons:arrow-trending-up",
children: [],
},
],
},
],
},
// {
// groupLabel: "",
// id: "settings",
// menus: [
// {
// id: "settings",
// href: "/admin/settings",
// label: t("settings"),
// active: pathname.includes("/settinng"),
// icon: "material-symbols:settings",
// submenus: [
// {
// href: "/admin/settings/category",
// label: t("category"),
// active: pathname === "/admin/settings/category",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "/admin/settings/tag",
// label: "Tag",
// active: pathname === "/admin/settings/tag",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "/admin/settings/banner",
// label: "Banner",
// active: pathname === "/admin/settings/banner",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "/admin/settings/feedback",
// label: "Feedback",
// active: pathname === "/admin/settings/feedback",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "/admin/settings/faq",
// label: "FAQ",
// active: pathname === "/admin/settings/faq",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "https://nat-mediahub.polri.go.id/",
// label: "Mediahub 2022",
// active: pathname === "/admin/settings/mediahub-2022",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// {
// href: "/admin/settings/privacy",
// label: t("privacy"),
// active: pathname === "/admin/settings/privacy",
// icon: "heroicons:arrow-trending-up",
// children: [],
// },
// ],
// },
// ],
// },
];
} else {
menusSelected = [
@ -3632,6 +3633,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
},
],
},
{
groupLabel: "",
id: "experts",
menus: [
{
id: "experts",
href: "/admin/add-experts",
label: t("add-experts"),
active: pathname.includes("/add-experts"),
icon: "majesticons:user",
submenus: [],
},
],
},
{
groupLabel: "",
id: "settings",

View File

@ -328,7 +328,7 @@
"performance-satker": "Performance Satker",
"analysis": "Analysis",
"management-content": "Content Management ",
"add-experts": "Add Experts",
"add-experts": "Experts",
"category": "Category",
"add-category": "Add Category",
"tags": "Tags",

View File

@ -329,7 +329,7 @@
"performance-satker": "Performa Satker",
"analysis": "Analisa",
"management-content": "Manajemen Konten",
"add-experts": "Tambah Tenaga Ahli",
"add-experts": "Tenaga Ahli",
"category": "Kategori",
"add-category": "Tambah Kategori",
"tags": "Tag",

View File

@ -70,12 +70,17 @@ export async function getProfile(token: any) {
export async function postEmailValidation(data: any) {
const url = "public/users/email-validation";
return postAPIWithJson(url, data);
return httpPostInterceptor(url, data);
}
export async function postSetupEmail(data: any) {
const url = "public/users/setup-email";
return httpGetInterceptorWithToken({ url, data });
return httpPostInterceptor(url, data);
}
export async function verifyOTPByUsername(username: any, otp: any) {
const url = `public/users/verify-otp?username=${username}&otp=${otp}`;
return httpPostInterceptor(url);
}
export async function getSubjects() {

View File

@ -175,10 +175,13 @@ export async function httpGetInterceptorWithToken(pathUrl: any, headers?: any) {
}
}
export async function postAPIWithJson(url: any, data: any, headers?: any) {
export async function postAPIWithJson(url: any, data: any, token: any) {
const headers = {
Authorization: `Bearer ${token}`,
};
const response = await axiosInstanceJson
.post(url, data, { headers })
.catch((error: any) => error.response);
.catch((error) => error.response);
if (response?.status > 300) {
return {
error: true,