From 4c807a7fee47026dcd90dd612844d541b66b8465 Mon Sep 17 00:00:00 2001 From: Rama Priyanto Date: Thu, 29 Jan 2026 19:00:18 +0700 Subject: [PATCH] fix:filter use query urt --- components/main/detail/list-news.tsx | 12 +- components/table/article-table.tsx | 189 ++++++++++++++++++++++----- services/article.ts | 2 +- 3 files changed, 155 insertions(+), 48 deletions(-) diff --git a/components/main/detail/list-news.tsx b/components/main/detail/list-news.tsx index 62d5466..80fcf10 100644 --- a/components/main/detail/list-news.tsx +++ b/components/main/detail/list-news.tsx @@ -110,18 +110,15 @@ export default function ListNews() { const getPoldaCategId = async () => { const poldaNow = category as string; - console.log("poldanow", poldaNow.split("-").join(" ")); const dataNow = await getCategory(poldaNow.split("-").join(" ")); - console.log("datanow", dataNow); if (dataNow?.length > 0) { const poldaObj = dataNow[0]; setPoldaCategId(poldaObj.id); - const option = setupCategory([poldaObj])[0]; // <-- wajib array + const option = setupCategory([poldaObj])[0]; setPoldaCategoryOption(option); - // pastikan masuk ke selectedCategoryId (kalau belum ada) setSelectedCategoryId((prev: any[]) => { const already = prev.some((x) => x.id === option.id); if (already) return prev; @@ -137,7 +134,6 @@ export default function ListNews() { const yearQ = searchParams.get("year"); const pageQ = searchParams.get("page"); - // sync UI state dari URL setSearchValue(search); if (pageQ) setPage(Number(pageQ)); @@ -210,20 +206,17 @@ export default function ListNews() { const usedPage = props?.page || page; const usedSearch = props?.title ?? searchValue ?? ""; - // 1) ambil kategori dari props atau state const baseCategories = props?.category && props.category.length > 0 ? props.category : selectedCategoryId; - // 2) kalau halaman polda, pastikan poldaCategId selalu ikut let finalCategories = baseCategories; if (isPoldaPage && poldaCategId) { const hasPolda = baseCategories.some((x: any) => x.id === poldaCategId); if (!hasPolda) { - // polda wajib selalu ada finalCategories = [ ...(poldaCategoryOption ? [poldaCategoryOption] : []), ...baseCategories, @@ -380,20 +373,17 @@ export default function ListNews() { onChange={(val: any) => { const nextValue = val || []; - // kalau bukan halaman polda, normal if (!pathname.includes("/news/polda/")) { setSelectedCategoryId(nextValue); return; } - // halaman polda: kategori polda harus tetap ada if (poldaCategoryOption) { const hasPolda = nextValue.some( (x: any) => x.id === poldaCategoryOption.id, ); if (!hasPolda) { - // user mencoba hapus kategori polda -> balikin lagi setSelectedCategoryId([poldaCategoryOption, ...nextValue]); return; } diff --git a/components/table/article-table.tsx b/components/table/article-table.tsx index 2621460..4758559 100644 --- a/components/table/article-table.tsx +++ b/components/table/article-table.tsx @@ -61,6 +61,7 @@ import { parseDate } from "@internationalized/date"; import { listMasterUsers } from "@/services/master-user"; import ReactSelect from "react-select"; import makeAnimated from "react-select/animated"; +import { useRouter, useSearchParams } from "next/navigation"; const columns = [ { name: "No", uid: "no" }, @@ -100,11 +101,14 @@ export default function ArticleTable() { const animatedComponents = makeAnimated(); const roleId = getCookiesDecrypt("urie"); - const [page, setPage] = useState(1); + const router = useRouter(); + const searchParams = useSearchParams(); + + const [page, setPage] = useState(Number(searchParams.get("page")) || 1); const [totalPage, setTotalPage] = useState(1); const [article, setArticle] = useState([]); - const [showData, setShowData] = useState("10"); - const [search, setSearch] = useState(""); + const [showData, setShowData] = useState(searchParams.get("limit") || "10"); + const [search, setSearch] = useState(searchParams.get("search") || ""); const [categories, setCategories] = useState([]); const [users, setUsers] = useState([]); const [selectedCategories, setSelectedCategories] = useState([]); @@ -116,36 +120,92 @@ export default function ArticleTable() { const [selectedArticles, setSelectedArticles] = useState(new Set([])); + // const [articleDate, setArticleDate] = useState({ + // startDate: parseDate( + // convertDateFormatNoTimeV2( + // new Date(new Date().setDate(new Date().getDate() - 7)), + // ), + // ), + // endDate: parseDate(convertDateFormatNoTimeV2(new Date())), + // }); const [articleDate, setArticleDate] = useState({ - startDate: parseDate( - convertDateFormatNoTimeV2( - new Date(new Date().setDate(new Date().getDate() - 7)) - ) - ), - endDate: parseDate(convertDateFormatNoTimeV2(new Date())), + startDate: searchParams.get("startDate") + ? parseDate(searchParams.get("startDate")!) + : null, + endDate: searchParams.get("endDate") + ? parseDate(searchParams.get("endDate")!) + : null, }); - - useEffect(() => { - initState(); - }, [page, showData]); - - useEffect(() => { - if (page == 1) { - initState(); - } else { - setPage(1); - } - }, [selectedCategories, selectedUsers, articleDate, startDateValue]); - useEffect(() => { getCategories(); getUsers(); }, []); + useEffect(() => { + initState(); + }, [searchParams]); + + const updateQuery = (params: Record) => { + const current = new URLSearchParams(searchParams.toString()); + + Object.entries(params).forEach(([key, value]) => { + if ( + value === undefined || + value === null || + value === "" || + (Array.isArray(value) && value.length === 0) + ) { + current.delete(key); + } else { + current.set(key, String(value)); + } + }); + + current.set("timeStamp", String(getUnixTimestamp())); + + router.push(`?${current.toString()}`); + }; + const setupList = (data: any, type: string) => { const temp = []; + const categoryIds = searchParams.get("categoryIds") || ""; + const createdByIds = searchParams.get("createdByIds") || ""; + let tempCateg: number[] = []; + let tempCreated: number[] = []; + + const selectedCat: any[] = []; + const selectedUsr: any[] = []; + + if (categoryIds && categoryIds !== "") { + tempCateg = categoryIds + .split(",") + .map((id) => Number(id)) + .filter((id) => !isNaN(id)); + } + + if (createdByIds && createdByIds !== "") { + tempCreated = createdByIds + .split(",") + .map((id) => Number(id)) + .filter((id) => !isNaN(id)); + } + if (data) { for (const element of data) { + if (type === "category" && tempCateg.includes(element.id)) { + selectedCat.push({ + id: element.id, + label: element.title, + value: element.id, + }); + } + if (type === "users" && tempCreated.includes(element.id)) { + selectedUsr.push({ + id: element.id, + label: element.fullname, + value: element.id, + }); + } temp.push({ id: element.id, label: element.title || element.fullname, @@ -154,10 +214,12 @@ export default function ArticleTable() { } if (type === "users") { setUsers(temp); + setSelectedUsers(selectedUsr); } if (type === "category") { setCategories(temp); + setSelectedCategories(selectedCat); } } }; @@ -208,16 +270,16 @@ export default function ArticleTable() { async function initState() { loading(); const req = { - limit: showData, - page: page, - search: search, - startDate: getDate(articleDate.startDate), - endDate: getDate(articleDate.endDate), - categoryIds: getIds(selectedCategories), - createdByIds: getIds(selectedUsers), + limit: searchParams.get("limit") || showData, + page: Number(searchParams.get("page")) || "", + search: searchParams.get("search") || "", + startDate: searchParams.get("startDate") || "", + endDate: searchParams.get("endDate") || "", + categoryIds: searchParams.get("categoryIds") || "", + createdByIds: searchParams.get("createdByIds") || "", sort: "desc", sortBy: "created_at", - timeStamp: getUnixTimestamp(), + timeStamp: searchParams.get("timeStamp") || getUnixTimestamp(), }; const res = await getListArticleAdminPage(req); await getTableNumber(parseInt(showData), res.data?.data); @@ -467,7 +529,7 @@ export default function ArticleTable() { return cellValue; } }, - [article, page, selectedArticles] + [article, page, selectedArticles], ); let typingTimer: NodeJS.Timeout; @@ -487,6 +549,19 @@ export default function ArticleTable() { initState(); } + const handleApplyFilter = () => { + setPage(1); + updateQuery({ + page: 1, + limit: showData, + search, + categoryIds: getIds(selectedCategories), + createdByIds: getIds(selectedUsers), + startDate: getDate(articleDate.startDate), + endDate: getDate(articleDate.endDate), + }); + }; + const [hasMounted, setHasMounted] = useState(false); useEffect(() => { @@ -507,16 +582,17 @@ export default function ArticleTable() { aria-label="Search" classNames={{ inputWrapper: "bg-default-100", - input: "text-sm", + input: "text-sm outline-none", }} labelPlacement="outside" startContent={ } type="text" + value={search} onChange={(e) => setSearch(e.target.value)} - onKeyUp={handleKeyUp} - onKeyDown={handleKeyDown} + // onKeyUp={handleKeyUp} + // onKeyDown={handleKeyDown} />
@@ -554,6 +630,7 @@ export default function ArticleTable() { isClearable={true} isSearchable={true} isMulti={true} + value={selectedCategories} placeholder="Kategori..." name="sub-module" options={categories} @@ -564,7 +641,7 @@ export default function ArticleTable() {

Author

"!rounded-lg bg-white !border-1 !border-gray-200 dark:!border-stone-500", @@ -572,6 +649,7 @@ export default function ArticleTable() { classNamePrefix="select" onChange={setSelectedUsers} closeMenuOnSelect={false} + value={selectedUsers} components={animatedComponents} isClearable={true} isSearchable={true} @@ -666,6 +744,42 @@ export default function ArticleTable() {
+
+

Filter

+
+ + +
+
setPage(page)} + onChange={(p) => { + setPage(p); + updateQuery({ page: p }); + }} /> diff --git a/services/article.ts b/services/article.ts index ed7be60..22a29fe 100644 --- a/services/article.ts +++ b/services/article.ts @@ -43,7 +43,7 @@ export async function getListArticle(props: PaginationRequest) { ); } -export async function getListArticleAdminPage(props: PaginationRequest) { +export async function getListArticleAdminPage(props: any) { const { page, limit,