feat:add table konten, dashboard
This commit is contained in:
parent
ead5912044
commit
655c72ee25
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Video",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,79 @@
|
|||
const VideoPage = async () => {
|
||||
return <div></div>;
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-video";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableVideo from "./table-video";
|
||||
|
||||
const ReactTableVideoPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center px-5">
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="icon-park-outline:check-one" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah disetujui hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="material-symbols:settings-backup-restore-rounded" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah direvisi hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="healthicons:no-outline" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah ditolak hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten Video
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Video
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Video Dengan AI
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableVideo />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoPage;
|
||||
export default ReactTableVideoPage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
|
|
@ -11,10 +11,9 @@ import {
|
|||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
|
||||
} from "@tanstack/react-table"
|
||||
import { columns } from "./columns"
|
||||
import { Input } from "@/components/ui/input"
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
|
|
@ -23,18 +22,19 @@ import {
|
|||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { useTranslations } from "next-intl";
|
||||
import { data } from "./data"
|
||||
} from "@/components/ui/table";
|
||||
|
||||
const TransactionsTable = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TableVideo = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
)
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({})
|
||||
const [rowSelection, setRowSelection] = React.useState({})
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
|
|
@ -53,14 +53,11 @@ const TransactionsTable = () => {
|
|||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
})
|
||||
const t = useTranslations("BankingDashboard");
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center py-5 px-5">
|
||||
<div className="flex-1 text-2xl font-semibold leading-none tracking-tight">
|
||||
{t("all_transactions")}
|
||||
</div>
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Filter Status..."
|
||||
|
|
@ -81,7 +78,7 @@ const t = useTranslations("BankingDashboard");
|
|||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id} className="last:text-end">
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
|
|
@ -117,7 +114,8 @@ const t = useTranslations("BankingDashboard");
|
|||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default TransactionsTable;
|
||||
};
|
||||
export default TableVideo;
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
|
|
@ -29,7 +28,8 @@ const TablePagination = ({ table }: DataTablePaginationProps) => {
|
|||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className={`w-8 h-8 hover:text-primary-foreground ${table.getState().pagination.pageIndex === pageIndex ? 'bg-default' : 'bg-default-300 text-default'}`}
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import FullCalendar from "@fullcalendar/react"; // must go before plugins
|
||||
import dayGridPlugin from "@fullcalendar/daygrid";
|
||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||
import interactionPlugin, { Draggable } from "@fullcalendar/interaction";
|
||||
import listPlugin from "@fullcalendar/list";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import ExternalDraggingevent from "./dragging-events";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { Plus } from "lucide-react";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { CalendarEvent, CalendarCategory } from "./data"
|
||||
import {
|
||||
EventContentArg,
|
||||
} from '@fullcalendar/core'
|
||||
import EventModal from "./event-modal";
|
||||
import { useTranslations } from "next-intl";
|
||||
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
interface CalendarViewProps {
|
||||
events: CalendarEvent[];
|
||||
categories: CalendarCategory[];
|
||||
|
||||
|
||||
}
|
||||
|
||||
const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
||||
const [selectedCategory, setSelectedCategory] = useState<string[] | null>(null);
|
||||
const [selectedEventDate, setSelectedEventDate] = useState<Date | null>(null);
|
||||
const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(null);
|
||||
const [draggableInitialized, setDraggableInitialized] = useState<boolean>(false);
|
||||
const t = useTranslations("CalendarApp")
|
||||
// event canvas state
|
||||
const [sheetOpen, setSheetOpen] = useState<boolean>(false);
|
||||
const [date, setDate] = React.useState<Date>(new Date());
|
||||
|
||||
const [dragEvents] = useState([
|
||||
{ title: "New Event Planning", id: "101", tag: "business" },
|
||||
{ title: "Meeting", id: "102", tag: "meeting" },
|
||||
{ title: "Generating Reports", id: "103", tag: "holiday" },
|
||||
{ title: "Create New theme", id: "104", tag: "etc" },
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedCategory(categories?.map((c) => c.value));
|
||||
}, [events, categories]);
|
||||
|
||||
useEffect(() => {
|
||||
const draggableEl = document.getElementById("external-events");
|
||||
|
||||
const initDraggable = () => {
|
||||
if (draggableEl) {
|
||||
new Draggable(draggableEl, {
|
||||
itemSelector: ".fc-event",
|
||||
eventData: function (eventEl) {
|
||||
let title = eventEl.getAttribute("title");
|
||||
let id = eventEl.getAttribute("data");
|
||||
let event = dragEvents.find((e) => e.id === id);
|
||||
let tag = event ? event.tag : "";
|
||||
return {
|
||||
title: title,
|
||||
id: id,
|
||||
extendedProps: {
|
||||
calendar: tag,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (dragEvents.length > 0) {
|
||||
initDraggable();
|
||||
}
|
||||
|
||||
return () => {
|
||||
draggableEl?.removeEventListener("mousedown", initDraggable);
|
||||
};
|
||||
}, [dragEvents]);
|
||||
// event click
|
||||
const handleEventClick = (arg: any) => {
|
||||
setSelectedEventDate(null);
|
||||
setSheetOpen(true);
|
||||
setSelectedEvent(arg);
|
||||
wait().then(() => (document.body.style.pointerEvents = "auto"));
|
||||
};
|
||||
// handle close modal
|
||||
const handleCloseModal = () => {
|
||||
setSheetOpen(false);
|
||||
setSelectedEvent(null);
|
||||
setSelectedEventDate(null);
|
||||
};
|
||||
const handleDateClick = (arg: any) => {
|
||||
setSheetOpen(true);
|
||||
setSelectedEventDate(arg);
|
||||
setSelectedEvent(null);
|
||||
wait().then(() => (document.body.style.pointerEvents = "auto"));
|
||||
};
|
||||
|
||||
const handleCategorySelection = (category: string) => {
|
||||
if (selectedCategory && selectedCategory.includes(category)) {
|
||||
setSelectedCategory(selectedCategory.filter((c) => c !== category));
|
||||
} else {
|
||||
setSelectedCategory([...selectedCategory || [], category]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClassName = (arg: EventContentArg) => {
|
||||
|
||||
if (arg.event.extendedProps.calendar === "holiday") {
|
||||
return "destructive";
|
||||
}
|
||||
else if (arg.event.extendedProps.calendar === "business") {
|
||||
return "primary";
|
||||
} else if (arg.event.extendedProps.calendar === "personal") {
|
||||
return "success";
|
||||
} else if (arg.event.extendedProps.calendar === "family") {
|
||||
return "info";
|
||||
} else if (arg.event.extendedProps.calendar === "etc") {
|
||||
return "info";
|
||||
} else if (arg.event.extendedProps.calendar === "meeting") {
|
||||
return "warning";
|
||||
}
|
||||
else {
|
||||
return "primary";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const filteredEvents = events?.filter((event) =>
|
||||
selectedCategory?.includes(event.extendedProps.calendar)
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
|
||||
<Card className="col-span-12 lg:col-span-4 2xl:col-span-3 pb-5">
|
||||
<CardContent className="p-0">
|
||||
<CardHeader className="border-none mb-2 pt-5">
|
||||
<Button
|
||||
onClick={handleDateClick}
|
||||
className="dark:bg-background dark:text-foreground"
|
||||
>
|
||||
<Plus className="w-4 h-4 me-1" />
|
||||
{t("addEvent")}
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<div className="px-3">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={(s) => {
|
||||
handleDateClick(s);
|
||||
}}
|
||||
className="rounded-md border w-full p-0 border-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="external-events" className=" space-y-1.5 mt-6 px-4">
|
||||
<p className="text-sm font-medium text-default-700 mb-3">
|
||||
{t("shortDesc")}
|
||||
</p>
|
||||
{dragEvents.map((event) => (
|
||||
<ExternalDraggingevent key={event.id} event={event} />
|
||||
))}
|
||||
</div>
|
||||
<div className="py-4 text-default-800 font-semibold text-xs uppercase mt-4 mb-2 px-4">
|
||||
{t("filter")}
|
||||
</div>
|
||||
<ul className="space-y-3 px-4">
|
||||
<li className=" flex gap-3">
|
||||
<Checkbox
|
||||
checked={selectedCategory?.length === categories?.length}
|
||||
onClick={() => {
|
||||
if (selectedCategory?.length === categories?.length) {
|
||||
setSelectedCategory([]);
|
||||
} else {
|
||||
setSelectedCategory(categories.map((c) => c.value));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Label>All</Label>
|
||||
</li>
|
||||
{categories?.map((category) => (
|
||||
<li className="flex gap-3 " key={category.value}>
|
||||
<Checkbox
|
||||
className={category.className}
|
||||
id={category.label}
|
||||
checked={selectedCategory?.includes(category.value)}
|
||||
onClick={() => handleCategorySelection(category.value)}
|
||||
/>
|
||||
<Label htmlFor={category.label}>{category.label}</Label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="col-span-12 lg:col-span-8 2xl:col-span-9 pt-5">
|
||||
<CardContent className="dashcode-app-calendar">
|
||||
<FullCalendar
|
||||
plugins={[
|
||||
dayGridPlugin,
|
||||
timeGridPlugin,
|
||||
interactionPlugin,
|
||||
listPlugin,
|
||||
]}
|
||||
headerToolbar={{
|
||||
left: "prev,next today",
|
||||
center: "title",
|
||||
right: "dayGridMonth,timeGridWeek,timeGridDay,listWeek",
|
||||
}}
|
||||
events={filteredEvents}
|
||||
editable={true}
|
||||
rerenderDelay={10}
|
||||
eventDurationEditable={false}
|
||||
selectable={true}
|
||||
selectMirror={true}
|
||||
droppable={true}
|
||||
dayMaxEvents={2}
|
||||
weekends={true}
|
||||
eventClassNames={handleClassName}
|
||||
dateClick={handleDateClick}
|
||||
eventClick={handleEventClick}
|
||||
initialView="dayGridMonth"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<EventModal
|
||||
open={sheetOpen}
|
||||
onClose={handleCloseModal}
|
||||
categories={categories}
|
||||
event={selectedEvent}
|
||||
selectedDate={selectedEventDate}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CalendarView;
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
import { faker } from "@faker-js/faker";
|
||||
|
||||
const date = new Date();
|
||||
const prevDay = new Date().getDate() - 1;
|
||||
const nextDay = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
|
||||
|
||||
// prettier-ignore
|
||||
const nextMonth = date.getMonth() === 11 ? new Date(date.getFullYear() + 1, 0, 1) : new Date(date.getFullYear(), date.getMonth() + 1, 1)
|
||||
// prettier-ignore
|
||||
const prevMonth = date.getMonth() === 11 ? new Date(date.getFullYear() - 1, 0, 1) : new Date(date.getFullYear(), date.getMonth() - 1, 1)
|
||||
export const calendarEvents = [
|
||||
{
|
||||
id: faker.string.uuid() ,
|
||||
title: "All Day Event",
|
||||
start: date,
|
||||
end: nextDay,
|
||||
allDay: false,
|
||||
//className: "warning",
|
||||
extendedProps: {
|
||||
calendar: "business",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: faker.string.uuid(),
|
||||
title: "Meeting With Client",
|
||||
start: new Date(date.getFullYear(), date.getMonth() + 1, -11),
|
||||
end: new Date(date.getFullYear(), date.getMonth() + 1, -10),
|
||||
allDay: true,
|
||||
//className: "success",
|
||||
extendedProps: {
|
||||
calendar: "personal",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: faker.string.uuid(),
|
||||
title: "Lunch",
|
||||
allDay: true,
|
||||
start: new Date(date.getFullYear(), date.getMonth() + 1, -9),
|
||||
end: new Date(date.getFullYear(), date.getMonth() + 1, -7),
|
||||
// className: "info",
|
||||
extendedProps: {
|
||||
calendar: "family",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: faker.string.uuid(),
|
||||
title: "Birthday Party",
|
||||
start: new Date(date.getFullYear(), date.getMonth() + 1, -11),
|
||||
end: new Date(date.getFullYear(), date.getMonth() + 1, -10),
|
||||
allDay: true,
|
||||
//className: "primary",
|
||||
extendedProps: {
|
||||
calendar: "meeting",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: faker.string.uuid(),
|
||||
title: "Birthday Party",
|
||||
start: new Date(date.getFullYear(), date.getMonth() + 1, -13),
|
||||
end: new Date(date.getFullYear(), date.getMonth() + 1, -12),
|
||||
allDay: true,
|
||||
// className: "danger",
|
||||
extendedProps: {
|
||||
calendar: "holiday",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: faker.string.uuid(),
|
||||
title: "Monthly Meeting",
|
||||
start: nextMonth,
|
||||
end: nextMonth,
|
||||
allDay: true,
|
||||
//className: "primary",
|
||||
extendedProps: {
|
||||
calendar: "business",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const calendarCategories = [
|
||||
{
|
||||
label: "Business",
|
||||
value: "business",
|
||||
activeClass: "ring-primary-500 bg-primary-500",
|
||||
className: "group-hover:border-blue-500",
|
||||
},
|
||||
{
|
||||
label: "Personal",
|
||||
value: "personal",
|
||||
activeClass: "ring-success-500 bg-success-500",
|
||||
className: " group-hover:border-green-500",
|
||||
},
|
||||
{
|
||||
label: "Holiday",
|
||||
value: "holiday",
|
||||
activeClass: "ring-danger-500 bg-danger-500",
|
||||
className: " group-hover:border-red-500",
|
||||
},
|
||||
{
|
||||
label: "Family",
|
||||
value: "family",
|
||||
activeClass: "ring-info-500 bg-info-500",
|
||||
className: " group-hover:border-cyan-500",
|
||||
},
|
||||
{
|
||||
label: "Meeting",
|
||||
value: "meeting",
|
||||
activeClass: "ring-warning-500 bg-warning-500",
|
||||
className: " group-hover:border-yellow-500",
|
||||
},
|
||||
{
|
||||
label: "Etc",
|
||||
value: "etc",
|
||||
activeClass: "ring-info-500 bg-info-500",
|
||||
className: " group-hover:border-cyan-500",
|
||||
}
|
||||
];
|
||||
|
||||
export const categories = [
|
||||
{
|
||||
label: "Business",
|
||||
value: "business",
|
||||
className: "data-[state=checked]:bg-primary data-[state=checked]:ring-primary",
|
||||
},
|
||||
{
|
||||
label: "Personal",
|
||||
value: "personal",
|
||||
|
||||
className: "data-[state=checked]:bg-success data-[state=checked]:ring-success",
|
||||
},
|
||||
{
|
||||
label: "Holiday",
|
||||
value: "holiday",
|
||||
className: "data-[state=checked]:bg-destructive data-[state=checked]:ring-destructive ",
|
||||
},
|
||||
{
|
||||
label: "Family",
|
||||
value: "family",
|
||||
className: "data-[state=checked]:bg-info data-[state=checked]:ring-info ",
|
||||
},
|
||||
{
|
||||
label: "Meeting",
|
||||
value: "meeting",
|
||||
className: "data-[state=checked]:bg-warning data-[state=checked]:ring-warning",
|
||||
},
|
||||
{
|
||||
label: "Etc",
|
||||
value: "etc",
|
||||
className: "data-[state=checked]:bg-info data-[state=checked]:ring-info",
|
||||
}
|
||||
];
|
||||
|
||||
export type CalendarEvent = (typeof calendarEvents)[number]
|
||||
export type CalendarCategory = (typeof calendarCategories)[number]
|
||||
export type Category = (typeof categories)[number]
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import { cn } from "@/lib/utils";
|
||||
const ExternalDraggingevent = ({ event }: any) => {
|
||||
const { title, id, tag } = event;
|
||||
|
||||
return (
|
||||
<div
|
||||
title={title}
|
||||
data-id={id}
|
||||
className="fc-event px-4 py-1.5 bg-default-100 dark:bg-default-300 rounded text-sm flex items-center gap-2 shadow-sm cursor-move" >
|
||||
<span
|
||||
className={cn("h-2 w-2 rounded-full block", {
|
||||
"bg-primary": tag === "business",
|
||||
"bg-warning": tag === "meeting",
|
||||
"bg-destructive": tag === "holiday",
|
||||
"bg-info": tag === "etc",
|
||||
})}
|
||||
></span>
|
||||
<span className="text-sm font-medium text-default-900">{title}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExternalDraggingevent;
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
"use client"
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { cn, } from "@/lib/utils";
|
||||
import { format } from "date-fns"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { Loader2, CalendarIcon } from "lucide-react";
|
||||
import DeleteConfirmationDialog from "@/components/delete-confirmation-dialog";
|
||||
import { CalendarCategory } from "./data";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
|
||||
const schema = z.object({
|
||||
title: z.string().min(3, { message: "Required" }),
|
||||
});
|
||||
|
||||
const EventModal = ({ open, onClose, categories, event, selectedDate }: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
categories: any;
|
||||
event: any;
|
||||
selectedDate: any
|
||||
}) => {
|
||||
const [startDate, setStartDate] = useState<Date>(new Date());
|
||||
const [endDate, setEndDate] = useState<Date>(new Date());
|
||||
const [isPending, startTransition] = React.useTransition();
|
||||
const [calendarProps, setCalendarProps] = React.useState<any>(categories[0].value);
|
||||
// delete modal state
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState<boolean>(false);
|
||||
const [eventIdToDelete, setEventIdToDelete] = useState<string | null>(null);
|
||||
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
reset,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
handleSubmit,
|
||||
} = useForm({
|
||||
resolver: zodResolver(schema),
|
||||
mode: "all",
|
||||
});
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
startTransition(async () => {
|
||||
if (!event) {
|
||||
data.start = startDate;
|
||||
data.end = endDate;
|
||||
data.allDay = false;
|
||||
data.extendedProps = {
|
||||
calendar: calendarProps,
|
||||
};
|
||||
}
|
||||
if (event) {
|
||||
}
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
if (selectedDate) {
|
||||
setStartDate(selectedDate.date);
|
||||
setEndDate(selectedDate.date);
|
||||
}
|
||||
if (event) {
|
||||
setStartDate(event?.event?.start);
|
||||
setEndDate(event?.event?.end);
|
||||
const eventCalendar = event?.event?.extendedProps?.calendar;
|
||||
if (eventCalendar) {
|
||||
setCalendarProps(eventCalendar);
|
||||
} else {
|
||||
setCalendarProps(categories[0].value);
|
||||
}
|
||||
}
|
||||
setValue("title", event?.event?.title || "");
|
||||
}, [event, selectedDate, open, categories, setValue]);
|
||||
|
||||
const onDeleteEventAction = async () => {
|
||||
try {
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenDeleteModal = (eventId: string) => {
|
||||
setEventIdToDelete(eventId);
|
||||
setDeleteModalOpen(true);
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DeleteConfirmationDialog
|
||||
open={deleteModalOpen}
|
||||
onClose={() => setDeleteModalOpen(false)}
|
||||
onConfirm={onDeleteEventAction}
|
||||
defaultToast={false}
|
||||
/>
|
||||
<Dialog open={open} onOpenChange={onClose}>
|
||||
<DialogContent
|
||||
onPointerDownOutside={onClose}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{event ? "Edit Event" : "Create Event"} {event?.title}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="mt-6 h-full">
|
||||
<form className="h-full" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="space-y-4 pb-5 ">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="title">Event Name</Label>
|
||||
<Input
|
||||
id="title"
|
||||
type="text"
|
||||
placeholder="Enter Event Name"
|
||||
{...register("title")}
|
||||
/>
|
||||
{errors?.title?.message && (
|
||||
<div className="text-destructive text-sm">
|
||||
{typeof errors?.title?.message === 'string'
|
||||
? errors?.title?.message
|
||||
: JSON.stringify(errors?.title?.message)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="startDate">Start Date </Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="md"
|
||||
className={cn(
|
||||
"w-full justify-between text-left font-normal border-default-200 text-default-600 md:px-4",
|
||||
!startDate && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{startDate ? (
|
||||
format(startDate, "PP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Controller
|
||||
name="startDate"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={startDate}
|
||||
onSelect={(date) => setStartDate(date as Date)}
|
||||
initialFocus
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="endDate">End Date</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="md"
|
||||
className={cn(
|
||||
"w-full justify-between text-left font-normal border-default-200 text-default-600 md:px-4",
|
||||
!endDate && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{endDate ? (
|
||||
format(endDate, "PP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Controller
|
||||
name="endDate"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={endDate}
|
||||
onSelect={(date) => setEndDate(date as Date)}
|
||||
initialFocus
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="calendarProps">Label </Label>
|
||||
<Controller
|
||||
name="calendarProps"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={calendarProps}
|
||||
onValueChange={(data) => setCalendarProps(data)}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Label" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{categories.map((category: CalendarCategory) => (
|
||||
<SelectItem
|
||||
value={category.value}
|
||||
key={category.value}
|
||||
>
|
||||
{category.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 mt-10">
|
||||
<Button type="submit" disabled={isPending} className="flex-1">
|
||||
{isPending ? (
|
||||
<>
|
||||
<Loader2 className="me-2 h-4 w-4 animate-spin" />
|
||||
{event ? "Updating..." : "Adding..."}
|
||||
</>
|
||||
) : event ? (
|
||||
"Update Event"
|
||||
) : (
|
||||
"Add Event"
|
||||
)}
|
||||
</Button>
|
||||
{event && (
|
||||
<Button
|
||||
type="button"
|
||||
color="destructive"
|
||||
onClick={() => handleOpenDeleteModal(event?.event?.id)}
|
||||
className="flex-1"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventModal;
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Audio",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,21 +1,79 @@
|
|||
import { getEvents, getCategories } from "./utils";
|
||||
import { Category } from "./data"
|
||||
import CalendarView from "./calender-view";
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-audio";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableAudio from "./table-audio";
|
||||
|
||||
|
||||
|
||||
const CalenderPage = async () => {
|
||||
const events = await getEvents();
|
||||
const categories = await getCategories();
|
||||
const formattedCategories = categories.map((category: Category) => ({
|
||||
...category,
|
||||
activeClass: "",
|
||||
}));
|
||||
const ReactTableAudioPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<CalendarView events={events} categories={formattedCategories} />
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center px-5">
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="icon-park-outline:check-one" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah disetujui hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="material-symbols:settings-backup-restore-rounded" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah direvisi hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="healthicons:no-outline" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah ditolak hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten Audio
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Audio
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Audio Dengan AI
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableAudio />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CalenderPage;
|
||||
export default ReactTableAudioPage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
|
|
@ -11,9 +11,9 @@ import {
|
|||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table"
|
||||
import { columns } from "./columns"
|
||||
import { Input } from "@/components/ui/input"
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
|
|
@ -22,20 +22,19 @@ import {
|
|||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { data } from "./data"
|
||||
import TablePagination from "./table-pagination"
|
||||
import { useTranslations } from "next-intl"
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TransactionsTable= () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
const TableAudio = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
)
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({})
|
||||
const [rowSelection, setRowSelection] = React.useState({})
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
|
|
@ -54,21 +53,18 @@ const TransactionsTable= () => {
|
|||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
})
|
||||
const t = useTranslations("CrmDashboard");
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center flex-wrap gap-2 py-4 px-5">
|
||||
<div className="flex-1 text-xl font-medium text-default-900 whitespace-nowrap">
|
||||
{t("latest_transactions")}
|
||||
</div>
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Search..."
|
||||
placeholder="Filter Status..."
|
||||
value={
|
||||
(table.getColumn("status")?.getFilterValue() as string) ?? ""
|
||||
}
|
||||
onChange={(event) =>
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
table.getColumn("status")?.setFilterValue(event.target.value)
|
||||
}
|
||||
className="max-w-sm "
|
||||
|
|
@ -77,7 +73,7 @@ const TransactionsTable= () => {
|
|||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader className="bg-default-200">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
|
|
@ -103,7 +99,7 @@ const TransactionsTable= () => {
|
|||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id} className="h-[75px]">
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
|
|
@ -121,5 +117,5 @@ const TransactionsTable= () => {
|
|||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default TransactionsTable;
|
||||
};
|
||||
export default TableAudio;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
}
|
||||
|
||||
const TablePagination = ({ table }: DataTablePaginationProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end py-4 px-10">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-none">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { calendarEvents, categories } from "./data";
|
||||
|
||||
// get events
|
||||
export const getEvents = async () => {
|
||||
return calendarEvents;
|
||||
};
|
||||
|
||||
// get categories
|
||||
export const getCategories = async () => {
|
||||
return categories;
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Image",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,78 @@
|
|||
const ImagePage = async () => {
|
||||
return <div></div>;
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-image";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
|
||||
const ReactTableImagePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center px-5">
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="icon-park-outline:check-one" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah disetujui hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="material-symbols:settings-backup-restore-rounded" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah direvisi hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="healthicons:no-outline" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah ditolak hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten Foto
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Foto
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Foto Dengan AI
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableImage />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImagePage;
|
||||
export default ReactTableImagePage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TableImage = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Filter Status..."
|
||||
value={
|
||||
(table.getColumn("status")?.getFilterValue() as string) ?? ""
|
||||
}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
table.getColumn("status")?.setFilterValue(event.target.value)
|
||||
}
|
||||
className="max-w-sm "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default TableImage;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
}
|
||||
|
||||
const TablePagination = ({ table }: DataTablePaginationProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end py-4 px-10">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-none">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { calendarEvents, categories } from "./data";
|
||||
|
||||
// get events
|
||||
export const getEvents = async () => {
|
||||
return calendarEvents;
|
||||
};
|
||||
|
||||
// get categories
|
||||
export const getCategories = async () => {
|
||||
return categories;
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Nulis",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,79 @@
|
|||
const CalenderPage = async () => {
|
||||
return <div></div>;
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-nulis";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableNulis from "./table-nulis";
|
||||
|
||||
const ReactTableNulisPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center px-5">
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="icon-park-outline:check-one" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah disetujui hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="material-symbols:settings-backup-restore-rounded" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah direvisi hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="healthicons:no-outline" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah ditolak hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten Foto
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Foto
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Foto Dengan AI
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableNulis />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CalenderPage;
|
||||
export default ReactTableNulisPage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TableNulis = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Filter Status..."
|
||||
value={
|
||||
(table.getColumn("status")?.getFilterValue() as string) ?? ""
|
||||
}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
table.getColumn("status")?.setFilterValue(event.target.value)
|
||||
}
|
||||
className="max-w-sm "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default TableNulis;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
}
|
||||
|
||||
const TablePagination = ({ table }: DataTablePaginationProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end py-4 px-10">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-none">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Spit",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,42 @@
|
|||
const CalenderPage = async () => {
|
||||
return <div></div>;
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-spit";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableSPIT from "./table-spit";
|
||||
|
||||
const ReactTableSPITPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten SPIT
|
||||
</div>
|
||||
{/* <div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Foto
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Foto Dengan AI
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableSPIT />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CalenderPage;
|
||||
export default ReactTableSPITPage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TableSPIT = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Filter Status..."
|
||||
value={
|
||||
(table.getColumn("status")?.getFilterValue() as string) ?? ""
|
||||
}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
table.getColumn("status")?.setFilterValue(event.target.value)
|
||||
}
|
||||
className="max-w-sm "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default TableSPIT;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
}
|
||||
|
||||
const TablePagination = ({ table }: DataTablePaginationProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end py-4 px-10">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-none">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
export const metadata = {
|
||||
title: "Teks",
|
||||
};
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashcode Next Js",
|
||||
description: "Dashcode is a popular dashboard template.",
|
||||
};
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,79 @@
|
|||
const TeksPage = async () => {
|
||||
return <div></div>;
|
||||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TableImage from "./table-teks";
|
||||
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableTeks from "./table-teks";
|
||||
|
||||
const ReactTableTeksPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center px-5">
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="icon-park-outline:check-one" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah disetujui hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="material-symbols:settings-backup-restore-rounded" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah direvisi hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center text-xl font-medium text-default-900 gap-2">
|
||||
<div>
|
||||
<Icon icon="healthicons:no-outline" />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
0 <span className="text-red-500">Rata - rata :0</span>
|
||||
</p>
|
||||
<p className="text-sm">Hasil Unggah ditolak hari ini</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="py-4 px-3">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Konten Teks
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Teks
|
||||
</Button>
|
||||
<Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Teks Dengan AI
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TableTeks />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeksPage;
|
||||
export default ReactTableTeksPage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: string;
|
||||
customer: {
|
||||
name: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
};
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
// {
|
||||
// id: "select",
|
||||
// header: ({ table }) => (
|
||||
// <Checkbox
|
||||
// checked={
|
||||
// table.getIsAllPageRowsSelected() ||
|
||||
// (table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
// }
|
||||
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
// aria-label="Select all"
|
||||
// />
|
||||
// ),
|
||||
// cell: ({ row }) => (
|
||||
// <div className="xl:w-16">
|
||||
// <Checkbox
|
||||
// checked={row.getIsSelected()}
|
||||
// onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
// aria-label="Select row"
|
||||
// />
|
||||
// </div>
|
||||
// ),
|
||||
// enableSorting: false,
|
||||
// enableHiding: false,
|
||||
// },
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="w-52">
|
||||
<span>{row.getValue("order")}</span>,
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal unggah",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("date")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Kreator",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("quantity")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Penempatan File",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status}{" "}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Kurasi Konten",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Saran",
|
||||
cell: ({ row }) => {
|
||||
return <span>{row.getValue("amount")}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { columns } from "./columns";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { data } from "./data";
|
||||
import TablePagination from "./table-pagination";
|
||||
|
||||
const TableTeks = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center py-4 px-5">
|
||||
<div className="flex-none">
|
||||
<Input
|
||||
placeholder="Filter Status..."
|
||||
value={
|
||||
(table.getColumn("status")?.getFilterValue() as string) ?? ""
|
||||
}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
table.getColumn("status")?.setFilterValue(event.target.value)
|
||||
}
|
||||
className="max-w-sm "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination table={table} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default TableTeks;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
table: Table<any>;
|
||||
}
|
||||
|
||||
const TablePagination = ({ table }: DataTablePaginationProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end py-4 px-10">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-none">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
|
|
@ -13,9 +13,9 @@ import {
|
|||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { data } from "./data"
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { data } from "./data";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -23,24 +23,40 @@ import {
|
|||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { ChevronLeft, ChevronRight, TrendingDown, TrendingUp } from "lucide-react"
|
||||
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
Badge,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
export type CompanyData = {
|
||||
company: string;
|
||||
category: string;
|
||||
views: number;
|
||||
revenue: string;
|
||||
sales: number;
|
||||
status: string;
|
||||
up: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export const columns: ColumnDef<CompanyData>[] = [
|
||||
{
|
||||
accessorKey: "company",
|
||||
header: "Company",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-none">
|
||||
|
|
@ -64,51 +80,91 @@ export const columns: ColumnDef<CompanyData>[] = [
|
|||
},
|
||||
{
|
||||
accessorKey: "category",
|
||||
header: "Category",
|
||||
header: "Tanggal Unggah",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("category")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "sales",
|
||||
header: "Sales",
|
||||
header: "Tipe Konten",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-4">
|
||||
<span>{row.getValue("sales")}</span>
|
||||
{
|
||||
row?.original.up ?
|
||||
<TrendingUp className="text-success w-4 h-4" />
|
||||
:
|
||||
<TrendingDown className="text-destructive w-4 h-4" />
|
||||
}
|
||||
{row?.original.up ? (
|
||||
<TrendingUp className="text-success w-4 h-4" />
|
||||
) : (
|
||||
<TrendingDown className="text-destructive w-4 h-4" />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "views",
|
||||
header: "Views",
|
||||
cell: ({ row }) => (
|
||||
<span>{row.getValue("views")}</span>
|
||||
)
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<CompanyData["status"], string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive",
|
||||
};
|
||||
const status = row.getValue<CompanyData["status"]>("status");
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusColors[status])}>
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "revenue",
|
||||
header: "Revenue",
|
||||
cell: ({ row }) => (
|
||||
<span>{row.getValue("revenue")}</span>
|
||||
)
|
||||
}
|
||||
]
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CompanyTable = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
||||
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
||||
const [rowSelection, setRowSelection] = React.useState({})
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 6,
|
||||
})
|
||||
});
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
|
|
@ -127,9 +183,9 @@ const CompanyTable = () => {
|
|||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination
|
||||
pagination,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
|
|
@ -139,10 +195,12 @@ const CompanyTable = () => {
|
|||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder ? null : flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
|
|
@ -158,20 +216,14 @@ const CompanyTable = () => {
|
|||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
@ -184,9 +236,9 @@ const CompanyTable = () => {
|
|||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8'
|
||||
className="w-8 h-8"
|
||||
>
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
<ChevronLeft className="w-4 h-4" />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
|
|
@ -194,25 +246,27 @@ const CompanyTable = () => {
|
|||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className="w-8 h-8"
|
||||
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
|
||||
variant={
|
||||
table.getState().pagination.pageIndex === pageIndex
|
||||
? "default"
|
||||
: "outline"
|
||||
}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8'
|
||||
className="w-8 h-8"
|
||||
>
|
||||
<ChevronRight className='w-4 h-4' />
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default CompanyTable;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
|
||||
export const data = [
|
||||
{
|
||||
company: "/images/users/user-1.jpg",
|
||||
category: "Ornamental Railings",
|
||||
views: 343,
|
||||
status: "paid",
|
||||
revenue: "$231.26",
|
||||
sales: 95,
|
||||
up: false,
|
||||
|
|
@ -12,7 +10,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-2.jpg",
|
||||
category: "Asphalt Paving",
|
||||
views: 315,
|
||||
status: "due",
|
||||
revenue: "$432.81",
|
||||
sales: 197,
|
||||
up: false,
|
||||
|
|
@ -20,7 +18,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-3.jpg",
|
||||
category: "Framing (Steel)",
|
||||
views: 329,
|
||||
status: "due",
|
||||
revenue: "$437.65",
|
||||
sales: 137,
|
||||
up: true,
|
||||
|
|
@ -28,7 +26,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-4.jpg",
|
||||
category: "Structural and Misc Steel (Fabrication)",
|
||||
views: 336,
|
||||
status: "canceled",
|
||||
revenue: "$387.55",
|
||||
sales: 101,
|
||||
up: true,
|
||||
|
|
@ -36,7 +34,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-5.jpg",
|
||||
category: "Wall Protection",
|
||||
views: 375,
|
||||
status: "canceled",
|
||||
revenue: "$489.80",
|
||||
sales: 99,
|
||||
up: false,
|
||||
|
|
@ -44,7 +42,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-6.jpg",
|
||||
category: "Marlite Panels (FED)",
|
||||
views: 490,
|
||||
status: "canceled",
|
||||
revenue: "$421.45",
|
||||
sales: 101,
|
||||
up: true,
|
||||
|
|
@ -52,7 +50,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-1.jpg",
|
||||
category: "Epoxy Flooring",
|
||||
views: 433,
|
||||
status: "canceled",
|
||||
revenue: "$207.61",
|
||||
sales: 197,
|
||||
up: false,
|
||||
|
|
@ -60,7 +58,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-2.jpg",
|
||||
category: "Epoxy Flooring",
|
||||
views: 499,
|
||||
status: "paid",
|
||||
revenue: "$392.86",
|
||||
sales: 91,
|
||||
up: false,
|
||||
|
|
@ -68,7 +66,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-3.jpg",
|
||||
category: "Marlite Panels (FED)",
|
||||
views: 441,
|
||||
status: "paid",
|
||||
revenue: "$162.87",
|
||||
sales: 115,
|
||||
up: false,
|
||||
|
|
@ -76,7 +74,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-4.jpg",
|
||||
category: "RF Shielding",
|
||||
views: 415,
|
||||
status: "paid",
|
||||
revenue: "$268.58",
|
||||
sales: 128,
|
||||
up: false,
|
||||
|
|
@ -84,7 +82,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-5.jpg",
|
||||
category: "Roofing (Metal)",
|
||||
views: 303,
|
||||
status: "paid",
|
||||
revenue: "$369.19",
|
||||
sales: 179,
|
||||
up: false,
|
||||
|
|
@ -92,7 +90,7 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-6.jpg",
|
||||
category: "RF Shielding",
|
||||
views: 415,
|
||||
status: "paid",
|
||||
revenue: "$420.87",
|
||||
sales: 148,
|
||||
up: false,
|
||||
|
|
@ -100,213 +98,9 @@ export const data = [
|
|||
{
|
||||
company: "/images/users/user-1.jpg",
|
||||
category: "Curb & Gutter",
|
||||
views: 493,
|
||||
status: "paid",
|
||||
revenue: "$420.26",
|
||||
sales: 152,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-2.jpg",
|
||||
category: "Structural & Misc Steel Erection",
|
||||
views: 498,
|
||||
revenue: "$228.41",
|
||||
sales: 151,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-3.jpg",
|
||||
category: "Retaining Wall and Brick Pavers",
|
||||
views: 465,
|
||||
revenue: "$140.83",
|
||||
sales: 71,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-4.jpg",
|
||||
category: "Sitework & Site Utilities",
|
||||
views: 468,
|
||||
revenue: "$475.63",
|
||||
sales: 114,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-5.jpg",
|
||||
category: "Framing (Steel)",
|
||||
views: 357,
|
||||
revenue: "$415.37",
|
||||
sales: 163,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-6.jpg",
|
||||
category: "Waterproofing & Caulking",
|
||||
views: 487,
|
||||
revenue: "$436.53",
|
||||
sales: 170,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-1.jpg",
|
||||
category: "Site Furnishings",
|
||||
views: 357,
|
||||
revenue: "$147.36",
|
||||
sales: 71,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-2.jpg",
|
||||
category: "Casework",
|
||||
views: 465,
|
||||
revenue: "$121.67",
|
||||
sales: 78,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-3.jpg",
|
||||
category: "Ornamental Railings",
|
||||
views: 438,
|
||||
revenue: "$213.25",
|
||||
sales: 155,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-4.jpg",
|
||||
category: "Waterproofing & Caulking",
|
||||
views: 461,
|
||||
revenue: "$186.48",
|
||||
sales: 137,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-5.jpg",
|
||||
category: "Masonry",
|
||||
views: 423,
|
||||
revenue: "$130.97",
|
||||
sales: 178,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-6.jpg",
|
||||
category: "Curb & Gutter",
|
||||
views: 339,
|
||||
revenue: "$255.69",
|
||||
sales: 101,
|
||||
up: false,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-1.jpg",
|
||||
category: "HVAC",
|
||||
views: 361,
|
||||
revenue: "$484.64",
|
||||
sales: 175,
|
||||
up: true,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-2.jpg",
|
||||
category: "Exterior Signage",
|
||||
views: 353,
|
||||
revenue: "$485.51",
|
||||
sales: 176,
|
||||
up: true,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-3.jpg",
|
||||
category: "Fire Protection",
|
||||
views: 364,
|
||||
revenue: "$449.45",
|
||||
sales: 136,
|
||||
up: true,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-4.jpg",
|
||||
category: "Rebar & Wire Mesh Install",
|
||||
views: 493,
|
||||
revenue: "$309.61",
|
||||
sales: 163,
|
||||
up: true,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-5.jpg",
|
||||
category: "Temp Fencing, Decorative Fencing and Gates",
|
||||
views: 393,
|
||||
revenue: "$372.45",
|
||||
sales: 180,
|
||||
up: true,
|
||||
},
|
||||
{
|
||||
company: "/images/users/user-6.jpg",
|
||||
category: "Fire Protection",
|
||||
views: 441,
|
||||
revenue: "$470.34",
|
||||
sales: 104,
|
||||
up: false,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const activity = [
|
||||
{
|
||||
id: 1,
|
||||
img: "/images/users/user-1.jpg",
|
||||
description: "Finance KPI Mobile app launch preparation meeting.",
|
||||
time: "1 hour",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
img: "/images/users/user-2.jpg",
|
||||
description: "Design review meeting.",
|
||||
time: "2 hours",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
img: "/images/users/user-3.jpg",
|
||||
description: "Project kick-off meeting.",
|
||||
time: "3 hours",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
img: "/images/users/user-4.jpg",
|
||||
description: "Weekly sync-up meeting.",
|
||||
time: "4 hours",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
img: "/images/users/user-5.jpg",
|
||||
description: "Client presentation meeting.",
|
||||
time: "5 hours",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
img: "/images/users/user-6.jpg",
|
||||
description: "Product roadmap discussion.",
|
||||
time: "6 hours",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
img: "/images/users/user-1.jpg",
|
||||
description: "Team retrospective meeting.",
|
||||
time: "7 hours",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
img: "/images/users/user-2.jpg",
|
||||
description: "Sprint planning meeting.",
|
||||
time: "8 hours",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
img: "/images/users/user-3.jpg",
|
||||
description: "Code review session.",
|
||||
time: "9 hours",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
img: "/images/users/user-4.jpg",
|
||||
description: "Stakeholder alignment meeting.",
|
||||
time: "10 hours",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,36 @@
|
|||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {activity} from "./data"
|
||||
"use client";
|
||||
|
||||
import {
|
||||
DockIcon,
|
||||
ImageIcon,
|
||||
MicIcon,
|
||||
PaperclipIcon,
|
||||
TextIcon,
|
||||
VideoIcon,
|
||||
YoutubeIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
const RecentActivity = () => {
|
||||
return (
|
||||
<ul className=" space-y-3 h-full ">
|
||||
{activity.map((item) => (
|
||||
<li
|
||||
className="flex items-center gap-3 border-b border-default-100 dark:border-default-300 last:border-b-0 pb-3 last:pb-0"
|
||||
key={item.id}
|
||||
>
|
||||
<Avatar className="w-8 h-8">
|
||||
<AvatarImage src={item.img} alt="next-avater" />
|
||||
<AvatarFallback> SA </AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 text-start overflow-hidden text-ellipsis whitespace-nowrap max-w-[63%]">
|
||||
<div className="text-sm text-default-600 overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-none ">
|
||||
<div className="text-sm font-light text-default-400 dark:text-default-600">
|
||||
{item.time}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex flex-col gap-5">
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<ImageIcon size={40} className="text-blue-700" />
|
||||
<p className="text-2xl">0 FOTO</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<YoutubeIcon size={40} className="text-blue-700" />
|
||||
<p className="text-2xl">0 AUDIO VISUAL</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<DockIcon size={40} className="text-blue-700" />
|
||||
<p className="text-2xl">0 TEXT</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<MicIcon size={40} className="text-blue-700" />
|
||||
<p className="text-2xl">0 AUDIO</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecentActivity;
|
||||
export default RecentActivity;
|
||||
|
|
|
|||
|
|
@ -15,44 +15,23 @@ const DashboardPage = () => {
|
|||
return (
|
||||
<div>
|
||||
<div className="grid grid-cols-12 items-center gap-5 mb-5">
|
||||
<div className="2xl:col-span-3 lg:col-span-4 col-span-12">
|
||||
<WelcomeBlock>
|
||||
<div className="max-w-[180px] relative z-10">
|
||||
<div className="text-xl font-medium text-default-900 dark:text-default-100 mb-2">
|
||||
{t("widget_title")}
|
||||
</div>
|
||||
<p className="text-sm text-default-800 dark:text-default-100">
|
||||
{t("widget_desc")}
|
||||
</p>
|
||||
</div>
|
||||
<BlockBadge className="end-3">{t("widget_badge")}</BlockBadge>
|
||||
<Image
|
||||
src="/images/all-img/widget-bg-1.png"
|
||||
width={400}
|
||||
height={150}
|
||||
priority
|
||||
alt="Description of the image"
|
||||
className="absolute top-0 start-0 w-full h-full object-cover rounded-md"
|
||||
/>
|
||||
</WelcomeBlock>
|
||||
</div>
|
||||
<div className="2xl:col-span-9 lg:col-span-8 col-span-12">
|
||||
<div className="2xl:col-span-12 lg:col-span-12 col-span-12">
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="grid md:grid-cols-3 gap-4">
|
||||
<StatisticsBlock
|
||||
title={t("revenue_chart_title")}
|
||||
title={"Hasil unggah disetujui hari ini"}
|
||||
total="3,564"
|
||||
className="bg-info/10 border-none shadow-none"
|
||||
/>
|
||||
<StatisticsBlock
|
||||
title={t("sold_chart_title")}
|
||||
title={"Hasil unggah direvisi hari ini"}
|
||||
total="564"
|
||||
className="bg-warning/10 border-none shadow-none"
|
||||
chartColor="#FB8F65"
|
||||
/>
|
||||
<StatisticsBlock
|
||||
title={t("growth_chart_title")}
|
||||
title={"Hasil unggah ditolak hari ini"}
|
||||
total="+5.0%"
|
||||
className="bg-primary/10 border-none shadow-none"
|
||||
chartColor="#2563eb"
|
||||
|
|
@ -63,44 +42,11 @@ const DashboardPage = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-8 col-span-12">
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<RevinueBarChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-4 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardTitle className="flex-1">
|
||||
{t("overview_circle_chart_title")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<OverviewChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-8 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardTitle className="flex-1">
|
||||
{t("company_table_title")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<CompanyTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-4 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardTitle className="flex-1">
|
||||
{t("recent_activity_table_title")}
|
||||
{"Total Produksi Konten"}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
|
|
@ -110,49 +56,13 @@ const DashboardPage = () => {
|
|||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-8 col-span-12">
|
||||
<MostSales />
|
||||
</div>
|
||||
<div className="lg:col-span-4 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardTitle className="flex-1">
|
||||
{t("overview_circle_chart_title")}
|
||||
</CardTitle>
|
||||
<CardTitle className="flex-1">{"Table"}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<OverviewRadialChart />
|
||||
<div className="bg-default-50 rounded p-4 mt-8 flex justify-between flex-wrap">
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-default-600 text-xs font-normal">
|
||||
{t("invested_amount")}
|
||||
</h4>
|
||||
<div className="text-sm font-medium text-default-900">
|
||||
$8264.35
|
||||
</div>
|
||||
<div className="text-default-500 text-xs font-normal">
|
||||
+0.001.23 (0.2%)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-default-600 text-xs font-normal">
|
||||
{t("invested_amount")}
|
||||
</h4>
|
||||
<div className="text-sm font-medium text-default-900">
|
||||
$8264.35
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-default-600 text-xs font-normal">
|
||||
{t("invested_amount")}
|
||||
</h4>
|
||||
<div className="text-sm font-medium text-default-900">
|
||||
$8264.35
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CardContent className="p-0">
|
||||
<CompanyTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { colors } from "@/lib/colors";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
import {
|
||||
getGridConfig,
|
||||
getYAxisConfig,
|
||||
} from "@/lib/appex-chart-options";
|
||||
|
||||
interface AccountChartProps {
|
||||
height?: number;
|
||||
series?: {
|
||||
data: number[]
|
||||
}[];
|
||||
chartType?: "line" | "area" | "bar";
|
||||
chartColor?: keyof typeof colors;
|
||||
}
|
||||
const AccountChart = (
|
||||
{
|
||||
height = 300,
|
||||
series = [
|
||||
{
|
||||
data: [31, 40, 28, 51, 42, 109, 100]
|
||||
}
|
||||
],
|
||||
chartType = "line",
|
||||
chartColor = "warning",
|
||||
}: AccountChartProps) => {
|
||||
|
||||
|
||||
const { theme: mode } = useTheme();
|
||||
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
curve: "smooth",
|
||||
width: 2,
|
||||
},
|
||||
colors: [colors[chartColor]],
|
||||
grid: getGridConfig(),
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
yaxis: getYAxisConfig(
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
),
|
||||
xaxis: {
|
||||
type: "datetime",
|
||||
categories: [
|
||||
"2018-09-19T00:00:00.000Z",
|
||||
"2018-09-19T01:30:00.000Z",
|
||||
"2018-09-19T02:30:00.000Z",
|
||||
"2018-09-19T03:30:00.000Z",
|
||||
"2018-09-19T04:30:00.000Z",
|
||||
"2018-09-19T05:30:00.000Z",
|
||||
"2018-09-19T06:30:00.000Z",
|
||||
],
|
||||
labels: {
|
||||
style: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"],
|
||||
fontFamily: "Inter",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
markers: {
|
||||
size: 4,
|
||||
colors: [colors[chartColor]],
|
||||
strokeColors: colors[chartColor],
|
||||
strokeWidth: 2,
|
||||
shape: "circle",
|
||||
radius: 2,
|
||||
hover: {
|
||||
sizeOffset: 1,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type={chartType}
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountChart;
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
"use client"
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Link } from '@/i18n/routing';
|
||||
import { useState } from "react";
|
||||
|
||||
const users = [
|
||||
{
|
||||
name: "Ab",
|
||||
},
|
||||
{
|
||||
name: "Bc",
|
||||
},
|
||||
{
|
||||
name: "Cd",
|
||||
},
|
||||
{
|
||||
name: "Df",
|
||||
},
|
||||
{
|
||||
name: "Ab",
|
||||
},
|
||||
{
|
||||
name: "Sd",
|
||||
},
|
||||
{
|
||||
name: "Sg",
|
||||
},
|
||||
];
|
||||
const AmountTransfer = () => {
|
||||
const t = useTranslations("BankingDashboard");
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="bg-default-50 rounded-md p-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="text-lg text-default-900 flex-1">{t("contacts")}</div>
|
||||
<Link
|
||||
href="#"
|
||||
className="flex-none font-medium text-default-900 underline text-sm"
|
||||
>
|
||||
{t("view_all")}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex overflow-x-auto gap-6 py-3 px-1">
|
||||
{users.map((user, index) => (
|
||||
<Avatar
|
||||
key={index}
|
||||
color="primary"
|
||||
className={cn("", {
|
||||
"ring-2 ring-primary ring-offset-2": index === activeIndex,
|
||||
})}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
<AvatarFallback className="text-lg">{user.name}</AvatarFallback>
|
||||
</Avatar>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-default-100 rounded-md p-4">
|
||||
<Label
|
||||
className="text-xs text-default-500 mb-1 cursor-pointer font-normal"
|
||||
htmlFor="cdp"
|
||||
>
|
||||
{t("total_amount")}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="$6547"
|
||||
id="cdp"
|
||||
className="bg-transparent border-none px-0 py-0 placeholder:text-default-400 text-base font-medium text-default-900"
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-default-100 rounded-md p-4">
|
||||
<Label
|
||||
className="text-xs text-default-500 mb-1 cursor-pointer font-normal"
|
||||
htmlFor="cd"
|
||||
>
|
||||
{t("recipient_account_number")}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="3458-3548-6548-3244"
|
||||
id="cd"
|
||||
className="bg-transparent border-none px-0 py-0 placeholder:text-default-400 text-base font-medium text-default-900"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1">
|
||||
<div className="text-xs text-default-500 mb-1">
|
||||
{t("total_amount")}
|
||||
</div>
|
||||
<div className="text-lg font-medium text-default-900">$6547</div>
|
||||
</div>
|
||||
<Button className="flex-none"> {t("send_money")} </Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AmountTransfer;
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
"use client"
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import "swiper/css";
|
||||
import "swiper/css/effect-cards";
|
||||
import { EffectCards } from 'swiper/modules';
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslations } from "next-intl";
|
||||
const cardLists = [
|
||||
{
|
||||
bg: "from-[#1EABEC] to-primary ",
|
||||
cardNo: "**** **** **** 3945",
|
||||
balance: "10,975"
|
||||
},
|
||||
{
|
||||
bg: "from-[#4C33F7] to-[#801FE0] ",
|
||||
cardNo: "**** **** **** 3945",
|
||||
balance: "12,975"
|
||||
},
|
||||
{
|
||||
bg: "from-[#FF9838] to-[#008773]",
|
||||
cardNo: "**** **** **** 3945",
|
||||
balance: "14,985"
|
||||
}
|
||||
];
|
||||
const CardSlider = () => {
|
||||
const t = useTranslations("BankingDashboard");
|
||||
return (
|
||||
<Swiper effect={"cards"} grabCursor={true} modules={[EffectCards]}>
|
||||
{cardLists.map((item, i) => (
|
||||
<SwiperSlide key={i}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-[200px] bg-gradient-to-r relative rounded-md p-4 text-white ",
|
||||
item.bg
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src="/images/all-img/visa-card-bg.png"
|
||||
alt=""
|
||||
fill
|
||||
sizes="(100vw, 100vh)"
|
||||
priority
|
||||
/>
|
||||
<div className="relative ">
|
||||
<Image
|
||||
src="/images/logo/visa.svg"
|
||||
height={48}
|
||||
width={90}
|
||||
className="w-20 h-10"
|
||||
alt=""
|
||||
/>
|
||||
<div className="mt-[18px] font-semibold text-lg mb-[17px]">
|
||||
{item.cardNo}
|
||||
</div>
|
||||
<div className="text-xs text-opacity-75 mb-0.5">
|
||||
{t("current_balance")}
|
||||
</div>
|
||||
<div className="text-2xl font-semibold">${item.balance}</div>
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardSlider;
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { useTheme } from "next-themes";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import {
|
||||
getGridConfig,
|
||||
getXAxisConfig,
|
||||
getYAxisConfig,
|
||||
} from "@/lib/appex-chart-options";
|
||||
import { colors } from "@/lib/colors";
|
||||
|
||||
interface HistoryChartProps {
|
||||
height?: number;
|
||||
series?: {
|
||||
name: string;
|
||||
data: number[]
|
||||
}[];
|
||||
}
|
||||
|
||||
const HistoryChart = ({
|
||||
height = 360,
|
||||
series = [
|
||||
{
|
||||
name: "Earnings",
|
||||
data: [31, 40, 28, 51, 42, 109, 100],
|
||||
},
|
||||
{
|
||||
name: "Expenses",
|
||||
data: [11, 32, 45, 32, 34, 52, 41],
|
||||
}
|
||||
]
|
||||
}: HistoryChartProps
|
||||
|
||||
) => {
|
||||
const [config] = useConfig();
|
||||
|
||||
const { theme: mode } = useTheme();
|
||||
|
||||
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
curve: "straight",
|
||||
width: 2,
|
||||
},
|
||||
colors: [colors.primary, colors.warning],
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
grid: getGridConfig(),
|
||||
|
||||
fill: {
|
||||
type: "gradient",
|
||||
gradient: {
|
||||
shadeIntensity: 0.3,
|
||||
opacityFrom: 0.4,
|
||||
opacityTo: 0.5,
|
||||
stops: [0, 30, 0],
|
||||
}
|
||||
},
|
||||
yaxis: getYAxisConfig(mode === 'light' ? colors["default-600"] : colors["default-300"]),
|
||||
xaxis: getXAxisConfig(
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
),
|
||||
legend: {
|
||||
offsetY: 4,
|
||||
show: true,
|
||||
fontSize: "12px",
|
||||
fontFamily: "Inter",
|
||||
labels: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"],
|
||||
},
|
||||
markers: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
offsetY: 0,
|
||||
offsetX: -5,
|
||||
radius: 12,
|
||||
},
|
||||
itemMargin: {
|
||||
horizontal: 18,
|
||||
vertical: 0,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type="area"
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryChart;
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import {
|
||||
ColumnDef,
|
||||
} from "@tanstack/react-table"
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
customer: {
|
||||
name: string;
|
||||
image: string;
|
||||
};
|
||||
history: {
|
||||
transId: string;
|
||||
},
|
||||
date: string;
|
||||
amount: string;
|
||||
status?: "paid" | "due" | "cancel";
|
||||
action: React.ReactNode;
|
||||
}
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Customer",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<Avatar
|
||||
className="rounded-full w-8 h-8"
|
||||
>
|
||||
{user?.image ? (
|
||||
<AvatarImage src={user.image} />
|
||||
) : (
|
||||
<AvatarFallback>AB</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "history",
|
||||
header: "History",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="text-default-600">
|
||||
Transfer
|
||||
</div>
|
||||
<div className="text-default-500 text-xs">
|
||||
Trans ID: {row.original.history.transId}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Date",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<span>{row.getValue("date")}</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: 'Amount',
|
||||
cell: ({ row }) => {
|
||||
const status = (row.getValue<string>('status') || 'paid') as 'paid' | 'due' | 'cancel';
|
||||
const classes: { [key in 'paid' | 'due' | 'cancel']: string } = {
|
||||
paid: 'text-primary',
|
||||
due: 'text-warning',
|
||||
cancel: 'text-destructive',
|
||||
};
|
||||
return <span className={cn(classes[status])}>{row.original.amount}</span>;
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent text-default-700 ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 " />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive group bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
history: {
|
||||
transId: "8HG654Pk32",
|
||||
},
|
||||
amount: "$1779.53",
|
||||
status:"paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
customer: {
|
||||
name: "Emily Davis",
|
||||
image: "/images/all-img/cus-1.png",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
history: {
|
||||
transId: "8HG654Pk33"
|
||||
},
|
||||
amount: "$2215.78",
|
||||
status:"due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
customer: {
|
||||
name: "Laura Smith",
|
||||
image: "/images/avatar/avatar-1.png",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
history: {
|
||||
transId: "8HG654Pk34"
|
||||
},
|
||||
amount: "$3183.60",
|
||||
status:"cancel",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
customer: {
|
||||
name: "Sarah Johnson",
|
||||
image: "/images/avatar/avatar-2.png",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
history: {
|
||||
transId: "8HG654Pk35"
|
||||
},
|
||||
amount: "$2587.86",
|
||||
status:"paid",
|
||||
action: null,
|
||||
}
|
||||
];
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { Metadata } from "next";
|
||||
|
||||
export const metadata:Metadata={
|
||||
title: 'Banking Page',
|
||||
description: 'Banking Page Description'
|
||||
}
|
||||
const Layout = ({children}: {children: React.ReactNode}) => {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
import { StatusBlock } from "@/components/blocks/status-block";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import CardSlider from "./components/card-slider";
|
||||
import AmountTransfer from "./components/amount-transfer";
|
||||
import TransactionsTable from "./components/transactions";
|
||||
import DashboardDropdown from "@/components/dashboard-dropdown";
|
||||
import HistoryChart from "./components/history-chart";
|
||||
import AccountChart from "./components/account-chart";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const BankingPage = () => {
|
||||
const t = useTranslations("BankingDashboard");
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<Card>
|
||||
<CardContent className=" p-6">
|
||||
<div className="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2 grid-cols-1 gap-5 place-content-center">
|
||||
<div className="flex space-x-4 h-full items-center rtl:space-x-reverse">
|
||||
<div className="flex-none">
|
||||
<Avatar className="h-20 w-20 bg-transparent hover:bg-transparent">
|
||||
<AvatarImage src="/images/all-img/main-user.png" />
|
||||
<AvatarFallback>SA</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h4 className="text-xl font-medium mb-2">
|
||||
<span className="block font-light text-default-800">
|
||||
{t("widget_title")},
|
||||
</span>
|
||||
<span className="block text-default-900">Mr. Jone Doe</span>
|
||||
</h4>
|
||||
<p className="text-sm text-default-600">{t("widget_desc")}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* status blocks */}
|
||||
<StatusBlock
|
||||
title={t("current_balance")}
|
||||
total="$34,564"
|
||||
chartType="bar"
|
||||
className="bg-default-50 shadow-none border-none"
|
||||
opacity={1}
|
||||
/>
|
||||
<StatusBlock
|
||||
title={t("credit")}
|
||||
total="$3,564"
|
||||
chartColor="#80fac1"
|
||||
className="bg-default-50 shadow-none border-none"
|
||||
series={[40, 70, 45, 100, 75, 40, 80, 90]}
|
||||
chartType="bar"
|
||||
opacity={1}
|
||||
/>
|
||||
<StatusBlock
|
||||
title={t("debit")}
|
||||
total="$3,564"
|
||||
chartColor="#ffbf99"
|
||||
className="bg-default-50 shadow-none border-none"
|
||||
chartType="bar"
|
||||
series={[40, 70, 45, 100, 75, 40, 80, 90]}
|
||||
opacity={1}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-4 col-span-12 space-y-5">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("my_card")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="max-w-[90%] mx-auto mt-2">
|
||||
<CardSlider />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("quick_transfer")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<AmountTransfer />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-8 col-span-12 space-y-5">
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<TransactionsTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row gap-1">
|
||||
<CardTitle className="flex-1">{t("history")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<HistoryChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid lg:grid-cols-2 grid-cols-1 gap-5">
|
||||
<Card>
|
||||
<CardHeader className="flex-row gap-1">
|
||||
<CardTitle className="flex-1">{t("account_receivable")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<AccountChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row gap-1">
|
||||
<CardTitle className="flex-1">{t("account_payable")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<AccountChart
|
||||
series={[
|
||||
{
|
||||
data: [31, 40, 28, 51, 42, 109, 100],
|
||||
},
|
||||
]}
|
||||
chartColor="primary"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BankingPage;
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { colors } from "@/lib/colors";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import { getGridConfig, getYAxisConfig } from "@/lib/appex-chart-options";
|
||||
|
||||
interface DealsDistributionChartProps {
|
||||
height?: number;
|
||||
series?: {
|
||||
name: string;
|
||||
data: number[];
|
||||
}[];
|
||||
}
|
||||
const defaultSeries = [
|
||||
{
|
||||
name: "Sales qualified",
|
||||
data: [44, 55, 57, 56, 61, 58, 63, 60, 66],
|
||||
},
|
||||
{
|
||||
name: "Meeting",
|
||||
data: [76, 85, 101, 98, 87, 105, 91, 114, 94],
|
||||
},
|
||||
{
|
||||
name: "In negotiation",
|
||||
data: [35, 41, 36, 26, 45, 48, 52, 53, 41],
|
||||
}
|
||||
];
|
||||
const DealDistributionsChart = ({ series = defaultSeries, height = 410 }: DealsDistributionChartProps) => {
|
||||
const [config] = useConfig();
|
||||
const { theme: mode } = useTheme();
|
||||
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
stacked: true,
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
dataLabels: {
|
||||
total: {
|
||||
enabled: false,
|
||||
}
|
||||
},
|
||||
columnWidth:"55%"
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
offsetX: 0,
|
||||
style: {
|
||||
fontSize: "12px",
|
||||
colors: [
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
]
|
||||
}
|
||||
},
|
||||
stroke: {
|
||||
show: false,
|
||||
width: 1,
|
||||
colors: [
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"],
|
||||
],
|
||||
},
|
||||
colors: [
|
||||
colors.primary,
|
||||
colors.info,
|
||||
colors.warning,
|
||||
],
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
grid: getGridConfig(),
|
||||
yaxis: getYAxisConfig(
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
),
|
||||
xaxis: {
|
||||
categories: [
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
],
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
},
|
||||
labels: {
|
||||
style: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
}
|
||||
}
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
position: "bottom",
|
||||
horizontalAlign: "center",
|
||||
fontSize: "12px",
|
||||
fontFamily: "Inter",
|
||||
offsetY: 0,
|
||||
labels: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"],
|
||||
},
|
||||
markers: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
radius: 12,
|
||||
offsetX: config.isRtl ? 5 : -5
|
||||
}
|
||||
},
|
||||
itemMargin: {
|
||||
horizontal: 18,
|
||||
vertical: 0,
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type="bar"
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DealDistributionsChart;
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
"use client"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip"
|
||||
|
||||
import {
|
||||
ColumnDef,
|
||||
} from "@tanstack/react-table"
|
||||
import { Eye, SquarePen, Trash2 } from "lucide-react"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Checkbox } from "@/components/ui/checkbox"
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export type DataProps = {
|
||||
id: string | number;
|
||||
order: number;
|
||||
customer: {
|
||||
name: string;
|
||||
image: string;
|
||||
};
|
||||
date: string;
|
||||
quantity: number;
|
||||
amount: string;
|
||||
status: "paid" | "due" | "canceled";
|
||||
action: React.ReactNode;
|
||||
}
|
||||
export const columns: ColumnDef<DataProps>[] = [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
}
|
||||
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
aria-label="Select all"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="xl:w-16">
|
||||
<Checkbox
|
||||
checked={row.getIsSelected()}
|
||||
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
aria-label="Select row"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "id",
|
||||
cell: ({ row }) => <span>{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "order",
|
||||
header: "Order",
|
||||
cell: ({ row }) => <span>{row.getValue("order")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "customer",
|
||||
header: "Customer",
|
||||
cell: ({ row }) => {
|
||||
const user = row.original.customer;
|
||||
return (
|
||||
<div className="font-medium text-card-foreground/80">
|
||||
<div className="flex gap-3 items-center">
|
||||
<Avatar
|
||||
className="rounded-full w-8 h-8"
|
||||
>
|
||||
{user?.image ? (
|
||||
<AvatarImage src={user.image} />
|
||||
) : (
|
||||
<AvatarFallback>AB</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<span className="text-sm text-default-600 whitespace-nowrap">
|
||||
{user?.name ?? "Unknown User"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Date",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<span>{row.getValue("date")}</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Quantity",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<span>{row.getValue("quantity")}</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: "Amount",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<span>{row.getValue("amount")}</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
paid: "bg-success/20 text-success",
|
||||
due: "bg-warning/20 text-warning",
|
||||
canceled: "bg-destructive/20 text-destructive"
|
||||
};
|
||||
const status = row.getValue<string>("status");
|
||||
const statusStyles = statusColors[status] || "default";
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5", statusStyles)}
|
||||
>{status} </Badge>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Action",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="w-7 h-7 ring-offset-transparent border-default-300 text-default-500"
|
||||
color="secondary"
|
||||
>
|
||||
<Eye className="w-4 h-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">
|
||||
<p>View</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="w-7 h-7 ring-offset-transparent border-default-300 text-default-500"
|
||||
color="secondary"
|
||||
>
|
||||
<SquarePen className="w-4 h-4" />
|
||||
</Button>
|
||||
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">
|
||||
<p>Edit</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="w-7 h-7 ring-offset-transparent border-default-300 text-default-500"
|
||||
color="secondary"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="bg-destructive text-destructive-foreground">
|
||||
<p>Delete</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,654 +0,0 @@
|
|||
import { DataProps } from "./columns";
|
||||
|
||||
export const data: DataProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
order: 951,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/26/2022",
|
||||
quantity: 13,
|
||||
amount: "$1779.53",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: 238,
|
||||
customer: {
|
||||
name: "Emily Davis",
|
||||
image: "/images/all-img/cus-1.png",
|
||||
},
|
||||
date: "2/6/2022",
|
||||
quantity: 13,
|
||||
amount: "$2215.78",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: 339,
|
||||
customer: {
|
||||
name: "Laura Smith",
|
||||
image: "/images/avatar/avatar-1.png",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 1,
|
||||
amount: "$3183.60",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: 365,
|
||||
customer: {
|
||||
name: "Sarah Johnson",
|
||||
image: "/images/avatar/avatar-2.png",
|
||||
},
|
||||
date: "11/7/2021",
|
||||
quantity: 13,
|
||||
amount: "$2587.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: 513,
|
||||
customer: {
|
||||
name: "Rachel Brown",
|
||||
image: "/images/avatar/avatar-3.png",
|
||||
},
|
||||
date: "5/6/2022",
|
||||
quantity: 12,
|
||||
amount: "$3840.73",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: 534,
|
||||
customer: {
|
||||
name: "Megan Taylor",
|
||||
image: "/images/avatar/avatar-4.png",
|
||||
},
|
||||
date: "2/14/2022",
|
||||
quantity: 12,
|
||||
amount: "$4764.18",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: 77,
|
||||
customer: {
|
||||
name: "Sophie Clark",
|
||||
image: "/images/avatar/avatar-5.png",
|
||||
},
|
||||
date: "7/30/2022",
|
||||
quantity: 6,
|
||||
amount: "$2875.05",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: 238,
|
||||
customer: {
|
||||
name: "Natalie Martin",
|
||||
image: "/images/avatar/avatar-6.png",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 9,
|
||||
amount: "$2491.02",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: 886,
|
||||
customer: {
|
||||
name: "Hannah Lewis",
|
||||
image: "/images/avatar/avatar-7.png",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 8,
|
||||
amount: "$3006.95",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
order: 3,
|
||||
customer: {
|
||||
name: "Lisa White",
|
||||
image: "/images/avatar/avatar-8.png",
|
||||
},
|
||||
date: "8/4/2022",
|
||||
quantity: 12,
|
||||
amount: "$2160.32",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
order: 198,
|
||||
customer: {
|
||||
name: "Emma Walker",
|
||||
image: "/images/avatar/avatar-9.png",
|
||||
},
|
||||
date: "4/5/2022",
|
||||
quantity: 8,
|
||||
amount: "$1272.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
order: 829,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-10.png",
|
||||
},
|
||||
date: "8/9/2022",
|
||||
quantity: 2,
|
||||
amount: "$4327.86",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
order: 595,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-11.png",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 11,
|
||||
amount: "$3671.81",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
order: 374,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-12.png",
|
||||
},
|
||||
date: "2/10/2022",
|
||||
quantity: 2,
|
||||
amount: "$3401.82",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
order: 32,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-1.png",
|
||||
},
|
||||
date: "5/20/2022",
|
||||
quantity: 4,
|
||||
amount: "$2387.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
order: 89,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-2.png",
|
||||
},
|
||||
date: "5/3/2022",
|
||||
quantity: 15,
|
||||
amount: "$4236.61",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
order: 912,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-3.png",
|
||||
},
|
||||
date: "10/31/2021",
|
||||
quantity: 11,
|
||||
amount: "$2975.66",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
order: 621,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-4.png",
|
||||
},
|
||||
date: "1/13/2022",
|
||||
quantity: 5,
|
||||
amount: "$4576.13",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
order: 459,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-5.png",
|
||||
},
|
||||
date: "6/14/2022",
|
||||
quantity: 5,
|
||||
amount: "$1276.56",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
order: 108,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-6.png",
|
||||
},
|
||||
date: "10/8/2021",
|
||||
quantity: 4,
|
||||
amount: "$1078.64",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 21,
|
||||
order: 492,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-7.png",
|
||||
},
|
||||
date: "11/17/2021",
|
||||
quantity: 9,
|
||||
amount: "$1678.19",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 22,
|
||||
order: 42,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-8.png",
|
||||
},
|
||||
date: "4/4/2022",
|
||||
quantity: 9,
|
||||
amount: "$1822.02",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 23,
|
||||
order: 841,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-9.png",
|
||||
},
|
||||
date: "3/21/2022",
|
||||
quantity: 5,
|
||||
amount: "$1578.39",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 24,
|
||||
order: 561,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-10.png",
|
||||
},
|
||||
date: "6/18/2022",
|
||||
quantity: 12,
|
||||
amount: "$2130.49",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 25,
|
||||
order: 720,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-1.png",
|
||||
},
|
||||
date: "8/15/2022",
|
||||
quantity: 8,
|
||||
amount: "$3721.11",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 26,
|
||||
order: 309,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-2.png",
|
||||
},
|
||||
date: "4/28/2022",
|
||||
quantity: 8,
|
||||
amount: "$4683.45",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 27,
|
||||
order: 24,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-3.png",
|
||||
},
|
||||
date: "9/6/2021",
|
||||
quantity: 7,
|
||||
amount: "$2863.71",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 28,
|
||||
order: 518,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-4.png",
|
||||
},
|
||||
date: "9/11/2021",
|
||||
quantity: 4,
|
||||
amount: "$3879.41",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 29,
|
||||
order: 98,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-5.png",
|
||||
},
|
||||
date: "1/27/2022",
|
||||
quantity: 5,
|
||||
amount: "$4660.81",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 30,
|
||||
order: 940,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/avatar/avatar-6.png",
|
||||
},
|
||||
date: "9/16/2021",
|
||||
quantity: 6,
|
||||
amount: "$4800.75",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 31,
|
||||
order: 925,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "1/8/2022",
|
||||
quantity: 1,
|
||||
amount: "$2299.05",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
order: 122,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "11/18/2021",
|
||||
quantity: 1,
|
||||
amount: "$3578.02",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 33,
|
||||
order: 371,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/30/2022",
|
||||
quantity: 13,
|
||||
amount: "$1996.06",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 34,
|
||||
order: 296,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "11/13/2021",
|
||||
quantity: 5,
|
||||
amount: "$2749.00",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 35,
|
||||
order: 887,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "12/7/2021",
|
||||
quantity: 11,
|
||||
amount: "$4353.01",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 36,
|
||||
order: 30,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "9/9/2021",
|
||||
quantity: 15,
|
||||
amount: "$3252.37",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 37,
|
||||
order: 365,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "2/12/2022",
|
||||
quantity: 5,
|
||||
amount: "$4044.10",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 38,
|
||||
order: 649,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/6/2022",
|
||||
quantity: 5,
|
||||
amount: "$3859.92",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 39,
|
||||
order: 923,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "7/25/2022",
|
||||
quantity: 14,
|
||||
amount: "$1652.47",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 40,
|
||||
order: 423,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/2/2022",
|
||||
quantity: 8,
|
||||
amount: "$2700.12",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 41,
|
||||
order: 703,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "12/8/2021",
|
||||
quantity: 8,
|
||||
amount: "$4508.13",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 42,
|
||||
order: 792,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "11/22/2021",
|
||||
quantity: 11,
|
||||
amount: "$4938.04",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 43,
|
||||
order: 400,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "4/6/2022",
|
||||
quantity: 1,
|
||||
amount: "$3471.32",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 44,
|
||||
order: 718,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "2/4/2022",
|
||||
quantity: 4,
|
||||
amount: "$4011.60",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 45,
|
||||
order: 970,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "3/30/2022",
|
||||
quantity: 15,
|
||||
amount: "$3723.64",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 46,
|
||||
order: 786,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "11/20/2021",
|
||||
quantity: 2,
|
||||
amount: "$2441.15",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 47,
|
||||
order: 925,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "10/24/2021",
|
||||
quantity: 11,
|
||||
amount: "$1196.76",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 48,
|
||||
order: 929,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "6/30/2022",
|
||||
quantity: 10,
|
||||
amount: "$3579.57",
|
||||
status: "canceled",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 49,
|
||||
order: 377,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "11/16/2021",
|
||||
quantity: 4,
|
||||
amount: "$2657.84",
|
||||
status: "due",
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
id: 50,
|
||||
order: 661,
|
||||
customer: {
|
||||
name: "Jenny Wilson",
|
||||
image: "/images/all-img/customer_1.png",
|
||||
},
|
||||
date: "8/15/2022",
|
||||
quantity: 6,
|
||||
amount: "$2905.94",
|
||||
status: "paid",
|
||||
action: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { colors } from "@/lib/colors";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
interface TrendsCalculationChartProps {
|
||||
height?: number;
|
||||
series?: number[];
|
||||
chartLabels?:string[];
|
||||
}
|
||||
const TrendsCalculationChart = ({
|
||||
series = [44, 55, 30],
|
||||
height = 360,
|
||||
chartLabels=["70% Sent", "18% Opend", "12% Rejected"],
|
||||
}: TrendsCalculationChartProps) => {
|
||||
const [config] = useConfig();
|
||||
const { theme: mode } = useTheme();
|
||||
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
width: 0
|
||||
},
|
||||
labels:chartLabels,
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
fontSize: "20px",
|
||||
},
|
||||
},
|
||||
colors: [
|
||||
colors.primary,
|
||||
colors.success,
|
||||
colors.warning,
|
||||
],
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
legend: {
|
||||
position:"bottom",
|
||||
labels: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"],
|
||||
},
|
||||
itemMargin: {
|
||||
horizontal: 5,
|
||||
vertical: 5,
|
||||
},
|
||||
markers: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
radius: 10,
|
||||
offsetX: config.isRtl ? 5 : -5
|
||||
}
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type="pie"
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrendsCalculationChart;
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
export const campaigns = [
|
||||
{
|
||||
name: "Channel",
|
||||
value: "roi",
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
value: "40%",
|
||||
},
|
||||
{
|
||||
name: "Website",
|
||||
value: "28%",
|
||||
},
|
||||
{
|
||||
name: "Facebook",
|
||||
value: "34%",
|
||||
},
|
||||
{
|
||||
name: "Offline",
|
||||
value: "17%",
|
||||
}
|
||||
];
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { Metadata } from "next";
|
||||
|
||||
export const metadata:Metadata={
|
||||
title: 'CRM',
|
||||
description: 'CRM Dashboard Description'
|
||||
}
|
||||
const Layout = ({children}: {children: React.ReactNode}) => {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
@ -1,206 +0,0 @@
|
|||
import DashboardDropdown from "@/components/dashboard-dropdown";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { TrendingDown, TrendingUp } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import DealDistributionsChart from "./components/deal-distributions-chart";
|
||||
import { campaigns } from "./data";
|
||||
import TrendsCalculationChart from "./components/trends-calculation-chart";
|
||||
import TransactionsTable from "./components/transactions";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const CrmPage = () => {
|
||||
const t = useTranslations("CrmDashboard");
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="col-span-12 lg:col-span-8 space-y-5">
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="grid xl:grid-cols-4 lg:grid-cols-2 grid-cols-1 gap-3">
|
||||
<Card className="bg-warning/20 relative shadow-none border-none">
|
||||
<CardContent className="p-4">
|
||||
<Image
|
||||
src="/images/all-img/shade-1.png"
|
||||
alt="images"
|
||||
draggable="false"
|
||||
className="absolute top-0 start-0 w-full h-full object-contain"
|
||||
width={300}
|
||||
height={200}
|
||||
priority
|
||||
/>
|
||||
<div className="mb-6 text-sm text-default-900 font-medium">
|
||||
{t("sales")}
|
||||
</div>
|
||||
<div className=" text-2xl text-default-900 font-medium mb-6">
|
||||
354
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-none text-xl">
|
||||
<TrendingUp className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1 text-sm">
|
||||
<span className="block mb-0.2">25.67% </span>
|
||||
<span className="block mb-1 text-default-600">
|
||||
{t("from_last_weeks")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-info/20 relative shadow-none border-none">
|
||||
<CardContent className="p-4">
|
||||
<Image
|
||||
src="/images/all-img/shade-2.png"
|
||||
alt="images"
|
||||
draggable="false"
|
||||
className="absolute top-0 start-0 w-full h-full object-contain"
|
||||
width={300}
|
||||
height={200}
|
||||
priority
|
||||
/>
|
||||
<div className="mb-6 text-sm text-default-900 font-medium">
|
||||
{t("revenue")}
|
||||
</div>
|
||||
<div className=" text-2xl text-default-900 font-medium mb-6">
|
||||
$86,954
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-none text-xl">
|
||||
<TrendingUp className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1 text-sm">
|
||||
<span className="block mb-0.2">8.67% </span>
|
||||
<span className="block mb-1 text-default-600">
|
||||
{t("from_last_weeks")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-primary/20 relative shadow-none border-none">
|
||||
<CardContent className="p-4">
|
||||
<Image
|
||||
src="/images/all-img/shade-3.png"
|
||||
alt="images"
|
||||
draggable="false"
|
||||
className="absolute top-0 start-0 w-full h-full object-contain"
|
||||
width={300}
|
||||
height={200}
|
||||
priority
|
||||
/>
|
||||
<div className="mb-6 text-sm text-default-900 font-medium">
|
||||
{t("conversion")}
|
||||
</div>
|
||||
<div className=" text-2xl text-default-900 font-medium mb-6">
|
||||
15%
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-none text-xl">
|
||||
<TrendingDown className="w-4 h-4 text-destructive" />
|
||||
</div>
|
||||
<div className="flex-1 text-sm">
|
||||
<span className="block mb-0.2 text-destructive">
|
||||
1.67%{" "}
|
||||
</span>
|
||||
<span className="block mb-1 text-default-600">
|
||||
{t("from_last_weeks")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-success/20 relative shadow-none border-none">
|
||||
<CardContent className=" p-4">
|
||||
<Image
|
||||
src="/images/all-img/shade-4.png"
|
||||
alt="images"
|
||||
draggable="false"
|
||||
className="absolute top-0 start-0 w-full h-full object-contain"
|
||||
width={300}
|
||||
height={200}
|
||||
priority
|
||||
/>
|
||||
<div className="mb-6 text-sm text-default-900 font-medium">
|
||||
{t("leads")}
|
||||
</div>
|
||||
<div className=" text-2xl text-default-900 font-medium mb-6">
|
||||
654
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-none text-xl">
|
||||
<TrendingDown className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1 text-sm">
|
||||
<span className="block mb-0.2 text-primary">
|
||||
1.67%{" "}
|
||||
</span>
|
||||
<span className="block mb-1 text-default-600">
|
||||
{t("from_last_weeks")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row flex-wrap gap-2">
|
||||
<CardTitle className="flex-1 whitespace-nowrap">
|
||||
{t("deal_distribution_by_stage")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<DealDistributionsChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4 space-y-5">
|
||||
<Card>
|
||||
<CardHeader className="flex-row gap-3">
|
||||
<CardTitle className="flex-1">{t("campaigns")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="divide-y divide-default-100 dark:divide-default-300">
|
||||
{campaigns.map((item, i) => (
|
||||
<li
|
||||
key={`campaign-${i}`}
|
||||
className="first:text-xs text-sm text-default-600 py-2.5 px-2 first:uppercase"
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<span>{item.name}</span>
|
||||
<span>{item.value}</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex-row gap-3">
|
||||
<CardTitle className="flex-1">
|
||||
{t("trends_calculation")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<TrendsCalculationChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Card>
|
||||
<CardContent className="px-0">
|
||||
<TransactionsTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CrmPage;
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
"use client"
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
const customers = [
|
||||
{
|
||||
title: "Nicole Kidman",
|
||||
img: "/images/all-img/cus-1.png",
|
||||
value: 70,
|
||||
bg: "before:bg-info/30",
|
||||
barColor: "info",
|
||||
number: 2,
|
||||
},
|
||||
{
|
||||
title: "Monica Bellucci",
|
||||
img: "/images/all-img/cus-2.png",
|
||||
value: 80,
|
||||
bg: "before:bg-warning/30",
|
||||
barColor: "warning",
|
||||
active: true,
|
||||
number: 1,
|
||||
},
|
||||
{
|
||||
title: "Pamela Anderson",
|
||||
img: "/images/all-img/cus-3.png",
|
||||
value: 65,
|
||||
bg: "before:bg-success/30",
|
||||
barColor: "success",
|
||||
number: 3,
|
||||
},
|
||||
{
|
||||
title: "Dianne Russell",
|
||||
img: "/images/users/user-1.jpg",
|
||||
value: 60,
|
||||
bg: "before:bg-info/30",
|
||||
barColor: "info",
|
||||
number: 4,
|
||||
},
|
||||
{
|
||||
title: "Robert De Niro",
|
||||
img: "/images/users/user-2.jpg",
|
||||
value: 50,
|
||||
bg: "before:bg-warning/30",
|
||||
barColor: "warning",
|
||||
number: 5,
|
||||
},
|
||||
{
|
||||
title: "De Niro",
|
||||
img: "/images/users/user-3.jpg",
|
||||
value: 60,
|
||||
bg: "before:bg-warning/30",
|
||||
barColor: "warning",
|
||||
number: 6,
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
const CustomerList = ({ item }: any) => {
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return (
|
||||
<div className="relative p-4 rounded md:flex items-center md:space-x-10 md:space-y-0 space-y-3 rtl:space-x-reverse">
|
||||
<div
|
||||
className={`${
|
||||
item.active ? "ring-2 ring-[#FFC155]" : ""
|
||||
} h-10 w-10 rounded-full relative`}
|
||||
>
|
||||
{item.active && (
|
||||
<span className="crown absolute -top-[14px] left-1/2 -translate-x-1/2">
|
||||
<Image
|
||||
width={40}
|
||||
height={40}
|
||||
className="w-7 h-7"
|
||||
src="/images/icon/crown.svg"
|
||||
alt=""
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<Image
|
||||
src={item.img}
|
||||
alt=""
|
||||
width={100}
|
||||
height={100}
|
||||
className="w-full h-full rounded-full"
|
||||
priority
|
||||
/>
|
||||
<span className="h-4 w-4 absolute right-0 bottom-0 rounded-full bg-[#FFC155] border border-white flex flex-col items-center justify-center text-white text-[10px] font-medium">
|
||||
{item.number}
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-sm text-default-600 font-semibold">{item.title}</h4>
|
||||
<div className="inline-block text-center bg-default-900 text-default-100 px-2.5 py-1.5 text-xs font-medium rounded-full min-w-[60px]">
|
||||
{item.value}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between text-sm font-normal mb-3">
|
||||
<span>{t("progress")}</span>
|
||||
<span className="font-normal">{item.value}%</span>
|
||||
</div>
|
||||
<Progress value={item.value} color={item.barColor} size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const CustomerCard = ({ item }: any) => {
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return <div
|
||||
className={` relative z-[1] text-center p-4 rounded before:w-full before:h-[calc(100%-60px)] before:absolute before:left-0 before:top-[60px] before:rounded before:z-[-1] before:bg-opacity-[0.1] ${item.bg}`}
|
||||
>
|
||||
<div
|
||||
className={`${item.active ? "ring-2 ring-[#FFC155]" : ""
|
||||
} h-[70px] w-[70px] rounded-full mx-auto mb-4 relative`}
|
||||
>
|
||||
{item.active && (
|
||||
<span className="crown absolute -top-[24px] left-1/2 -translate-x-1/2">
|
||||
<Image width={40} height={40} className="w-7 h-7" src="/images/icon/crown.svg" alt="" />
|
||||
</span>
|
||||
)}
|
||||
<Image
|
||||
src={item.img}
|
||||
alt=""
|
||||
width={100}
|
||||
height={100}
|
||||
className="w-full h-full rounded-full"
|
||||
priority
|
||||
/>
|
||||
<span className="h-[27px] w-[27px] absolute right-0 bottom-0 rounded-full bg-[#FFC155] border border-white flex flex-col items-center justify-center text-white text-xs font-medium">
|
||||
{item.number}
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-sm text-default-600 font-semibold mb-4">
|
||||
{item.title}
|
||||
</h4>
|
||||
<div className="inline-block bg-default-900 text-default-100 px-2.5 py-1.5 text-xs font-medium rounded-full min-w-[60px]">
|
||||
{item.value}
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm font-normal mb-3 mt-4">
|
||||
<span>{t("progress")}</span>
|
||||
<span className="font-normal">{item.value}%</span>
|
||||
</div>
|
||||
<Progress value={item.value} color={item.barColor} size="sm" />
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
const Customer = () => {
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return (
|
||||
<div className="pb-2">
|
||||
<div className="grid md:grid-cols-3 grid-cols-1 gap-5">
|
||||
{customers.slice(0, 3).map((item, i) => <CustomerCard item={item} key={`customer-${i}`} />)}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-5 mt-5">
|
||||
{customers.slice(3, 8).map((item, i) => <CustomerList item={item} key={`customer-item-${i}`} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Customer;
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
import { OrdersDataProps } from "./recent-order-table";
|
||||
|
||||
export const data:OrdersDataProps[] = [
|
||||
{
|
||||
user: {
|
||||
name: "Esther Howard",
|
||||
image: "/images/users/user-1.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#324567",
|
||||
price: "$90.99",
|
||||
status: "paid",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Guy Hawkins",
|
||||
image: "/images/users/user-2.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "due",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Bessie Cooper",
|
||||
image: "/images/users/user-3.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Kathryn Murphy",
|
||||
image: "/images/users/user-4.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$38.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-5.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$178.65",
|
||||
status: "shipped",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-6.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$74.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Esther Howard",
|
||||
image: "/images/users/user-1.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#324567",
|
||||
price: "$90.99",
|
||||
status: "paid",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Guy Hawkins",
|
||||
image: "/images/users/user-2.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "due",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Bessie Cooper",
|
||||
image: "/images/users/user-3.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Kathryn Murphy",
|
||||
image: "/images/users/user-4.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$38.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-5.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$178.65",
|
||||
status: "shipped",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-6.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$74.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Esther Howard",
|
||||
image: "/images/users/user-1.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#324567",
|
||||
price: "$90.99",
|
||||
status: "paid",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Guy Hawkins",
|
||||
image: "/images/users/user-2.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "due",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Bessie Cooper",
|
||||
image: "/images/users/user-3.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Kathryn Murphy",
|
||||
image: "/images/users/user-4.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$38.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-5.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$178.65",
|
||||
status: "shipped",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-6.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$74.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Esther Howard",
|
||||
image: "/images/users/user-1.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#324567",
|
||||
price: "$90.99",
|
||||
status: "paid",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Guy Hawkins",
|
||||
image: "/images/users/user-2.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "due",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Bessie Cooper",
|
||||
image: "/images/users/user-3.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$78.65",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Kathryn Murphy",
|
||||
image: "/images/users/user-4.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$38.65",
|
||||
status: "cancled",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-5.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$178.65",
|
||||
status: "shipped",
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: "Darrell Steward",
|
||||
image: "/images/users/user-6.jpg",
|
||||
},
|
||||
product: "Headphone",
|
||||
invoice: "#4224",
|
||||
price: "$74.65",
|
||||
status: "cancled",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const products = [
|
||||
{
|
||||
img: "/images/all-img/p-1.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
{
|
||||
img: "/images/all-img/p-2.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
{
|
||||
img: "/images/all-img/p-3.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
{
|
||||
img: "/images/all-img/p-4.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
{
|
||||
img: "/images/all-img/p-5.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
{
|
||||
img: "/images/all-img/p-6.png",
|
||||
price: "$150.00",
|
||||
title: "Car engine oil",
|
||||
href:"#"
|
||||
},
|
||||
];
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
"use client"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import world from "./world-map.json";
|
||||
import { VectorMap } from "@south-paw/react-vector-maps";
|
||||
import { useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const sales = [
|
||||
{
|
||||
title: "Nevada",
|
||||
amount: "$125k",
|
||||
cls: "bg-primary/70 ring-primary/30",
|
||||
},
|
||||
{
|
||||
title: "Colorado",
|
||||
amount: "$325k",
|
||||
cls: "bg-success/70 ring-success/30",
|
||||
},
|
||||
{
|
||||
title: "Iowa",
|
||||
amount: "$67",
|
||||
cls: "bg-info/70 ring-info/30",
|
||||
},
|
||||
{
|
||||
title: "Arkansas",
|
||||
amount: "$354k",
|
||||
cls: "bg-warning/70 ring-warning/30",
|
||||
},
|
||||
{
|
||||
title: "Wyoming",
|
||||
amount: "$195k",
|
||||
cls: "bg-success/70 ring-success/30",
|
||||
},
|
||||
{
|
||||
title: "Other countries",
|
||||
amount: "$295k",
|
||||
cls: "bg-secondary/70 ring-secondary/30",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const MostSales = () => {
|
||||
const [filterMap, setFilterMap] = useState("usa");
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardTitle className="flex-1">{t("most_sales_map_title")}</CardTitle>
|
||||
<div className="border border-default-200 dark:border-default-300 rounded p-1 flex items-center bg-background">
|
||||
<span
|
||||
className={cn(
|
||||
"flex-1 text-sm font-normal px-3 py-1 transition-all duration-150 rounded cursor-pointer",
|
||||
{
|
||||
"bg-default-900 text-primary-foreground":
|
||||
filterMap === "global",
|
||||
}
|
||||
)}
|
||||
onClick={() => setFilterMap("global")}
|
||||
>
|
||||
{t("total_earning_map_button_1")}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"flex-1 text-sm font-normal px-3 py-1 transition-all duration-150 rounded cursor-pointer",
|
||||
{ "bg-default-900 text-primary-foreground": filterMap === "usa" }
|
||||
)}
|
||||
onClick={() => setFilterMap("usa")}
|
||||
>
|
||||
USA
|
||||
</span>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<VectorMap {...world} className="h-[280px] w-full dash-codevmap" />
|
||||
<ul className="bg-default-50 rounded p-4 min-w-[184px] mt-8 flex justify-between flex-wrap items-center text-center">
|
||||
{sales.map((item, i) => (
|
||||
<li key={i} className="text-sm text-default-600">
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex h-1.5 w-1.5 bg-primary/60 ring-opacity-25 rounded-full ring-4",
|
||||
item.cls
|
||||
)}
|
||||
></span>
|
||||
<span>{item.title}</span>
|
||||
</div>
|
||||
<div className="block mt-1">{item.amount}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default MostSales;
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import { Link } from '@/i18n/routing';
|
||||
|
||||
interface Product {
|
||||
img: string;
|
||||
price: string;
|
||||
title: string;
|
||||
href: string
|
||||
}
|
||||
const Product = ({ product }: { product: Product }) => {
|
||||
const { img, href, price, title } = product;
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return (
|
||||
<div className="bg-default-50 p-4 rounded text-center">
|
||||
<div className="h-12 w-12 rounded-full mb-4 mx-auto">
|
||||
<Image
|
||||
src={img}
|
||||
alt=""
|
||||
height={100}
|
||||
width={100}
|
||||
className="w-full h-full rounded-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-default-500 text-sm mb-1 font-normal">
|
||||
{" "}
|
||||
{price}{" "}
|
||||
</div>
|
||||
<div className="text-default-600 text-sm mb-4">{title}</div>
|
||||
<Button
|
||||
asChild
|
||||
color="secondary"
|
||||
size="md"
|
||||
fullWidth
|
||||
>
|
||||
<Link href={href}> {t("best_selling_products_button")}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Product;
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { data } from "./data"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
export type OrdersDataProps = {
|
||||
user: {
|
||||
name: string;
|
||||
image: string;
|
||||
}
|
||||
product: string;
|
||||
invoice: string;
|
||||
price: string;
|
||||
status: "paid" | "due" | "pending" | "cancled" | "shipped";
|
||||
}
|
||||
|
||||
export const columns: ColumnDef<OrdersDataProps>[] = [
|
||||
{
|
||||
accessorKey: "user",
|
||||
header: "User",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-none">
|
||||
<div className="w-8 h-8">
|
||||
<Avatar>
|
||||
<AvatarImage src={row.original.user.image}></AvatarImage>
|
||||
<AvatarFallback>SC</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 text-start">
|
||||
{row.original.user.name}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "invoice",
|
||||
header: "Invoice",
|
||||
cell: ({ row }) => (
|
||||
<span>{row.getValue("invoice")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "price",
|
||||
header: "Price",
|
||||
cell: ({ row }) => (
|
||||
<span>{row.getValue("price")}</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const status = row.getValue("status") as string;
|
||||
const statusClass:{[key: string]: string} = {
|
||||
"paid": "bg-success/10 text-success",
|
||||
"due": "bg-warning/10 text-warning",
|
||||
"pending": "bg-primary/10 text-primary",
|
||||
"cancled": "bg-destructive/10 text-destructive",
|
||||
"shipped": "bg-warning/10 text-warning",
|
||||
}
|
||||
const className = statusClass[status] || "bg-default/10 text-default";
|
||||
return (
|
||||
<Badge className={cn("px-3 min-w-[90px] justify-center py-1 rounded-full",className)}>{status}</Badge>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const RecentOrderTable = () => {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
||||
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
||||
const [rowSelection, setRowSelection] = React.useState({})
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 6,
|
||||
})
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder ? null : flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<div className="flex items-center justify-center gap-2 flex-none py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className='w-8 h-8 border-transparent hover:bg-transparent'
|
||||
>
|
||||
<ChevronLeft className='w-5 h-5 text-default-900' />
|
||||
</Button>
|
||||
{table.getPageOptions().map((page, pageIndex) => (
|
||||
<Button
|
||||
key={`basic-data-table-${pageIndex}`}
|
||||
onClick={() => table.setPageIndex(pageIndex)}
|
||||
size="icon"
|
||||
className={`w-7 h-7 hover:text-primary-foreground ${table.getState().pagination.pageIndex === pageIndex ? 'bg-default' : 'bg-default-100 text-default'}`}
|
||||
>
|
||||
{page + 1}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className='w-8 h-8 border-transparent hover:bg-transparent'>
|
||||
<ChevronRight className='w-5 h-5 text-default-900' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RecentOrderTable;
|
||||
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { colors } from "@/lib/colors";
|
||||
import { useTheme } from "next-themes";
|
||||
import { getLabel, getYAxisConfig } from "@/lib/appex-chart-options";
|
||||
|
||||
const VisitorsChart = ({ height = 350 }) => {
|
||||
const { theme: mode } = useTheme();
|
||||
|
||||
const series = [
|
||||
{
|
||||
name: "Male",
|
||||
data: [41, 64, 81, 60, 42, 42, 33, 23],
|
||||
},
|
||||
{
|
||||
name: "Female",
|
||||
data: [65, 46, 42, 25, 58, 63, 76, 43],
|
||||
},
|
||||
];
|
||||
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: false,
|
||||
blur: 8,
|
||||
left: 1,
|
||||
top: 1,
|
||||
opacity: 0.5,
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
colors: [colors.warning, colors.primary],
|
||||
fill: {
|
||||
opacity: [0.4, 0.4],
|
||||
},
|
||||
yaxis: getYAxisConfig(
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
),
|
||||
xaxis: {
|
||||
categories: ["2019", "2020", "2021", "2017", "2018", "2015", "2014", "2013"],
|
||||
labels: getLabel(mode === 'light' ? colors["default-600"] : colors["default-300"]),
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
fontSize: "14px",
|
||||
fontFamily: "Inter",
|
||||
labels: {
|
||||
colors: mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
radar: {
|
||||
size: undefined,
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
polygons: {
|
||||
strokeColors: 'transparent',
|
||||
strokeWidth: 0.5,
|
||||
connectorColors: 'transparent',
|
||||
},
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
width: 2,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type="radar"
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default VisitorsChart;
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
const Chart = dynamic(() => import("react-apexcharts"), { ssr: false });
|
||||
import { useTheme } from "next-themes";
|
||||
import {
|
||||
getGridConfig,
|
||||
getXAxisConfig,
|
||||
getYAxisConfig,
|
||||
} from "@/lib/appex-chart-options";
|
||||
import { colors } from "@/lib/colors";
|
||||
|
||||
interface VisitorsReportChartProps {
|
||||
height?: number;
|
||||
seriesData?: number[];
|
||||
}
|
||||
const VisitorsReportChart = ({
|
||||
height = 300 ,
|
||||
seriesData =[90, 70, 85, 60, 80, 70, 90, 75, 60, 80]
|
||||
|
||||
}: VisitorsReportChartProps) => {
|
||||
|
||||
const { theme: mode } = useTheme();
|
||||
const series = [
|
||||
{
|
||||
data:seriesData
|
||||
},
|
||||
];
|
||||
const options: any = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
curve: "smooth",
|
||||
width: 4,
|
||||
},
|
||||
colors: [colors.primary],
|
||||
tooltip: {
|
||||
theme: mode === "dark" ? "dark" : "light",
|
||||
},
|
||||
grid: getGridConfig(),
|
||||
fill: {
|
||||
type: "gradient",
|
||||
colors: [colors.primary],
|
||||
gradient: {
|
||||
shadeIntensity: 1,
|
||||
opacityFrom: 0.4,
|
||||
opacityTo: 0.5,
|
||||
stops: [50, 100, 0],
|
||||
},
|
||||
},
|
||||
yaxis: getYAxisConfig(mode === 'light' ? colors["default-600"] : colors["default-300"]),
|
||||
xaxis: getXAxisConfig(
|
||||
mode === 'light' ? colors["default-600"] : colors["default-300"]
|
||||
),
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Chart
|
||||
options={options}
|
||||
series={series}
|
||||
type="area"
|
||||
height={height}
|
||||
width={"100%"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default VisitorsReportChart;
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,15 +0,0 @@
|
|||
import { Metadata } from "next";
|
||||
|
||||
export const metadata:Metadata={
|
||||
title: 'Ecommerce',
|
||||
description: 'Ecommerce Description'
|
||||
}
|
||||
const Layout = ({children}: {children: React.ReactNode}) => {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
import { StatusBlock } from "@/components/blocks/status-block";
|
||||
import { WelcomeBlock } from "@/components/blocks/welcome-block";
|
||||
import { Box, ShoppingCart, TrendingUp } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import RevinueBarChart from "@/components/revenue-bar-chart";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import DashboardDropdown from "@/components/dashboard-dropdown";
|
||||
import OrdersBlock from "@/components/blocks/orders-block";
|
||||
import EarningBlock from "@/components/blocks/earning-block";
|
||||
import Customer from "./components/customer";
|
||||
import RecentOrderTable from "./components/recent-order-table";
|
||||
import VisitorsReportChart from "./components/visitors-report";
|
||||
import VisitorsChart from "./components/visitors-chart";
|
||||
import MostSales from "./components/most-sales";
|
||||
import { products } from "./components/data";
|
||||
import Product from "./components/product";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const EcommercePage = () => {
|
||||
const t = useTranslations("EcommerceDashboard");
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
<WelcomeBlock>
|
||||
<div className="max-w-[180px] relative z-10">
|
||||
<h4 className="text-xl font-medium text-primary-foreground dark:text-default-900 mb-2">
|
||||
<span className="block font-normal"> {t("widget_title")}</span>
|
||||
<span className="block">Mr. Dianne Russell</span>
|
||||
</h4>
|
||||
<p className="text-sm text-primary-foreground dark:text-default-900 font-normal">
|
||||
{t("widget_desc")}
|
||||
</p>
|
||||
</div>
|
||||
<Image
|
||||
src="/images/all-img/widget-bg-2.png"
|
||||
width={400}
|
||||
height={150}
|
||||
priority
|
||||
alt="Description of the image"
|
||||
className="absolute top-0 start-0 w-full h-full object-cover rounded-md"
|
||||
/>
|
||||
</WelcomeBlock>
|
||||
<StatusBlock
|
||||
title={t("revenue_chart_title")}
|
||||
total="3,564"
|
||||
iconWrapperClass="bg-info/10"
|
||||
chartColor="#00EBFF"
|
||||
icon={<ShoppingCart className="w-5 h-5 text-info" />}
|
||||
/>
|
||||
<StatusBlock
|
||||
title={t("sold_chart_title")}
|
||||
total="564"
|
||||
icon={<Box className="w-5 h-5 text-warning" />}
|
||||
iconWrapperClass="bg-warning/10"
|
||||
chartColor="#FB8F65"
|
||||
/>
|
||||
<StatusBlock
|
||||
title={t("growth_chart_title")}
|
||||
total="+5.0%"
|
||||
icon={<TrendingUp className="w-5 h-5 text-primary" />}
|
||||
iconWrapperClass="bg-primary/10"
|
||||
chartColor="#2563eb"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="col-span-12 lg:col-span-8">
|
||||
<Card>
|
||||
<CardContent className="pt-5">
|
||||
<RevinueBarChart height={420} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">{t("statistics")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 gap-5">
|
||||
<div className="col-span-2 md:col-span-1">
|
||||
<OrdersBlock
|
||||
title={t("orders")}
|
||||
total="123k"
|
||||
chartColor="#f1595c"
|
||||
className="border-none shadow-none bg-default-50 "
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 md:col-span-1">
|
||||
<OrdersBlock
|
||||
title={t("profit")}
|
||||
total="123k"
|
||||
chartColor="#4669fa"
|
||||
chartType="line"
|
||||
percentageContent={
|
||||
<span className="text-primary">+2.5%</span>
|
||||
}
|
||||
className="border-none shadow-none bg-default-50 col-span-2 md:col-span-1"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<EarningBlock
|
||||
title={t("earnings")}
|
||||
total="$12,335.00"
|
||||
percentage="+08%"
|
||||
className="col-span-2 border-none shadow-none bg-default-50"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid lg:grid-cols-2 grid-cols-1 gap-5">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">{t("customer")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Customer />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">
|
||||
{t("recent_order_table_title")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="px-0">
|
||||
<RecentOrderTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-8 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">{t("visitors_report")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<VisitorsReportChart height={350} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="lg:col-span-4 col-span-12">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">
|
||||
{t("Visitors_by_gender")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<VisitorsChart />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid lg:grid-cols-2 grid-cols-1 gap-5">
|
||||
<MostSales />
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center gap-1">
|
||||
<CardTitle className="flex-1">
|
||||
{t("best_selling_products")}
|
||||
</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid md:grid-cols-3 grid-cols-1 gap-5">
|
||||
{products.map((product, index) => (
|
||||
<Product key={index} product={product} />
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EcommercePage;
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
|
||||
|
||||
export const meets = [
|
||||
{
|
||||
img: "/images/svg/sk.svg",
|
||||
title: "Meeting with client",
|
||||
date: "01 Nov 2021",
|
||||
meet: "Zoom meeting",
|
||||
},
|
||||
{
|
||||
img: "/images/svg/path.svg",
|
||||
title: "Design meeting (team)",
|
||||
date: "01 Nov 2021",
|
||||
meet: "Skyp meeting",
|
||||
},
|
||||
{
|
||||
img: "/images/svg/dc.svg",
|
||||
title: "Background research",
|
||||
date: "01 Nov 2021",
|
||||
meet: "Google meeting",
|
||||
},
|
||||
{
|
||||
img: "/images/svg/sk.svg",
|
||||
title: "Meeting with client",
|
||||
date: "01 Nov 2021",
|
||||
meet: "Zoom meeting",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const tasks = [
|
||||
{
|
||||
id: 1,
|
||||
image: "/images/users/user-1.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: "/images/users/user-2.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: "/images/users/user-3.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
image: "/images/users/user-4.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
image: "/images/users/user-5.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
image: "/images/users/user-6.jpg",
|
||||
title: "Amet minim mollit non deserunt ullam.",
|
||||
}]
|
||||
|
||||
export const messagesData = [
|
||||
{
|
||||
title: "Wade Warren",
|
||||
desc: "Hi! How are you doing?.....",
|
||||
active: true,
|
||||
hasnotifaction: true,
|
||||
notification_count: 1,
|
||||
image: "/images/users/user-1.jpg"
|
||||
},
|
||||
{
|
||||
title: "Savannah Nguyen",
|
||||
desc: "Hi! How are you doing?.....",
|
||||
active: false,
|
||||
hasnotifaction: false,
|
||||
image:"/images/users/user-2.jpg"
|
||||
},
|
||||
{
|
||||
title: "Ralph Edwards",
|
||||
desc: "Hi! How are you doing?.....",
|
||||
active: false,
|
||||
hasnotifaction: true,
|
||||
notification_count: 8,
|
||||
image: "/images/users/user-3.jpg"
|
||||
},
|
||||
{
|
||||
title: "Cody Fisher",
|
||||
desc: "Hi! How are you doing?.....",
|
||||
active: true,
|
||||
hasnotifaction: false,
|
||||
image: "/images/users/user-4.jpg"
|
||||
},
|
||||
{
|
||||
title: "Savannah Nguyen",
|
||||
desc: "Hi! How are you doing?.....",
|
||||
active: false,
|
||||
hasnotifaction: false,
|
||||
image: "/images/users/user-4.jpg"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const activityList = [
|
||||
{
|
||||
title: "Project start date",
|
||||
desc: "This parcel is paid for by the customer. Please contact the customer for any further information.",
|
||||
date: "Sep 20, 2021 ",
|
||||
time: "12:32 AM",
|
||||
status: "ok",
|
||||
},
|
||||
{
|
||||
title: "Project start date",
|
||||
date: "Sep 20, 2021 ",
|
||||
desc: "This parcel is paid for by the customer. Please contact the customer for any further information.",
|
||||
time: "12:32 AM",
|
||||
status: "ok",
|
||||
},
|
||||
{
|
||||
title: "Project start date",
|
||||
date: "Sep 20, 2021 ",
|
||||
desc: "This parcel is paid for by the customer. Please contact the customer for any further information.",
|
||||
time: "12:32 AM",
|
||||
status: "ok",
|
||||
},
|
||||
{
|
||||
title: "Project start date",
|
||||
date: "Sep 20, 2021 ",
|
||||
desc: "This parcel is paid for by the customer. Please contact the customer for any further information.",
|
||||
time: "12:32 AM",
|
||||
},
|
||||
{
|
||||
title: "Project start date",
|
||||
date: "Sep 20, 2021 ",
|
||||
desc: "This parcel is paid for by the customer. Please contact the customer for any further information.",
|
||||
time: "12:32 AM",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const teamData = [
|
||||
{
|
||||
customer: {
|
||||
name: "Arlene McCoy",
|
||||
image: "/images/users/user-1.jpg",
|
||||
deg: "Ux designer",
|
||||
},
|
||||
status: "progress",
|
||||
time: "42.5 hours",
|
||||
chart: null,
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
customer: {
|
||||
name: "Arlene McCoy",
|
||||
image: "/images/users/user-2.jpg",
|
||||
deg: "Ux designer",
|
||||
},
|
||||
status: "complete",
|
||||
time: "42.5 hours",
|
||||
chart: null,
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
customer: {
|
||||
name: "Arlene McCoy",
|
||||
image: "/images/users/user-3.jpg",
|
||||
deg: "Ux designer",
|
||||
},
|
||||
status: "progress",
|
||||
time: "42.5 hours",
|
||||
chart: null,
|
||||
action: null,
|
||||
},
|
||||
{
|
||||
customer: {
|
||||
name: "Arlene McCoy",
|
||||
image: "/images/users/user-4.jpg",
|
||||
deg: "Ux designer",
|
||||
},
|
||||
status: "complete",
|
||||
time: "42.5 hours",
|
||||
chart: null,
|
||||
action: null
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
export const files = [
|
||||
{
|
||||
img: "/images/icon/file-1.svg",
|
||||
title: "Dashboard.fig",
|
||||
date: "06 June 2021 / 155MB",
|
||||
},
|
||||
{
|
||||
img: "/images/icon/pdf-1.svg",
|
||||
title: "Ecommerce.pdf",
|
||||
date: "06 June 2021 / 155MB",
|
||||
},
|
||||
{
|
||||
img: "/images/icon/zip-1.svg",
|
||||
title: "Job portal_app.zip",
|
||||
date: "06 June 2021 / 155MB",
|
||||
},
|
||||
{
|
||||
img: "/images/icon/pdf-2.svg",
|
||||
title: "Ecommerce.pdf",
|
||||
date: "06 June 2021 / 155MB",
|
||||
},
|
||||
{
|
||||
img: "/images/icon/scr-1.svg",
|
||||
title: "Screenshot.jpg",
|
||||
date: "06 June 2021 / 155MB",
|
||||
}
|
||||
];
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { Metadata } from "next";
|
||||
|
||||
export const metadata:Metadata={
|
||||
title: 'Project Dashboard',
|
||||
description: 'Project Dashboard Description'
|
||||
}
|
||||
const Layout = ({children}: {children: React.ReactNode}) => {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
import ProgressBlock from "@/components/blocks/progress-block";
|
||||
import DashboardDropdown from "@/components/dashboard-dropdown";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Icon } from "@/components/ui/icon";
|
||||
import { BarChart } from "lucide-react";
|
||||
import { meets, messagesData, tasks, activityList, teamData, files } from "./data";
|
||||
import Image from "next/image";
|
||||
import TaskItem from "@/components/project/task-item";
|
||||
import MessageListItem from "@/components/project/message-list-item";
|
||||
import ActivityItem from "@/components/project/activity";
|
||||
import TeamTable from "@/components/project/team-table";
|
||||
import NotesCalendar from "@/components/project/notes-calendar";
|
||||
import DealsDistributionChart from "@/components/project/deals-distribution-chart";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const ProjectPage = () => {
|
||||
const t = useTranslations("ProjectDashboard");
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="col-span-12 lg:col-span-8 space-y-5">
|
||||
<Card>
|
||||
<CardContent className="p-5">
|
||||
<div className="grid grid-cols-12 gap-3">
|
||||
<div className="col-span-12 lg:col-span-8 grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-3">
|
||||
<Card className="bg-info/20 shadow-none border-none">
|
||||
<CardContent className=" p-4 text-center">
|
||||
<div className="mx-auto h-10 w-10 rounded-full flex items-center justify-center bg-white mb-4">
|
||||
<BarChart className=" h-6 w-6 text-info" />
|
||||
</div>
|
||||
<div className="block text-sm text-default-600 font-medium mb-1.5">
|
||||
{" "}
|
||||
{t("total_task")}
|
||||
</div>
|
||||
<div className="text-2xl text-default-900 font-medium">
|
||||
64
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-warning/20 shadow-none border-none">
|
||||
<CardContent className=" p-4 text-center">
|
||||
<div className="mx-auto h-10 w-10 rounded-full flex items-center justify-center bg-white mb-4">
|
||||
<Icon
|
||||
className="w-6 h-6 text-warning"
|
||||
icon="heroicons:chart-pie"
|
||||
/>
|
||||
</div>
|
||||
<div className="block text-sm text-default-600 font-medium mb-1.5">
|
||||
{t("completed")}
|
||||
</div>
|
||||
<div className="text-2xl text-default-900 font-medium">
|
||||
45
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-primary/20 shadow-none border-none">
|
||||
<CardContent className=" p-4 text-center">
|
||||
<div className="mx-auto h-10 w-10 rounded-full flex items-center justify-center bg-white mb-4">
|
||||
<Icon
|
||||
className="w-6 h-6 text-primary"
|
||||
icon="heroicons:clock"
|
||||
/>
|
||||
</div>
|
||||
<div className="block text-sm text-default-600 font-medium mb-1.5">
|
||||
{t("hours")}
|
||||
</div>
|
||||
<div className="text-2xl text-default-900 font-medium">
|
||||
190
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-success/20 shadow-none border-none">
|
||||
<CardContent className="p-4 text-center">
|
||||
<div className="mx-auto h-10 w-10 rounded-full flex items-center justify-center bg-white mb-4">
|
||||
<Icon
|
||||
className="w-6 h-6 text-success"
|
||||
icon="heroicons:calculator"
|
||||
/>
|
||||
</div>
|
||||
<div className="block text-sm text-default-600 font-medium mb-1.5">
|
||||
{t("spendings")}
|
||||
</div>
|
||||
<div className="text-2xl text-default-900 font-medium">
|
||||
$3,564
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<ProgressBlock
|
||||
title={t("progress")}
|
||||
height={113}
|
||||
className="border-none shadow-none"
|
||||
chartType="pie"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row justify-between">
|
||||
<CardTitle>{t("deal_distribution_by_stage")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<DealsDistributionChart height={310} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("notes")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="px-2">
|
||||
<NotesCalendar />
|
||||
<ul className="divide-y divide-default-100 dark:divide-default-300">
|
||||
{meets.map((item, i) => (
|
||||
<li key={i} className=" py-2.5 px-3">
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-1 flex gap-2.5">
|
||||
<div className="flex-none">
|
||||
<div className="h-8 w-8">
|
||||
<Image
|
||||
src={item.img}
|
||||
alt=""
|
||||
className="w-full h-full "
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="text-default-600 text-sm mb-1 font-medium">
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="flex gap-1 font-normal text-xs text-default-500">
|
||||
<div className="text-base">
|
||||
<Icon icon="heroicons-outline:video-camera" />
|
||||
</div>
|
||||
{item.meet}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-none text-xs text-default-600">
|
||||
{item.date}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-5">
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle>{t("task_list")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<ul className="divide-y divide-default-100 dark:divide-default-300">
|
||||
{tasks.map((task, index) => (
|
||||
<TaskItem key={index} task={task} />
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle>{t("messages")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<ul className="divide-y divide-default-100 dark:divide-default-300">
|
||||
{messagesData.map((message, index) => (
|
||||
<MessageListItem message={message} key={index} />
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle>{t("activity")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<ul className="relative before:absolute before:start-6 before:top-3.5 before:w-[1px] before:h-[80%] before:bg-default-200 dark:before:bg-default-300">
|
||||
{activityList.map((activity, index) => (
|
||||
<ActivityItem activity={activity} key={index} />
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="col-span-12 lg:col-span-8">
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle>{t("team_members")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<TeamTable data={teamData} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle>{t("files")}</CardTitle>
|
||||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="divide-y divide-default-100 dark:divide-default-300">
|
||||
{files.map((item, i) => (
|
||||
<li key={i} className="py-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 flex gap-2">
|
||||
<div className="flex-none">
|
||||
<div className="h-8 w-8">
|
||||
<Image
|
||||
src={item.img}
|
||||
alt=""
|
||||
width={32}
|
||||
height={32}
|
||||
className=" w-full h-full object-cover rounded-full border hover:border-primary-foreground border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="text-default-600 text-sm">
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="font-normal text-xs text-default-500 mt-1">
|
||||
{item.date}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs text-default-900 "
|
||||
>
|
||||
{t("download")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectPage;
|
||||
|
|
@ -1,38 +1,38 @@
|
|||
'use client'
|
||||
"use client";
|
||||
import React from "react";
|
||||
import DashCodeLogo from "./dascode-logo";
|
||||
import { Link } from '@/i18n/routing';
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import { useMenuHoverConfig } from "@/hooks/use-menu-hover";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
|
||||
|
||||
|
||||
const Logo = () => {
|
||||
const [config] = useConfig()
|
||||
const [hoverConfig] = useMenuHoverConfig();
|
||||
const { hovered } = hoverConfig
|
||||
const isDesktop = useMediaQuery('(min-width: 1280px)');
|
||||
|
||||
if (config.sidebar === 'compact') {
|
||||
return <Link href="/dashboard/analytics" className="flex gap-2 items-center justify-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
|
||||
</Link>
|
||||
}
|
||||
if (config.sidebar === 'two-column' || !isDesktop) return null
|
||||
const [config] = useConfig();
|
||||
const [hoverConfig] = useMenuHoverConfig();
|
||||
const { hovered } = hoverConfig;
|
||||
const isDesktop = useMediaQuery("(min-width: 1280px)");
|
||||
|
||||
if (config.sidebar === "compact") {
|
||||
return (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
{(!config?.collapsed || hovered) && (
|
||||
<h1 className="text-xl font-semibold text-default-900 ">
|
||||
DashCode
|
||||
</h1>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/dashboard/analytics"
|
||||
className="flex gap-2 items-center justify-center "
|
||||
>
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
if (config.sidebar === "two-column" || !isDesktop) return null;
|
||||
|
||||
return (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
{/* <DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
{(!config?.collapsed || hovered) && (
|
||||
<h1 className="text-xl font-semibold text-default-900 ">D</h1>
|
||||
)} */}
|
||||
<img src="/../images/all-img/mediahub-logo.png" alt="logo" width={150} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default Logo;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,32 @@
|
|||
"use client";
|
||||
import React from "react";
|
||||
import DateRangePicker from "@/components/date-range-picker";
|
||||
import { usePathname } from "@/components/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import DateRangePicker from '@/components/date-range-picker'
|
||||
import { usePathname } from '@/components/navigation'
|
||||
import { cn } from "@/lib/utils"
|
||||
const PageTitle = ({
|
||||
title,
|
||||
className,
|
||||
}: {
|
||||
title?: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
const pathname = usePathname();
|
||||
const name = pathname?.split("/").slice(1).join(" ");
|
||||
|
||||
const PageTitle = ({ title, className }: { title?: string, className?: string }) => {
|
||||
const pathname = usePathname();
|
||||
const name = pathname?.split('/').slice(1).join(' ');
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-wrap gap-4 items-center justify-between",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="text-2xl font-medium text-default-800 capitalize">
|
||||
Dashboard
|
||||
</div>
|
||||
<DateRangePicker />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-wrap gap-4 items-center justify-between', className)}>
|
||||
<div className="text-2xl font-medium text-default-800 capitalize">
|
||||
{title ? title : name ? name : null}
|
||||
</div>
|
||||
<DateRangePicker />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageTitle
|
||||
export default PageTitle;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,32 @@
|
|||
'use client'
|
||||
import React from 'react'
|
||||
import { Link } from '@/components/navigation'
|
||||
import DashCodeLogo from "@/components/dascode-logo"
|
||||
import { useConfig } from '@/hooks/use-config'
|
||||
import { useMediaQuery } from '@/hooks/use-media-query'
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { Link } from "@/components/navigation";
|
||||
import DashCodeLogo from "@/components/dascode-logo";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
|
||||
const HeaderLogo = () => {
|
||||
const [config] = useConfig();
|
||||
const [config] = useConfig();
|
||||
|
||||
const isDesktop = useMediaQuery('(min-width: 1280px)');
|
||||
const isDesktop = useMediaQuery("(min-width: 1280px)");
|
||||
|
||||
return (
|
||||
config.layout === 'horizontal' ? (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
<h1 className="text-xl font-semibold text-default-900 lg:block hidden ">
|
||||
DashCode
|
||||
</h1>
|
||||
</Link>
|
||||
) :
|
||||
!isDesktop && (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
<h1 className="text-xl font-semibold text-default-900 lg:block hidden ">
|
||||
DashCode
|
||||
</h1>
|
||||
</Link>
|
||||
)
|
||||
return config.layout === "horizontal" ? (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
<h1 className="text-xl font-semibold text-default-900 lg:block hidden ">
|
||||
DashCode
|
||||
</h1>
|
||||
</Link>
|
||||
) : (
|
||||
!isDesktop && (
|
||||
<Link href="/dashboard/analytics" className="flex gap-2 items-center ">
|
||||
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
|
||||
<h1 className="text-xl font-semibold text-default-900 lg:block hidden ">
|
||||
DashCode
|
||||
</h1>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderLogo
|
||||
export default HeaderLogo;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,234 @@
|
|||
"use client";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import qs from "qs";
|
||||
|
||||
import axiosInstance from "./axiosInstance";
|
||||
import axiosInstanceJson from "./axiosInstanceJson";
|
||||
import axiosInterceptor from "./axiosInterceptor";
|
||||
import { data } from "@/app/[locale]/(protected)/charts/rechart/charts-rechart-bar/data";
|
||||
import { url } from "inspector";
|
||||
|
||||
const baseURL = "https://netidhub.com/api/";
|
||||
const tokenAuth = Cookies.get("access_token")
|
||||
? Cookies.get("access_token")
|
||||
: null;
|
||||
|
||||
export async function postAPI(url: any, data: any) {
|
||||
const headers = {
|
||||
Authorization: `Bearer ${tokenAuth}`,
|
||||
};
|
||||
const response = await axiosInstance
|
||||
.post(url, qs.stringify(data), { headers })
|
||||
.catch((error) => error.response);
|
||||
if (response?.status > 300) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data.error_description,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAPI(url: any, token: any) {
|
||||
const headers = {
|
||||
Authorization: `Bearer ${token || tokenAuth}`,
|
||||
};
|
||||
const response = await axios
|
||||
.get(baseURL + url, { headers })
|
||||
.catch((error) => error.response);
|
||||
if (response?.status > 300) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.error_description,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
export async function postAPIWithJson(url: any, data: any, token: any) {
|
||||
const headers = {
|
||||
Authorization: `Bearer ${token || tokenAuth}`,
|
||||
};
|
||||
const response = await axiosInstanceJson
|
||||
.post(url, data, { headers })
|
||||
.catch((error) => error.response);
|
||||
if (response?.status > 300) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteAPIWithJson(url: any) {
|
||||
const response = await axiosInstanceJson
|
||||
.delete(url)
|
||||
.catch((error) => error.response);
|
||||
if (response?.status > 300) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAPIInterceptor(url: any) {
|
||||
const response = await axiosInterceptor
|
||||
.get(url)
|
||||
.catch((error) => error.response);
|
||||
if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else if (response?.status > 300 && response?.status != 401) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
} else if (response?.data.success) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function postAPIInterceptor(url: any, data: any) {
|
||||
const response = await axiosInterceptor
|
||||
.post(url, data)
|
||||
.catch((error) => error.response);
|
||||
if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else if (response?.status > 300 && response?.status != 401) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
} else if (response?.data.success) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data.message,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteAPIInterceptor(url: any, data: any) {
|
||||
const response = await axiosInterceptor
|
||||
.delete(url, { data })
|
||||
.catch((error) => error.response);
|
||||
if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else if (response?.status > 300 && response?.status != 401) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
} else if (response?.data.success) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAPIInterceptorProfile(url: any) {
|
||||
const response = await axiosInterceptor
|
||||
.get(url)
|
||||
.catch((error) => error.response);
|
||||
if (response?.status > 300) {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
message: response?.data?.message,
|
||||
data: response?.data,
|
||||
};
|
||||
}
|
||||
|
||||
// export async function postFileApiInterceptor(url: any, data: any) {
|
||||
// const response = await axiosInterceptor
|
||||
// .post(url, data, {
|
||||
// onUploadProgress: (progressEvent) => {
|
||||
// const percentage = Math.round(
|
||||
// (progressEvent.loaded * 100) / progressEvent.total
|
||||
// );
|
||||
// console.log(percentage);
|
||||
// },
|
||||
// })
|
||||
// .catch((error) => error.response);
|
||||
// if (response?.status > 300) {
|
||||
// return {
|
||||
// error: true,
|
||||
// message: response?.data?.message,
|
||||
// data: null,
|
||||
// };
|
||||
// }
|
||||
// if (response?.data.success) {
|
||||
// return {
|
||||
// error: false,
|
||||
// message: "success",
|
||||
// data: response?.data,
|
||||
// };
|
||||
// }
|
||||
// return {
|
||||
// error: true,
|
||||
// message: response?.data.message,
|
||||
// data: null,
|
||||
// };
|
||||
// }
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
"use client";
|
||||
import axios from "axios";
|
||||
|
||||
const baseURL = "https://netidhub.com/api/";
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
withCredentials: false,
|
||||
});
|
||||
|
||||
export default axiosInstance;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
"use client";
|
||||
import axios from "axios";
|
||||
|
||||
const baseURL = "https://netidhub.com/api/";
|
||||
|
||||
const axiosInstanceJson = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
export default axiosInstanceJson;
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
"use client";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import qs from "qs";
|
||||
|
||||
const baseURL = "https://netidhub.com/api/";
|
||||
const tokenAuth = Cookies.get("access_token")
|
||||
? Cookies.get("access_token")
|
||||
: null;
|
||||
const expired = Cookies.get("time_refresh")
|
||||
? Cookies.get("time_refresh")
|
||||
: null;
|
||||
|
||||
const axiosInterceptor = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${tokenAuth}`,
|
||||
},
|
||||
});
|
||||
|
||||
axiosInterceptor.interceptors.request.use(async (req) => {
|
||||
const time = new Date();
|
||||
const expiredValue = Cookies.get("time_refresh"); // Assuming 'time_refresh' contains `expired`
|
||||
|
||||
if (expiredValue) {
|
||||
const expired = new Date(expiredValue); // Ensure valid Date object
|
||||
if (time.getTime() >= expired.getTime()) {
|
||||
const url = `${baseURL}/signin`;
|
||||
const data = {
|
||||
grant_type: "refresh_token",
|
||||
client_id: "mediahub-app",
|
||||
refresh_token: Cookies.get("refresh_token") || "", // Fallback to empty string if undefined
|
||||
};
|
||||
|
||||
const response = await axios
|
||||
.post(url, qs.stringify(data))
|
||||
.catch((error) => error.response);
|
||||
|
||||
if (response?.status === 401) {
|
||||
Object.keys(Cookies.get() || {}).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else {
|
||||
const { access_token, refresh_token } = response?.data || {};
|
||||
const dateTime = new Date();
|
||||
const newTime = dateTime.getTime() + 10 * 60 * 1000;
|
||||
Cookies.set("access_token", access_token, { expires: 1 });
|
||||
Cookies.set("refresh_token", refresh_token, { expires: 1 });
|
||||
Cookies.set("time_refresh", new Date(newTime).toISOString(), {
|
||||
expires: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return req;
|
||||
});
|
||||
|
||||
export default axiosInterceptor;
|
||||
40
lib/menus.ts
40
lib/menus.ts
|
|
@ -51,48 +51,48 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "content",
|
||||
href: "/content/image",
|
||||
label: t("konten"),
|
||||
label: "konten",
|
||||
active: pathname.includes("/content"),
|
||||
icon: "line-md:youtube",
|
||||
submenus: [
|
||||
{
|
||||
href: "/content/image",
|
||||
label: t("image"),
|
||||
label: "image",
|
||||
active: pathname === "/content/image",
|
||||
icon: "ic:outline-image",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/content/audio-visual",
|
||||
label: t("audio visual"),
|
||||
label: "audio visual",
|
||||
active: pathname === "/content/audio-visual",
|
||||
icon: "line-md:youtube",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/content/teks",
|
||||
label: t("text"),
|
||||
label: "teks",
|
||||
active: pathname === "/content/teks",
|
||||
icon: "heroicons:document",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/content/audio",
|
||||
label: t("audio"),
|
||||
label: "audio",
|
||||
active: pathname === "/content/audio",
|
||||
icon: "heroicons:share",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/content/spit",
|
||||
label: t("spit"),
|
||||
label: "spit",
|
||||
active: pathname === "/content/spit",
|
||||
icon: "heroicons:credit-card",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/content/nulis-ai",
|
||||
label: t("nulis ai"),
|
||||
label: "nulis ai",
|
||||
active: pathname === "/content/nulisai",
|
||||
icon: "heroicons:credit-card",
|
||||
children: [],
|
||||
|
|
@ -108,7 +108,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "agenda-setting",
|
||||
href: "/agenda-setting",
|
||||
label: t("agenda setting"),
|
||||
label: "agenda setting",
|
||||
active: pathname.includes("/agenda-setting"),
|
||||
icon: "iconoir:journal-page",
|
||||
submenus: [],
|
||||
|
|
@ -122,20 +122,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "planning",
|
||||
href: "/planning",
|
||||
label: t("perencanaan"),
|
||||
label: "perencanaan",
|
||||
active: pathname.includes("/planning"),
|
||||
icon: "pajamas:planning",
|
||||
submenus: [
|
||||
{
|
||||
href: "/planning/mediahub",
|
||||
label: t("mediaHub"),
|
||||
label: "mediaHub",
|
||||
active: pathname === "/planning/mediahub",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/planning/medsos-mediahub",
|
||||
label: t("medsos mediahub"),
|
||||
label: "medsos mediahub",
|
||||
active: pathname === "/planning/medsos-mediahub",
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -151,7 +151,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "task",
|
||||
href: "/task",
|
||||
label: t("penugasan"),
|
||||
label: "penugasan",
|
||||
active: pathname.includes("/task"),
|
||||
icon: "fluent:clipboard-task-add-24-regular",
|
||||
submenus: [],
|
||||
|
|
@ -165,27 +165,27 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "schedule",
|
||||
href: "/schedule",
|
||||
label: t("schedule"),
|
||||
label: "schedule",
|
||||
active: pathname.includes("/schedule"),
|
||||
icon: "uil:schedule",
|
||||
submenus: [
|
||||
{
|
||||
href: "/schedule/press-conference",
|
||||
label: t("konfesensi pers"),
|
||||
label: "konfesensi pers",
|
||||
active: pathname === "/schedule/press-conference",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/schedule/event",
|
||||
label: t("event"),
|
||||
label: "event",
|
||||
active: pathname === "/schedule/event",
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/schedule/press-release",
|
||||
label: t("pers rilis"),
|
||||
label: "pers rilis",
|
||||
active: pathname === "/schedule/press-release",
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -201,7 +201,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "blog",
|
||||
href: "/blog",
|
||||
label: t("indeks"),
|
||||
label: "indeks",
|
||||
active: pathname.includes("/blog"),
|
||||
icon: "fluent:clipboard-text-32-regular",
|
||||
submenus: [],
|
||||
|
|
@ -215,7 +215,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "curatedcontent",
|
||||
href: "/curated-content",
|
||||
label: t("kurasi konten"),
|
||||
label: "kurasi konten",
|
||||
active: pathname.includes("/curated-content"),
|
||||
icon: "pixelarticons:calendar-text",
|
||||
submenus: [],
|
||||
|
|
@ -229,7 +229,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "communication",
|
||||
href: "/communication",
|
||||
label: t("komunikasi"),
|
||||
label: "komunikasi",
|
||||
active: pathname.includes("/communication"),
|
||||
icon: "token:chat",
|
||||
submenus: [],
|
||||
|
|
@ -243,7 +243,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
{
|
||||
id: "contest",
|
||||
href: "/contest",
|
||||
label: t("lomba"),
|
||||
label: "lomba",
|
||||
active: pathname.includes("/contest"),
|
||||
icon: "ic:outline-emoji-events",
|
||||
submenus: [],
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -53,14 +53,18 @@
|
|||
"@south-paw/react-vector-maps": "^3.2.0",
|
||||
"@tanstack/react-table": "^8.19.2",
|
||||
"@types/cleave.js": "^1.4.12",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/qs": "^6.9.17",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"apexcharts": "^3.49.2",
|
||||
"axios": "^1.7.8",
|
||||
"chart.js": "^4.4.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"cleave.js": "^1.6.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"cookie": "^1.0.2",
|
||||
"date-fns": "^3.6.0",
|
||||
"dayjs": "^1.11.11",
|
||||
"embla-carousel-autoplay": "^8.1.3",
|
||||
|
|
@ -71,6 +75,7 @@
|
|||
"google-map-react": "^2.2.1",
|
||||
"input-otp": "^1.2.4",
|
||||
"jotai": "^2.9.3",
|
||||
"js-cookie": "^3.0.5",
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.390.0",
|
||||
"moment": "^2.30.1",
|
||||
|
|
@ -80,6 +85,7 @@
|
|||
"next-themes": "^0.3.0",
|
||||
"nextra": "^2.13.4",
|
||||
"nextra-theme-docs": "^2.13.4",
|
||||
"qs": "^6.13.1",
|
||||
"quill": "^2.0.2",
|
||||
"react": "^18",
|
||||
"react-apexcharts": "^1.4.1",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 332 KiB |
|
|
@ -0,0 +1,77 @@
|
|||
import {
|
||||
deleteAPIInterceptor,
|
||||
getAPI,
|
||||
getAPIInterceptor,
|
||||
postAPIInterceptor,
|
||||
} from "../config/api";
|
||||
|
||||
export async function listDataMedia(
|
||||
page: any,
|
||||
limit: any,
|
||||
search: any,
|
||||
categoryFilter: any,
|
||||
statusFilter: any
|
||||
) {
|
||||
const name = search || "";
|
||||
const url = `media/list?isForAdmin=true&title=${name}&enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=1&categoryId=${categoryFilter}&statusId=${statusFilter}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
||||
export async function listDataVideo(
|
||||
isForSelf: any,
|
||||
isApproval: any,
|
||||
page: any,
|
||||
limit: any,
|
||||
search: any,
|
||||
categoryFilter: any,
|
||||
statusFilter: any,
|
||||
needApprovalFromLevel: any,
|
||||
creator: any,
|
||||
source: any,
|
||||
startDate: any,
|
||||
endDate: any
|
||||
) {
|
||||
const name = search || "";
|
||||
const url = `media/list?title=${name}&enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=2&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
||||
export async function listDataImage(
|
||||
isForSelf: any,
|
||||
isApproval: any,
|
||||
page: any,
|
||||
limit: any,
|
||||
search: any,
|
||||
categoryFilter: any,
|
||||
statusFilter: any,
|
||||
needApprovalFromLevel: any,
|
||||
creator: any,
|
||||
source: any,
|
||||
startDate: any,
|
||||
endDate: any
|
||||
) {
|
||||
const name = search || "";
|
||||
const url = `media/list?title=${name}&enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
||||
export async function listDataAll(
|
||||
isForSelf: any,
|
||||
isApproval: any,
|
||||
page: any,
|
||||
limit: any,
|
||||
search: any,
|
||||
fileTypeFilter: any,
|
||||
statusFilter: any,
|
||||
startDate: any,
|
||||
endDate: any,
|
||||
needApprovalFromLevel: any
|
||||
) {
|
||||
const name = search || "";
|
||||
const url = `media/list?title=${name}&enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&isForSelf=${isForSelf}&isApproval=${isApproval}&typeId=${fileTypeFilter}&statusId=${statusFilter}&startDate=${
|
||||
startDate == undefined ? "" : startDate
|
||||
}&endDate=${
|
||||
endDate == undefined ? "" : endDate
|
||||
}&needApprovalFromLevel=${needApprovalFromLevel}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
import React from 'react'
|
||||
import { DocsThemeConfig } from 'nextra-theme-docs'
|
||||
import DashCodeLogo from '@/components/dascode-logo';
|
||||
import React from "react";
|
||||
import { DocsThemeConfig } from "nextra-theme-docs";
|
||||
import DashCodeLogo from "@/components/dascode-logo";
|
||||
const config: DocsThemeConfig = {
|
||||
logo: (
|
||||
<span className=" inline-flex gap-2.5 items-center">
|
||||
|
|
@ -34,9 +33,9 @@ const config: DocsThemeConfig = {
|
|||
themeSwitch: {
|
||||
useOptions() {
|
||||
return {
|
||||
light: 'Light',
|
||||
dark: 'Dark',
|
||||
system: 'System', // Add this line
|
||||
light: "Light",
|
||||
dark: "Dark",
|
||||
system: "System", // Add this line
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
@ -47,4 +46,4 @@ const config: DocsThemeConfig = {
|
|||
},
|
||||
};
|
||||
|
||||
export default config
|
||||
export default config;
|
||||
|
|
|
|||
Loading…
Reference in New Issue