fix:category landing
This commit is contained in:
parent
af5b8000cd
commit
70ac77dba4
|
|
@ -29,7 +29,7 @@ import {
|
|||
UserIcon,
|
||||
} from "../../icons";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
getArticleByCategoryLanding,
|
||||
getListArticle,
|
||||
|
|
@ -49,6 +49,7 @@ import {
|
|||
import { close, loading } from "@/config/swal";
|
||||
import { format } from "date-fns";
|
||||
import { getCategoryById } from "@/services/master-categories";
|
||||
import AsyncSelect from "react-select/async";
|
||||
|
||||
const months = [
|
||||
"Jan",
|
||||
|
|
@ -81,12 +82,7 @@ export default function ListNews() {
|
|||
searchParams.get("search") || ""
|
||||
);
|
||||
const [categorySearch, setCategorySearch] = useState("");
|
||||
const [debouncedValue, setDebouncedValue] = useState("");
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<any>(
|
||||
categoryIds ? categoryIds : ""
|
||||
);
|
||||
|
||||
const [count, setCount] = useState(0);
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<any>([]);
|
||||
|
||||
const today = new Date();
|
||||
const [year, setYear] = useState(today.getFullYear());
|
||||
|
|
@ -101,42 +97,43 @@ export default function ListNews() {
|
|||
setSelectedDate(new Date(year, monthIndex, 1));
|
||||
};
|
||||
|
||||
const getCategoryId = async () => {
|
||||
if (categoryIds) {
|
||||
const res = await getCategoryById(Number(selectedCategoryId));
|
||||
setCategorySearch(res?.data?.data.title);
|
||||
setCategories([res?.data?.data]);
|
||||
setCount(1);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getCategory();
|
||||
if (categoryIds && count == 0) {
|
||||
getCategoryId();
|
||||
const search = searchParams.get("search");
|
||||
const category = searchParams.get("category_id");
|
||||
if (searchParams.get("search")) {
|
||||
setSearchValue(String(searchParams.get("search")));
|
||||
getArticle({ title: String(search) });
|
||||
}
|
||||
}, [debouncedValue]);
|
||||
|
||||
if (category && category !== "") {
|
||||
getCategoryFromQueries(category.split(","));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
const getCategoryFromQueries = async (category: string[]) => {
|
||||
const temp = [];
|
||||
for (const element of category) {
|
||||
const res = await getCategoryById(Number(element));
|
||||
if (res?.data?.data) {
|
||||
temp.push(res?.data?.data);
|
||||
}
|
||||
}
|
||||
|
||||
const setup = setupCategory(temp);
|
||||
setSelectedCategoryId(setup);
|
||||
getArticle({ category: setup });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getArticle();
|
||||
}, [page]);
|
||||
}, [page, searchParams]);
|
||||
|
||||
const getCategory = async () => {
|
||||
const res = await getArticleByCategoryLanding({
|
||||
limit: debouncedValue === "" ? "5" : "",
|
||||
title: debouncedValue,
|
||||
});
|
||||
if (res?.data?.data) {
|
||||
setCategories(res?.data?.data);
|
||||
}
|
||||
};
|
||||
|
||||
async function getArticle() {
|
||||
async function getArticle(props?: { title?: string; category?: any }) {
|
||||
loading();
|
||||
// topRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
const req = {
|
||||
page: page,
|
||||
search: searchValue || "",
|
||||
search: props?.title || searchValue || "",
|
||||
limit: "9",
|
||||
isPublish: true,
|
||||
sort: "desc",
|
||||
|
|
@ -144,9 +141,12 @@ export default function ListNews() {
|
|||
pathname.includes("polda") || pathname.includes("satker")
|
||||
? String(category)
|
||||
: "",
|
||||
categoryIds: selectedCategoryId,
|
||||
// categoryIds:
|
||||
// selectedCategoryId && categorySearch !== "" ? selectedCategoryId : "",
|
||||
categoryIds: props?.category
|
||||
? props.category.map((val: any) => val.id).join(",")
|
||||
: selectedCategoryId.length > 0
|
||||
? selectedCategoryId.map((val: any) => val.id).join(",")
|
||||
: "",
|
||||
|
||||
startDate:
|
||||
selectedDate && selectedMonth !== null
|
||||
? convertDateFormatNoTimeV2(new Date(year, selectedMonth, 1))
|
||||
|
|
@ -162,21 +162,52 @@ export default function ListNews() {
|
|||
close();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
setDebouncedValue(categorySearch);
|
||||
}, 1500);
|
||||
const debounceTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [categorySearch]);
|
||||
|
||||
const onInputChange = (value: string) => {
|
||||
setCategorySearch(value);
|
||||
if (value === "") {
|
||||
setSelectedCategoryId("");
|
||||
const getCategory = async (search?: string) => {
|
||||
const res = await getArticleByCategoryLanding({
|
||||
// limit: debouncedValue === "" ? "5" : "",
|
||||
// title: debouncedValue,
|
||||
limit: !search || search === "" ? "5" : "",
|
||||
title: search ? search : "",
|
||||
});
|
||||
if (res?.data?.data) {
|
||||
setCategories(res?.data?.data);
|
||||
return res?.data?.data;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const setupCategory = (data: any) => {
|
||||
const temp = [];
|
||||
for (const element of data) {
|
||||
temp.push({
|
||||
id: element.id,
|
||||
label: element.title,
|
||||
value: element.id,
|
||||
});
|
||||
}
|
||||
return temp;
|
||||
};
|
||||
|
||||
const loadOptions = useCallback(
|
||||
(inputValue: string, callback: (options: any) => void) => {
|
||||
if (debounceTimeout.current) {
|
||||
clearTimeout(debounceTimeout.current);
|
||||
}
|
||||
|
||||
debounceTimeout.current = setTimeout(async () => {
|
||||
try {
|
||||
const data = await getCategory(inputValue);
|
||||
callback(setupCategory(data));
|
||||
} catch (error) {
|
||||
callback([]);
|
||||
}
|
||||
}, 1500);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="bg-white border-b-1" ref={topRef}>
|
||||
<div className="text-black py-5 px-3 lg:w-[75vw] mx-auto bg-white">
|
||||
|
|
@ -187,118 +218,104 @@ export default function ListNews() {
|
|||
<ChevronRightIcon />
|
||||
<p className="text-black">Berita</p>
|
||||
</div>
|
||||
<div className="py-5 lg:py-10 lg:px-10 flex flex-col lg:flex-row gap-2 items-end">
|
||||
<Input
|
||||
aria-label="Judul"
|
||||
className="w-full"
|
||||
classNames={{
|
||||
inputWrapper: "bg-white hover:!bg-gray-100 border-1",
|
||||
input: "text-sm !text-black",
|
||||
}}
|
||||
// onKeyDown={(event) => {
|
||||
// if (event.key === "Enter") {
|
||||
// router.push(pathname + `?search=${searchValue}`);
|
||||
// getArticle();
|
||||
// }
|
||||
// }}
|
||||
labelPlacement="outside"
|
||||
placeholder="Judul..."
|
||||
value={searchValue}
|
||||
onValueChange={setSearchValue}
|
||||
type="search"
|
||||
/>
|
||||
<div className="flex w-full lg:w-fit gap-4">
|
||||
<Autocomplete
|
||||
className="w-full lg:w-[240px] mt-0"
|
||||
label=""
|
||||
<div className="w-full flex justify-center">
|
||||
<div className="py-5 lg:py-10 lg:mx-auto flex flex-col lg:flex-row gap-2 items-end grow-0 mx-auto">
|
||||
<Input
|
||||
aria-label="Judul"
|
||||
className="w-full lg:w-[300px]"
|
||||
classNames={{
|
||||
inputWrapper: "bg-white hover:!bg-gray-100 border-1 rounded-md",
|
||||
input: "text-sm !text-black",
|
||||
}}
|
||||
// onKeyDown={(event) => {
|
||||
// if (event.key === "Enter") {
|
||||
// router.push(pathname + `?search=${searchValue}`);
|
||||
// getArticle();
|
||||
// }
|
||||
// }}
|
||||
labelPlacement="outside"
|
||||
variant="bordered"
|
||||
placeholder="Judul..."
|
||||
value={searchValue}
|
||||
onValueChange={setSearchValue}
|
||||
type="search"
|
||||
/>
|
||||
<AsyncSelect
|
||||
isMulti
|
||||
loadOptions={loadOptions}
|
||||
defaultOptions
|
||||
placeholder="Kategori"
|
||||
inputValue={categorySearch}
|
||||
// selectedKey={selectedCategoryId}
|
||||
onInputChange={onInputChange}
|
||||
onSelectionChange={(e) => setSelectedCategoryId(e)}
|
||||
inputProps={{ classNames: { inputWrapper: "border-1" } }}
|
||||
defaultItems={categories}
|
||||
>
|
||||
{/* {categories.length > 0 &&
|
||||
categories.map((category: any) => (
|
||||
<AutocompleteItem key={`${category.id}`}>
|
||||
{category.title}
|
||||
</AutocompleteItem>
|
||||
))} */}
|
||||
{(item: any) => (
|
||||
<AutocompleteItem key={item.id}>{item.title}</AutocompleteItem>
|
||||
)}
|
||||
</Autocomplete>
|
||||
</div>
|
||||
<div className="flex flex-row items-center border-1 h-[40px] w-full lg:w-[240px] rounded-xl px-2">
|
||||
<Popover placement="bottom" showArrow={true} className="w-full">
|
||||
<PopoverTrigger>
|
||||
<a className="px-2 py-1 text-sm w-[220px]">
|
||||
{" "}
|
||||
{selectedDate
|
||||
? format(selectedDate, "MMMM yyyy")
|
||||
: "Pilih Bulan"}
|
||||
</a>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-4 w-[220px]">
|
||||
<div className="flex items-center justify-between mb-2 px-1 w-full">
|
||||
<button
|
||||
className="text-gray-500 hover:text-black"
|
||||
onClick={() => setYear((prev) => prev - 1)}
|
||||
>
|
||||
<ChevronLeftIcon />
|
||||
</button>
|
||||
<span className="font-semibold text-center">{year}</span>
|
||||
<button
|
||||
className="text-gray-500 hover:text-black"
|
||||
onClick={() => setYear((prev) => prev + 1)}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-2 w-full">
|
||||
{months.map((month, idx) => (
|
||||
className="z-50 min-w-[300px] max-w-[600px]"
|
||||
classNames={{
|
||||
control: () =>
|
||||
"border border-gray-300 border-1 rounded-xl min-w-[300px] max-w-[600px]",
|
||||
menu: () => "z-50",
|
||||
}}
|
||||
value={selectedCategoryId}
|
||||
onChange={setSelectedCategoryId}
|
||||
/>
|
||||
<div className="flex flex-row items-center border-1 h-[40px] w-full lg:w-[200px] rounded-md px-2">
|
||||
<Popover placement="bottom" showArrow={true} className="w-full">
|
||||
<PopoverTrigger>
|
||||
<a className="px-2 py-1 text-sm w-[220px]">
|
||||
{" "}
|
||||
{selectedDate
|
||||
? format(selectedDate, "MMMM yyyy")
|
||||
: "Pilih Bulan"}
|
||||
</a>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-4 w-[200px]">
|
||||
<div className="flex items-center justify-between mb-2 px-1 w-full">
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => handleMonthClick(idx)}
|
||||
className={`py-1 rounded-md text-sm transition-colors ${
|
||||
selectedDate &&
|
||||
selectedDate.getMonth() === idx &&
|
||||
selectedDate.getFullYear() === year
|
||||
? "bg-blue-500 text-white"
|
||||
: "hover:bg-gray-200 text-gray-700"
|
||||
}`}
|
||||
className="text-gray-500 hover:text-black"
|
||||
onClick={() => setYear((prev) => prev - 1)}
|
||||
>
|
||||
{month}
|
||||
<ChevronLeftIcon />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>{" "}
|
||||
{selectedDate && (
|
||||
<a
|
||||
className="cursor-pointer w-[20px]"
|
||||
onClick={() => setSelectedDate(null)}
|
||||
>
|
||||
<TimesIcon size={20} />
|
||||
</a>
|
||||
)}
|
||||
<span className="font-semibold text-center">{year}</span>
|
||||
<button
|
||||
className="text-gray-500 hover:text-black"
|
||||
onClick={() => setYear((prev) => prev + 1)}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-2 w-full">
|
||||
{months.map((month, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => handleMonthClick(idx)}
|
||||
className={`py-1 rounded-md text-sm transition-colors ${
|
||||
selectedDate &&
|
||||
selectedDate.getMonth() === idx &&
|
||||
selectedDate.getFullYear() === year
|
||||
? "bg-blue-500 text-white"
|
||||
: "hover:bg-gray-200 text-gray-700"
|
||||
}`}
|
||||
>
|
||||
{month}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>{" "}
|
||||
{selectedDate && (
|
||||
<a
|
||||
className="cursor-pointer w-[20px]"
|
||||
onClick={() => setSelectedDate(null)}
|
||||
>
|
||||
<TimesIcon size={20} />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
onPress={() => getArticle()}
|
||||
className="bg-red-600 text-white w-[80px] rounded-md"
|
||||
>
|
||||
Cari
|
||||
</Button>
|
||||
{/* </Link> */}
|
||||
</div>
|
||||
{/* <Link
|
||||
href={`/news/all?search=${searchValue}&category_id=${
|
||||
selectedCategoryId || ""
|
||||
}&month=${selectedMonth && selectedDate ? selectedMonth + 1 : ""}`}
|
||||
> */}
|
||||
<Button
|
||||
onPress={getArticle}
|
||||
className="bg-red-600 text-white w-[80px]"
|
||||
>
|
||||
Cari
|
||||
</Button>
|
||||
{/* </Link> */}
|
||||
</div>
|
||||
{article?.length < 1 || !article ? (
|
||||
<div className="flex justify-center items-center">Tidak ada Data</div>
|
||||
|
|
|
|||
|
|
@ -260,7 +260,11 @@ export default function DetailNews(props: { data: any; listArticle: any }) {
|
|||
<p className="text-lg border-b-3 border-red-600 font-semibold">TAGS</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{data?.categories?.map((category: any) => (
|
||||
<Link href={""} key={category?.id} className="text-sm ">
|
||||
<Link
|
||||
href={`/news/all?category_id=${category?.id}`}
|
||||
key={category?.id}
|
||||
className="text-sm "
|
||||
>
|
||||
<Button className="bg-[#BE0106] text-white px-2 py-2 rounded-md ">
|
||||
{category?.title}
|
||||
</Button>
|
||||
|
|
@ -268,17 +272,20 @@ export default function DetailNews(props: { data: any; listArticle: any }) {
|
|||
))}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{data?.tags?.split(",").map((tag: any) => (
|
||||
<Link href={""} key={tag} className="text-xs">
|
||||
<Button
|
||||
className="border-[#BE0106] px-2 py-2 rounded-md "
|
||||
variant="bordered"
|
||||
size="sm"
|
||||
>
|
||||
{tag}
|
||||
</Button>
|
||||
</Link>
|
||||
))}
|
||||
{data?.tags?.split(",").map(
|
||||
(tag: any) =>
|
||||
tag !== "" && (
|
||||
<Link href={``} key={tag} className="text-xs">
|
||||
<Button
|
||||
className="border-[#BE0106] px-2 py-2 rounded-md "
|
||||
variant="bordered"
|
||||
size="sm"
|
||||
>
|
||||
{tag}
|
||||
</Button>
|
||||
</Link>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:flex lg:justify-between gap-2 lg:gap-10 my-8">
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ export default function RelatedNews(props: { categories: any }) {
|
|||
);
|
||||
}}
|
||||
>
|
||||
{article?.map((newsItem: any) => (
|
||||
<SwiperSlide key={newsItem.id}>
|
||||
{article?.map((newsItem: any, index: number) => (
|
||||
<SwiperSlide key={`${newsItem.id}-${index}`}>
|
||||
<Card isFooterBlurred radius="lg" className="border-none">
|
||||
<Image
|
||||
width={480}
|
||||
|
|
|
|||
Loading…
Reference in New Issue