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 { close, error, loading } from "@/config/swal";
import Image from "next/image";
import { createAdvertise } from "@/service/advertisement";
import {
createAdvertise,
createMediaFileAdvertise,
} from "@/service/advertisement";
const createArticleSchema = z.object({
title: z.string().min(2, {
@ -87,6 +90,15 @@ export default function AdvertisePage() {
error(res?.message);
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();
setRefresh(!refresh);
MySwal.fire({
@ -270,7 +282,7 @@ export default function AdvertisePage() {
<Button
className=" border-none rounded-full"
variant="bordered"
onClick={() => handleRemoveFile(files[0])}
onPress={() => handleRemoveFile(files[0])}
>
<TimesIcon />
</Button>

View File

@ -8,11 +8,14 @@ import Cookies from "js-cookie";
import { close, error, loading } from "@/config/swal";
import {
checkUsernames,
emailValidation,
getProfile,
otpRequest,
otpValidation,
otpValidationLogin,
postSignIn,
savePassword,
setupEmail,
updateProfile,
} from "@/service/master-user";
import { useRouter } from "next/navigation";
@ -27,7 +30,8 @@ export default function Login() {
const router = useRouter();
const [isVisible, setIsVisible] = useState(false);
const [isVisibleSetup, setIsVisibleSetup] = useState([false, false]);
const [emailSetup, setEmailSetup] = useState("");
const [oldEmail, setOldEmail] = useState("");
const [newEmail, setNewEmail] = useState("");
const [passwordSetup, setPasswordSetup] = useState("");
const [confPasswordSetup, setConfPasswordSetup] = useState("");
@ -39,7 +43,12 @@ export default function Login() {
const [password, setPassword] = useState("");
const [accessData, setAccessData] = 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 data = {
@ -50,28 +59,23 @@ export default function Login() {
if (!username || !password) {
error("Username & Password Wajib Diisi !");
} 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();
const response = await postSignIn(data);
if (response?.error) {
error("Username / Password Tidak Sesuai");
} else {
setAccessData(response?.data?.data);
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 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 [checkUsernameValue, setCheckUsernameValue] = useState("");
const MySwal = withReactContent(Swal);
@ -183,19 +182,31 @@ export default function Login() {
const submitOtp = async () => {
loading();
const validation = await otpValidation(profile?.email, otpValue);
const validation = await otpValidationLogin({
username: username,
otpCode: otpValue,
});
if (validation?.error) {
error("OTP Tidak Sesuai");
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 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,
});
Cookies.set("refresh_token", accessData?.refresh_token, {
Cookies.set("refresh_token", response?.data?.data?.refresh_token, {
expires: 1,
});
Cookies.set("time_refresh", newTime, {
@ -253,23 +264,27 @@ export default function Login() {
close();
};
const submitResetEmail = async () => {
const submitCheckEmail = async () => {
const req = {
email: emailSetup,
fullName: profile?.fullname,
username: profile?.username,
userLevelId: profile?.userLevelId,
userRoleId: profile?.userRoleId,
oldEmail: oldEmail,
newEmail: newEmail,
username: username,
password: password,
};
const res = await updateProfile(req);
const res = await setupEmail(req);
if (res?.error) {
error(res.message);
if (res.message?.messages[0]) {
error(res.message?.messages[0]);
} else {
error(res?.message);
}
return false;
}
close();
console.log("profile", req, passwordSetup, confPasswordSetup);
setNeedOtp(true);
setFirstLogin(false);
};
return (
@ -295,7 +310,7 @@ export default function Login() {
<p className="text-[72px] text-[#DD8306] font-semibold mb-10">
Setting Account
</p>
<p className="my-2 text-white">Email</p>
<p className="my-2 text-white">Email Lama</p>
<Input
isRequired
type="email"
@ -303,14 +318,24 @@ export default function Login() {
placeholder=""
className="my-2"
classNames={{ input: "rounded-md", inputWrapper: "rounded-md" }}
value={emailSetup}
onValueChange={setEmailSetup}
value={oldEmail}
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
size="lg"
className="w-fit bg-[#DD8306] rounded-md font-semibold my-3 text-white"
onPress={submitResetEmail}
onPress={submitCheckEmail}
>
Submit
</Button>
@ -318,7 +343,7 @@ export default function Login() {
) : needOtp ? (
<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">
Login
Submit OTP
</p>
<p className="my-2 text-white">OTP</p>
<InputOtp length={6} value={otpValue} onValueChange={setOtpValue} />

View File

@ -28,6 +28,7 @@ export default function HeaderNews() {
const t = useTranslations("Landing");
const [selectedTab, setSelectedTab] = useState("media");
const [hotNews, setHotNews] = useState<any>([]);
const [banner, setBanner] = useState<any>([]);
// useEffect(() => {
@ -35,7 +36,7 @@ export default function HeaderNews() {
useEffect(() => {
getArticle();
getBanner();
getHotNews();
}, []);
@ -50,6 +51,18 @@ export default function HeaderNews() {
const response = await getListArticle(req);
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() {
const req = {
@ -69,7 +82,7 @@ export default function HeaderNews() {
<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="lg:hidden w-[90%] h-[300px] md:h-[500px] mx-auto">
{article ? (
{banner ? (
<Swiper
centeredSlides={true}
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}>
<Card
radius="lg"
@ -199,7 +212,7 @@ export default function HeaderNews() {
</div>
<div className="hidden lg:flex w-full lg:w-[50%] h-[500px]">
{article ? (
{banner ? (
<Swiper
centeredSlides={true}
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]">
<Card
isFooterBlurred

View File

@ -2,8 +2,10 @@
import React, { Component, useEffect, useState } from "react";
import ReactApexChart from "react-apexcharts";
import dummyData from "../../../../const/dummy.json";
import { getStatisticMonthly } from "@/service/article";
import { get } from "http";
import {
getStatisticMonthly,
getStatisticMonthlyFeedback,
} from "@/service/article";
type WeekData = {
week: number;
@ -89,11 +91,13 @@ const SuggestionsChart = (props: {
const initFetch = async () => {
const splitDate = date.split(" ");
// const res = await getStatisticMonthly(splitDate[1]);
// const data = res?.data?.data;
const data = dummyData.data;
const res = await getStatisticMonthlyFeedback(splitDate[1]);
const data = res?.data?.data;
// const data = dummyData.data;
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);
if (getDatas) {
@ -112,7 +116,10 @@ const SuggestionsChart = (props: {
);
if (getDatas) {
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);
if (type == "weekly") {
setSeriesSuggestions(

View File

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

View File

@ -13,6 +13,7 @@ import {
deleteArticle,
getArticleByCategory,
getListArticle,
updateIsBannerArticle,
} from "@/service/article";
import { Article } from "@/types/globals";
import { convertDateFormat } from "@/utils/global";
@ -168,7 +169,12 @@ export default function ArticleTable() {
};
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) => {
@ -259,7 +265,7 @@ export default function ArticleTable() {
<DropdownItem
key="setBanner"
onPress={() =>
handleBanner(article?.id, !article?.isBanner || true)
handleBanner(article?.id, !article?.isBanner)
}
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";
const token = Cookies.get("access_token");
@ -11,6 +16,13 @@ export async function createAdvertise(data: any) {
const pathUrl = `/advertisement`;
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) {
const headers = {
@ -37,3 +49,19 @@ export async function editAdvertise(data: any) {
const pathUrl = `/advertisement/${data?.id}`;
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,
} from "./http-config/axios-base-service";
import Cookies from "js-cookie";
import { stat } from "fs";
const token = Cookies.get("access_token");
export async function getListArticle(props: PaginationRequest) {
@ -20,6 +21,7 @@ export async function getListArticle(props: PaginationRequest) {
sortBy,
sort,
categorySlug,
isBanner,
} = props;
const headers = {
"content-type": "application/json",
@ -31,7 +33,7 @@ export async function getListArticle(props: PaginationRequest) {
endDate || ""
}&categoryId=${category || ""}&sortBy=${sortBy || "created_at"}&sort=${
sort || "asc"
}&category=${categorySlug || ""}`,
}&category=${categorySlug || ""}&isBanner=${isBanner || ""}`,
headers
);
}
@ -148,6 +150,13 @@ export async function getStatisticMonthly(year: string) {
};
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() {
const headers = {
"content-type": "application/json",
@ -167,3 +176,11 @@ export async function submitApproval(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`;
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) {
const headers = {
@ -103,6 +117,12 @@ export async function otpValidation(email: string, otpCode: string) {
};
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) {
const headers = token

View File

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