merge main
This commit is contained in:
commit
1068b9e6a3
|
|
@ -1,30 +0,0 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { UploadIcon } from "lucide-react";
|
||||
import PressReleaseTable from "../schedule/press-conference/components/presscon-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import ContestTable from "./table-contest/contest-table";
|
||||
|
||||
const ContestPage = async () => {
|
||||
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">
|
||||
Table Lomba
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<ContestTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContestPage;
|
||||
|
|
@ -1,348 +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 {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
Badge,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
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 = {
|
||||
no: number;
|
||||
hastagCode: string;
|
||||
theme: string;
|
||||
duration: string;
|
||||
targetOutput: string;
|
||||
targetParticipantTopLevel: string;
|
||||
isPublishForAll: string;
|
||||
};
|
||||
import { data } from "./data";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { listTask } from "@/service/task";
|
||||
import { listContest } from "@/service/contest/contest";
|
||||
|
||||
export const columns: ColumnDef<CompanyData>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "hastagCode",
|
||||
header: "Kode",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4
|
||||
className="text-sm font-bold
|
||||
text-default-600 whitespace-nowrap mb-1"
|
||||
>
|
||||
{row.getValue("hastagCode")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "theme",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("theme")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: "Durasi ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("duration")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetOutput",
|
||||
header: "Target Output ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("targetOutput")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetParticipantTopLevel",
|
||||
header: "Tag ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetParticipantTopLevel")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "isPublishForAll",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<span className="whitespace-nowrap text-blue-600">
|
||||
{row.getValue("isPublishForAll")}
|
||||
</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 ContestTable = () => {
|
||||
const [contestTable, setContestTable] = React.useState<CompanyData[]>([]);
|
||||
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: 2,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
|
||||
const table = useReactTable({
|
||||
data: contestTable,
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
initState();
|
||||
}, [page, limit]);
|
||||
|
||||
async function initState() {
|
||||
try {
|
||||
const res = await listContest(limit, page);
|
||||
console.log("res", res?.data?.data);
|
||||
const data = res.data.data.content.map((item: any, index: number) => ({
|
||||
no: (page - 1) * limit + index + 1,
|
||||
hastagCode: item.hastagCode,
|
||||
theme: item.theme,
|
||||
targetOutput: item.targetOutput,
|
||||
targetParticipantTopLevel: item.targetParticipantTopLevel,
|
||||
duration: item.duration,
|
||||
isDone: item.isDone,
|
||||
}));
|
||||
|
||||
setContestTable(data);
|
||||
setTotalPage(res.data.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center py-4 px-5">
|
||||
<div>
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
<Search className=" h-4 w-4 dark:text-white" />
|
||||
</InputGroupText>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<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 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 py-4 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 ContestTable;
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
export const data = [
|
||||
{
|
||||
title: "Ops Mantap Praja & Pilkada 2024",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Ops Mantap Praja & Pilkada 2024",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Ops Mantap Praja & Pilkada 2024",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
{
|
||||
title: "Seputar Prestasi",
|
||||
code: "#NEWLOMBA",
|
||||
duration: "2023-08-31 07:00:00 - 2023-09-01 07:00:00",
|
||||
targetOutput: "Foto",
|
||||
targetParticipant: "Polda, mabes",
|
||||
status: "Terkirim",
|
||||
},
|
||||
];
|
||||
|
|
@ -12,7 +12,7 @@ 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 { CalendarCategory } from "./data";
|
||||
import { EventContentArg } from "@fullcalendar/core";
|
||||
import EventModal from "./event-modal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
|
@ -26,15 +26,49 @@ interface CalendarViewProps {
|
|||
|
||||
const INITIAL_YEAR = dayjs().format("YYYY");
|
||||
const INITIAL_MONTH = dayjs().format("M");
|
||||
export interface CalendarEvent {
|
||||
id: string;
|
||||
title: string;
|
||||
start: Date;
|
||||
end: Date;
|
||||
allDay: boolean;
|
||||
extendedProps: {
|
||||
calendar: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AgendaSettingsAPIResponse {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
agendaType: string;
|
||||
startDate: string; // API mengembalikan tanggal dalam bentuk string
|
||||
endDate: string;
|
||||
isActive: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
createdById: number | null;
|
||||
createdByName: string | null;
|
||||
}
|
||||
|
||||
interface APIResponse {
|
||||
error: boolean;
|
||||
message: any;
|
||||
data: AgendaSettingsAPIResponse[] | null; // `data` bisa berupa array atau null
|
||||
}
|
||||
|
||||
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 [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(
|
||||
// null
|
||||
// );
|
||||
|
||||
const [apiEvents, setApiEvents] = useState<CalendarEvent[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [draggableInitialized, setDraggableInitialized] =
|
||||
useState<boolean>(false);
|
||||
const t = useTranslations("CalendarApp");
|
||||
|
|
@ -65,6 +99,73 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
setSelectedCategory(categories?.map((c) => c.value));
|
||||
}, [events, categories]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Fetched events from API:", apiEvents);
|
||||
}, [apiEvents]);
|
||||
|
||||
const filteredEvents = apiEvents?.filter((event) =>
|
||||
selectedCategory?.includes(event.extendedProps.calendar)
|
||||
);
|
||||
|
||||
const displayedEvents =
|
||||
filteredEvents?.length > 0 ? filteredEvents : apiEvents;
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Filtered events based on category:", displayedEvents);
|
||||
}, [filteredEvents, apiEvents]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedCategory(categories?.map((c) => c.value));
|
||||
}, [categories]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Selected categories:", selectedCategory);
|
||||
}, [selectedCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAgendaEvents = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const selectedMonth = new Date(); // Replace with your logic for selected month
|
||||
const year = selectedMonth.getFullYear().toString();
|
||||
const month = (selectedMonth.getMonth() + 1).toString();
|
||||
const typeFilter = ""; // Replace with your type filter logic if needed
|
||||
|
||||
const response: APIResponse = await getAgendaSettingsList(
|
||||
year,
|
||||
month,
|
||||
typeFilter
|
||||
);
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
// Transform API data to match CalendarEvent type
|
||||
const eventsFromAPI: CalendarEvent[] = response.data.map((item) => ({
|
||||
id: item.id.toString(),
|
||||
title: item.title,
|
||||
start: new Date(item.startDate),
|
||||
end: new Date(item.endDate),
|
||||
allDay: true, // Sesuaikan jika memang ada event sepanjang hari
|
||||
extendedProps: {
|
||||
calendar: item.agendaType,
|
||||
description: item.description,
|
||||
},
|
||||
}));
|
||||
setApiEvents(eventsFromAPI);
|
||||
} else {
|
||||
console.warn("No events found in API response.");
|
||||
setApiEvents([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch agenda settings:", error);
|
||||
setApiEvents([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchAgendaEvents();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const draggableEl = document.getElementById("external-events");
|
||||
|
||||
|
|
@ -97,23 +198,24 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
draggableEl?.removeEventListener("mousedown", initDraggable);
|
||||
};
|
||||
}, [dragEvents]);
|
||||
|
||||
// event click
|
||||
const handleEventClick = (arg: any) => {
|
||||
setSelectedEventDate(null);
|
||||
setSheetOpen(true);
|
||||
setSelectedEvent(arg);
|
||||
setApiEvents(arg);
|
||||
wait().then(() => (document.body.style.pointerEvents = "auto"));
|
||||
};
|
||||
// handle close modal
|
||||
const handleCloseModal = () => {
|
||||
setSheetOpen(false);
|
||||
setSelectedEvent(null);
|
||||
setApiEvents([]);
|
||||
setSelectedEventDate(null);
|
||||
};
|
||||
const handleDateClick = (arg: any) => {
|
||||
setSheetOpen(true);
|
||||
setSelectedEventDate(arg);
|
||||
setSelectedEvent(null);
|
||||
setApiEvents([]);
|
||||
wait().then(() => (document.body.style.pointerEvents = "auto"));
|
||||
};
|
||||
|
||||
|
|
@ -126,12 +228,12 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
};
|
||||
|
||||
const handleClassName = (arg: EventContentArg) => {
|
||||
if (arg.event.extendedProps.calendar === "national") {
|
||||
return "destructive";
|
||||
} else if (arg.event.extendedProps.calendar === "polda") {
|
||||
if (arg.event.extendedProps.calendar === "mabes") {
|
||||
return "primary";
|
||||
} else if (arg.event.extendedProps.calendar === "polres") {
|
||||
} else if (arg.event.extendedProps.calendar === "polda") {
|
||||
return "success";
|
||||
} else if (arg.event.extendedProps.calendar === "polres") {
|
||||
return "destructive";
|
||||
} else if (arg.event.extendedProps.calendar === "international") {
|
||||
return "info";
|
||||
} else {
|
||||
|
|
@ -139,10 +241,6 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
const filteredEvents = events?.filter((event) =>
|
||||
selectedCategory?.includes(event.extendedProps.calendar)
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
|
||||
|
|
@ -222,7 +320,7 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
center: "title",
|
||||
right: "dayGridMonth,timeGridWeek,timeGridDay,listWeek",
|
||||
}}
|
||||
events={filteredEvents}
|
||||
events={displayedEvents} // Use apiEvents here
|
||||
editable={true}
|
||||
rerenderDelay={10}
|
||||
eventDurationEditable={false}
|
||||
|
|
@ -243,7 +341,7 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
open={sheetOpen}
|
||||
onClose={handleCloseModal}
|
||||
categories={categories}
|
||||
event={selectedEvent}
|
||||
event={apiEvents}
|
||||
selectedDate={selectedEventDate}
|
||||
/>
|
||||
</>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
"use client";
|
||||
// "use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
|
@ -30,9 +30,18 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { error, loading } from "@/lib/swal";
|
||||
import Cookies from "js-cookie";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { postSchedule } from "@/service/schedule/schedule";
|
||||
import { saveAgendaSettings } from "@/service/agenda-setting/agenda-setting";
|
||||
|
||||
const schema = z.object({
|
||||
title: z.string().min(3, { message: "Required" }),
|
||||
description: z.string().min(3, { message: "Required" }),
|
||||
});
|
||||
|
||||
const EventModal = ({
|
||||
|
|
@ -57,6 +66,8 @@ const EventModal = ({
|
|||
// delete modal state
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState<boolean>(false);
|
||||
const [eventIdToDelete, setEventIdToDelete] = useState<string | null>(null);
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
register,
|
||||
|
|
@ -70,20 +81,45 @@ const EventModal = ({
|
|||
mode: "all",
|
||||
});
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
startTransition(() => {
|
||||
if (!event) {
|
||||
data.start = startDate;
|
||||
data.end = endDate;
|
||||
data.allDay = false;
|
||||
data.extendedProps = {
|
||||
calendar: calendarProps,
|
||||
};
|
||||
}
|
||||
if (event) {
|
||||
}
|
||||
const save = async (data: any) => {
|
||||
// loading();
|
||||
|
||||
const reqData = {
|
||||
title: data.title,
|
||||
description: data.description || "",
|
||||
agendaType: calendarProps,
|
||||
startDate: format(startDate, "yyyy-MM-dd"),
|
||||
endDate: format(endDate, "yyyy-MM-dd"),
|
||||
};
|
||||
|
||||
console.log("Submitted Data:", reqData);
|
||||
|
||||
const response = await saveAgendaSettings(reqData);
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Cookies.set("AgendaSetting", response.data.data.id, {
|
||||
expires: 1,
|
||||
});
|
||||
|
||||
// Optional: Use Swal for success feedback
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/contributor/agenda-setting");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
save(data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDate) {
|
||||
setStartDate(selectedDate.date);
|
||||
|
|
@ -93,13 +129,10 @@ const EventModal = ({
|
|||
setStartDate(event?.event?.start);
|
||||
setEndDate(event?.event?.end);
|
||||
const eventCalendar = event?.event?.extendedProps?.calendar;
|
||||
if (eventCalendar) {
|
||||
setCalendarProps(eventCalendar);
|
||||
} else {
|
||||
setCalendarProps(categories[0].value);
|
||||
}
|
||||
setCalendarProps(eventCalendar || categories[0].value);
|
||||
}
|
||||
setValue("title", event?.event?.title || "");
|
||||
setValue("description", event?.event?.description || "");
|
||||
}, [event, selectedDate, open, categories, setValue]);
|
||||
|
||||
const onDeleteEventAction = async () => {
|
||||
|
|
@ -125,14 +158,15 @@ const EventModal = ({
|
|||
<DialogContent onPointerDownOutside={onClose}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{event ? "Edit Event" : "Create Event"} {event?.title}
|
||||
{event ? "Edit Agenda Setting" : "Create Agenda Setting"}{" "}
|
||||
{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>
|
||||
<Label htmlFor="title">Judul Agenda</Label>
|
||||
<Input
|
||||
id="title"
|
||||
type="text"
|
||||
|
|
@ -222,7 +256,7 @@ const EventModal = ({
|
|||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="calendarProps">Label </Label>
|
||||
<Label htmlFor="calendarProps">Jenis Agenda </Label>
|
||||
<Controller
|
||||
name="calendarProps"
|
||||
control={control}
|
||||
|
|
@ -248,6 +282,21 @@ const EventModal = ({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="description">Isi Agenda Setting</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
placeholder="Enter Event Name"
|
||||
{...register("description")}
|
||||
/>
|
||||
{errors?.description?.message && (
|
||||
<div className="text-destructive text-sm">
|
||||
{typeof errors?.description?.message === "string"
|
||||
? errors?.description?.message
|
||||
: JSON.stringify(errors?.description?.message)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 mt-10">
|
||||
|
|
@ -258,9 +307,9 @@ const EventModal = ({
|
|||
{event ? "Updating..." : "Adding..."}
|
||||
</>
|
||||
) : event ? (
|
||||
"Update Event"
|
||||
"Update Agenda Setting"
|
||||
) : (
|
||||
"Add Event"
|
||||
"Simpan Agenda Setting"
|
||||
)}
|
||||
</Button>
|
||||
{event && (
|
||||
|
|
@ -55,6 +55,7 @@ const BlogTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -86,11 +87,11 @@ const BlogTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await paginationBlog(limit, page - 1, "");
|
||||
const res = await paginationBlog(limit, page - 1, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -107,6 +108,11 @@ const BlogTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -119,6 +125,8 @@ const BlogTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -95,18 +96,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<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>
|
||||
</Link>
|
||||
{/*
|
||||
<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>
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormImage from "@/components/form/content/image-form";
|
||||
import FormBlog from "@/components/form/blog/blog-form";
|
||||
|
||||
const BlogCreatePage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormBlog />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogCreatePage;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormBlogDetail from "@/components/form/blog/blog--detail-form";
|
||||
|
||||
const BlogDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormBlogDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogDetailPage;
|
||||
|
|
@ -3,6 +3,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|||
import BlogTable from "./components/blog-table";
|
||||
import { Plus } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const BlogPage = async () => {
|
||||
return (
|
||||
|
|
@ -17,10 +18,12 @@ const BlogPage = async () => {
|
|||
Table Indeks
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Button fullWidth size="md">
|
||||
<Plus className="w-6 h-6 me-1.5" />
|
||||
Add Index
|
||||
</Button>
|
||||
<Link href={"/contributor/blog/create"}>
|
||||
<Button fullWidth color="primary">
|
||||
<Plus className="w-6 h-6 me-1.5" />
|
||||
Add Index
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</CardTitle>
|
||||
|
|
@ -139,7 +139,7 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -121,7 +121,7 @@ const TableAudio = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
|
|
@ -140,7 +140,7 @@ const TableAudio = () => {
|
|||
filterBySource,
|
||||
startDateString,
|
||||
endDateString,
|
||||
""
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
|
|
@ -157,6 +157,10 @@ const TableAudio = () => {
|
|||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
|
|
@ -170,6 +174,8 @@ const TableAudio = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,6 @@ import { Link, UploadIcon } from "lucide-react";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import TableAudio from "./components/table-audio";
|
||||
import TableVideo from "../audio-visual/components/table-video";
|
||||
|
||||
const ReactTableAudioPage = () => {
|
||||
return (
|
||||
|
|
@ -139,7 +139,7 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -73,7 +73,7 @@ const TableImage = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
const [search, setSearch] = React.useState("");
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ const TableImage = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
|
|
@ -136,7 +136,7 @@ const TableImage = () => {
|
|||
filterBySource,
|
||||
startDateString,
|
||||
endDateString,
|
||||
""
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
|
|
@ -154,6 +154,11 @@ const TableImage = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -166,6 +171,8 @@ const TableImage = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -6,7 +6,6 @@ import { UploadIcon } from "lucide-react";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { Link } from "@/components/navigation";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
|
||||
const ReactTableImagePage = () => {
|
||||
return (
|
||||
|
|
@ -58,7 +57,7 @@ const ReactTableImagePage = () => {
|
|||
Konten Foto
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/content/image/create"}>
|
||||
<Link href={"/contributor/content/image/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Foto
|
||||
|
|
@ -88,7 +88,7 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -121,12 +121,12 @@ const TableTeks = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const isForSelf = Number(roleId) == 4;
|
||||
const res = await listNulisAI(limit, page - 1, "");
|
||||
const res = await listNulisAI(limit, page - 1, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -143,6 +143,11 @@ const TableTeks = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -155,6 +160,8 @@ const TableTeks = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -177,7 +177,7 @@ const columns: ColumnDef<CompanyData>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -139,7 +139,7 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -117,7 +117,7 @@ const TableTeks = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
|
|
@ -136,7 +136,7 @@ const TableTeks = () => {
|
|||
filterBySource,
|
||||
startDateString,
|
||||
endDateString,
|
||||
""
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
|
|
@ -154,6 +154,11 @@ const TableTeks = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -166,6 +171,8 @@ const TableTeks = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -139,7 +139,7 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<a href="/contributor/task/detail/[id]">
|
||||
<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
|
||||
|
|
@ -117,7 +117,7 @@ const TableImage = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
|
|
@ -136,7 +136,7 @@ const TableImage = () => {
|
|||
filterBySource,
|
||||
startDateString,
|
||||
endDateString,
|
||||
""
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
|
|
@ -154,6 +154,11 @@ const TableImage = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -166,6 +171,8 @@ const TableImage = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -58,7 +58,7 @@ const ReactTableVideoPage = () => {
|
|||
Konten Video
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/content/audio-visual/create"}>
|
||||
<Link href={"/contributor/content/audio-visual/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Unggah Video
|
||||
|
|
@ -11,6 +11,8 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -42,9 +44,18 @@ const columns: ColumnDef<any>[] = [
|
|||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
|
|
@ -81,15 +92,18 @@ const columns: ColumnDef<any>[] = [
|
|||
</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">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<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" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -52,6 +52,7 @@ import { useRouter, useSearchParams } from "next/navigation";
|
|||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
import { getPlanningSentPagination } from "@/service/planning/planning";
|
||||
import search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||
|
||||
const MediahubTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -73,6 +74,7 @@ const MediahubTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -104,11 +106,11 @@ const MediahubTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await getPlanningSentPagination(limit, page - 1, 1, "");
|
||||
const res = await getPlanningSentPagination(limit, page - 1, 1, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -125,6 +127,11 @@ const MediahubTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -137,6 +144,8 @@ const MediahubTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -4,7 +4,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|||
import { UploadIcon } from "lucide-react";
|
||||
import TaskTable from "../../task/components/task-table";
|
||||
import MediahubTable from "./components/mediahub-table";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
|
||||
const MediahubPage = async () => {
|
||||
return (
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import PublishMediahub from "@/components/form/planning/mediahub-publish";
|
||||
|
||||
const MediahubPublishPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<PublishMediahub />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MediahubPublishPage;
|
||||
|
|
@ -11,6 +11,8 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -42,9 +44,18 @@ const columns: ColumnDef<any>[] = [
|
|||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
|
|
@ -81,14 +92,15 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<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" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<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
|
||||
|
|
@ -73,6 +73,7 @@ const MedsosTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -104,11 +105,11 @@ const MedsosTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await getPlanningSentPagination(limit, page - 1, 2, "");
|
||||
const res = await getPlanningSentPagination(limit, page - 1, 2, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -125,6 +126,11 @@ const MedsosTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -137,6 +143,8 @@ const MedsosTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
onChange={handleSearch}
|
||||
value={search}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import MedsosTable from "./components/medsos-table";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
|
||||
const MedsosMediahubPage = async () => {
|
||||
return (
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import PublishMedsos from "@/components/form/planning/medsos-publish";
|
||||
|
||||
const MedsosPublishPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<PublishMedsos />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MedsosPublishPage;
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -54,11 +55,17 @@ const columns: ColumnDef<any>[] = [
|
|||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "startTime",
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
|
|
@ -99,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -131,14 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -50,6 +50,7 @@ const EventTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -81,11 +82,11 @@ const EventTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await paginationSchedule(limit, page - 1, 2, "");
|
||||
const res = await paginationSchedule(limit, page - 1, 2, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -102,6 +103,11 @@ const EventTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -114,6 +120,8 @@ const EventTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormEventDetail from "@/components/form/schedule/event-detail-form";
|
||||
|
||||
const EventDetailPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormEventDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventDetailPage;
|
||||
|
|
@ -5,7 +5,6 @@ import { UploadIcon } from "lucide-react";
|
|||
import PressConferenceTable from "../press-conference/components/presscon-table";
|
||||
import EventTable from "./components/event-table";
|
||||
import { Link } from "@/components/navigation";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
|
||||
const EventPage = async () => {
|
||||
return (
|
||||
|
|
@ -20,7 +19,7 @@ const EventPage = async () => {
|
|||
Jadwal Event
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/schedule/event/create"}>
|
||||
<Link href={"/contributor/schedule/event/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Jadwal
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
import FormEventUpdate from "@/components/form/schedule/event-update-form";
|
||||
|
||||
const EventUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormEventUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventUpdatePage;
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -54,11 +55,17 @@ const columns: ColumnDef<any>[] = [
|
|||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "startTime",
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
|
|
@ -99,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -131,14 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<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" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -63,6 +63,7 @@ const PressConferenceTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -94,11 +95,11 @@ const PressConferenceTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await paginationSchedule(limit, page - 1, 1, "");
|
||||
const res = await paginationSchedule(limit, page - 1, 1, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -115,6 +116,11 @@ const PressConferenceTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
|
|
@ -127,6 +133,8 @@ const PressConferenceTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -3,7 +3,7 @@ import SiteBreadcrumb from "@/components/site-breadcrumb";
|
|||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
|
||||
const PressConCreatePage = async () => {
|
||||
const PressConCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
|
||||
const PressConDetailPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailPressConference />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressConDetailPage;
|
||||
|
|
@ -4,7 +4,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|||
import PressConferenceTable from "./components/presscon-table";
|
||||
import { UploadIcon } from "lucide-react";
|
||||
import { Link } from "@/components/navigation";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
|
||||
const PressConferencePage = async () => {
|
||||
return (
|
||||
|
|
@ -19,7 +18,7 @@ const PressConferencePage = async () => {
|
|||
Jadwal Konferensi Pers
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/schedule/press-conference/create"}>
|
||||
<Link href={"/contributor/schedule/press-conference/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Jadwal
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
|
||||
const PressConUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormUpdatePressConference />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressConUpdatePage;
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -54,11 +55,17 @@ const columns: ColumnDef<any>[] = [
|
|||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "startTime",
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
|
|
@ -99,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -131,14 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -64,6 +64,7 @@ const PressReleaseTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -95,11 +96,11 @@ const PressReleaseTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await paginationSchedule(limit, page - 1, 3, "");
|
||||
const res = await paginationSchedule(limit, page - 1, 3, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -116,9 +117,14 @@ const PressReleaseTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div className="flex justify-between items-center px-5 mt-3">
|
||||
<div>
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
|
|
@ -128,6 +134,8 @@ const PressReleaseTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -4,7 +4,7 @@ import FormTask from "@/components/form/task/task-form";
|
|||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormPressRelease from "@/components/form/schedule/pers-release-form";
|
||||
|
||||
const PressReleaseCreatePage = async () => {
|
||||
const PressReleaseCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import FormDetailPressRillis from "@/components/form/schedule/pers-release--detail-form";
|
||||
|
||||
const PressRilisDetailPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailPressRillis />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressRilisDetailPage;
|
||||
|
|
@ -3,7 +3,6 @@ import { Button } from "@/components/ui/button";
|
|||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { UploadIcon } from "lucide-react";
|
||||
import { Link } from "@/components/navigation";
|
||||
import TicketingTable from "../../ticketing/components/table";
|
||||
import PressReleaseTable from "./components/pressrilis-table";
|
||||
|
||||
const PressReleasePage = async () => {
|
||||
|
|
@ -19,7 +18,7 @@ const PressReleasePage = async () => {
|
|||
Jadwal Pers Rilis
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/schedule/press-release/create"}>
|
||||
<Link href={"/contributor/schedule/press-release/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Jadwal
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
import FormUpdatePressRelease from "@/components/form/schedule/pers-release--update-form";
|
||||
|
||||
const PressRilisUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormUpdatePressRelease />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressRilisUpdatePage;
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -111,10 +112,12 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -73,7 +73,8 @@ const TaskTable = () => {
|
|||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [activeTab, setActiveTab] = React.useState("atensi-khusus");
|
||||
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
|
|
@ -105,11 +106,16 @@ const TaskTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, activeTab]);
|
||||
}, [page, limit, isSpecificAttention, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await listTask("", page - 1, limit, activeTab);
|
||||
const res = await listTask(
|
||||
search,
|
||||
page - 1,
|
||||
limit,
|
||||
isSpecificAttention ? "atensi-khusus" : "tugas-harian"
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -126,27 +132,47 @@ const TaskTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="mx-5 mb-3">
|
||||
<div className="">
|
||||
<div className="row">
|
||||
<Button
|
||||
onClick={() => setActiveTab("atensi-khusus")}
|
||||
className={`col-md-6 text-center rounded-none ${
|
||||
activeTab == "atensi-khusus" ? "text-blue-600" : "text-muted"
|
||||
}`}
|
||||
>
|
||||
Atensi Khusus
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setActiveTab("tugas-harian")}
|
||||
className={`col text-center rounded-none ${
|
||||
activeTab == "tugas-harian" ? "text-blue-600" : "text-muted"
|
||||
}`}
|
||||
>
|
||||
Tugas Harian
|
||||
</Button>
|
||||
<div className="flex justify-between mb-6">
|
||||
<label className="inline-flex text-md cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={() => setIsSpecificAttention(!isSpecificAttention)}
|
||||
hidden
|
||||
/>
|
||||
<span
|
||||
className={` ${
|
||||
isSpecificAttention
|
||||
? "bg-default-900 text-white"
|
||||
: "dark:text-default-700 border-2"
|
||||
}
|
||||
px-[18px] py-1 transition duration-100 rounded`}
|
||||
>
|
||||
Atensi Khusus
|
||||
</span>
|
||||
<span
|
||||
className={`
|
||||
${
|
||||
!isSpecificAttention
|
||||
? "bg-default-900 text-white"
|
||||
: " dark:text-default-700 border-2"
|
||||
}
|
||||
px-[18px] py-1 transition duration-100 rounded
|
||||
`}
|
||||
>
|
||||
Tugas Harian
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -160,6 +186,8 @@ const TaskTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -2,7 +2,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
|
||||
const TaskCreatePage = async () => {
|
||||
const TaskCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormTaskDetail from "@/components/form/task/task-detail-form";
|
||||
|
||||
const TaskDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormTask />
|
||||
<FormTaskDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -7,7 +7,6 @@ import SiteBreadcrumb from "@/components/site-breadcrumb";
|
|||
import { Link } from "@/components/navigation";
|
||||
import { checkAuthorization, checkLoginSession } from "@/lib/utils";
|
||||
import React, { useEffect } from "react";
|
||||
import TicketingTable from "../ticketing/components/table";
|
||||
|
||||
const TaskPage = () => {
|
||||
useEffect(() => {
|
||||
|
|
@ -31,7 +30,7 @@ const TaskPage = () => {
|
|||
Table Penugasan
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/task/create"}>
|
||||
<Link href={"/contributor/task/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
|
|
@ -6,16 +6,18 @@ import { useTranslations } from "next-intl";
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { UploadIcon } from "lucide-react";
|
||||
import RecentActivity from "./routine-task/recent-activity";
|
||||
import CompanyTable from "./routine-task/routine-task-table";
|
||||
import TaskTable from "../task/components/task-table";
|
||||
import PressConferenceTable from "../schedule/press-release/components/pressrilis-table";
|
||||
import BlogTable from "../blog/components/blog-table";
|
||||
|
||||
import Cookies from "js-cookie";
|
||||
import { useEffect } from "react";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import DashboardVisualization from "@/components/visualization/dashboard-viz";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import TaskTable from "../contributor/task/components/task-table";
|
||||
import PressConferenceTable from "../contributor/schedule/press-release/components/pressrilis-table";
|
||||
import BlogTable from "../contributor/blog/components/blog-table";
|
||||
import ContentTable from "./routine-task/components/content-table";
|
||||
import RecentActivity from "./routine-task/components/recent-activity";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const DashboardPage = () => {
|
||||
const t = useTranslations("AnalyticsDashboard");
|
||||
|
|
@ -107,7 +109,7 @@ const DashboardPage = () => {
|
|||
<DashboardDropdown />
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<CompanyTable />
|
||||
<ContentTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
@ -123,14 +125,16 @@ const DashboardPage = () => {
|
|||
Table Penugasan
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
</Button>
|
||||
<Link href={"/contributor/task/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 mt-3">
|
||||
<TaskTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -141,7 +145,7 @@ const DashboardPage = () => {
|
|||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-12 col-span-12">
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 ">
|
||||
<PressConferenceTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -158,14 +162,16 @@ const DashboardPage = () => {
|
|||
Table Indeks
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Tambah Indeks
|
||||
</Button>
|
||||
<Link href={"/contributor/blog/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Tambah Indeks
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 mt-3">
|
||||
<BlogTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
import * as React from "react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { format } from "date-fns";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="">
|
||||
{title.length > 50 ? `${title.slice(0, 10)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "fileTypeName",
|
||||
header: "Type Content",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("fileTypeName");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
// {
|
||||
// accessorKey: "creatorGroup",
|
||||
// header: "Creator Group",
|
||||
// cell: ({ row }) => (
|
||||
// <span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
|
||||
// ),
|
||||
// },
|
||||
// {
|
||||
// accessorKey: "creatorName",
|
||||
// header: "Sumber",
|
||||
// cell: ({ row }) => (
|
||||
// <span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
// ),
|
||||
// },
|
||||
// {
|
||||
// accessorKey: "publishedOn",
|
||||
// header: "Published",
|
||||
// cell: ({ row }) => {
|
||||
// const isPublish = row.original.isPublish;
|
||||
// const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
// let displayText = "-";
|
||||
// if (isPublish && !isPublishOnPolda) {
|
||||
// displayText = "Mabes";
|
||||
// } else if (isPublish && isPublishOnPolda) {
|
||||
// displayText = "Mabes & Polda";
|
||||
// } else if (!isPublish && isPublishOnPolda) {
|
||||
// displayText = "Polda";
|
||||
// }
|
||||
|
||||
// return (
|
||||
// <div className="text-center whitespace-nowrap" title={displayText}>
|
||||
// {displayText}
|
||||
// </div>
|
||||
// );
|
||||
// },
|
||||
// },
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
// Mendapatkan nilai statusName
|
||||
const statusName = row.getValue<string>("statusName");
|
||||
|
||||
// Mapping warna berdasarkan statusName
|
||||
const colorMapping: Record<string, string> = {
|
||||
"Menunggu Review": "text-orange-500 border-orange-500",
|
||||
Diterima: "text-green-500 border-green-500",
|
||||
"Minta Update": "text-blue-500 border-blue-500",
|
||||
Ditolak: "text-red-500 border-red-500",
|
||||
};
|
||||
|
||||
// Mendapatkan kelas warna dari mapping, default ke abu-abu jika tidak ditemukan
|
||||
const buttonClass =
|
||||
colorMapping[statusName] || "text-gray-500 border-gray-500";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className={`btn btn-sm pill-btn ml-1 ${buttonClass}`}
|
||||
>
|
||||
{statusName || "Tidak Diketahui"}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
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">
|
||||
<a href="/en/task/detail/[id]">
|
||||
<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>
|
||||
</a>
|
||||
<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>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
"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 {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
import { listDataAll, listDataImage } from "@/service/content/content";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
type StatusFilter = string[];
|
||||
|
||||
const ContentTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
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: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
const [categories, setCategories] = React.useState<string[]>();
|
||||
const [categoryFilter, setCategoryFilter] = React.useState<string[]>([]);
|
||||
const [statusFilter, setStatusFilter] = React.useState<StatusFilter>([]);
|
||||
const [startDateString, setStartDateString] = React.useState<string>("");
|
||||
const [endDateString, setEndDateString] = React.useState<string>("");
|
||||
const [filterByCreator, setFilterByCreator] = React.useState<string>("");
|
||||
const [fileTypeFilter, setFileTypeFilter] = React.useState<string[]>([]);
|
||||
const [filterBySource, setFilterBySource] = React.useState<string>("");
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, fileTypeFilter, statusFilter, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const isForSelf = Number(roleId) === 4;
|
||||
const res = await listDataAll(
|
||||
isForSelf,
|
||||
!isForSelf,
|
||||
page - 1,
|
||||
limit,
|
||||
fileTypeFilter.sort().join(","),
|
||||
categoryFilter.sort().join(","),
|
||||
statusFilter.sort().join(","),
|
||||
statusFilter.sort().join(",").includes("1") ? userLevelId : "",
|
||||
filterByCreator,
|
||||
filterBySource,
|
||||
startDateString,
|
||||
endDateString,
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
});
|
||||
|
||||
console.log("contentData : ", contentData);
|
||||
|
||||
setDataTable(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div>
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
<Search className="h-4 w-4 dark:text-white" />
|
||||
</InputGroupText>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
{/* <Select
|
||||
onValueChange={(value) => {
|
||||
setStatusFilter([value]);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Select a Filter Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Status</SelectLabel>
|
||||
<SelectItem value="1">Menunggu Review</SelectItem>
|
||||
<SelectItem value="2">Diterima</SelectItem>
|
||||
<SelectItem value="3">Minta Update</SelectItem>
|
||||
<SelectItem value="4">Ditolak</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select> */}
|
||||
<Select
|
||||
onValueChange={(value) => {
|
||||
setFileTypeFilter([value]);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Select a Filter" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Filter</SelectLabel>
|
||||
<SelectItem value="1">Image</SelectItem>
|
||||
<SelectItem value="2">Video</SelectItem>
|
||||
<SelectItem value="3">Teks</SelectItem>
|
||||
<SelectItem value="4">Audio</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<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>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentTable;
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
"use client";
|
||||
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import { listDataAll } from "@/service/content/content";
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
} from "@tanstack/react-table";
|
||||
import { DockIcon, ImageIcon, MicIcon, YoutubeIcon } from "lucide-react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React from "react";
|
||||
import search from "../../../app/chat/components/search";
|
||||
|
||||
type StatusFilter = string[];
|
||||
|
||||
interface Counts {
|
||||
images: number;
|
||||
audiovisual: number;
|
||||
text: number;
|
||||
audio: number;
|
||||
}
|
||||
|
||||
const RecentActivity: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
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: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
const [categories, setCategories] = React.useState<string[]>();
|
||||
const [categoryFilter, setCategoryFilter] = React.useState<string[]>([]);
|
||||
const [statusFilter, setStatusFilter] = React.useState<StatusFilter>([]);
|
||||
const [startDateString, setStartDateString] = React.useState<string>("");
|
||||
const [endDateString, setEndDateString] = React.useState<string>("");
|
||||
const [filterByCreator, setFilterByCreator] = React.useState<string>("");
|
||||
const [fileTypeFilter, setFileTypeFilter] = React.useState<string[]>([]);
|
||||
const [filterBySource, setFilterBySource] = React.useState<string>("");
|
||||
|
||||
const [counts, setCounts] = React.useState<Counts>({
|
||||
images: 0,
|
||||
audiovisual: 0,
|
||||
text: 0,
|
||||
audio: 0,
|
||||
});
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const isForSelf = Number(roleId) === 4;
|
||||
const res = await listDataAll(
|
||||
isForSelf,
|
||||
!isForSelf,
|
||||
page - 1,
|
||||
limit,
|
||||
search,
|
||||
fileTypeFilter.sort().join(","),
|
||||
categoryFilter.sort().join(","),
|
||||
statusFilter.sort().join(","),
|
||||
statusFilter.sort().join(",").includes("1") ? userLevelId : "",
|
||||
filterByCreator,
|
||||
filterBySource,
|
||||
startDateString,
|
||||
endDateString
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const { content } = data || [];
|
||||
|
||||
// Calculate counts for each typeId
|
||||
const newCounts: Counts = {
|
||||
images: content.filter((item: any) => item.typeId === 1).length,
|
||||
audiovisual: content.filter((item: any) => item.typeId === 2).length,
|
||||
text: content.filter((item: any) => item.typeId === 3).length,
|
||||
audio: content.filter((item: any) => item.typeId === 4).length,
|
||||
};
|
||||
|
||||
setDataTable(content);
|
||||
setCounts(newCounts);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<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-xl">{counts.images} FOTO</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<YoutubeIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">{counts.audiovisual} AUDIO VISUAL</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<DockIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">{counts.text} TEXT</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<MicIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">{counts.audio} AUDIO</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecentActivity;
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import {
|
||||
DockIcon,
|
||||
ImageIcon,
|
||||
MicIcon,
|
||||
PaperclipIcon,
|
||||
TextIcon,
|
||||
VideoIcon,
|
||||
YoutubeIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
const RecentActivity = () => {
|
||||
return (
|
||||
<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-xl">0 FOTO</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<YoutubeIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">0 AUDIO VISUAL</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<DockIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">0 TEXT</p>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<MicIcon size={40} className="text-blue-700" />
|
||||
<p className="text-xl">0 AUDIO</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecentActivity;
|
||||
|
|
@ -1,272 +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 {
|
||||
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;
|
||||
revenue: string;
|
||||
sales: number;
|
||||
status: string;
|
||||
up: boolean;
|
||||
};
|
||||
|
||||
export const columns: ColumnDef<CompanyData>[] = [
|
||||
{
|
||||
accessorKey: "company",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-none">
|
||||
<div className="w-8 h-8">
|
||||
<Avatar>
|
||||
<AvatarImage src={row.getValue("company")}></AvatarImage>
|
||||
<AvatarFallback>SC</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
Biffco Enterprises Ltd.
|
||||
</h4>
|
||||
<div className="text-xs font-normal text-default-600 ">
|
||||
Biffco@example.com
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "category",
|
||||
header: "Tanggal Unggah",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("category")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "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" />
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
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>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
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 [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 py-4 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 CompanyTable;
|
||||
|
|
@ -126,14 +126,14 @@ const EscalationTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await getTicketingCollaborationPagination(
|
||||
page - 1,
|
||||
limit,
|
||||
""
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
|
|
@ -149,10 +149,15 @@ const EscalationTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div>
|
||||
<div className="mt-3">
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
<Search className=" h-4 w-4 dark:text-white" />
|
||||
|
|
@ -161,6 +166,8 @@ const EscalationTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormInternal from "@/components/form/communication/internal-form";
|
||||
import FormCollaboration from "@/components/form/communication/collaboration-form";
|
||||
|
||||
const CollaborationCreatePage = async () => {
|
||||
const CollaborationCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -111,10 +112,14 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/shared/communication/escalation/detail/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -125,11 +125,15 @@ const EscalationTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await getTicketingEscalationPagination(page - 1, limit, "");
|
||||
const res = await getTicketingEscalationPagination(
|
||||
page - 1,
|
||||
limit,
|
||||
search
|
||||
);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -144,10 +148,15 @@ const EscalationTable = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div>
|
||||
<div className="mt-3">
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
<Search className=" h-4 w-4 dark:text-white" />
|
||||
|
|
@ -156,6 +165,8 @@ const EscalationTable = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormTaskDetail from "@/components/form/task/task-detail-form";
|
||||
import FormDetailInternal from "@/components/form/communication/internal-detail-form";
|
||||
import FormDetailEscalation from "@/components/form/communication/escalation-detail-form";
|
||||
|
||||
const EscalationDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailEscalation />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EscalationDetailPage;
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -96,10 +97,14 @@ const columns: ColumnDef<any>[] = [
|
|||
</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>
|
||||
<Link
|
||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
||||
>
|
||||
<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>
|
||||
</Link>
|
||||
<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
|
||||
|
|
@ -35,6 +35,7 @@ import {
|
|||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
UploadIcon,
|
||||
} from "lucide-react";
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||
import {
|
||||
|
|
@ -57,6 +58,7 @@ import {
|
|||
listDataVideo,
|
||||
} from "@/service/content/content";
|
||||
import { listTicketingInternal } from "@/service/communication/communication";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const TableAudio = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -122,11 +124,11 @@ const TableAudio = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
}, [page, limit, search]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await listTicketingInternal(page - 1, limit, "");
|
||||
const res = await listTicketingInternal(page - 1, limit, search);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -143,10 +145,21 @@ const TableAudio = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="w-full overflow-x-auto mt-3">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div>
|
||||
<div className="mt-3 flex flex-row items-center gap-2">
|
||||
<Link href={"/shared/communication/internal/create"}>
|
||||
<Button color="primary" className="text-white" size="md">
|
||||
<UploadIcon />
|
||||
Pertanyaan Baru
|
||||
</Button>
|
||||
</Link>
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
<Search className=" h-4 w-4 dark:text-white" />
|
||||
|
|
@ -155,6 +168,8 @@ const TableAudio = () => {
|
|||
type="text"
|
||||
placeholder="Search Judul..."
|
||||
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormInternal from "@/components/form/communication/internal-form";
|
||||
|
||||
const InternalCreatePage = async () => {
|
||||
const InternalCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue