309 lines
10 KiB
TypeScript
309 lines
10 KiB
TypeScript
"use client";
|
|
|
|
import { getVisitorLog } from "@/services/activity-log";
|
|
import {
|
|
convertDateFormat,
|
|
convertDateFormatNoTime,
|
|
convertDateFormatNoTimeV2,
|
|
} from "@/utils/global";
|
|
import {
|
|
Button,
|
|
Calendar,
|
|
Pagination,
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
Select,
|
|
SelectItem,
|
|
Spinner,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableColumn,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@heroui/react";
|
|
import { Key, useCallback, useEffect, useState } from "react";
|
|
import { parseDate } from "@internationalized/date";
|
|
import Link from "next/link";
|
|
|
|
const columns = [
|
|
{ name: "No", uid: "no" },
|
|
{ name: "Browser", uid: "browserName" },
|
|
{ name: "Date & Time ", uid: "createdAt" },
|
|
{ name: "IP Visitors", uid: "visitorIp" },
|
|
{ name: "URL", uid: "url" },
|
|
{ name: "City", uid: "visitorCity" },
|
|
{ name: "Region", uid: "visitorRegion" },
|
|
// { name: "Country", uid: "visitorCountry" },
|
|
];
|
|
|
|
const provinces = [
|
|
{ engName: "ACEH", inName: "ACEH" },
|
|
{ engName: "NORTH SUMATRA", inName: "SUMATERA UTARA" },
|
|
{ engName: "WEST SUMATRA", inName: "SUMATERA BARAT" },
|
|
{ engName: "RIAU", inName: "RIAU" },
|
|
{ engName: "JAMBI", inName: "JAMBI" },
|
|
{ engName: "SOUTH SUMATRA", inName: "SUMATERA SELATAN" },
|
|
{ engName: "BENGKULU", inName: "BENGKULU" },
|
|
{ engName: "LAMPUNG", inName: "LAMPUNG" },
|
|
{ engName: "BANGKA BELITUNG ISLANDS", inName: "KEPULAUAN BANGKA BELITUNG" },
|
|
{ engName: "RIAU ISLANDS", inName: "KEPULAUAN RIAU" },
|
|
{ engName: "JAKARTA", inName: "DKI JAKARTA" },
|
|
{ engName: "WEST JAVA", inName: "JAWA BARAT" },
|
|
{ engName: "CENTRAL JAVA", inName: "JAWA TENGAH" },
|
|
{ engName: "YOGYAKARTA", inName: "DI YOGYAKARTA" },
|
|
{ engName: "EAST JAVA", inName: "JAWA TIMUR" },
|
|
{ engName: "BANTEN", inName: "BANTEN" },
|
|
{ engName: "BALI", inName: "BALI" },
|
|
{ engName: "WEST NUSA TENGGARA", inName: "NUSA TENGGARA BARAT" },
|
|
{ engName: "EAST NUSA TENGGARA", inName: "NUSA TENGGARA TIMUR" },
|
|
{ engName: "WEST KALIMANTAN", inName: "KALIMANTAN BARAT" },
|
|
{ engName: "CENTRAL KALIMANTAN", inName: "KALIMANTAN TENGAH" },
|
|
{ engName: "SOUTH KALIMANTAN", inName: "KALIMANTAN SELATAN" },
|
|
{ engName: "EAST KALIMANTAN", inName: "KALIMANTAN TIMUR" },
|
|
{ engName: "NORTH KALIMANTAN", inName: "KALIMANTAN UTARA" },
|
|
{ engName: "NORTH SULAWESI", inName: "SULAWESI UTARA" },
|
|
{ engName: "CENTRAL SULAWESI", inName: "SULAWESI TENGAH" },
|
|
{ engName: "SOUTH SULAWESI", inName: "SULAWESI SELATAN" },
|
|
{ engName: "SOUTHEAST SULAWESI", inName: "SULAWESI TENGGARA" },
|
|
{ engName: "GORONTALO", inName: "GORONTALO" },
|
|
{ engName: "WEST SULAWESI", inName: "SULAWESI BARAT" },
|
|
{ engName: "MALUKU", inName: "MALUKU" },
|
|
{ engName: "NORTH MALUKU", inName: "MALUKU UTARA" },
|
|
{ engName: "PAPUA", inName: "PAPUA" },
|
|
{ engName: "WEST PAPUA", inName: "PAPUA BARAT" },
|
|
{ engName: "SOUTH PAPUA", inName: "PAPUA SELATAN" },
|
|
{ engName: "CENTRAL PAPUA", inName: "PAPUA TENGAH" },
|
|
{ engName: "HIGHLAND PAPUA", inName: "PAPUA PEGUNUNGAN" },
|
|
{ engName: "SOUTHWEST PAPUA", inName: "PAPUA BARAT DAYA" },
|
|
];
|
|
|
|
const findRegion = (name: string): string => {
|
|
const find = provinces.find((a) => a.engName === name);
|
|
return find ? find.inName : "";
|
|
};
|
|
export default function DashboardVisitorsTable() {
|
|
const [page, setPage] = useState(0);
|
|
const [totalPage, setTotalPage] = useState(1);
|
|
const [showData, setShowData] = useState("10");
|
|
const [tableVisitorData, setTableVisitorData] = useState<any>([]);
|
|
const [visitorBrowserDate, setVisitorBrowserDate] = useState<any>({
|
|
startDate: parseDate(
|
|
convertDateFormatNoTimeV2(
|
|
new Date(new Date().setDate(new Date().getDate() - 7))
|
|
)
|
|
),
|
|
endDate: parseDate(convertDateFormatNoTimeV2(new Date())),
|
|
});
|
|
useEffect(() => {
|
|
initFetch();
|
|
}, [
|
|
page,
|
|
visitorBrowserDate.startDate,
|
|
visitorBrowserDate.endDate,
|
|
showData,
|
|
]);
|
|
|
|
const initFetch = async () => {
|
|
const getDate = (data: any) => {
|
|
return `${data.year}-${data.month < 10 ? `0${data.month}` : data.month}-${
|
|
data.day < 10 ? `0${data.day}` : data.day
|
|
}`;
|
|
};
|
|
const res = await getVisitorLog({
|
|
page: page,
|
|
limit: showData,
|
|
startDate: getDate(visitorBrowserDate.startDate),
|
|
endDate: getDate(visitorBrowserDate.endDate),
|
|
});
|
|
console.log("resssss", res?.data?.data);
|
|
getTableNumber(Number(showData), res?.data?.data);
|
|
setTotalPage(res?.data?.meta?.totalPage);
|
|
};
|
|
|
|
const getTableNumber = (limit: number, data: any) => {
|
|
if (data) {
|
|
const startIndex = limit * page;
|
|
let iterate = 0;
|
|
const newData = data.map((value: any) => {
|
|
iterate++;
|
|
value.no = startIndex + iterate;
|
|
return value;
|
|
});
|
|
setTableVisitorData(newData);
|
|
} else {
|
|
setTableVisitorData([]);
|
|
}
|
|
};
|
|
|
|
const renderCell = useCallback(
|
|
(visitor: any, columnKey: Key) => {
|
|
const cellValue = visitor[columnKey as keyof any];
|
|
|
|
switch (columnKey) {
|
|
case "url":
|
|
return (
|
|
<Link
|
|
href={cellValue}
|
|
target="_blank"
|
|
className="hover:text-primary hover:underline"
|
|
>
|
|
{cellValue}
|
|
</Link>
|
|
);
|
|
case "browserName":
|
|
return (
|
|
<div>
|
|
{cellValue}{" "}
|
|
{cellValue !== null ? "Ver " + visitor.browserVersion : ""}
|
|
</div>
|
|
);
|
|
case "visitorRegion":
|
|
return (
|
|
<p className="capitalize">
|
|
{cellValue
|
|
? findRegion(cellValue.toUpperCase()).toLowerCase()
|
|
: ""}
|
|
</p>
|
|
);
|
|
case "createdAt":
|
|
return <p>{convertDateFormat(visitor.createdAt)}</p>;
|
|
|
|
default:
|
|
return cellValue;
|
|
}
|
|
},
|
|
[tableVisitorData]
|
|
);
|
|
return (
|
|
<div className="flex w-full mt-5 gap-4">
|
|
<div className="border p-3 rounded-lg flex flex-col gap-2 w-full">
|
|
<p className="font-bold">Visitors Table</p>
|
|
<div className="flex flex-row gap-2">
|
|
<div className="flex flex-col gap-1 w-full lg:w-[72px]">
|
|
<p className="font-semibold text-sm">Show Data</p>
|
|
<Select
|
|
label=""
|
|
variant="bordered"
|
|
labelPlacement="outside"
|
|
placeholder="Select"
|
|
selectedKeys={[showData]}
|
|
className="w-full"
|
|
classNames={{ trigger: "border-1" }}
|
|
onChange={(e) =>
|
|
e.target.value === "" ? "" : setShowData(e.target.value)
|
|
}
|
|
>
|
|
<SelectItem key="5">5</SelectItem>
|
|
<SelectItem key="10">10</SelectItem>
|
|
<SelectItem key="25">25</SelectItem>
|
|
<SelectItem key="50">50</SelectItem>
|
|
</Select>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<p className="font-semibold text-sm">Start Date</p>
|
|
|
|
<Popover
|
|
placement="bottom"
|
|
classNames={{ content: ["!bg-transparent", "p-0"] }}
|
|
>
|
|
<PopoverTrigger>
|
|
<Button className="border-1" variant="bordered">
|
|
{convertDateFormatNoTime(visitorBrowserDate.startDate)}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="bg-transparent">
|
|
<Calendar
|
|
value={visitorBrowserDate.startDate}
|
|
onChange={(e) =>
|
|
setVisitorBrowserDate({
|
|
startDate: e,
|
|
endDate: visitorBrowserDate.endDate,
|
|
})
|
|
}
|
|
maxValue={visitorBrowserDate.endDate}
|
|
/>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<p className="font-semibold text-sm">End Date</p>
|
|
|
|
<Popover
|
|
placement="bottom"
|
|
classNames={{ content: ["!bg-transparent", "p-0"] }}
|
|
>
|
|
<PopoverTrigger>
|
|
<Button className="border-1" variant="bordered">
|
|
{convertDateFormatNoTime(visitorBrowserDate.endDate)}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="bg-transparent">
|
|
<Calendar
|
|
value={visitorBrowserDate.endDate}
|
|
onChange={(e) =>
|
|
setVisitorBrowserDate({
|
|
startDate: visitorBrowserDate.startDate,
|
|
endDate: e,
|
|
})
|
|
}
|
|
minValue={visitorBrowserDate.startDate}
|
|
/>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col items-start rounded-2xl gap-3">
|
|
<Table
|
|
aria-label="micro issue table"
|
|
className="rounded-3xl"
|
|
classNames={{
|
|
th: "bg-white dark:bg-black text-black dark:text-white border-b-1 text-md",
|
|
base: "bg-white dark:bg-black border",
|
|
wrapper:
|
|
"min-h-[50px] bg-transpararent text-black dark:text-white ",
|
|
}}
|
|
>
|
|
<TableHeader columns={columns}>
|
|
{(column) => (
|
|
<TableColumn key={column.uid}>{column.name}</TableColumn>
|
|
)}
|
|
</TableHeader>
|
|
<TableBody
|
|
items={tableVisitorData}
|
|
emptyContent={"No data to display."}
|
|
loadingContent={<Spinner label="Loading..." />}
|
|
>
|
|
{(item: any) => (
|
|
<TableRow key={item.id}>
|
|
{(columnKey) => (
|
|
<TableCell>{renderCell(item, columnKey)}</TableCell>
|
|
)}
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
<div className="my-2 w-full flex justify-center">
|
|
<Pagination
|
|
isCompact
|
|
showControls
|
|
showShadow
|
|
color="primary"
|
|
classNames={{
|
|
base: "bg-transparent",
|
|
wrapper: "bg-transparent",
|
|
item: "w-fit px-3",
|
|
cursor: "w-fit px-3",
|
|
}}
|
|
page={page}
|
|
total={totalPage}
|
|
onChange={(page) => setPage(page)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|