feat:create schedule,create agenda setting, curated-content,communication
This commit is contained in:
parent
a2c1269bdd
commit
47d24e8a29
|
|
@ -110,11 +110,11 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
|
|||
|
||||
const handleClassName = (arg: EventContentArg) => {
|
||||
if (arg.event.extendedProps.calendar === "national") {
|
||||
return "destructive";
|
||||
} else if (arg.event.extendedProps.calendar === "polda") {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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("/en/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 && (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import { getEvents, getCategories } from "./utils";
|
||||
import { Category } from "./data"
|
||||
import { Category } from "./data";
|
||||
import CalendarView from "./calender-view";
|
||||
|
||||
|
||||
|
||||
const CalenderPage = async () => {
|
||||
const events = await getEvents();
|
||||
const categories = await getCategories();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
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 { Badge } from "@/components/ui/badge";
|
||||
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: "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>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
"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 } 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 { listTask } from "@/service/task";
|
||||
import { listContest } from "@/service/contest/contest";
|
||||
|
||||
const TaskTable = () => {
|
||||
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 [activeTab, setActiveTab] = React.useState("atensi-khusus");
|
||||
|
||||
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]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await listContest(limit, page - 1, "");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
/>
|
||||
</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 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 TaskTable;
|
||||
|
|
@ -1,23 +1,33 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Card, CardContent, CardHeader, CardTitle } 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";
|
||||
import ContestTable from "./components/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>
|
||||
<CardHeader className="border-b border-solid border-default-200 mb-6">
|
||||
<CardTitle>
|
||||
<div className="flex items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
Table Lomba
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
{/* <Link href={"/task/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
</Button>
|
||||
</Link> */}
|
||||
</div>
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<ContestTable />
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -1,347 +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: 6,
|
||||
});
|
||||
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);
|
||||
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",
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian, generateLocalizedPath } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const VideoSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "2",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel className="w-full max-w-7xl mx-auto ">
|
||||
<CarouselContent>
|
||||
{newContent?.map((video: any) => (
|
||||
<CarouselItem
|
||||
key={video?.id}
|
||||
className="md:basis-1/2 lg:basis-1/3 "
|
||||
>
|
||||
<Link
|
||||
href={generateLocalizedPath(
|
||||
`/video/detail/${video?.id}`,
|
||||
String(locale)
|
||||
)}
|
||||
className="relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
className="w-full h-32 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300 rounded-md"
|
||||
/>
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-r from-black to-slate-500 text-white p-2">
|
||||
<h1 className="text-sm font-semibold truncate">
|
||||
{video?.title}
|
||||
</h1>
|
||||
<p className="flex flex-row items-center text-sm gap-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||
{video?.timezone ? video?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{video.clickCount}{" "}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoSliderPage;
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const AudioSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "4",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((audio: any) => (
|
||||
<CarouselItem key={audio?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<div className="flex flex-row gap-6">
|
||||
<a
|
||||
href="#"
|
||||
className="flex flex-col sm:flex-row items-center bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-16 h-8 lg:h-16">
|
||||
<svg
|
||||
width="32"
|
||||
height="34"
|
||||
viewBox="0 0 32 34"
|
||||
fill="null"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M23.404 0.452014C23.7033 0.35857 24.0204 0.336816 24.3297 0.388509C24.639 0.440203 24.9318 0.563895 25.1845 0.749599C25.4371 0.935304 25.6426 1.17782 25.7843 1.45756C25.9259 1.73731 25.9998 2.04644 26 2.36001V14.414C25.3462 14.2296 24.6766 14.1064 24 14.046V8.36001L10 12.736V27C10 28.1264 9.6197 29.2197 8.92071 30.1029C8.22172 30.9861 7.24499 31.6075 6.14877 31.8663C5.05255 32.125 3.90107 32.0061 2.88089 31.5287C1.86071 31.0514 1.03159 30.2435 0.52787 29.2361C0.024152 28.2286 -0.124656 27.0806 0.105556 25.9781C0.335768 24.8755 0.931513 23.883 1.79627 23.1613C2.66102 22.4396 3.74413 22.031 4.87009 22.0017C5.99606 21.9724 7.09893 22.3242 8.00001 23V6.73601C7.99982 6.30956 8.13596 5.8942 8.38854 5.55059C8.64112 5.20698 8.99692 4.9531 9.40401 4.82601L23.404 0.452014ZM10 10.64L24 6.26601V2.36001L10 6.73601V10.64ZM5.00001 24C4.20436 24 3.44129 24.3161 2.87869 24.8787C2.31608 25.4413 2.00001 26.2044 2.00001 27C2.00001 27.7957 2.31608 28.5587 2.87869 29.1213C3.44129 29.6839 4.20436 30 5.00001 30C5.79566 30 6.55872 29.6839 7.12133 29.1213C7.68394 28.5587 8.00001 27.7957 8.00001 27C8.00001 26.2044 7.68394 25.4413 7.12133 24.8787C6.55872 24.3161 5.79566 24 5.00001 24ZM32 25C32 27.387 31.0518 29.6761 29.364 31.364C27.6761 33.0518 25.387 34 23 34C20.6131 34 18.3239 33.0518 16.636 31.364C14.9482 29.6761 14 27.387 14 25C14 22.6131 14.9482 20.3239 16.636 18.6361C18.3239 16.9482 20.6131 16 23 16C25.387 16 27.6761 16.9482 29.364 18.6361C31.0518 20.3239 32 22.6131 32 25ZM27.47 24.128L21.482 20.828C21.3298 20.7443 21.1583 20.7016 20.9846 20.7043C20.8108 20.707 20.6408 20.7549 20.4912 20.8433C20.3416 20.9317 20.2176 21.0576 20.1315 21.2086C20.0453 21.3595 20 21.5302 20 21.704V28.304C20 28.4778 20.0453 28.6486 20.1315 28.7995C20.2176 28.9504 20.3416 29.0763 20.4912 29.1647C20.6408 29.2531 20.8108 29.301 20.9846 29.3037C21.1583 29.3064 21.3298 29.2638 21.482 29.18L27.47 25.88C27.6268 25.7937 27.7575 25.6669 27.8486 25.5128C27.9397 25.3587 27.9877 25.183 27.9877 25.004C27.9877 24.825 27.9397 24.6493 27.8486 24.4952C27.7575 24.3412 27.6268 24.2143 27.47 24.128Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(new Date(audio?.createdAt))}{" "}
|
||||
{audio?.timezone ? audio?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{audio?.clickCount}{" "}
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{textEllipsis(audio.title, 50)}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AudioSliderPage;
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const ImageSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "3",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((image: any) => (
|
||||
<CarouselItem key={image?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<Link
|
||||
href={generateLocalizedPath(
|
||||
`/image/detail/${image?.id}`,
|
||||
String(locale)
|
||||
)}
|
||||
className="relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={image?.thumbnailLink}
|
||||
className="w-full h-32 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300 rounded-md"
|
||||
/>
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-r from-black to-slate-500 text-white p-2">
|
||||
<h1 className="text-sm font-semibold truncate">
|
||||
{image?.title}
|
||||
</h1>
|
||||
<p className="flex flex-row items-center text-sm gap-2">
|
||||
{formatDateToIndonesian(new Date(image?.createdAt))}{" "}
|
||||
{image?.timezone ? image?.timezone : "WIB"}|{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{image?.clickCount}{" "}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageSliderPage;
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const TeksSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "1",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((text: any) => (
|
||||
<CarouselItem key={text?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<div className="md:basis-1/2 lg:basis-1/3">
|
||||
<a
|
||||
href="#"
|
||||
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full h-[100px]"
|
||||
>
|
||||
<div className="flex items-center justify-center rounded-lg w-16 h-2 lg:h-16">
|
||||
<svg
|
||||
width="28"
|
||||
height="34"
|
||||
viewBox="0 0 28 34"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.6665 17.4167C5.6665 17.0851 5.7982 16.7672 6.03262 16.5328C6.26704 16.2984 6.58498 16.1667 6.9165 16.1667C7.24802 16.1667 7.56597 16.2984 7.80039 16.5328C8.03481 16.7672 8.1665 17.0851 8.1665 17.4167C8.1665 17.7482 8.03481 18.0661 7.80039 18.3005C7.56597 18.535 7.24802 18.6667 6.9165 18.6667C6.58498 18.6667 6.26704 18.535 6.03262 18.3005C5.7982 18.0661 5.6665 17.7482 5.6665 17.4167ZM6.9165 21.1667C6.58498 21.1667 6.26704 21.2984 6.03262 21.5328C5.7982 21.7672 5.6665 22.0851 5.6665 22.4167C5.6665 22.7482 5.7982 23.0661 6.03262 23.3005C6.26704 23.535 6.58498 23.6667 6.9165 23.6667C7.24802 23.6667 7.56597 23.535 7.80039 23.3005C8.03481 23.0661 8.1665 22.7482 8.1665 22.4167C8.1665 22.0851 8.03481 21.7672 7.80039 21.5328C7.56597 21.2984 7.24802 21.1667 6.9165 21.1667ZM5.6665 27.4167C5.6665 27.0851 5.7982 26.7672 6.03262 26.5328C6.26704 26.2984 6.58498 26.1667 6.9165 26.1667C7.24802 26.1667 7.56597 26.2984 7.80039 26.5328C8.03481 26.7672 8.1665 27.0851 8.1665 27.4167C8.1665 27.7482 8.03481 28.0661 7.80039 28.3005C7.56597 28.535 7.24802 28.6667 6.9165 28.6667C6.58498 28.6667 6.26704 28.535 6.03262 28.3005C5.7982 28.0661 5.6665 27.7482 5.6665 27.4167ZM11.9165 16.1667C11.585 16.1667 11.267 16.2984 11.0326 16.5328C10.7982 16.7672 10.6665 17.0851 10.6665 17.4167C10.6665 17.7482 10.7982 18.0661 11.0326 18.3005C11.267 18.535 11.585 18.6667 11.9165 18.6667H21.0832C21.4147 18.6667 21.7326 18.535 21.9671 18.3005C22.2015 18.0661 22.3332 17.7482 22.3332 17.4167C22.3332 17.0851 22.2015 16.7672 21.9671 16.5328C21.7326 16.2984 21.4147 16.1667 21.0832 16.1667H11.9165ZM10.6665 22.4167C10.6665 22.0851 10.7982 21.7672 11.0326 21.5328C11.267 21.2984 11.585 21.1667 11.9165 21.1667H21.0832C21.4147 21.1667 21.7326 21.2984 21.9671 21.5328C22.2015 21.7672 22.3332 22.0851 22.3332 22.4167C22.3332 22.7482 22.2015 23.0661 21.9671 23.3005C21.7326 23.535 21.4147 23.6667 21.0832 23.6667H11.9165C11.585 23.6667 11.267 23.535 11.0326 23.3005C10.7982 23.0661 10.6665 22.7482 10.6665 22.4167ZM11.9165 26.1667C11.585 26.1667 11.267 26.2984 11.0326 26.5328C10.7982 26.7672 10.6665 27.0851 10.6665 27.4167C10.6665 27.7482 10.7982 28.0661 11.0326 28.3005C11.267 28.535 11.585 28.6667 11.9165 28.6667H21.0832C21.4147 28.6667 21.7326 28.535 21.9671 28.3005C22.2015 28.0661 22.3332 27.7482 22.3332 27.4167C22.3332 27.0851 22.2015 26.7672 21.9671 26.5328C21.7326 26.2984 21.4147 26.1667 21.0832 26.1667H11.9165ZM26.3565 11.0233L16.6415 1.31C16.6157 1.28605 16.5885 1.26378 16.5598 1.24333C16.5392 1.22742 16.5192 1.21074 16.4998 1.19333C16.3852 1.08512 16.2632 0.984882 16.1348 0.893332C16.0922 0.865802 16.0476 0.841298 16.0015 0.819999L15.9215 0.779999L15.8382 0.731666C15.7482 0.679999 15.6565 0.626665 15.5615 0.586665C15.2296 0.454104 14.8783 0.376423 14.5215 0.356665C14.4885 0.354519 14.4557 0.350625 14.4232 0.344999C14.3779 0.338012 14.3323 0.334114 14.2865 0.333332H3.99984C3.11578 0.333332 2.26794 0.684521 1.64281 1.30964C1.01769 1.93476 0.666504 2.78261 0.666504 3.66667V30.3333C0.666504 31.2174 1.01769 32.0652 1.64281 32.6904C2.26794 33.3155 3.11578 33.6667 3.99984 33.6667H23.9998C24.8839 33.6667 25.7317 33.3155 26.3569 32.6904C26.982 32.0652 27.3332 31.2174 27.3332 30.3333V13.38C27.333 12.496 26.9817 11.6483 26.3565 11.0233ZM24.8332 30.3333C24.8332 30.5543 24.7454 30.7663 24.5891 30.9226C24.4328 31.0789 24.2208 31.1667 23.9998 31.1667H3.99984C3.77882 31.1667 3.56686 31.0789 3.41058 30.9226C3.2543 30.7663 3.1665 30.5543 3.1665 30.3333V3.66667C3.1665 3.44565 3.2543 3.23369 3.41058 3.07741C3.56686 2.92113 3.77882 2.83333 3.99984 2.83333H13.9998V10.3333C13.9998 11.2174 14.351 12.0652 14.9761 12.6904C15.6013 13.3155 16.4491 13.6667 17.3332 13.6667H24.8332V30.3333ZM16.4998 4.70166L22.9632 11.1667H17.3332C17.1122 11.1667 16.9002 11.0789 16.7439 10.9226C16.5876 10.7663 16.4998 10.5543 16.4998 10.3333V4.70166Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(new Date(text?.createdAt))}{" "}
|
||||
{text?.timezone ? text?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{text?.clickCount}{" "}
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{textEllipsis(text?.title, 50)}
|
||||
</div>
|
||||
<div className="flex gap-2 items-center text-sm text-red-500 dark:text-red-500">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
d="M224 30v256h-64l96 128l96-128h-64V30zM32 434v48h448v-48z"
|
||||
/>
|
||||
</svg>
|
||||
Download Dokumen
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeksSliderPage;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian, generateLocalizedPath } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const VideoSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "2",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel className="w-full max-w-7xl mx-auto ">
|
||||
<CarouselContent>
|
||||
{newContent?.map((video: any) => (
|
||||
<CarouselItem
|
||||
key={video?.id}
|
||||
className="md:basis-1/2 lg:basis-1/3 "
|
||||
>
|
||||
<Link
|
||||
href={generateLocalizedPath(
|
||||
`/video/detail/${video?.id}`,
|
||||
String(locale)
|
||||
)}
|
||||
className="relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
className="w-full h-32 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300 rounded-md"
|
||||
/>
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-r from-black to-slate-500 text-white p-2">
|
||||
<h1 className="text-sm font-semibold truncate">
|
||||
{video?.title}
|
||||
</h1>
|
||||
<p className="flex flex-row items-center text-sm gap-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||
{video?.timezone ? video?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{video.clickCount}{" "}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoSliderPage;
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const AudioSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "4",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((audio: any) => (
|
||||
<CarouselItem key={audio?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<div className="flex flex-row gap-6">
|
||||
<a
|
||||
href="#"
|
||||
className="flex flex-col sm:flex-row items-center bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-16 h-8 lg:h-16">
|
||||
<svg
|
||||
width="32"
|
||||
height="34"
|
||||
viewBox="0 0 32 34"
|
||||
fill="null"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M23.404 0.452014C23.7033 0.35857 24.0204 0.336816 24.3297 0.388509C24.639 0.440203 24.9318 0.563895 25.1845 0.749599C25.4371 0.935304 25.6426 1.17782 25.7843 1.45756C25.9259 1.73731 25.9998 2.04644 26 2.36001V14.414C25.3462 14.2296 24.6766 14.1064 24 14.046V8.36001L10 12.736V27C10 28.1264 9.6197 29.2197 8.92071 30.1029C8.22172 30.9861 7.24499 31.6075 6.14877 31.8663C5.05255 32.125 3.90107 32.0061 2.88089 31.5287C1.86071 31.0514 1.03159 30.2435 0.52787 29.2361C0.024152 28.2286 -0.124656 27.0806 0.105556 25.9781C0.335768 24.8755 0.931513 23.883 1.79627 23.1613C2.66102 22.4396 3.74413 22.031 4.87009 22.0017C5.99606 21.9724 7.09893 22.3242 8.00001 23V6.73601C7.99982 6.30956 8.13596 5.8942 8.38854 5.55059C8.64112 5.20698 8.99692 4.9531 9.40401 4.82601L23.404 0.452014ZM10 10.64L24 6.26601V2.36001L10 6.73601V10.64ZM5.00001 24C4.20436 24 3.44129 24.3161 2.87869 24.8787C2.31608 25.4413 2.00001 26.2044 2.00001 27C2.00001 27.7957 2.31608 28.5587 2.87869 29.1213C3.44129 29.6839 4.20436 30 5.00001 30C5.79566 30 6.55872 29.6839 7.12133 29.1213C7.68394 28.5587 8.00001 27.7957 8.00001 27C8.00001 26.2044 7.68394 25.4413 7.12133 24.8787C6.55872 24.3161 5.79566 24 5.00001 24ZM32 25C32 27.387 31.0518 29.6761 29.364 31.364C27.6761 33.0518 25.387 34 23 34C20.6131 34 18.3239 33.0518 16.636 31.364C14.9482 29.6761 14 27.387 14 25C14 22.6131 14.9482 20.3239 16.636 18.6361C18.3239 16.9482 20.6131 16 23 16C25.387 16 27.6761 16.9482 29.364 18.6361C31.0518 20.3239 32 22.6131 32 25ZM27.47 24.128L21.482 20.828C21.3298 20.7443 21.1583 20.7016 20.9846 20.7043C20.8108 20.707 20.6408 20.7549 20.4912 20.8433C20.3416 20.9317 20.2176 21.0576 20.1315 21.2086C20.0453 21.3595 20 21.5302 20 21.704V28.304C20 28.4778 20.0453 28.6486 20.1315 28.7995C20.2176 28.9504 20.3416 29.0763 20.4912 29.1647C20.6408 29.2531 20.8108 29.301 20.9846 29.3037C21.1583 29.3064 21.3298 29.2638 21.482 29.18L27.47 25.88C27.6268 25.7937 27.7575 25.6669 27.8486 25.5128C27.9397 25.3587 27.9877 25.183 27.9877 25.004C27.9877 24.825 27.9397 24.6493 27.8486 24.4952C27.7575 24.3412 27.6268 24.2143 27.47 24.128Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(new Date(audio?.createdAt))}{" "}
|
||||
{audio?.timezone ? audio?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{audio?.clickCount}{" "}
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{textEllipsis(audio.title, 50)}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AudioSliderPage;
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const ImageSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "3",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((image: any) => (
|
||||
<CarouselItem key={image?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<Link
|
||||
href={generateLocalizedPath(
|
||||
`/image/detail/${image?.id}`,
|
||||
String(locale)
|
||||
)}
|
||||
className="relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={image?.thumbnailLink}
|
||||
className="w-full h-32 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300 rounded-md"
|
||||
/>
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-r from-black to-slate-500 text-white p-2">
|
||||
<h1 className="text-sm font-semibold truncate">
|
||||
{image?.title}
|
||||
</h1>
|
||||
<p className="flex flex-row items-center text-sm gap-2">
|
||||
{formatDateToIndonesian(new Date(image?.createdAt))}{" "}
|
||||
{image?.timezone ? image?.timezone : "WIB"}|{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{image?.clickCount}{" "}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageSliderPage;
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
const TeksSliderPage = () => {
|
||||
const [newContent, setNewContent] = useState<any>();
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
const type = "popular";
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
});
|
||||
const initFetch = async () => {
|
||||
const request = {
|
||||
sortBy: type == "popular" ? "clickCount" : "createdAt",
|
||||
contentTypeId: "1",
|
||||
};
|
||||
const response = await getListContent(request);
|
||||
console.log("category", response);
|
||||
setNewContent(response?.data?.data?.content);
|
||||
};
|
||||
return (
|
||||
<div className="mx-3 px-5">
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
{newContent?.map((text: any) => (
|
||||
<CarouselItem key={text?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<div className="md:basis-1/2 lg:basis-1/3">
|
||||
<a
|
||||
href="#"
|
||||
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full h-[100px]"
|
||||
>
|
||||
<div className="flex items-center justify-center rounded-lg w-16 h-2 lg:h-16">
|
||||
<svg
|
||||
width="28"
|
||||
height="34"
|
||||
viewBox="0 0 28 34"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.6665 17.4167C5.6665 17.0851 5.7982 16.7672 6.03262 16.5328C6.26704 16.2984 6.58498 16.1667 6.9165 16.1667C7.24802 16.1667 7.56597 16.2984 7.80039 16.5328C8.03481 16.7672 8.1665 17.0851 8.1665 17.4167C8.1665 17.7482 8.03481 18.0661 7.80039 18.3005C7.56597 18.535 7.24802 18.6667 6.9165 18.6667C6.58498 18.6667 6.26704 18.535 6.03262 18.3005C5.7982 18.0661 5.6665 17.7482 5.6665 17.4167ZM6.9165 21.1667C6.58498 21.1667 6.26704 21.2984 6.03262 21.5328C5.7982 21.7672 5.6665 22.0851 5.6665 22.4167C5.6665 22.7482 5.7982 23.0661 6.03262 23.3005C6.26704 23.535 6.58498 23.6667 6.9165 23.6667C7.24802 23.6667 7.56597 23.535 7.80039 23.3005C8.03481 23.0661 8.1665 22.7482 8.1665 22.4167C8.1665 22.0851 8.03481 21.7672 7.80039 21.5328C7.56597 21.2984 7.24802 21.1667 6.9165 21.1667ZM5.6665 27.4167C5.6665 27.0851 5.7982 26.7672 6.03262 26.5328C6.26704 26.2984 6.58498 26.1667 6.9165 26.1667C7.24802 26.1667 7.56597 26.2984 7.80039 26.5328C8.03481 26.7672 8.1665 27.0851 8.1665 27.4167C8.1665 27.7482 8.03481 28.0661 7.80039 28.3005C7.56597 28.535 7.24802 28.6667 6.9165 28.6667C6.58498 28.6667 6.26704 28.535 6.03262 28.3005C5.7982 28.0661 5.6665 27.7482 5.6665 27.4167ZM11.9165 16.1667C11.585 16.1667 11.267 16.2984 11.0326 16.5328C10.7982 16.7672 10.6665 17.0851 10.6665 17.4167C10.6665 17.7482 10.7982 18.0661 11.0326 18.3005C11.267 18.535 11.585 18.6667 11.9165 18.6667H21.0832C21.4147 18.6667 21.7326 18.535 21.9671 18.3005C22.2015 18.0661 22.3332 17.7482 22.3332 17.4167C22.3332 17.0851 22.2015 16.7672 21.9671 16.5328C21.7326 16.2984 21.4147 16.1667 21.0832 16.1667H11.9165ZM10.6665 22.4167C10.6665 22.0851 10.7982 21.7672 11.0326 21.5328C11.267 21.2984 11.585 21.1667 11.9165 21.1667H21.0832C21.4147 21.1667 21.7326 21.2984 21.9671 21.5328C22.2015 21.7672 22.3332 22.0851 22.3332 22.4167C22.3332 22.7482 22.2015 23.0661 21.9671 23.3005C21.7326 23.535 21.4147 23.6667 21.0832 23.6667H11.9165C11.585 23.6667 11.267 23.535 11.0326 23.3005C10.7982 23.0661 10.6665 22.7482 10.6665 22.4167ZM11.9165 26.1667C11.585 26.1667 11.267 26.2984 11.0326 26.5328C10.7982 26.7672 10.6665 27.0851 10.6665 27.4167C10.6665 27.7482 10.7982 28.0661 11.0326 28.3005C11.267 28.535 11.585 28.6667 11.9165 28.6667H21.0832C21.4147 28.6667 21.7326 28.535 21.9671 28.3005C22.2015 28.0661 22.3332 27.7482 22.3332 27.4167C22.3332 27.0851 22.2015 26.7672 21.9671 26.5328C21.7326 26.2984 21.4147 26.1667 21.0832 26.1667H11.9165ZM26.3565 11.0233L16.6415 1.31C16.6157 1.28605 16.5885 1.26378 16.5598 1.24333C16.5392 1.22742 16.5192 1.21074 16.4998 1.19333C16.3852 1.08512 16.2632 0.984882 16.1348 0.893332C16.0922 0.865802 16.0476 0.841298 16.0015 0.819999L15.9215 0.779999L15.8382 0.731666C15.7482 0.679999 15.6565 0.626665 15.5615 0.586665C15.2296 0.454104 14.8783 0.376423 14.5215 0.356665C14.4885 0.354519 14.4557 0.350625 14.4232 0.344999C14.3779 0.338012 14.3323 0.334114 14.2865 0.333332H3.99984C3.11578 0.333332 2.26794 0.684521 1.64281 1.30964C1.01769 1.93476 0.666504 2.78261 0.666504 3.66667V30.3333C0.666504 31.2174 1.01769 32.0652 1.64281 32.6904C2.26794 33.3155 3.11578 33.6667 3.99984 33.6667H23.9998C24.8839 33.6667 25.7317 33.3155 26.3569 32.6904C26.982 32.0652 27.3332 31.2174 27.3332 30.3333V13.38C27.333 12.496 26.9817 11.6483 26.3565 11.0233ZM24.8332 30.3333C24.8332 30.5543 24.7454 30.7663 24.5891 30.9226C24.4328 31.0789 24.2208 31.1667 23.9998 31.1667H3.99984C3.77882 31.1667 3.56686 31.0789 3.41058 30.9226C3.2543 30.7663 3.1665 30.5543 3.1665 30.3333V3.66667C3.1665 3.44565 3.2543 3.23369 3.41058 3.07741C3.56686 2.92113 3.77882 2.83333 3.99984 2.83333H13.9998V10.3333C13.9998 11.2174 14.351 12.0652 14.9761 12.6904C15.6013 13.3155 16.4491 13.6667 17.3332 13.6667H24.8332V30.3333ZM16.4998 4.70166L22.9632 11.1667H17.3332C17.1122 11.1667 16.9002 11.0789 16.7439 10.9226C16.5876 10.7663 16.4998 10.5543 16.4998 10.3333V4.70166Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(new Date(text?.createdAt))}{" "}
|
||||
{text?.timezone ? text?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
{text?.clickCount}{" "}
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{textEllipsis(text?.title, 50)}
|
||||
</div>
|
||||
<div className="flex gap-2 items-center text-sm text-red-500 dark:text-red-500">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
d="M224 30v256h-64l96 128l96-128h-64V30zM32 434v48h448v-48z"
|
||||
/>
|
||||
</svg>
|
||||
Download Dokumen
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeksSliderPage;
|
||||
|
|
@ -1,13 +1,30 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import InternalTable from "../communication/internal/components/internal-table";
|
||||
import EscalationTable from "../communication/escalation/components/escalation-table";
|
||||
import CollaborationTable from "../communication/collaboration/components/collabroation-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Search, UploadIcon } from "lucide-react";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { formatDateToIndonesian, generateLocalizedPath } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import newContent from "@/components/landing-page/new-content";
|
||||
import { locale } from "dayjs";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import GiatRoutine from "./giat-routine/audio-visual";
|
||||
import VideoSliderPage from "./giat-routine/audio-visual";
|
||||
import AudioSliderPage from "./giat-routine/audio";
|
||||
import ImageSliderPage from "./giat-routine/image";
|
||||
import TeksSliderPage from "./giat-routine/teks";
|
||||
import ContestTable from "../contest/components/contest-table";
|
||||
|
||||
const CuratedContentPage = async () => {
|
||||
return (
|
||||
|
|
@ -56,6 +73,24 @@ const CuratedContentPage = async () => {
|
|||
</InputGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-5 pb-3">
|
||||
<Label>Audio Visual</Label>
|
||||
<div className="px-5 my-5">
|
||||
<VideoSliderPage />
|
||||
</div>
|
||||
<Label>Audio</Label>
|
||||
<div className="px-5 my-5">
|
||||
<AudioSliderPage />
|
||||
</div>
|
||||
<Label>Foto</Label>
|
||||
<div className="px-5 my-5">
|
||||
<ImageSliderPage />
|
||||
</div>
|
||||
<Label>Teks</Label>
|
||||
<div className="px-5 my-5">
|
||||
<TeksSliderPage />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -78,32 +113,35 @@ const CuratedContentPage = async () => {
|
|||
</InputGroup>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="contest">
|
||||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-12 col-span-12">
|
||||
<Card>
|
||||
<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 className="ml-5 pb-3">
|
||||
<Label>Audio Visual</Label>
|
||||
<div className="px-5 my-5">
|
||||
<VideoSliderPage />
|
||||
</div>
|
||||
<Label>Audio</Label>
|
||||
<div className="px-5 my-5">
|
||||
<AudioSliderPage />
|
||||
</div>
|
||||
<Label>Foto</Label>
|
||||
<div className="px-5 my-5">
|
||||
<ImageSliderPage />
|
||||
</div>
|
||||
<Label>Teks</Label>
|
||||
<div className="px-5 my-5">
|
||||
<TeksSliderPage />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="contest">
|
||||
<Card>
|
||||
<div className="py-3">
|
||||
<ContestTable />
|
||||
</div>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
@ -132,8 +139,10 @@ const columns: ColumnDef<any>[] = [
|
|||
</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
|
||||
<Link href={`/schedule/press-conference/detail/${row.id}`}>
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</Link>
|
||||
</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" />
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
const PressConDetailPage = async () => {
|
||||
const params = useParams();
|
||||
const id = params?.id;
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailPressConference id={id} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressConDetailPage;
|
||||
|
|
@ -37,15 +37,15 @@ import "react-clock/dist/Clock.css";
|
|||
import { register } from "module";
|
||||
import MapHome from "@/components/maps/MapHome";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { error } from "@/lib/swal";
|
||||
import Cookies from "js-cookie";
|
||||
import { postSchedule } from "@/service/schedule/schedule";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
rankName: z.string().min(1, { message: "Nama Pangkat diperlukan" }),
|
||||
fullName: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
naration: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
location: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
level: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
name: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
location: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
export default function FormEvent() {
|
||||
|
|
@ -69,13 +69,6 @@ export default function FormEvent() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
// State for various form fields
|
||||
const [output, setOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
|
|
@ -102,16 +95,33 @@ export default function FormEvent() {
|
|||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
output,
|
||||
assignmentType,
|
||||
assignmentCategory,
|
||||
target: selectedTarget,
|
||||
unitSelection,
|
||||
title: data.title,
|
||||
address: data.location,
|
||||
speakerTitle: data.level,
|
||||
speakerName: data.name,
|
||||
startTime, // Start time from state
|
||||
endTime, // End time from state
|
||||
addressLat: "0.0", // Replace with actual latitude
|
||||
addressLong: "0.0", // Replace with actual longitude
|
||||
startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
|
||||
endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
|
||||
isYoutube: isLiveStreamingEnabled,
|
||||
scheduleTypeId: 2,
|
||||
};
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
||||
const response = await postSchedule(requestData);
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Cookies.set("scheduleId", response.data.data.id, {
|
||||
expires: 1,
|
||||
});
|
||||
|
||||
// Optional: Use Swal for success feedback
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
|
|
@ -119,7 +129,7 @@ export default function FormEvent() {
|
|||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/task");
|
||||
router.push("/en/schedule/event");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -143,7 +153,7 @@ export default function FormEvent() {
|
|||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Konferensi Pers</p>
|
||||
<p className="text-lg font-semibold mb-3">Form Event</p>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className=" gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
|
|
@ -298,7 +308,7 @@ export default function FormEvent() {
|
|||
<Label>Nama Pangkat</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="rankName"
|
||||
name="level"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -309,9 +319,9 @@ export default function FormEvent() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.rankName?.message && (
|
||||
{errors.level?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.rankName.message}
|
||||
{errors.level.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -321,7 +331,7 @@ export default function FormEvent() {
|
|||
<Label>Nama Lengkap</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="fullName"
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -332,9 +342,9 @@ export default function FormEvent() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.fullName?.message && (
|
||||
{errors.name?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.fullName.message}
|
||||
{errors.name.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,15 +37,15 @@ import "react-clock/dist/Clock.css";
|
|||
import { register } from "module";
|
||||
import MapHome from "@/components/maps/MapHome";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { error } from "@/lib/swal";
|
||||
import Cookies from "js-cookie";
|
||||
import { postSchedule } from "@/service/schedule/schedule";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
rankName: z.string().min(1, { message: "Nama Pangkat diperlukan" }),
|
||||
fullName: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
naration: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
location: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
level: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
name: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
location: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
export default function FormPressRelease() {
|
||||
|
|
@ -69,13 +69,6 @@ export default function FormPressRelease() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
// State for various form fields
|
||||
const [output, setOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
|
|
@ -102,16 +95,33 @@ export default function FormPressRelease() {
|
|||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
output,
|
||||
assignmentType,
|
||||
assignmentCategory,
|
||||
target: selectedTarget,
|
||||
unitSelection,
|
||||
title: data.title,
|
||||
address: data.location,
|
||||
speakerTitle: data.level,
|
||||
speakerName: data.name,
|
||||
startTime, // Start time from state
|
||||
endTime, // End time from state
|
||||
addressLat: "0.0", // Replace with actual latitude
|
||||
addressLong: "0.0", // Replace with actual longitude
|
||||
startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
|
||||
endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
|
||||
isYoutube: isLiveStreamingEnabled,
|
||||
scheduleTypeId: 3,
|
||||
};
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
||||
const response = await postSchedule(requestData);
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Cookies.set("scheduleId", response.data.data.id, {
|
||||
expires: 1,
|
||||
});
|
||||
|
||||
// Optional: Use Swal for success feedback
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
|
|
@ -119,7 +129,7 @@ export default function FormPressRelease() {
|
|||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/task");
|
||||
router.push("/en/schedule/press-release");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -143,7 +153,7 @@ export default function FormPressRelease() {
|
|||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Konferensi Pers</p>
|
||||
<p className="text-lg font-semibold mb-3">Form Pers Rilis</p>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className=" gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
|
|
@ -315,7 +325,7 @@ export default function FormPressRelease() {
|
|||
<Label>Nama Pangkat</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="rankName"
|
||||
name="level"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -326,9 +336,9 @@ export default function FormPressRelease() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.rankName?.message && (
|
||||
{errors.level?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.rankName.message}
|
||||
{errors.level.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -338,7 +348,7 @@ export default function FormPressRelease() {
|
|||
<Label>Nama Lengkap</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="fullName"
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -349,9 +359,9 @@ export default function FormPressRelease() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.fullName?.message && (
|
||||
{errors.name?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.fullName.message}
|
||||
{errors.name.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,341 @@
|
|||
"use client";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import * as z from "zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import JoditEditor from "jodit-react";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, setDate } from "date-fns";
|
||||
import { DateRange } from "react-day-picker";
|
||||
import TimePicker from "react-time-picker";
|
||||
import "react-time-picker/dist/TimePicker.css";
|
||||
import "react-clock/dist/Clock.css";
|
||||
import MapHome from "@/components/maps/MapHome";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { error, loading } from "@/lib/swal";
|
||||
import Cookies from "js-cookie";
|
||||
import { detailSchedule, postSchedule } from "@/service/schedule/schedule";
|
||||
import { id } from "date-fns/locale";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
level: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
name: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
location: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
interface Detail {
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormDetailPressConference(props: { id: any }) {
|
||||
const router = useRouter();
|
||||
const id = props.id;
|
||||
const [isLiveStreamingEnabled, setIsLiveStreamingEnabled] = useState(false);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
const [startTime, setStartTime] = useState("08:00");
|
||||
const [endTime, setEndTime] = useState("09:00");
|
||||
|
||||
const [date, setDate] = React.useState<DateRange | undefined>({
|
||||
from: new Date(2024, 0, 1),
|
||||
});
|
||||
|
||||
const handleStartTime = (e: any) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: any) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
const [detail, setDetail] = useState<Detail | null>(null);
|
||||
const [dataForm, setDataForm] = useState(null);
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
defaultValues: {
|
||||
location: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
try {
|
||||
loading();
|
||||
const response = await detailSchedule(id);
|
||||
const details = response.data?.data;
|
||||
console.log("res", id, response?.data?.data);
|
||||
if (details) {
|
||||
setDetail(details);
|
||||
setValue("title", details.title || "");
|
||||
setValue("location", details.address || "");
|
||||
setValue("level", details.speakerTitle || "");
|
||||
setValue("name", details.speakerName || "");
|
||||
|
||||
Cookies.set("map_lat", details.addressLat, {
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
Cookies.set("map_long", details.addressLong, {
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
}
|
||||
Swal.close();
|
||||
} catch (err) {
|
||||
Swal.fire("Error", "Failed to fetch details", "error");
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Konferensi Pers</p>
|
||||
{detail !== undefined ? (
|
||||
<div className=" gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
<Label>Judul Kegiatan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="mt-5">
|
||||
<Label>Live Streaming</Label>
|
||||
<div className="flex items-center gap-3">
|
||||
<p>Aktifkan fitur live streaming</p>
|
||||
<Switch
|
||||
defaultChecked={isLiveStreamingEnabled}
|
||||
color="primary"
|
||||
id="c2"
|
||||
onCheckedChange={(checked) =>
|
||||
setIsLiveStreamingEnabled(checked)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLiveStreamingEnabled && (
|
||||
<div className="mt-1">
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan ID youtube"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col lg:flex-row mt-3 items-start lg:items-center justify-between">
|
||||
<div className="flex flex-col ">
|
||||
<Label className="mr-3 mb-1">Tanggal</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
id="date"
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] lg:w-[300px] justify-start text-left font-normal",
|
||||
!date && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon />
|
||||
{date?.from ? (
|
||||
date.to ? (
|
||||
<>
|
||||
{format(date.from, "LLL dd, y")} -{" "}
|
||||
{format(date.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(date.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
initialFocus
|
||||
mode="range"
|
||||
defaultMonth={date?.from}
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
numberOfMonths={1}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="title">Rentang Waktu</Label>
|
||||
<div className="">
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
defaultValue="08:00"
|
||||
type="time"
|
||||
onChange={(e) => handleStartTime(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
defaultValue="09:00"
|
||||
type="time"
|
||||
onChange={(e) => handleEndTime(e)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{/* Kirim setValue ke MapHome */}
|
||||
<MapHome
|
||||
draggable
|
||||
setLocation={(location) => setValue("location", location)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="location"
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
rows={3}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan lokasi"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="invalid-feedback">
|
||||
{errors.location?.message}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm my-2 font-semibold">DI SAMPAIKAN OLEH</p>
|
||||
<div className="flex flex-col ">
|
||||
<div className="mt-1">
|
||||
<Label>Nama Pangkat</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="level"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Pangkat"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.level?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.level.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col my-3">
|
||||
<div className="mt-1">
|
||||
<Label>Nama Lengkap</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Lengkap"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.name?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.name.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{/* Submit Button
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -37,15 +37,15 @@ import "react-clock/dist/Clock.css";
|
|||
import { register } from "module";
|
||||
import MapHome from "@/components/maps/MapHome";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { error } from "@/lib/swal";
|
||||
import Cookies from "js-cookie";
|
||||
import { postSchedule } from "@/service/schedule/schedule";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
rankName: z.string().min(1, { message: "Nama Pangkat diperlukan" }),
|
||||
fullName: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
naration: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
location: z.string().min(1, { message: "Nama Lengkap diperlukan" }),
|
||||
level: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
name: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
location: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
export default function FormPressConference() {
|
||||
|
|
@ -69,13 +69,6 @@ export default function FormPressConference() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
// State for various form fields
|
||||
const [output, setOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
|
|
@ -102,16 +95,33 @@ export default function FormPressConference() {
|
|||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
output,
|
||||
assignmentType,
|
||||
assignmentCategory,
|
||||
target: selectedTarget,
|
||||
unitSelection,
|
||||
title: data.title,
|
||||
address: data.location,
|
||||
speakerTitle: data.level,
|
||||
speakerName: data.name,
|
||||
startTime, // Start time from state
|
||||
endTime, // End time from state
|
||||
addressLat: "0.0", // Replace with actual latitude
|
||||
addressLong: "0.0", // Replace with actual longitude
|
||||
startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
|
||||
endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
|
||||
isYoutube: isLiveStreamingEnabled,
|
||||
scheduleTypeId: 1,
|
||||
};
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
||||
const response = await postSchedule(requestData);
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Cookies.set("scheduleId", response.data.data.id, {
|
||||
expires: 1,
|
||||
});
|
||||
|
||||
// Optional: Use Swal for success feedback
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
|
|
@ -119,7 +129,7 @@ export default function FormPressConference() {
|
|||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/task");
|
||||
router.push("/en/schedule/press-conference");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -298,7 +308,7 @@ export default function FormPressConference() {
|
|||
<Label>Nama Pangkat</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="rankName"
|
||||
name="level"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -309,9 +319,9 @@ export default function FormPressConference() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.rankName?.message && (
|
||||
{errors.level?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.rankName.message}
|
||||
{errors.level.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -321,7 +331,7 @@ export default function FormPressConference() {
|
|||
<Label>Nama Lengkap</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="fullName"
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
|
|
@ -332,9 +342,9 @@ export default function FormPressConference() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.fullName?.message && (
|
||||
{errors.name?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.fullName.message}
|
||||
{errors.name.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
import useEmblaCarousel, {
|
||||
type UseEmblaCarouselType,
|
||||
} from "embla-carousel-react"
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||
} from "embla-carousel-react";
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
type CarouselApi = UseEmblaCarouselType[1]
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||
type CarouselOptions = UseCarouselParameters[0]
|
||||
type CarouselPlugin = UseCarouselParameters[1]
|
||||
type CarouselApi = UseEmblaCarouselType[1];
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||
type CarouselOptions = UseCarouselParameters[0];
|
||||
type CarouselPlugin = UseCarouselParameters[1];
|
||||
|
||||
type CarouselProps = {
|
||||
opts?: CarouselOptions
|
||||
plugins?: CarouselPlugin
|
||||
orientation?: "horizontal" | "vertical"
|
||||
setApi?: (api: CarouselApi) => void
|
||||
}
|
||||
opts?: CarouselOptions;
|
||||
plugins?: CarouselPlugin;
|
||||
orientation?: "horizontal" | "vertical";
|
||||
setApi?: (api: CarouselApi) => void;
|
||||
};
|
||||
|
||||
type CarouselContextProps = {
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||
scrollPrev: () => void
|
||||
scrollNext: () => void
|
||||
canScrollPrev: boolean
|
||||
canScrollNext: boolean
|
||||
} & CarouselProps
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
||||
api: ReturnType<typeof useEmblaCarousel>[1];
|
||||
scrollPrev: () => void;
|
||||
scrollNext: () => void;
|
||||
canScrollPrev: boolean;
|
||||
canScrollNext: boolean;
|
||||
} & CarouselProps;
|
||||
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
|
||||
|
||||
function useCarousel() {
|
||||
const context = React.useContext(CarouselContext)
|
||||
const context = React.useContext(CarouselContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useCarousel must be used within a <Carousel />")
|
||||
throw new Error("useCarousel must be used within a <Carousel />");
|
||||
}
|
||||
|
||||
return context
|
||||
return context;
|
||||
}
|
||||
|
||||
const Carousel = React.forwardRef<
|
||||
|
|
@ -64,61 +64,61 @@ const Carousel = React.forwardRef<
|
|||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
},
|
||||
plugins
|
||||
)
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||
);
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
||||
|
||||
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||
if (!api) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollPrev(api.canScrollPrev())
|
||||
setCanScrollNext(api.canScrollNext())
|
||||
}, [])
|
||||
setCanScrollPrev(api.canScrollPrev());
|
||||
setCanScrollNext(api.canScrollNext());
|
||||
}, []);
|
||||
|
||||
const scrollPrev = React.useCallback(() => {
|
||||
api?.scrollPrev()
|
||||
}, [api])
|
||||
api?.scrollPrev();
|
||||
}, [api]);
|
||||
|
||||
const scrollNext = React.useCallback(() => {
|
||||
api?.scrollNext()
|
||||
}, [api])
|
||||
api?.scrollNext();
|
||||
}, [api]);
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault()
|
||||
scrollPrev()
|
||||
event.preventDefault();
|
||||
scrollPrev();
|
||||
} else if (event.key === "ArrowRight") {
|
||||
event.preventDefault()
|
||||
scrollNext()
|
||||
event.preventDefault();
|
||||
scrollNext();
|
||||
}
|
||||
},
|
||||
[scrollPrev, scrollNext]
|
||||
)
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api || !setApi) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
setApi(api);
|
||||
}, [api, setApi]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
onSelect(api)
|
||||
api.on("reInit", onSelect)
|
||||
api.on("select", onSelect)
|
||||
onSelect(api);
|
||||
api.on("reInit", onSelect);
|
||||
api.on("select", onSelect);
|
||||
|
||||
return () => {
|
||||
api?.off("select", onSelect)
|
||||
}
|
||||
}, [api, onSelect])
|
||||
api?.off("select", onSelect);
|
||||
};
|
||||
}, [api, onSelect]);
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider
|
||||
|
|
@ -145,16 +145,16 @@ const Carousel = React.forwardRef<
|
|||
{children}
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
Carousel.displayName = "Carousel"
|
||||
);
|
||||
Carousel.displayName = "Carousel";
|
||||
|
||||
const CarouselContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { carouselRef, orientation } = useCarousel()
|
||||
const { carouselRef, orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
<div ref={carouselRef} className="overflow-hidden">
|
||||
|
|
@ -168,15 +168,15 @@ const CarouselContent = React.forwardRef<
|
|||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
CarouselContent.displayName = "CarouselContent"
|
||||
);
|
||||
});
|
||||
CarouselContent.displayName = "CarouselContent";
|
||||
|
||||
const CarouselItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { orientation } = useCarousel()
|
||||
const { orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -190,15 +190,15 @@ const CarouselItem = React.forwardRef<
|
|||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
CarouselItem.displayName = "CarouselItem"
|
||||
);
|
||||
});
|
||||
CarouselItem.displayName = "CarouselItem";
|
||||
|
||||
const CarouselPrevious = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -206,7 +206,7 @@ const CarouselPrevious = React.forwardRef<
|
|||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-6 w-6 rounded-full",
|
||||
"absolute h-6 w-6 rounded-full ml-3",
|
||||
orientation === "horizontal"
|
||||
? "-left-12 top-1/2 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
|
|
@ -219,15 +219,15 @@ const CarouselPrevious = React.forwardRef<
|
|||
<ArrowLeft className="h-4 w-4" />
|
||||
<span className="sr-only">Previous slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselPrevious.displayName = "CarouselPrevious"
|
||||
);
|
||||
});
|
||||
CarouselPrevious.displayName = "CarouselPrevious";
|
||||
|
||||
const CarouselNext = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -235,7 +235,7 @@ const CarouselNext = React.forwardRef<
|
|||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-6 w-6 rounded-full",
|
||||
"absolute h-6 w-6 rounded-full mr-3",
|
||||
orientation === "horizontal"
|
||||
? "-right-12 top-1/2 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
|
|
@ -248,9 +248,9 @@ const CarouselNext = React.forwardRef<
|
|||
<ArrowRight className="h-4 w-4" />
|
||||
<span className="sr-only">Next slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselNext.displayName = "CarouselNext"
|
||||
);
|
||||
});
|
||||
CarouselNext.displayName = "CarouselNext";
|
||||
|
||||
export {
|
||||
type CarouselApi,
|
||||
|
|
@ -259,4 +259,4 @@ export {
|
|||
CarouselItem,
|
||||
CarouselPrevious,
|
||||
CarouselNext,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import { getAPIInterceptor, postAPIInterceptor } from "@/config/api";
|
||||
|
||||
export async function getAgendaSettingsById(id: any) {
|
||||
const url = `agenda-settings?id=${id}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
||||
export async function getAgendaSettingsList(year = "", month = "", type = "") {
|
||||
const url = `agenda-settings/list?year=${year}&month=${month}&type=${type}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
||||
export async function saveAgendaSettings(data: any) {
|
||||
const url = `agenda-settings`;
|
||||
return postAPIInterceptor(url, data);
|
||||
}
|
||||
|
|
@ -3,9 +3,13 @@ import {
|
|||
httpPostInterceptor,
|
||||
} from "../http-config/http-interceptor-service";
|
||||
|
||||
export async function listContest(size: number, page: number) {
|
||||
export async function listContest(
|
||||
size: number,
|
||||
page: number,
|
||||
title: string = ""
|
||||
) {
|
||||
return await httpGetInterceptor(
|
||||
`contest/pagination?enablePage=1&size=${size}&page=${page}`
|
||||
`contest/pagination?enablePage=1&size=${size}&page=${page}&title=${title}`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { title } from "process";
|
||||
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
|
||||
import { type } from "os";
|
||||
import { getAPI, getAPIInterceptor, postAPIInterceptor } from "@/config/api";
|
||||
|
||||
export async function paginationSchedule(
|
||||
size: number,
|
||||
|
|
@ -12,3 +13,13 @@ export async function paginationSchedule(
|
|||
`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function postSchedule(data: any) {
|
||||
const url = "schedule";
|
||||
return postAPIInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function detailSchedule(id: any) {
|
||||
const url = `public/schedule?id=${id}`;
|
||||
return getAPIInterceptor({ url });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue