diff --git a/app/(admin)/admin/advertise/page.tsx b/app/(admin)/admin/advertise/page.tsx index d943c07..22fbde8 100644 --- a/app/(admin)/admin/advertise/page.tsx +++ b/app/(admin)/admin/advertise/page.tsx @@ -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() { diff --git a/components/form/login.tsx b/components/form/login.tsx index b56843f..c062ee1 100644 --- a/components/form/login.tsx +++ b/components/form/login.tsx @@ -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(); const [profile, setProfile] = useState(); - 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() {

Setting Account

-

Email

+

Email Lama

+

Email Baru

+ - Validasi Email @@ -318,7 +343,7 @@ export default function Login() { ) : needOtp ? (

- Login + Submit OTP

OTP

diff --git a/components/landing/HeaderNews.tsx b/components/landing/HeaderNews.tsx index e0a345f..1132afb 100644 --- a/components/landing/HeaderNews.tsx +++ b/components/landing/HeaderNews.tsx @@ -28,6 +28,7 @@ export default function HeaderNews() { const t = useTranslations("Landing"); const [selectedTab, setSelectedTab] = useState("media"); const [hotNews, setHotNews] = useState([]); + const [banner, setBanner] = useState([]); // 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() {
- {article ? ( + {banner ? ( - {article?.map((newsItem: any, index: number) => ( + {banner?.map((newsItem: any, index: number) => (
- {article ? ( + {banner ? ( - {article?.map((newsItem: any, index: number) => ( + {banner?.map((newsItem: any, index: number) => ( { 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( diff --git a/components/table/advertise/advertise-table.tsx b/components/table/advertise/advertise-table.tsx index 0c08e91..ff5e1d4 100644 --- a/components/table/advertise/advertise-table.tsx +++ b/components/table/advertise/advertise-table.tsx @@ -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

{cellValue}

; + case "isActive": + return ( +
+ handleAdvertise(e, advertise?.id)} + /> + {advertise?.isActive ? "Ya" : "Tidak"} +
+ ); case "actions": return (
@@ -278,7 +300,7 @@ export default function AdvertiseTable(props: { triggerRefresh: boolean }) { handleDelete(article.id)} + onPress={() => handleDelete(advertise.id)} > { - 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() { - handleBanner(article?.id, !article?.isBanner || true) + handleBanner(article?.id, !article?.isBanner) } className={username === "admin-mabes" ? "" : "hidden"} > diff --git a/service/advertisement.ts b/service/advertisement.ts index 0669a81..7ade999 100644 --- a/service/advertisement.ts +++ b/service/advertisement.ts @@ -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); +} diff --git a/service/article.ts b/service/article.ts index e966da4..d2aa217 100644 --- a/service/article.ts +++ b/service/article.ts @@ -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); +} diff --git a/service/master-user.ts b/service/master-user.ts index 925f7e0..c867242 100644 --- a/service/master-user.ts +++ b/service/master-user.ts @@ -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 diff --git a/types/globals.tsx b/types/globals.tsx index 9b5dff5..ec13d3e 100644 --- a/types/globals.tsx +++ b/types/globals.tsx @@ -66,4 +66,5 @@ export type PaginationRequest = { sortBy?: string; sort?: string; categorySlug?: string; + isBanner?: boolean; };