feat:filter date top article dashboar, create magazine category

This commit is contained in:
Rama Priyanto 2025-06-03 14:58:43 +07:00
parent 70ac77dba4
commit dbb2fbb464
2 changed files with 154 additions and 26 deletions

View File

@ -81,6 +81,9 @@ const createArticleSchema = z.object({
}), }),
}) })
), ),
category: z.array(categorySchema).nonempty({
message: "Kategori harus memiliki setidaknya satu item",
}),
}); });
export default function NewCreateMagazineForm() { export default function NewCreateMagazineForm() {
@ -90,6 +93,30 @@ export default function NewCreateMagazineForm() {
const editor = useRef(null); const editor = useRef(null);
const [files, setFiles] = useState<FileWithPreview[]>([]); const [files, setFiles] = useState<FileWithPreview[]>([]);
const [thumbnailImg, setThumbnailImg] = useState<File[]>([]); const [thumbnailImg, setThumbnailImg] = useState<File[]>([]);
const [listCategory, setListCategory] = useState<CategoryType[]>([]);
useEffect(() => {
fetchCategory();
}, []);
const fetchCategory = async () => {
const res = await getArticleByCategory();
if (res?.data?.data) {
setupCategory(res?.data?.data);
}
};
const setupCategory = (data: any) => {
const temp = [];
for (const element of data) {
temp.push({
id: element.id,
label: element.title,
value: element.id,
});
}
setListCategory(temp);
};
const { getRootProps, getInputProps } = useDropzone({ const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => { onDrop: (acceptedFiles) => {
@ -153,6 +180,8 @@ export default function NewCreateMagazineForm() {
typeId: 1, typeId: 1,
slug: values.slug, slug: values.slug,
statusId: 1, statusId: 1,
categoryIds: values.category.map((a) => a.id).join(","),
// description: htmlToString(removeImgTags(values.description)), // description: htmlToString(removeImgTags(values.description)),
description: values.description, description: values.description,
// rows: values.rows, // rows: values.rows,
@ -385,6 +414,37 @@ export default function NewCreateMagazineForm() {
{errors?.slug && ( {errors?.slug && (
<p className="text-red-400 text-sm mb-3">{errors.slug?.message}</p> <p className="text-red-400 text-sm mb-3">{errors.slug?.message}</p>
)} )}
<p className="text-sm mt-3">Kategori</p>
<Controller
control={control}
name="category"
render={({ field: { onChange, value } }) => (
<ReactSelect
className="basic-single text-black z-50"
classNames={{
control: (state: any) =>
"!rounded-lg bg-white !border-1 !border-gray-200 dark:!border-stone-500",
}}
classNamePrefix="select"
onChange={onChange}
closeMenuOnSelect={false}
components={animatedComponents}
isClearable={true}
isSearchable={true}
isMulti={true}
placeholder="Kategori..."
name="sub-module"
options={listCategory}
/>
)}
/>
{errors?.category && (
<p className="text-red-400 text-sm mb-3">
{errors.category?.message}
</p>
)}
<p className="text-sm mt-3">Thumbnail</p> <p className="text-sm mt-3">Thumbnail</p>
{thumbnailImg.length > 0 ? ( {thumbnailImg.length > 0 ? (

View File

@ -89,6 +89,15 @@ export default function DashboardContainer() {
endDate: parseDate(convertDateFormatNoTimeV2(new Date())), endDate: parseDate(convertDateFormatNoTimeV2(new Date())),
}); });
const [topContentDate, setTopContentDate] = useState({
startDate: parseDate(
convertDateFormatNoTimeV2(
new Date(new Date().setDate(new Date().getDate() - 7))
)
),
endDate: parseDate(convertDateFormatNoTimeV2(new Date())),
});
const [typeDate, setTypeDate] = useState("monthly"); const [typeDate, setTypeDate] = useState("monthly");
const [summary, setSummary] = useState<any>(); const [summary, setSummary] = useState<any>();
@ -122,7 +131,17 @@ export default function DashboardContainer() {
useEffect(() => { useEffect(() => {
fetchTopPages(); fetchTopPages();
}, [topPagespage]); }, [topPagespage, topContentDate]);
const getDate = (data: any) => {
if (data === null) {
return "";
} else {
return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${
data.day < 10 ? `0${data.day}` : data.day
}`;
}
};
async function fetchTopPages() { async function fetchTopPages() {
const req = { const req = {
@ -130,6 +149,8 @@ export default function DashboardContainer() {
page: topPagespage, page: topPagespage,
search: "", search: "",
sort: "desc", sort: "desc",
startDate: getDate(topContentDate.startDate),
endDate: getDate(topContentDate.endDate),
}; };
const res = await getTopArticles(req); const res = await getTopArticles(req);
setTopPages(getTableNumber(10, res.data?.data)); setTopPages(getTableNumber(10, res.data?.data));
@ -139,6 +160,7 @@ export default function DashboardContainer() {
useEffect(() => { useEffect(() => {
fetchPostCount(); fetchPostCount();
}, [postContentDate]); }, [postContentDate]);
async function fetchPostCount() { async function fetchPostCount() {
const getDate = (data: any) => { const getDate = (data: any) => {
return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${ return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${
@ -432,14 +454,6 @@ export default function DashboardContainer() {
Mingguan Mingguan
</Button> </Button>
<div className="w-[140px]"> <div className="w-[140px]">
{/* <Datepicker
value={startDateValue}
displayFormat="DD/MM/YYYY"
asSingle={true}
useRange={false}
onChange={(e: any) => setStartDateValue(e)}
inputClassName="z-50 w-full text-xs lg:text-sm bg-transparent border-1 border-gray-200 px-2 py-[6px] rounded-sm lg:rounded-lg h-[30px] lg:h-[40px] text-gray-600 dark:text-gray-300"
/> */}
<Popover <Popover
placement="bottom" placement="bottom"
classNames={{ content: ["!bg-transparent", "p-0"] }} classNames={{ content: ["!bg-transparent", "p-0"] }}
@ -472,12 +486,64 @@ export default function DashboardContainer() {
<div className="flex flex-col w-full lg:w-[45%] gap-6 shadow-md bg-white dark:bg-[#18181b] rounded-lg p-8 text-xs lg:text-sm"> <div className="flex flex-col w-full lg:w-[45%] gap-6 shadow-md bg-white dark:bg-[#18181b] rounded-lg p-8 text-xs lg:text-sm">
<div className="flex justify-between font-semibold"> <div className="flex justify-between font-semibold">
<p>Top Pages</p> <p>Top Pages</p>
<div className="w-[220px] flex flex-row gap-2 justify-between font-semibold">
<Popover
placement="bottom"
classNames={{ content: ["!bg-transparent", "p-0"] }}
>
<PopoverTrigger>
<a className="cursor-pointer">
{convertDateFormatNoTime(topContentDate.startDate)}
</a>
</PopoverTrigger>
<PopoverContent className="bg-transparent">
<Calendar
value={topContentDate.startDate}
onChange={(e) =>
setTopContentDate({
startDate: e,
endDate: topContentDate.endDate,
})
}
maxValue={topContentDate.endDate}
/>
</PopoverContent>
</Popover>
-
<Popover
placement="bottom"
classNames={{ content: ["!bg-transparent", "p-0"] }}
>
<PopoverTrigger>
<a className="cursor-pointer ">
{convertDateFormatNoTime(topContentDate.endDate)}
</a>
</PopoverTrigger>
<PopoverContent className="bg-transparent">
<Calendar
value={topContentDate.endDate}
onChange={(e) =>
setTopContentDate({
startDate: topContentDate.startDate,
endDate: e,
})
}
minValue={topContentDate.startDate}
/>
</PopoverContent>
</Popover>
</div>
</div> </div>
<div className="flex flex-row border-b-1"> <div className="flex flex-row border-b-1">
<div className="w-[5%]">No</div> <div className="w-[5%]">No</div>
<div className="w-[85%]">Title</div> <div className="w-[85%]">Title</div>
<div className="w-[10%] text-center">Visits</div> <div className="w-[10%] text-center">Visits</div>
</div> </div>
{(!topPages || topPages?.length < 1) && (
<div className="flex justify-center items-center">
Tidak ada Data
</div>
)}
{topPages?.map((list) => ( {topPages?.map((list) => (
<div key={list.id} className="flex flex-row border-b-1"> <div key={list.id} className="flex flex-row border-b-1">
<div className="w-[5%]">{list?.no}</div> <div className="w-[5%]">{list?.no}</div>
@ -485,23 +551,25 @@ export default function DashboardContainer() {
<div className="w-[10%] text-center">{list?.viewCount}</div> <div className="w-[10%] text-center">{list?.viewCount}</div>
</div> </div>
))} ))}
<div className="my-2 w-full flex justify-center"> {topPages?.length > 0 && (
<Pagination <div className="my-2 w-full flex justify-center">
isCompact <Pagination
showControls isCompact
showShadow showControls
color="primary" showShadow
classNames={{ color="primary"
base: "bg-transparent", classNames={{
wrapper: "bg-transparent", base: "bg-transparent",
item: "w-fit px-3", wrapper: "bg-transparent",
cursor: "w-fit px-3", item: "w-fit px-3",
}} cursor: "w-fit px-3",
page={topPagespage} }}
total={topPagesTotalPage} page={topPagespage}
onChange={(page) => setTopPagesPage(page)} total={topPagesTotalPage}
/> onChange={(page) => setTopPagesPage(page)}
</div> />
</div>
)}
</div> </div>
</div> </div>
</div> </div>