fix:otp login(disabled), isBanner,isPublish advertise

This commit is contained in:
Rama Priyanto 2025-04-07 14:17:35 +07:00
parent 5e3ca91963
commit 673bd461db
10 changed files with 219 additions and 68 deletions

View File

@ -30,7 +30,10 @@ import withReactContent from "sweetalert2-react-content";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { close, error, loading } from "@/config/swal"; import { close, error, loading } from "@/config/swal";
import Image from "next/image"; import Image from "next/image";
import { createAdvertise } from "@/service/advertisement"; import {
createAdvertise,
createMediaFileAdvertise,
} from "@/service/advertisement";
const createArticleSchema = z.object({ const createArticleSchema = z.object({
title: z.string().min(2, { title: z.string().min(2, {
@ -87,6 +90,15 @@ export default function AdvertisePage() {
error(res?.message); error(res?.message);
return false; return false;
} }
const idNow = res?.data?.data?.id;
if (files.length > 0) {
const formFiles = new FormData();
formFiles.append("file", files[0]);
const resFile = await createMediaFileAdvertise(idNow, formFiles);
}
close(); close();
setRefresh(!refresh); setRefresh(!refresh);
MySwal.fire({ MySwal.fire({
@ -270,7 +282,7 @@ export default function AdvertisePage() {
<Button <Button
className=" border-none rounded-full" className=" border-none rounded-full"
variant="bordered" variant="bordered"
onClick={() => handleRemoveFile(files[0])} onPress={() => handleRemoveFile(files[0])}
> >
<TimesIcon /> <TimesIcon />
</Button> </Button>

View File

@ -8,11 +8,14 @@ import Cookies from "js-cookie";
import { close, error, loading } from "@/config/swal"; import { close, error, loading } from "@/config/swal";
import { import {
checkUsernames, checkUsernames,
emailValidation,
getProfile, getProfile,
otpRequest, otpRequest,
otpValidation, otpValidation,
otpValidationLogin,
postSignIn, postSignIn,
savePassword, savePassword,
setupEmail,
updateProfile, updateProfile,
} from "@/service/master-user"; } from "@/service/master-user";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@ -27,7 +30,8 @@ export default function Login() {
const router = useRouter(); const router = useRouter();
const [isVisible, setIsVisible] = useState(false); const [isVisible, setIsVisible] = useState(false);
const [isVisibleSetup, setIsVisibleSetup] = useState([false, false]); const [isVisibleSetup, setIsVisibleSetup] = useState([false, false]);
const [emailSetup, setEmailSetup] = useState(""); const [oldEmail, setOldEmail] = useState("");
const [newEmail, setNewEmail] = useState("");
const [passwordSetup, setPasswordSetup] = useState(""); const [passwordSetup, setPasswordSetup] = useState("");
const [confPasswordSetup, setConfPasswordSetup] = useState(""); const [confPasswordSetup, setConfPasswordSetup] = useState("");
@ -39,7 +43,12 @@ export default function Login() {
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [accessData, setAccessData] = useState<any>(); const [accessData, setAccessData] = useState<any>();
const [profile, setProfile] = useState<any>(); const [profile, setProfile] = useState<any>();
const [isValidPassword, setIsValidPassword] = useState(false); const [isValidEmail, setIsValidEmail] = useState(false);
const setValUsername = (e: any) => {
const uname = e.replaceAll(/[^\w.-]/g, "");
setUsername(uname.toLowerCase());
};
const onSubmit = async () => { const onSubmit = async () => {
const data = { const data = {
@ -50,28 +59,23 @@ export default function Login() {
if (!username || !password) { if (!username || !password) {
error("Username & Password Wajib Diisi !"); error("Username & Password Wajib Diisi !");
} else { } else {
// const response = await emailValidation(data);
// if (response?.error) {
// error("Username / Password Tidak Sesuai");
// }
// if (response?.data?.messages[0] === "Continue to setup email") {
// setFirstLogin(true);
// } else {
// setNeedOtp(true);
// }
loading(); loading();
const response = await postSignIn(data); const response = await postSignIn(data);
if (response?.error) { if (response?.error) {
error("Username / Password Tidak Sesuai"); error("Username / Password Tidak Sesuai");
} else { } else {
setAccessData(response?.data?.data);
const profile = await getProfile(response?.data?.data?.access_token); const profile = await getProfile(response?.data?.data?.access_token);
console.log("PROFILE : ", profile?.data?.data);
// setEmailSetup(profile?.data?.data?.email);
// setProfile(profile?.data?.data);
// setFirstLogin(true);
// if (profile?.data?.data?.isFirstLogin) {
// setFirstLogin(true);
// } else {
// const res = await otpRequest(
// profile?.data?.data?.email,
// profile?.data?.data?.fullname
// );
// setNeedOtp(true);
// }
const dateTime: any = new Date(); const dateTime: any = new Date();
const newTime: any = dateTime.getTime() + 10 * 60 * 1000; const newTime: any = dateTime.getTime() + 10 * 60 * 1000;
@ -141,11 +145,6 @@ export default function Login() {
// } // }
}; };
const setValUsername = (e: any) => {
const uname = e.replaceAll(/[^\w.-]/g, "");
setUsername(uname.toLowerCase());
};
const [isResetPassword, setIsResetPassword] = useState(false); const [isResetPassword, setIsResetPassword] = useState(false);
const [checkUsernameValue, setCheckUsernameValue] = useState(""); const [checkUsernameValue, setCheckUsernameValue] = useState("");
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
@ -183,19 +182,31 @@ export default function Login() {
const submitOtp = async () => { const submitOtp = async () => {
loading(); loading();
const validation = await otpValidation(profile?.email, otpValue); const validation = await otpValidationLogin({
username: username,
otpCode: otpValue,
});
if (validation?.error) { if (validation?.error) {
error("OTP Tidak Sesuai"); error("OTP Tidak Sesuai");
return false; return false;
} }
const response = await postSignIn({
username: username,
password: password,
});
const resProfile = await getProfile(response?.data?.data?.access_token);
const profile = resProfile?.data?.data;
const dateTime: any = new Date(); const dateTime: any = new Date();
const newTime: any = dateTime.getTime() + 10 * 60 * 1000; const newTime: any = dateTime.getTime() + 10 * 60 * 1000;
Cookies.set("access_token", accessData?.access_token, { Cookies.set("access_token", response?.data?.data?.access_token, {
expires: 1, expires: 1,
}); });
Cookies.set("refresh_token", accessData?.refresh_token, { Cookies.set("refresh_token", response?.data?.data?.refresh_token, {
expires: 1, expires: 1,
}); });
Cookies.set("time_refresh", newTime, { Cookies.set("time_refresh", newTime, {
@ -253,23 +264,27 @@ export default function Login() {
close(); close();
}; };
const submitResetEmail = async () => { const submitCheckEmail = async () => {
const req = { const req = {
email: emailSetup, oldEmail: oldEmail,
fullName: profile?.fullname, newEmail: newEmail,
username: profile?.username, username: username,
userLevelId: profile?.userLevelId, password: password,
userRoleId: profile?.userRoleId,
}; };
const res = await updateProfile(req); const res = await setupEmail(req);
if (res?.error) { if (res?.error) {
error(res.message); if (res.message?.messages[0]) {
error(res.message?.messages[0]);
} else {
error(res?.message);
}
return false; return false;
} }
close(); close();
setNeedOtp(true);
console.log("profile", req, passwordSetup, confPasswordSetup); setFirstLogin(false);
}; };
return ( return (
@ -295,7 +310,7 @@ export default function Login() {
<p className="text-[72px] text-[#DD8306] font-semibold mb-10"> <p className="text-[72px] text-[#DD8306] font-semibold mb-10">
Setting Account Setting Account
</p> </p>
<p className="my-2 text-white">Email</p> <p className="my-2 text-white">Email Lama</p>
<Input <Input
isRequired isRequired
type="email" type="email"
@ -303,14 +318,24 @@ export default function Login() {
placeholder="" placeholder=""
className="my-2" className="my-2"
classNames={{ input: "rounded-md", inputWrapper: "rounded-md" }} classNames={{ input: "rounded-md", inputWrapper: "rounded-md" }}
value={emailSetup} value={oldEmail}
onValueChange={setEmailSetup} onValueChange={setOldEmail}
/>
<p className="my-2 text-white">Email Baru</p>
<Input
isRequired
type="email"
label=""
placeholder=""
className="my-2"
classNames={{ input: "rounded-md", inputWrapper: "rounded-md" }}
value={newEmail}
onValueChange={setNewEmail}
/> />
<a className="text-[#DD8306] text-sm">Validasi Email</a>
<Button <Button
size="lg" size="lg"
className="w-fit bg-[#DD8306] rounded-md font-semibold my-3 text-white" className="w-fit bg-[#DD8306] rounded-md font-semibold my-3 text-white"
onPress={submitResetEmail} onPress={submitCheckEmail}
> >
Submit Submit
</Button> </Button>
@ -318,7 +343,7 @@ export default function Login() {
) : needOtp ? ( ) : needOtp ? (
<div className="bg-[#1F1A17] w-full md:w-2/5 p-8 md:px-24 justify-center flex flex-col"> <div className="bg-[#1F1A17] w-full md:w-2/5 p-8 md:px-24 justify-center flex flex-col">
<p className="text-[72px] text-[#DD8306] font-semibold mb-10"> <p className="text-[72px] text-[#DD8306] font-semibold mb-10">
Login Submit OTP
</p> </p>
<p className="my-2 text-white">OTP</p> <p className="my-2 text-white">OTP</p>
<InputOtp length={6} value={otpValue} onValueChange={setOtpValue} /> <InputOtp length={6} value={otpValue} onValueChange={setOtpValue} />

View File

@ -28,6 +28,7 @@ export default function HeaderNews() {
const t = useTranslations("Landing"); const t = useTranslations("Landing");
const [selectedTab, setSelectedTab] = useState("media"); const [selectedTab, setSelectedTab] = useState("media");
const [hotNews, setHotNews] = useState<any>([]); const [hotNews, setHotNews] = useState<any>([]);
const [banner, setBanner] = useState<any>([]);
// useEffect(() => { // useEffect(() => {
@ -35,7 +36,7 @@ export default function HeaderNews() {
useEffect(() => { useEffect(() => {
getArticle(); getArticle();
getBanner();
getHotNews(); getHotNews();
}, []); }, []);
@ -50,6 +51,18 @@ export default function HeaderNews() {
const response = await getListArticle(req); const response = await getListArticle(req);
setArticle(response?.data?.data); setArticle(response?.data?.data);
} }
async function getBanner() {
const req = {
page: 1,
search: "",
limit: "10",
sort: "desc",
isPublish: true,
isBanner: true,
};
const response = await getListArticle(req);
setBanner(response?.data?.data);
}
async function getHotNews() { async function getHotNews() {
const req = { const req = {
@ -69,7 +82,7 @@ export default function HeaderNews() {
<div className="w-full"> <div className="w-full">
<div className="flex flex-col lg:flex-row gap-3 lg:gap-8 bg-white dark:bg-black p-1 lg:p-8 lg:h-[540px] w-full lg:w-[75%] lg:mx-auto"> <div className="flex flex-col lg:flex-row gap-3 lg:gap-8 bg-white dark:bg-black p-1 lg:p-8 lg:h-[540px] w-full lg:w-[75%] lg:mx-auto">
<div className="lg:hidden w-[90%] h-[300px] md:h-[500px] mx-auto"> <div className="lg:hidden w-[90%] h-[300px] md:h-[500px] mx-auto">
{article ? ( {banner ? (
<Swiper <Swiper
centeredSlides={true} centeredSlides={true}
autoplay={{ autoplay={{
@ -96,7 +109,7 @@ export default function HeaderNews() {
); );
}} }}
> >
{article?.map((newsItem: any, index: number) => ( {banner?.map((newsItem: any, index: number) => (
<SwiperSlide key={newsItem?.id}> <SwiperSlide key={newsItem?.id}>
<Card <Card
radius="lg" radius="lg"
@ -199,7 +212,7 @@ export default function HeaderNews() {
</div> </div>
<div className="hidden lg:flex w-full lg:w-[50%] h-[500px]"> <div className="hidden lg:flex w-full lg:w-[50%] h-[500px]">
{article ? ( {banner ? (
<Swiper <Swiper
centeredSlides={true} centeredSlides={true}
autoplay={{ autoplay={{
@ -226,7 +239,7 @@ export default function HeaderNews() {
); );
}} }}
> >
{article?.map((newsItem: any, index: number) => ( {banner?.map((newsItem: any, index: number) => (
<SwiperSlide key={newsItem?.id} className="!w-full h-[50vh]"> <SwiperSlide key={newsItem?.id} className="!w-full h-[50vh]">
<Card <Card
isFooterBlurred isFooterBlurred

View File

@ -2,8 +2,10 @@
import React, { Component, useEffect, useState } from "react"; import React, { Component, useEffect, useState } from "react";
import ReactApexChart from "react-apexcharts"; import ReactApexChart from "react-apexcharts";
import dummyData from "../../../../const/dummy.json"; import dummyData from "../../../../const/dummy.json";
import { getStatisticMonthly } from "@/service/article"; import {
import { get } from "http"; getStatisticMonthly,
getStatisticMonthlyFeedback,
} from "@/service/article";
type WeekData = { type WeekData = {
week: number; week: number;
@ -89,11 +91,13 @@ const SuggestionsChart = (props: {
const initFetch = async () => { const initFetch = async () => {
const splitDate = date.split(" "); const splitDate = date.split(" ");
// const res = await getStatisticMonthly(splitDate[1]); const res = await getStatisticMonthlyFeedback(splitDate[1]);
// const data = res?.data?.data; const data = res?.data?.data;
const data = dummyData.data; // const data = dummyData.data;
if (type === "monthly") { if (type === "monthly") {
const getDatas = data?.filter((a) => a.year === Number(splitDate[1])); const getDatas = data?.filter(
(a: any) => a.year === Number(splitDate[1])
);
console.log("teemp,tota", getDatas); console.log("teemp,tota", getDatas);
if (getDatas) { if (getDatas) {
@ -112,7 +116,10 @@ const SuggestionsChart = (props: {
); );
if (getDatas) { if (getDatas) {
const temp = processMonthlyData(getDatas?.suggestions); const temp = processMonthlyData(getDatas?.suggestions);
const sum = getDatas.suggestions.reduce((acc, curr) => acc + curr, 0); const sum = getDatas.suggestions.reduce(
(acc: any, curr: any) => acc + curr,
0
);
totals(sum); totals(sum);
if (type == "weekly") { if (type == "weekly") {
setSeriesSuggestions( setSeriesSuggestions(

View File

@ -59,7 +59,9 @@ import { useDropzone } from "react-dropzone";
import Image from "next/image"; import Image from "next/image";
import { import {
createAdvertiseById, createAdvertiseById,
deleteAdvertise,
editAdvertise, editAdvertise,
editAdvertiseIsActive,
getAdvertise, getAdvertise,
} from "@/service/advertisement"; } from "@/service/advertisement";
@ -69,6 +71,7 @@ const columns = [
{ name: "Deskripsi", uid: "description" }, { name: "Deskripsi", uid: "description" },
{ name: "Penempatan", uid: "placement" }, { name: "Penempatan", uid: "placement" },
{ name: "Link", uid: "redirectLink" }, { name: "Link", uid: "redirectLink" },
{ name: "Aktif", uid: "isActive" },
{ name: "Aksi", uid: "actions" }, { name: "Aksi", uid: "actions" },
]; ];
@ -166,16 +169,16 @@ export default function AdvertiseTable(props: { triggerRefresh: boolean }) {
}; };
async function doDelete(id: any) { async function doDelete(id: any) {
// loading(); loading();
// const resDelete = await deleteArticle(id); const resDelete = await deleteAdvertise(id);
// if (resDelete?.error) { if (resDelete?.error) {
// error(resDelete.message); error(resDelete.message);
// return false; return false;
// } }
close(); close();
success("Berhasil Hapus"); success("Berhasil Hapus");
initState(); setRefresh(!refresh);
} }
const handleDelete = (id: any) => { const handleDelete = (id: any) => {
@ -233,6 +236,15 @@ export default function AdvertiseTable(props: { triggerRefresh: boolean }) {
onOpen(); onOpen();
}; };
const handleAdvertise = async (e: boolean, id: number) => {
const res = await editAdvertiseIsActive({ id, isActive: e });
if (res?.error) {
error(res?.message);
return false;
}
setRefresh(!refresh);
};
const renderCell = useCallback( const renderCell = useCallback(
(advertise: any, columnKey: Key) => { (advertise: any, columnKey: Key) => {
const cellValue = advertise[columnKey as keyof any]; const cellValue = advertise[columnKey as keyof any];
@ -252,6 +264,16 @@ export default function AdvertiseTable(props: { triggerRefresh: boolean }) {
); );
case "placement": case "placement":
return <p className="capitalize">{cellValue}</p>; return <p className="capitalize">{cellValue}</p>;
case "isActive":
return (
<div className="flex flex-row gap-2">
<Switch
isSelected={advertise?.isActive}
onValueChange={(e) => handleAdvertise(e, advertise?.id)}
/>
{advertise?.isActive ? "Ya" : "Tidak"}
</div>
);
case "actions": case "actions":
return ( return (
<div className="relative flex justify-star items-center gap-2"> <div className="relative flex justify-star items-center gap-2">
@ -278,7 +300,7 @@ export default function AdvertiseTable(props: { triggerRefresh: boolean }) {
<DropdownItem <DropdownItem
key="delete" key="delete"
// onPress={() => handleDelete(article.id)} onPress={() => handleDelete(advertise.id)}
> >
<DeleteIcon <DeleteIcon
color="red" color="red"

View File

@ -13,6 +13,7 @@ import {
deleteArticle, deleteArticle,
getArticleByCategory, getArticleByCategory,
getListArticle, getListArticle,
updateIsBannerArticle,
} from "@/service/article"; } from "@/service/article";
import { Article } from "@/types/globals"; import { Article } from "@/types/globals";
import { convertDateFormat } from "@/utils/global"; import { convertDateFormat } from "@/utils/global";
@ -168,7 +169,12 @@ export default function ArticleTable() {
}; };
const handleBanner = async (id: number, status: boolean) => { const handleBanner = async (id: number, status: boolean) => {
console.log("vbanner", id, status); const res = await updateIsBannerArticle(id, status);
if (res?.error) {
error(res?.message);
return false;
}
initState();
}; };
const copyUrlArticle = async (id: number, slug: string) => { const copyUrlArticle = async (id: number, slug: string) => {
@ -259,7 +265,7 @@ export default function ArticleTable() {
<DropdownItem <DropdownItem
key="setBanner" key="setBanner"
onPress={() => onPress={() =>
handleBanner(article?.id, !article?.isBanner || true) handleBanner(article?.id, !article?.isBanner)
} }
className={username === "admin-mabes" ? "" : "hidden"} className={username === "admin-mabes" ? "" : "hidden"}
> >

View File

@ -1,4 +1,9 @@
import { httpGet, httpPost, httpPut } from "./http-config/axios-base-service"; import {
httpDeleteInterceptor,
httpGet,
httpPost,
httpPut,
} from "./http-config/axios-base-service";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
const token = Cookies.get("access_token"); const token = Cookies.get("access_token");
@ -11,6 +16,13 @@ export async function createAdvertise(data: any) {
const pathUrl = `/advertisement`; const pathUrl = `/advertisement`;
return await httpPost(pathUrl, headers, data); return await httpPost(pathUrl, headers, data);
} }
export async function createMediaFileAdvertise(id: string | number, data: any) {
const headers = {
"content-type": "multipart/form-data",
};
const pathUrl = `/advertisement/upload/${id}`;
return await httpPost(pathUrl, headers, data);
}
export async function getAdvertise(data: any) { export async function getAdvertise(data: any) {
const headers = { const headers = {
@ -37,3 +49,19 @@ export async function editAdvertise(data: any) {
const pathUrl = `/advertisement/${data?.id}`; const pathUrl = `/advertisement/${data?.id}`;
return await httpPut(pathUrl, headers, data); return await httpPut(pathUrl, headers, data);
} }
export async function editAdvertiseIsActive(data: any) {
const headers = {
"content-type": "application/json",
};
const pathUrl = `/advertisement/publish/${data?.id}?isPublish=${data?.isActive}`;
return await httpPut(pathUrl, headers);
}
export async function deleteAdvertise(id: number) {
const headers = {
"content-type": "application/json",
};
const pathUrl = `/advertisement/${id}`;
return await httpDeleteInterceptor(pathUrl, headers);
}

View File

@ -6,6 +6,7 @@ import {
httpPut, httpPut,
} from "./http-config/axios-base-service"; } from "./http-config/axios-base-service";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { stat } from "fs";
const token = Cookies.get("access_token"); const token = Cookies.get("access_token");
export async function getListArticle(props: PaginationRequest) { export async function getListArticle(props: PaginationRequest) {
@ -20,6 +21,7 @@ export async function getListArticle(props: PaginationRequest) {
sortBy, sortBy,
sort, sort,
categorySlug, categorySlug,
isBanner,
} = props; } = props;
const headers = { const headers = {
"content-type": "application/json", "content-type": "application/json",
@ -31,7 +33,7 @@ export async function getListArticle(props: PaginationRequest) {
endDate || "" endDate || ""
}&categoryId=${category || ""}&sortBy=${sortBy || "created_at"}&sort=${ }&categoryId=${category || ""}&sortBy=${sortBy || "created_at"}&sort=${
sort || "asc" sort || "asc"
}&category=${categorySlug || ""}`, }&category=${categorySlug || ""}&isBanner=${isBanner || ""}`,
headers headers
); );
} }
@ -148,6 +150,13 @@ export async function getStatisticMonthly(year: string) {
}; };
return await httpGet(`/articles/statistic/monthly?year=${year}`, headers); return await httpGet(`/articles/statistic/monthly?year=${year}`, headers);
} }
export async function getStatisticMonthlyFeedback(year: string) {
const headers = {
"content-type": "application/json",
Authorization: `Bearer ${token}`,
};
return await httpGet(`/feedbacks/statistic/monthly?year=${year}`, headers);
}
export async function getStatisticSummary() { export async function getStatisticSummary() {
const headers = { const headers = {
"content-type": "application/json", "content-type": "application/json",
@ -167,3 +176,11 @@ export async function submitApproval(data: {
}; };
return await httpPost(`/article-approvals`, headers, data); return await httpPost(`/article-approvals`, headers, data);
} }
export async function updateIsBannerArticle(id: number, status: boolean) {
const headers = {
"content-type": "application/json",
};
const pathUrl = `/articles/banner/${id}?isBanner=${status}`;
return await httpPut(pathUrl, headers);
}

View File

@ -23,6 +23,20 @@ export async function createMasterUser(data: any) {
const pathUrl = `/users`; const pathUrl = `/users`;
return await httpPost(pathUrl, headers, data); return await httpPost(pathUrl, headers, data);
} }
export async function emailValidation(data: any) {
const headers = {
"content-type": "application/json",
};
const pathUrl = `/users/email-validation`;
return await httpPost(pathUrl, headers, data);
}
export async function setupEmail(data: any) {
const headers = {
"content-type": "application/json",
};
const pathUrl = `/users/setup-email`;
return await httpPost(pathUrl, headers, data);
}
export async function getDetailMasterUsers(id: string) { export async function getDetailMasterUsers(id: string) {
const headers = { const headers = {
@ -103,6 +117,12 @@ export async function otpValidation(email: string, otpCode: string) {
}; };
return await httpPost(`/users/otp-validation`, headers, { email, otpCode }); return await httpPost(`/users/otp-validation`, headers, { email, otpCode });
} }
export async function otpValidationLogin(data: any) {
const headers = {
"content-type": "application/json",
};
return await httpPost(`/users/otp-validation`, headers, data);
}
export async function postArticleComment(data: any) { export async function postArticleComment(data: any) {
const headers = token const headers = token

View File

@ -66,4 +66,5 @@ export type PaginationRequest = {
sortBy?: string; sortBy?: string;
sort?: string; sort?: string;
categorySlug?: string; categorySlug?: string;
isBanner?: boolean;
}; };