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