[QUDO-154] - fix:create live report form & flow, polda sidebar
This commit is contained in:
parent
9703c25ea2
commit
9231546780
|
|
@ -13,8 +13,12 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import { deleteSchedule } from "@/service/schedule/schedule";
|
||||
import { error } from "@/config/swal";
|
||||
|
||||
const useTableColumns = () => {
|
||||
const useTableColumns = (props: { selectedTypeSchedule: string }) => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
|
|
@ -138,6 +142,33 @@ const useTableColumns = () => {
|
|||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
|
||||
const response = await deleteSchedule(id);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
|
@ -151,7 +182,7 @@ const useTableColumns = () => {
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
href={`/contributor/schedule/live-report/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
|
|
@ -159,14 +190,17 @@ const useTableColumns = () => {
|
|||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
href={`/contributor/schedule/live-report/update/${row.original.id}?scheduleType=${props.selectedTypeSchedule}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<DropdownMenuItem
|
||||
onClick={() => doDelete(row.original.id)}
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ const LiveReportTable = () => {
|
|||
const [search, setSearch] = React.useState<string>("");
|
||||
const [statusFilter, setStatusFilter] = React.useState<number[]>([]);
|
||||
const [selectedType, setSelectedType] = React.useState<string>("1");
|
||||
const columns = useTableColumns();
|
||||
const columns = useTableColumns({ selectedTypeSchedule: selectedType });
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
@ -197,11 +197,11 @@ const LiveReportTable = () => {
|
|||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<div className="">
|
||||
<div className="grid grid-cols-2 w-full md:w-fit md:flex lg:flex-row items-center gap-3">
|
||||
<div className="w-full md:w-fit">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="md" variant="outline">
|
||||
<Button size="md" variant="outline" className="w-full">
|
||||
1 - {showData} Data
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
|
@ -226,12 +226,12 @@ const LiveReportTable = () => {
|
|||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div className="border border-black rounded-md">
|
||||
<div className="border border-black rounded-md w-full md:w-fit">
|
||||
<Select
|
||||
value={selectedType}
|
||||
onValueChange={(value) => setSelectedType(value)}
|
||||
>
|
||||
<SelectTrigger className="w-[150px] text-black">
|
||||
<SelectTrigger className="w-full md:w-[150px] text-black">
|
||||
<SelectValue placeholder="Tipe" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -244,10 +244,14 @@ const LiveReportTable = () => {
|
|||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="w-full md:w-fit">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="ml-auto" size="md">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full md:ml-auto"
|
||||
size="md"
|
||||
>
|
||||
Filter <ChevronDown />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
|
@ -287,10 +291,14 @@ const LiveReportTable = () => {
|
|||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center w-full md:w-fit">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="ml-auto" size="md">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="md:ml-auto w-full"
|
||||
size="md"
|
||||
>
|
||||
Columns <ChevronDown />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormDetailLiveReport from "@/components/form/schedule/live-report-detail-form";
|
||||
|
||||
const LiveReportDetailPage = () => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
import FormUpdateLiveReport from "@/components/form/schedule/live-report-update-form";
|
||||
|
||||
const LiveReportUpdatePage = () => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||
import { CalendarIcon, Clock1, Locate, MapPin, User2 } from "lucide-react";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||
|
|
@ -32,6 +32,7 @@ import {
|
|||
detailSchedule,
|
||||
listScheduleNext,
|
||||
listScheduleToday,
|
||||
postApprovalSchedule,
|
||||
postSchedule,
|
||||
} from "@/service/schedule/schedule";
|
||||
import {
|
||||
|
|
@ -42,6 +43,18 @@ import {
|
|||
} from "@/components/ui/accordion";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { formatDate } from "@fullcalendar/core/index.js";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { useTranslations } from "next-intl";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { close } from "@/config/swal";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
|
|
@ -58,14 +71,23 @@ interface Detail {
|
|||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
isYoutube: boolean;
|
||||
youtubeUrl: string;
|
||||
needApprovalFrom: number;
|
||||
uploadedById: number;
|
||||
}
|
||||
|
||||
export default function FormDetailLiveReport() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
const [isLiveStreamingEnabled, setIsLiveStreamingEnabled] = useState(false);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
const userLevelNumber = getCookiesDecrypt("ulne");
|
||||
|
||||
console.log("cookie", userId, userLevelId, roleId, userLevelNumber);
|
||||
const [startTime, setStartTime] = useState("08:00");
|
||||
const [endTime, setEndTime] = useState("09:00");
|
||||
const [date, setDate] = useState<DateRange | undefined>();
|
||||
|
|
@ -75,6 +97,12 @@ export default function FormDetailLiveReport() {
|
|||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const t = useTranslations("Form");
|
||||
|
||||
const [status, setStatus] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
|
|
@ -82,9 +110,6 @@ export default function FormDetailLiveReport() {
|
|||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
defaultValues: {
|
||||
location: "",
|
||||
},
|
||||
});
|
||||
|
||||
async function getDataByDate() {
|
||||
|
|
@ -98,27 +123,30 @@ export default function FormDetailLiveReport() {
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await detailSchedule(id);
|
||||
const details = response?.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
getDataByDate();
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
}, [refresh]);
|
||||
|
||||
async function initState() {
|
||||
if (id) {
|
||||
loading();
|
||||
const response = await detailSchedule(id);
|
||||
close();
|
||||
const details = response?.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
getDataByDate();
|
||||
}
|
||||
}
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
|
|
@ -128,6 +156,75 @@ export default function FormDetailLiveReport() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const actionApproval = (e: string) => {
|
||||
setStatus(e);
|
||||
setDescription("");
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
if (
|
||||
description?.length > 1 &&
|
||||
(Number(status) == 3 || Number(status) == 2 || Number(status) == 4)
|
||||
) {
|
||||
save();
|
||||
}
|
||||
};
|
||||
|
||||
async function save() {
|
||||
const data = {
|
||||
scheduleId: Number(id),
|
||||
statusId: Number(status),
|
||||
message: description,
|
||||
isPublish: status === "2",
|
||||
placements: schedulePlacements?.filter((val) => val != "all")?.join(","),
|
||||
};
|
||||
|
||||
loading();
|
||||
const response = await postApprovalSchedule(data);
|
||||
close();
|
||||
setModalOpen(false);
|
||||
if (response?.error) {
|
||||
error(response?.message);
|
||||
return false;
|
||||
}
|
||||
initState();
|
||||
return false;
|
||||
}
|
||||
|
||||
const [schedulePlacements, setSchedulePlacements] = useState<string[]>([]);
|
||||
|
||||
const setupPlacement = (placement: string, checked: boolean) => {
|
||||
let temp = [...schedulePlacements];
|
||||
if (checked) {
|
||||
if (placement === "all") {
|
||||
temp = ["all", "mabes", "polda", "international"];
|
||||
} else {
|
||||
const now = temp;
|
||||
now.push(placement);
|
||||
if (now.length === 3 && !now.includes("all")) {
|
||||
now.push("all");
|
||||
}
|
||||
temp = now;
|
||||
}
|
||||
} else {
|
||||
if (placement === "all") {
|
||||
temp = [];
|
||||
} else {
|
||||
const now = temp.filter((a) => a !== placement);
|
||||
console.log("now", now);
|
||||
temp = now;
|
||||
if (now.length === 3 && now.includes("all")) {
|
||||
const newData = now.filter((b) => b !== "all");
|
||||
temp = newData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("temp");
|
||||
setSchedulePlacements(temp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
|
|
@ -157,39 +254,24 @@ export default function FormDetailLiveReport() {
|
|||
<div className="mt-6">
|
||||
<Label>Live Streaming</Label>
|
||||
<div className="flex items-center gap-3">
|
||||
<p>Aktifkan fitur live streaming</p>
|
||||
<p className="text-sm">Aktifkan fitur live streaming</p>
|
||||
<Switch
|
||||
defaultChecked={isLiveStreamingEnabled}
|
||||
checked={detail.isYoutube}
|
||||
color="primary"
|
||||
id="c2"
|
||||
onCheckedChange={(checked) =>
|
||||
setIsLiveStreamingEnabled(checked)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLiveStreamingEnabled && (
|
||||
{detail.isYoutube && (
|
||||
<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"
|
||||
/>
|
||||
)}
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={detail.youtubeUrl}
|
||||
placeholder="Masukan ID youtube"
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -332,12 +414,6 @@ export default function FormDetailLiveReport() {
|
|||
) : (
|
||||
""
|
||||
)}
|
||||
{/* Submit Button
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
|
|
@ -349,13 +425,31 @@ export default function FormDetailLiveReport() {
|
|||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
{todayList?.length > 0 ? (
|
||||
<ul className="list-disc ml-4">
|
||||
<div className="list-disc ">
|
||||
{todayList.map((item: any, index) => (
|
||||
<li key={index} className="py-1">
|
||||
{item.name}
|
||||
</li>
|
||||
<div key={index} className="">
|
||||
<li className="text-base font-semibold">{item.title}</li>
|
||||
<p className="text-sm ml-5 flex my-2 gap-2">
|
||||
<CalendarIcon size={20} />
|
||||
{formatDate(item?.startDate)}-
|
||||
{formatDate(item?.endDate)}
|
||||
</p>
|
||||
<p className="text-sm ml-5 flex my-2 gap-2">
|
||||
<Clock1 size={20} />
|
||||
{item?.startTime}-{item?.endTime}
|
||||
</p>
|
||||
<p className="text-sm ml-5 flex items-center my-2 gap-2">
|
||||
<MapPin size={20} />
|
||||
{item?.address}
|
||||
</p>
|
||||
<p className="text-sm ml-5">Disampaikan oleh:</p>
|
||||
<p className="text-sm ml-5 flex my-2 items-center gap-2">
|
||||
<User2 size={20} />
|
||||
{item?.speakerTitle} {item?.speakerName}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-gray-500">Tidak ada jadwal hari ini</p>
|
||||
)}
|
||||
|
|
@ -373,26 +467,25 @@ export default function FormDetailLiveReport() {
|
|||
{nextDayList.map((item: any, index) => (
|
||||
<div key={index} className="">
|
||||
<li className="text-base font-semibold">{item.title}</li>
|
||||
<p className="text-sm ml-5 flex my-2">
|
||||
<p className="text-sm ml-5 flex my-2 gap-2">
|
||||
<CalendarIcon size={20} />
|
||||
{formatDate(item?.startDate)}-
|
||||
{formatDate(item?.endDate)}
|
||||
</p>
|
||||
<p className="text-sm ml-5 flex my-2">
|
||||
<p className="text-sm ml-5 flex my-2 gap-2">
|
||||
<Clock1 size={20} />
|
||||
{item?.startTime}-{item?.endTime}
|
||||
</p>
|
||||
<p className="text-sm ml-5 flex items-center my-2">
|
||||
<MapPin size={50} />
|
||||
<p className="text-sm ml-5 flex items-center my-2 gap-2">
|
||||
<MapPin size={20} />
|
||||
{item?.address}
|
||||
</p>
|
||||
<p className="text-sm ml-5">Disampaikan oleh:</p>
|
||||
<p className="text-sm ml-5 flex my-2">
|
||||
<User2 />
|
||||
<p className="text-sm ml-5 flex my-2 items-center gap-2">
|
||||
<User2 size={20} />
|
||||
{item?.speakerTitle} {item?.speakerName}
|
||||
</p>
|
||||
</div>
|
||||
// <p>{item.startDate}</p>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -401,7 +494,162 @@ export default function FormDetailLiveReport() {
|
|||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
{Number(detail?.needApprovalFrom) == Number(userLevelId) &&
|
||||
Number(userLevelNumber) < 2 ? (
|
||||
Number(detail?.uploadedById) == Number(userId) ? (
|
||||
""
|
||||
) : (
|
||||
<div className="flex flex-col gap-2 p-3">
|
||||
<Button
|
||||
onClick={() => actionApproval("2")}
|
||||
color="primary"
|
||||
type="button"
|
||||
>
|
||||
<Icon icon="fa:check" className="mr-3" />
|
||||
{t("accept")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => actionApproval("3")}
|
||||
className="bg-orange-400 hover:bg-orange-300"
|
||||
type="button"
|
||||
>
|
||||
<Icon icon="fa:comment-o" className="mr-3" /> {t("revision")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => actionApproval("4")}
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
<Icon icon="fa:times" className="mr-3" />
|
||||
{t("reject")}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
||||
<DialogContent className="overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("leave-comment")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-1 text-sm">
|
||||
<p>
|
||||
{" "}
|
||||
Status:{" "}
|
||||
<span
|
||||
className={
|
||||
status === "2"
|
||||
? "text-primary"
|
||||
: status === "3"
|
||||
? "text-warning"
|
||||
: "text-destructive"
|
||||
}
|
||||
>
|
||||
{status === "2"
|
||||
? "Disetujui"
|
||||
: status === "3"
|
||||
? "Revisi"
|
||||
: "Ditolak"}
|
||||
</span>
|
||||
</p>
|
||||
{status === "2" && (
|
||||
<div className="flex flex-row gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
value="all"
|
||||
checked={schedulePlacements?.includes("all")}
|
||||
onCheckedChange={(e) => setupPlacement("all", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="terms"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{t("all")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
checked={schedulePlacements?.includes("mabes")}
|
||||
onCheckedChange={(e) => setupPlacement("mabes", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="terms"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Nasional
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
checked={schedulePlacements?.includes("polda")}
|
||||
onCheckedChange={(e) => setupPlacement("polda", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="terms"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Wilayah
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
checked={schedulePlacements?.includes("international")}
|
||||
onCheckedChange={(e) =>
|
||||
setupPlacement("international", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="terms"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Internasional
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<p>Deskripsi:</p>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Textarea
|
||||
placeholder="Type your message here."
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
color="primary"
|
||||
onClick={() => submit()}
|
||||
disabled={
|
||||
description.length < 1 ||
|
||||
(schedulePlacements.length < 1 && status === "2")
|
||||
}
|
||||
>
|
||||
{t("submit")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
color="destructive"
|
||||
onClick={() => {
|
||||
setModalOpen(false);
|
||||
}}
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,14 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { toast } from "sonner";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
||||
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" }),
|
||||
title: z.string().min(1, { message: "Judul harus diisi" }),
|
||||
level: z.string().min(1, { message: "Pangkat harus diisi" }),
|
||||
name: z.string().min(1, { message: "Nama harus diisi" }),
|
||||
location: z.string().min(1, { message: "Lokasi harus diisi" }),
|
||||
});
|
||||
|
||||
export default function FormLiveReport() {
|
||||
|
|
@ -56,9 +58,11 @@ export default function FormLiveReport() {
|
|||
const [startTime, setStartTime] = useState("08:00");
|
||||
const [endTime, setEndTime] = useState("09:00");
|
||||
const [scheduleTypeId, setScheduleTypeId] = React.useState<string>("1");
|
||||
const [youtubeUrl, setYoutubeUrl] = useState("");
|
||||
|
||||
const [date, setDate] = React.useState<DateRange | undefined>({
|
||||
from: new Date(2024, 0, 1),
|
||||
from: new Date(),
|
||||
to: new Date(),
|
||||
});
|
||||
|
||||
const handleStartTime = (e: any) => {
|
||||
|
|
@ -106,12 +110,14 @@ export default function FormLiveReport() {
|
|||
startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
|
||||
endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
|
||||
isYoutube: isLiveStreamingEnabled,
|
||||
youtubeUrl: isLiveStreamingEnabled ? youtubeUrl : null,
|
||||
scheduleTypeId: Number(scheduleTypeId),
|
||||
};
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
||||
loading();
|
||||
const response = await postSchedule(requestData);
|
||||
close();
|
||||
if (response?.error) {
|
||||
error(response?.message);
|
||||
return false;
|
||||
|
|
@ -134,6 +140,11 @@ export default function FormLiveReport() {
|
|||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
if (isLiveStreamingEnabled && youtubeUrl == "") {
|
||||
toast(<p className="text-red-600">Youtube ID harus diisi</p>);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
|
|
@ -195,24 +206,13 @@ export default function FormLiveReport() {
|
|||
|
||||
{isLiveStreamingEnabled && (
|
||||
<div className="mb-2 mt-1">
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan ID youtube"
|
||||
/>
|
||||
)}
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={youtubeUrl}
|
||||
onChange={(e) => setYoutubeUrl(e.target.value)}
|
||||
placeholder="Masukan Youtube ID"
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col space-y-2">
|
||||
|
|
@ -314,9 +314,11 @@ export default function FormLiveReport() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="invalid-feedback">
|
||||
{errors.location?.message}
|
||||
</div>
|
||||
{errors.location?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.location.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm mt-4 font-semibold">DI SAMPAIKAN OLEH</p>
|
||||
<div className="flex flex-col ">
|
||||
|
|
@ -376,9 +378,9 @@ export default function FormLiveReport() {
|
|||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
{/* <Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</Card> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ 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 { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Popover,
|
||||
|
|
@ -29,12 +29,13 @@ 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 { toast } from "sonner";
|
||||
|
||||
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" }),
|
||||
title: z.string().min(1, { message: "Judul harus diisi" }),
|
||||
level: z.string().min(1, { message: "Pangkat harus diisi" }),
|
||||
name: z.string().min(1, { message: "Nama harus diisi" }),
|
||||
location: z.string().min(1, { message: "Lokasi harus diisi" }),
|
||||
});
|
||||
|
||||
interface Detail {
|
||||
|
|
@ -49,8 +50,9 @@ interface Detail {
|
|||
|
||||
export default function FormUpdateLiveReport() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
const params = useSearchParams();
|
||||
const scheduleTypeId = params?.get("scheduleType");
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [isLiveStreamingEnabled, setIsLiveStreamingEnabled] = useState(false);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
|
|
@ -60,7 +62,7 @@ export default function FormUpdateLiveReport() {
|
|||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const [location, setLocation] = useState("");
|
||||
const [youtubeUrl, setYoutubeUrl] = useState("");
|
||||
|
||||
const {
|
||||
control,
|
||||
|
|
@ -69,28 +71,28 @@ export default function FormUpdateLiveReport() {
|
|||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
defaultValues: {
|
||||
location: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await detailSchedule(id);
|
||||
const details = response?.data?.data;
|
||||
const data = response?.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
if (data) {
|
||||
setDetail(data);
|
||||
setValue("title", data.title);
|
||||
setValue("level", data.speakerTitle);
|
||||
setValue("name", data.speakerName);
|
||||
setValue("location", data.address);
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
from: parseISO(data.startDate),
|
||||
to: parseISO(data.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
setLocation(details.address);
|
||||
setStartTime(data.startTime);
|
||||
setYoutubeUrl(data.youtubeUrl);
|
||||
setEndTime(data.endTime);
|
||||
setIsLiveStreamingEnabled(data.isYoutube);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +109,6 @@ export default function FormUpdateLiveReport() {
|
|||
|
||||
const handleLocationChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const value = e.target.value;
|
||||
setLocation(value);
|
||||
setValue("location", value);
|
||||
};
|
||||
|
||||
|
|
@ -126,6 +127,7 @@ export default function FormUpdateLiveReport() {
|
|||
endDate: string | null;
|
||||
isYoutube: boolean;
|
||||
scheduleTypeId: number;
|
||||
youtubeUrl: string;
|
||||
} = {
|
||||
title: data.title,
|
||||
address: data.location,
|
||||
|
|
@ -138,7 +140,8 @@ export default function FormUpdateLiveReport() {
|
|||
startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
|
||||
endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
|
||||
isYoutube: isLiveStreamingEnabled,
|
||||
scheduleTypeId: 1,
|
||||
scheduleTypeId: Number(scheduleTypeId),
|
||||
youtubeUrl: youtubeUrl,
|
||||
};
|
||||
|
||||
if (id) {
|
||||
|
|
@ -165,11 +168,16 @@ export default function FormUpdateLiveReport() {
|
|||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/schedule/press-conference");
|
||||
router.push("/en/contributor/schedule/live-report");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
if (isLiveStreamingEnabled && youtubeUrl == "") {
|
||||
toast(<p className="text-red-600">Youtube ID harus diisi</p>);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
|
|
@ -191,7 +199,7 @@ export default function FormUpdateLiveReport() {
|
|||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Konferensi Pers</p>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{detail !== undefined ? (
|
||||
{detail ? (
|
||||
<div className=" gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
|
|
@ -202,7 +210,7 @@ export default function FormUpdateLiveReport() {
|
|||
render={({ field }) => (
|
||||
<Input
|
||||
type="text"
|
||||
defaultValue={detail?.title}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -219,7 +227,7 @@ export default function FormUpdateLiveReport() {
|
|||
<div className="flex items-center gap-3">
|
||||
<p>Aktifkan fitur live streaming</p>
|
||||
<Switch
|
||||
defaultChecked={isLiveStreamingEnabled}
|
||||
checked={isLiveStreamingEnabled}
|
||||
color="primary"
|
||||
id="c2"
|
||||
onCheckedChange={(checked) =>
|
||||
|
|
@ -231,25 +239,14 @@ export default function FormUpdateLiveReport() {
|
|||
</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"
|
||||
/>
|
||||
)}
|
||||
<div className="mb-2 mt-1">
|
||||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={youtubeUrl}
|
||||
onChange={(e) => setYoutubeUrl(e.target.value)}
|
||||
placeholder="Masukan Youtube ID"
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -319,7 +316,6 @@ export default function FormUpdateLiveReport() {
|
|||
<MapHome
|
||||
draggable
|
||||
setLocation={(location) => {
|
||||
setLocation(location);
|
||||
setValue("location", location);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -331,8 +327,8 @@ export default function FormUpdateLiveReport() {
|
|||
render={({ field }) => (
|
||||
<Textarea
|
||||
rows={3}
|
||||
value={location}
|
||||
onChange={handleLocationChange}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan lokasi"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -352,7 +348,7 @@ export default function FormUpdateLiveReport() {
|
|||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
defaultValue={detail?.speakerTitle}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Pangkat"
|
||||
/>
|
||||
|
|
@ -375,7 +371,7 @@ export default function FormUpdateLiveReport() {
|
|||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
defaultValue={detail?.speakerName}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Lengkap"
|
||||
/>
|
||||
|
|
@ -401,9 +397,9 @@ export default function FormUpdateLiveReport() {
|
|||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
{/* <Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</Card> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
64
lib/menus.ts
64
lib/menus.ts
|
|
@ -1804,6 +1804,42 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// groupLabel: "",
|
||||
// id: "schedule",
|
||||
// menus: [
|
||||
// {
|
||||
// id: "schedule",
|
||||
// href: "/contributor/schedule",
|
||||
// label: t("schedule"),
|
||||
// active: pathname.includes("/schedule"),
|
||||
// icon: "uil:schedule",
|
||||
// submenus: [
|
||||
// {
|
||||
// href: "/contributor/schedule/press-conference",
|
||||
// label: t("press-conference"),
|
||||
// active: pathname.includes("/schedule/press-conference"),
|
||||
// icon: "heroicons:arrow-trending-up",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// href: "/contributor/schedule/event",
|
||||
// label: t("event"),
|
||||
// active: pathname.includes("/schedule/event"),
|
||||
// icon: "heroicons:shopping-cart",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// href: "/contributor/schedule/press-release",
|
||||
// label: t("press-release"),
|
||||
// active: pathname.includes("/schedule/press-release"),
|
||||
// icon: "heroicons:shopping-cart",
|
||||
// children: [],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "schedule",
|
||||
|
|
@ -1816,26 +1852,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
icon: "uil:schedule",
|
||||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
href: "/contributor/schedule/live-report",
|
||||
label: t("live-report"),
|
||||
active: pathname.includes("/schedule/live-report"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/event",
|
||||
label: t("event"),
|
||||
active: pathname.includes("/schedule/event"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
|
||||
// {
|
||||
// href: "/contributor/schedule/calendar-polri",
|
||||
// label: t("calendar-polri"),
|
||||
// active: pathname.includes("/schedule/calendar-polri"),
|
||||
// icon: "heroicons:arrow-trending-up",
|
||||
// children: [],
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ export async function postSchedule(data: any) {
|
|||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function deleteSchedule(id: string | number) {
|
||||
const url = `schedule?id=${id}`;
|
||||
return httpDeleteInterceptor(url);
|
||||
}
|
||||
|
||||
export async function detailSchedule(id: any) {
|
||||
const url = `public/schedule?id=${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
|
|
@ -98,3 +103,8 @@ export async function deleteCalendar(id: any) {
|
|||
const url = `calendars?id=${id}`;
|
||||
return httpDeleteInterceptor(url);
|
||||
}
|
||||
|
||||
export async function postApprovalSchedule(data: any) {
|
||||
const url = "schedule/approval";
|
||||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue