Merge branch 'dev-anang' of https://gitlab.com/hanifsalafi/mediahub_redesign
This commit is contained in:
commit
fecc753abb
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -95,18 +96,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/*
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormBlogDetail from "@/components/form/blog/blog--detail-form";
|
||||
|
||||
const BlogDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormBlogDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogDetailPage;
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -54,11 +55,17 @@ const columns: ColumnDef<any>[] = [
|
|||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "startTime",
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
|
|
@ -99,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -131,14 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormEventDetail from "@/components/form/schedule/event-detail-form";
|
||||
|
||||
const EventDetailPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormEventDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventDetailPage;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
import FormEventUpdate from "@/components/form/schedule/event-update-form";
|
||||
|
||||
const EventUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormEventUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventUpdatePage;
|
||||
|
|
@ -106,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -138,16 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link href={`/contributor/schedule/press-conference/detail/${row.id}`}>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</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" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -8,13 +8,11 @@ import { useParams } from "next/navigation";
|
|||
import { id } from "date-fns/locale";
|
||||
|
||||
const PressConDetailPage = () => {
|
||||
const params = useParams();
|
||||
const id = params?.id;
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailPressConference id={id} />
|
||||
<FormDetailPressConference />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
|
||||
const PressConUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormUpdatePressConference />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressConUpdatePage;
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -54,11 +55,17 @@ const columns: ColumnDef<any>[] = [
|
|||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "startTime",
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
|
|
@ -99,11 +106,17 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speakerName",
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
|
||||
),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
|
|
@ -131,14 +144,22 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import FormDetailPressRillis from "@/components/form/schedule/pers-release--detail-form";
|
||||
|
||||
const PressRilisDetailPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormDetailPressRillis />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressRilisDetailPage;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use client";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormPressConference from "@/components/form/schedule/press-conference-form";
|
||||
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
|
||||
import { useParams } from "next/navigation";
|
||||
import { id } from "date-fns/locale";
|
||||
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
|
||||
import FormUpdatePressRelease from "@/components/form/schedule/pers-release--update-form";
|
||||
|
||||
const PressRilisUpdatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormUpdatePressRelease />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PressRilisUpdatePage;
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormTaskDetail from "@/components/form/task/task-detail-form";
|
||||
|
||||
const TaskDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormTask />
|
||||
<FormTaskDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -108,18 +109,20 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/* <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTask from "@/components/form/task/task-form";
|
||||
import FormContestDetail from "@/components/form/contest/contest-detail-form";
|
||||
|
||||
const ContestDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormContestDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContestDetailPage;
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
"use client";
|
||||
import React, { ChangeEvent, 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 { register } from "module";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import Cookies from "js-cookie";
|
||||
import { createTask } from "@/config/api";
|
||||
import {
|
||||
createMedia,
|
||||
getTagsBySubCategoryId,
|
||||
listEnableCategory,
|
||||
} from "@/service/content/content";
|
||||
import { getBlog, postBlog } from "@/service/blog/blog";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
slug: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
meta: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
description: z
|
||||
.string()
|
||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
|
||||
categoryName: z.string().min(1, { message: "Kategori diperlukan" }),
|
||||
});
|
||||
|
||||
type Category = {
|
||||
id: string;
|
||||
categoryName: string;
|
||||
};
|
||||
|
||||
type Detail = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
metadata: string;
|
||||
categoryName: string;
|
||||
thumbnailLink: string;
|
||||
};
|
||||
|
||||
const initialCategories: Category[] = [
|
||||
{
|
||||
id: "1",
|
||||
categoryName: "Giat Polri",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
categoryName: "Giat Pimpinan",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
categoryName: "Liputan Kegiatan",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
categoryName: "Seputar Prestasi",
|
||||
},
|
||||
];
|
||||
|
||||
export default function FormBlogDetail() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
|
||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||
const taskId = Cookies.get("taskId");
|
||||
const scheduleId = Cookies.get("scheduleId");
|
||||
const scheduleType = Cookies.get("scheduleType");
|
||||
|
||||
const [categories] = useState<Category[]>(initialCategories);
|
||||
const [selectedTarget, setSelectedTarget] = useState<string>("");
|
||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [isDraft, setIsDraft] = useState(false);
|
||||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
allUnit: false,
|
||||
mabes: false,
|
||||
polda: false,
|
||||
polres: false,
|
||||
});
|
||||
|
||||
let fileTypeId = "1";
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
});
|
||||
|
||||
// const handleKeyDown = (e: any) => {
|
||||
// const newTag = e.target.value.trim(); // Ambil nilai input
|
||||
// if (e.key === "Enter" && newTag) {
|
||||
// e.preventDefault(); // Hentikan submit form
|
||||
// if (!tags.includes(newTag)) {
|
||||
// setTags((prevTags) => [...prevTags, newTag]); // Tambah tag baru
|
||||
// setValue("tags", ""); // Kosongkan input
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleRemoveTag = (index: any) => {
|
||||
setTags((prevTags) => prevTags.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const handleImageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files) {
|
||||
const files = Array.from(event.target.files);
|
||||
setSelectedFiles((prevImages: any) => [...prevImages, ...files]);
|
||||
console.log("DATAFILE::", selectedFiles);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveImage = (index: number) => {
|
||||
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await getBlog(id);
|
||||
const details = response.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
|
||||
// Set categoryId dari API ke form dan Select
|
||||
setValue("categoryName", details.categoryName);
|
||||
setSelectedTarget(details.categoryId); // Untuk dropdown
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
categoryId: selectedTarget,
|
||||
slug: data.slug,
|
||||
metadata: data.meta,
|
||||
// tags: data.tags,
|
||||
isDraft,
|
||||
};
|
||||
|
||||
const response = await postBlog(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/blog");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handlePublish = () => {
|
||||
setIsDraft(false);
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
setIsDraft(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{detail !== undefined ? (
|
||||
<div className="flex lg:flex-row gap-10">
|
||||
<Card className="w-full lg:w-8/12">
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Detail Indeks</p>
|
||||
<div className="gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2 py-3">
|
||||
<Label>Judul</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="py-3">
|
||||
<Label>Deskripsi</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={detail.description}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.description?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.description.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className=" py-3">
|
||||
<div className="space-y-2">
|
||||
<Label>Slug</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="slug"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.slug}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Slug"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.slug?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.slug.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className=" py-3">
|
||||
<div className="space-y-2">
|
||||
<Label>Meta</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="meta"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.metadata}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Meta"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.meta?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.meta.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<div className="w-4/12">
|
||||
<Card className=" h-[600px]">
|
||||
<div className="px-3 py-3">
|
||||
<Label htmlFor="fileInput">Gambar Utama</Label>
|
||||
<Input
|
||||
id="fileInput"
|
||||
type="file"
|
||||
// onChange={(e) => {
|
||||
// const file = e.target.files[0];
|
||||
// if (file) {
|
||||
// console.log("Selected File:", file);
|
||||
// // Tambahkan logika jika diperlukan, misalnya upload file ke server
|
||||
// }
|
||||
// }}
|
||||
className=""
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-3 px-3">
|
||||
<Label>Pratinjau Gambar Utama</Label>
|
||||
<Card className="mt-2">
|
||||
<img
|
||||
src={detail.thumbnailLink}
|
||||
alt="Thumbnail Gambar Utama"
|
||||
className="w-full h-auto rounded"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="px-3 py-3">
|
||||
<label
|
||||
htmlFor="kategori"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Kategori
|
||||
</label>
|
||||
<Controller
|
||||
name="categoryName"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={detail?.categoryName}
|
||||
onValueChange={(value) => {
|
||||
setSelectedTarget(value);
|
||||
field.onChange(value); // Sinkronisasi dengan react-hook-form
|
||||
}}
|
||||
>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{categories.map((category) => (
|
||||
<SelectItem
|
||||
key={category.id}
|
||||
value={category.categoryName}
|
||||
>
|
||||
{category.categoryName}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-3 py-3">
|
||||
<Label>Tags</Label>
|
||||
{/* <Controller
|
||||
control={control}
|
||||
name="tags"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
)}
|
||||
/> */}
|
||||
<div className="text-sm text-red-500">
|
||||
{tags.length === 0 && "Please add at least one tag."}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2 border border-gray-300 mt-2 rounded-md p-2 items-center">
|
||||
{tags.map((tag, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-1 bg-blue-100 text-blue-800 rounded-full px-3 py-1 text-sm font-medium"
|
||||
>
|
||||
<span>{tag}</span>
|
||||
<button
|
||||
className="text-blue-600 hover:text-blue-800 focus:outline-none"
|
||||
onClick={() => handleRemoveTag(index)}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
{/* <div className="flex flex-row justify-end gap-3">
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
type="submit"
|
||||
color="success"
|
||||
onClick={() => handlePublish()}
|
||||
>
|
||||
Publish
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
type="submit"
|
||||
color="primary"
|
||||
onClick={() => handleSave()}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary" variant="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
"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 { createTask, getTask } from "@/service/task";
|
||||
import { getContestById } from "@/service/contest/contest";
|
||||
import page from "@/app/[locale]/page";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { format, parseISO } from "date-fns";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { DateRange } from "react-day-picker";
|
||||
|
||||
const contestSchema = z.object({
|
||||
theme: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
hastagCode: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
description: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
});
|
||||
|
||||
export type taskDetail = {
|
||||
id: number;
|
||||
theme: string;
|
||||
hastagCode: string;
|
||||
assignedToTopLevel: string;
|
||||
assignmentType: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
assignmentMainType: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
targetOutput: string;
|
||||
targetParticipantTopLevel: string;
|
||||
description: string;
|
||||
is_active: string;
|
||||
};
|
||||
|
||||
export default function FormContestDetail() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type ContestSchema = z.infer<typeof contestSchema>;
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
|
||||
// State for various form fields
|
||||
const [taskOutput, setTaskOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
// const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
const [mainType, setMainType] = useState<string>("1");
|
||||
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
|
||||
const [type, setType] = useState<string>("1");
|
||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||
const [detail, setDetail] = useState<taskDetail>();
|
||||
const [refresh] = useState(false);
|
||||
const [date, setDate] = useState<DateRange | undefined>();
|
||||
|
||||
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
allUnit: false,
|
||||
mabes: false,
|
||||
polda: false,
|
||||
polres: false,
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<ContestSchema>({
|
||||
resolver: zodResolver(contestSchema),
|
||||
});
|
||||
|
||||
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const selectedValue = Number(event.target.value);
|
||||
// setMainType(selectedValue);
|
||||
|
||||
// setPlatformTypeVisible(selectedValue === 2);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await getContestById(id);
|
||||
const details = response.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
// if (details?.createdAt) {
|
||||
// // Memisahkan string duration menjadi start dan end date
|
||||
// const [startDate, endDate] = details.createdAt.split(" - ");
|
||||
// setDate({
|
||||
// from: parseISO(startDate),
|
||||
// to: parseISO(endDate),
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [id, refresh]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.targetOutput) {
|
||||
const outputSet = new Set(detail.targetOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor
|
||||
setTaskOutput({
|
||||
all: outputSet.has(0),
|
||||
video: outputSet.has(2),
|
||||
audio: outputSet.has(4),
|
||||
image: outputSet.has(1),
|
||||
text: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.targetOutput]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.targetParticipantTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.targetParticipantTopLevel.split(",").map(Number)
|
||||
);
|
||||
setUnitSelection({
|
||||
allUnit: outputSet.has(0),
|
||||
mabes: outputSet.has(1),
|
||||
polda: outputSet.has(2),
|
||||
polres: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.targetParticipantTopLevel]);
|
||||
|
||||
const save = async (data: ContestSchema) => {
|
||||
const fileTypeMapping = {
|
||||
all: "1",
|
||||
video: "2",
|
||||
audio: "3",
|
||||
image: "4",
|
||||
text: "5",
|
||||
};
|
||||
|
||||
const selectedOutputs = Object.keys(taskOutput)
|
||||
.filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true`
|
||||
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string
|
||||
.join(",");
|
||||
|
||||
const requestData = {
|
||||
...data,
|
||||
// assignmentType,
|
||||
// assignmentCategory,
|
||||
target: selectedTarget,
|
||||
unitSelection,
|
||||
assignedToRole: "3",
|
||||
taskType: taskType,
|
||||
broadcastType: broadcastType,
|
||||
assignmentMainTypeId: mainType,
|
||||
assignmentPurpose: "1",
|
||||
assignmentTypeId: type,
|
||||
fileTypeOutput: selectedOutputs,
|
||||
id: null,
|
||||
description: data.description,
|
||||
platformType: "",
|
||||
theme: data.theme,
|
||||
};
|
||||
|
||||
const response = await createTask(requestData);
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/task");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: ContestSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Contest</p>
|
||||
{detail !== undefined ? (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
<div className="space-y-2">
|
||||
<Label>Kode Lomba</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="hastagCode"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.hastagCode}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter hastagCode"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.hastagCode?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.hastagCode.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2 mt-5">
|
||||
<Label>Judul Lomba</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="theme"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.theme}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter theme"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.theme?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.theme.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col mt-5">
|
||||
<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 className="mt-5">
|
||||
<Label>Output Lomba</Label>
|
||||
<div className="flex flex-wrap gap-3 mt-2">
|
||||
{Object.keys(taskOutput).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col mt-5">
|
||||
<Label>Pelaksana Tugas</Label>
|
||||
<div className="flex flex-row mt-2 gap-2">
|
||||
{Object.keys(unitSelection).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={
|
||||
unitSelection[key as keyof typeof unitSelection]
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={detail?.description}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.description?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.description.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
"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 { 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, parseISO, 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";
|
||||
|
||||
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 {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormEventDetail() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
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] = useState<DateRange | undefined>();
|
||||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
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;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
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 Event</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>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</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={detail?.address}
|
||||
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={detail?.speakerTitle}
|
||||
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={detail?.speakerName}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,400 @@
|
|||
"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 { 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, parseISO, 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";
|
||||
|
||||
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 {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormEventUpdate() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
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] = useState<DateRange | undefined>();
|
||||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
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;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData: {
|
||||
id?: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
addressLat: string;
|
||||
addressLong: string;
|
||||
startDate: string | null;
|
||||
endDate: string | null;
|
||||
isYoutube: boolean;
|
||||
scheduleTypeId: number;
|
||||
} = {
|
||||
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,
|
||||
};
|
||||
|
||||
// Add id property if it exists
|
||||
if (id) {
|
||||
requestData.id = parseInt(id, 10); // Ensure id is a number
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/schedule/event");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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 Event</p>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{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"
|
||||
defaultValue={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>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</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}
|
||||
defaultValue={detail?.address}
|
||||
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"
|
||||
defaultValue={detail?.speakerTitle}
|
||||
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"
|
||||
defaultValue={detail?.speakerName}
|
||||
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>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
"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 { 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, parseISO, 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 {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
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 {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormDetailPressRillis() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
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] = useState<DateRange | undefined>();
|
||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
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;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
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 Pers Rilis</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>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</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={detail?.address}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan lokasi"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="invalid-feedback">
|
||||
{errors.location?.message}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Invitation</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="kompas">
|
||||
PT. kompas Cyber Media{" "}
|
||||
</SelectItem>
|
||||
<SelectItem value="trans">
|
||||
PT. Trans Digital Media
|
||||
</SelectItem>
|
||||
<SelectItem value="mnc">MNC</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</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={detail?.speakerTitle}
|
||||
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={detail?.speakerName}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
"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 { 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, parseISO, 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 {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
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 {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormUpdatePressRelease() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
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] = useState<DateRange | undefined>();
|
||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
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;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData: {
|
||||
id?: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
addressLat: string;
|
||||
addressLong: string;
|
||||
startDate: string | null;
|
||||
endDate: string | null;
|
||||
isYoutube: boolean;
|
||||
scheduleTypeId: number;
|
||||
} = {
|
||||
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,
|
||||
};
|
||||
|
||||
// Add id property if it exists
|
||||
if (id) {
|
||||
requestData.id = parseInt(id, 10); // Ensure id is a number
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/schedule/press-release");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{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"
|
||||
defaultValue={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>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</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}
|
||||
defaultValue={detail?.address}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan lokasi"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="invalid-feedback">
|
||||
{errors.location?.message}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Invitation</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="kompas">
|
||||
PT. kompas Cyber Media{" "}
|
||||
</SelectItem>
|
||||
<SelectItem value="trans">
|
||||
PT. Trans Digital Media
|
||||
</SelectItem>
|
||||
<SelectItem value="mnc">MNC</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</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"
|
||||
defaultValue={detail?.speakerTitle}
|
||||
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"
|
||||
defaultValue={detail?.speakerName}
|
||||
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>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ export default function FormPressRelease() {
|
|||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/contributor/schedule/press-release");
|
||||
router.push("/en/contributor/schedule/press-release");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,6 @@ 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,
|
||||
|
|
@ -29,7 +19,7 @@ import {
|
|||
import { cn } from "@/lib/utils";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, setDate } from "date-fns";
|
||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||
import { DateRange } from "react-day-picker";
|
||||
import TimePicker from "react-time-picker";
|
||||
import "react-time-picker/dist/TimePicker.css";
|
||||
|
|
@ -39,7 +29,6 @@ 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" }),
|
||||
|
|
@ -49,6 +38,7 @@ const taskSchema = z.object({
|
|||
});
|
||||
|
||||
interface Detail {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
|
|
@ -57,27 +47,17 @@ interface Detail {
|
|||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormDetailPressConference(props: { id: any }) {
|
||||
export default function FormDetailPressConference() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
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] = useState<DateRange | undefined>();
|
||||
|
||||
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 [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
|
|
@ -94,35 +74,34 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
try {
|
||||
loading();
|
||||
if (id) {
|
||||
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",
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
Swal.close();
|
||||
} catch (err) {
|
||||
Swal.fire("Error", "Failed to fetch details", "error");
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
|
|
@ -189,7 +168,7 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
)}
|
||||
|
||||
<div className="flex flex-col lg:flex-row mt-3 items-start lg:items-center justify-between">
|
||||
<div className="flex flex-col ">
|
||||
<div className="flex flex-col">
|
||||
<Label className="mr-3 mb-1">Tanggal</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
|
|
@ -230,20 +209,20 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
</div>
|
||||
<div>
|
||||
<Label htmlFor="title">Rentang Waktu</Label>
|
||||
<div className="">
|
||||
<div>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
defaultValue="08:00"
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={(e) => handleStartTime(e)}
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
defaultValue="09:00"
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={(e) => handleEndTime(e)}
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -264,7 +243,7 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
render={({ field }) => (
|
||||
<Textarea
|
||||
rows={3}
|
||||
value={field.value}
|
||||
value={detail?.address}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan lokasi"
|
||||
/>
|
||||
|
|
@ -285,7 +264,7 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
value={detail?.speakerTitle}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Pangkat"
|
||||
/>
|
||||
|
|
@ -308,7 +287,7 @@ export default function FormDetailPressConference(props: { id: any }) {
|
|||
<Input
|
||||
size={"md"}
|
||||
type="text"
|
||||
value={field.value}
|
||||
value={detail?.speakerName}
|
||||
onChange={field.onChange}
|
||||
placeholder="Masukan Nama Lengkap"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -10,16 +10,6 @@ import * as z from "zod";
|
|||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { 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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,400 @@
|
|||
"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 { 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, parseISO, 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";
|
||||
|
||||
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 {
|
||||
id: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
addressLat: number;
|
||||
addressLong: number;
|
||||
}
|
||||
|
||||
export default function FormUpdatePressConference() {
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
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] = useState<DateRange | undefined>();
|
||||
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
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;
|
||||
|
||||
setDetail(details);
|
||||
if (details) {
|
||||
setDate({
|
||||
from: parseISO(details.startDate),
|
||||
to: parseISO(details.endDate),
|
||||
});
|
||||
}
|
||||
if (details) {
|
||||
setStartTime(details.startTime);
|
||||
setEndTime(details.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStartTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleEndTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData: {
|
||||
id?: number;
|
||||
title: string;
|
||||
address: string;
|
||||
speakerTitle: string;
|
||||
speakerName: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
addressLat: string;
|
||||
addressLong: string;
|
||||
startDate: string | null;
|
||||
endDate: string | null;
|
||||
isYoutube: boolean;
|
||||
scheduleTypeId: number;
|
||||
} = {
|
||||
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,
|
||||
};
|
||||
|
||||
// Add id property if it exists
|
||||
if (id) {
|
||||
requestData.id = parseInt(id, 10); // Ensure id is a number
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/schedule/press-conference");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{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"
|
||||
defaultValue={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>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={startTime}
|
||||
type="time"
|
||||
onChange={handleStartTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<Input
|
||||
value={endTime}
|
||||
type="time"
|
||||
onChange={handleEndTime}
|
||||
/>
|
||||
</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}
|
||||
defaultValue={detail?.address}
|
||||
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"
|
||||
defaultValue={detail?.speakerTitle}
|
||||
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"
|
||||
defaultValue={detail?.speakerName}
|
||||
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>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="w-full lg:w-3/12">
|
||||
<div className="px-3 py-3">Jadwal Selanjutnya</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
"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 { createTask, getTask } from "@/service/task";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
naration: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
});
|
||||
|
||||
export type taskDetail = {
|
||||
id: number;
|
||||
title: string;
|
||||
fileTypeOutput: string;
|
||||
assignedToTopLevel: string;
|
||||
assignmentType: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
assignmentMainType: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
taskType: string;
|
||||
broadcastType: string;
|
||||
narration: string;
|
||||
is_active: string;
|
||||
};
|
||||
|
||||
export default function FormTaskDetail() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
|
||||
// State for various form fields
|
||||
const [taskOutput, setTaskOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
// const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
const [mainType, setMainType] = useState<string>("1");
|
||||
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
|
||||
const [type, setType] = useState<string>("1");
|
||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||
const [detail, setDetail] = useState<taskDetail>();
|
||||
const [refresh] = useState(false);
|
||||
|
||||
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
allUnit: false,
|
||||
mabes: false,
|
||||
polda: false,
|
||||
polres: false,
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
});
|
||||
|
||||
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const selectedValue = Number(event.target.value);
|
||||
// setMainType(selectedValue);
|
||||
|
||||
// setPlatformTypeVisible(selectedValue === 2);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await getTask(id);
|
||||
const details = response.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [id, refresh]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.broadcastType) {
|
||||
setBroadcastType(detail.broadcastType); // Mengatur nilai broadcastType dari API
|
||||
}
|
||||
}, [detail?.broadcastType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.fileTypeOutput) {
|
||||
const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor
|
||||
setTaskOutput({
|
||||
all: outputSet.has(0),
|
||||
video: outputSet.has(2),
|
||||
audio: outputSet.has(4),
|
||||
image: outputSet.has(1),
|
||||
text: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.fileTypeOutput]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
);
|
||||
setUnitSelection({
|
||||
allUnit: outputSet.has(0),
|
||||
mabes: outputSet.has(1),
|
||||
polda: outputSet.has(2),
|
||||
polres: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.fileTypeOutput]);
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const fileTypeMapping = {
|
||||
all: "1",
|
||||
video: "2",
|
||||
audio: "3",
|
||||
image: "4",
|
||||
text: "5",
|
||||
};
|
||||
|
||||
const selectedOutputs = Object.keys(taskOutput)
|
||||
.filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true`
|
||||
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string
|
||||
.join(",");
|
||||
|
||||
const requestData = {
|
||||
...data,
|
||||
// assignmentType,
|
||||
// assignmentCategory,
|
||||
target: selectedTarget,
|
||||
unitSelection,
|
||||
assignedToRole: "3",
|
||||
taskType: taskType,
|
||||
broadcastType: broadcastType,
|
||||
assignmentMainTypeId: mainType,
|
||||
assignmentPurpose: "1",
|
||||
assignmentTypeId: type,
|
||||
fileTypeOutput: selectedOutputs,
|
||||
id: null,
|
||||
narration: data.naration,
|
||||
platformType: "",
|
||||
title: data.title,
|
||||
};
|
||||
|
||||
const response = await createTask(requestData);
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/task");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Penugasan</p>
|
||||
{detail !== undefined ? (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
<Label>Judul</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{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>Tujuan Pemilihan Tugas</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
||||
<SelectItem value="approver">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 mt-5 pt-5 ml-3">
|
||||
{Object.keys(unitSelection).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={
|
||||
unitSelection[key as keyof typeof unitSelection]
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Tipe Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentMainType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setMainType(value)}
|
||||
// value={String(mainType)}
|
||||
// onValueChange={(value) => setMainType(Number(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="1" id="mediahub" />
|
||||
<Label htmlFor="mediahub">Mediahub</Label>
|
||||
<RadioGroupItem value="2" id="medsos-mediahub" />
|
||||
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Tugas </Label>
|
||||
<RadioGroup
|
||||
value={detail.taskType.toString()}
|
||||
onValueChange={(value) => setTaskType(String(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="atensi-khusus" id="khusus" />
|
||||
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
||||
<RadioGroupItem value="tugas-harian" id="harian" />
|
||||
<Label htmlFor="tugas-harian">Tugas Harian</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
{/* RadioGroup Assignment Category */}
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="1" id="publication" />
|
||||
<Label htmlFor="publication">Publikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="2" id="amplification" />
|
||||
<Label htmlFor="amplification">Amplifikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="3" id="contra" />
|
||||
<Label htmlFor="contra">Kontra</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Output Tugas</Label>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{Object.keys(taskOutput).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Broadcast </Label>
|
||||
<RadioGroup
|
||||
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
|
||||
onValueChange={(value) => setBroadcastType(value)} // Mengatur nilai saat radio berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="all" id="all" />
|
||||
<Label htmlFor="all">Semua</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="email" id="email" />
|
||||
<Label htmlFor="email">Email Blast</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="whatsapp" id="whatsapp" />
|
||||
<Label htmlFor="whatsapp">WhatsApp Blast</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="naration"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={detail?.narration}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.naration?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.naration.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -98,51 +98,6 @@ export default function FormTask() {
|
|||
// setPlatformTypeVisible(selectedValue === 2);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await getTask(id);
|
||||
const details = response.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [id, refresh]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.broadcastType) {
|
||||
setBroadcastType(detail.broadcastType); // Mengatur nilai broadcastType dari API
|
||||
}
|
||||
}, [detail?.broadcastType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.fileTypeOutput) {
|
||||
const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor
|
||||
setTaskOutput({
|
||||
all: outputSet.has(0),
|
||||
video: outputSet.has(2),
|
||||
audio: outputSet.has(4),
|
||||
image: outputSet.has(1),
|
||||
text: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.fileTypeOutput]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
);
|
||||
setUnitSelection({
|
||||
allUnit: outputSet.has(0),
|
||||
mabes: outputSet.has(1),
|
||||
polda: outputSet.has(2),
|
||||
polres: outputSet.has(3),
|
||||
});
|
||||
}
|
||||
}, [detail?.fileTypeOutput]);
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const fileTypeMapping = {
|
||||
all: "1",
|
||||
|
|
@ -212,184 +167,179 @@ export default function FormTask() {
|
|||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Penugasan</p>
|
||||
{detail !== undefined ? (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
<Label>Judul</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{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>Tujuan Pemilihan Tugas</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
||||
<SelectItem value="approver">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 mt-5 pt-5 ml-3">
|
||||
{Object.keys(unitSelection).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={
|
||||
unitSelection[key as keyof typeof unitSelection]
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Tipe Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentMainType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setMainType(value)}
|
||||
// value={String(mainType)}
|
||||
// onValueChange={(value) => setMainType(Number(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="1" id="mediahub" />
|
||||
<Label htmlFor="mediahub">Mediahub</Label>
|
||||
<RadioGroupItem value="2" id="medsos-mediahub" />
|
||||
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Tugas </Label>
|
||||
<RadioGroup
|
||||
value={detail.taskType.toString()}
|
||||
onValueChange={(value) => setTaskType(String(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="atensi-khusus" id="khusus" />
|
||||
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
||||
<RadioGroupItem value="tugas-harian" id="harian" />
|
||||
<Label htmlFor="tugas-harian">Tugas Harian</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
{/* RadioGroup Assignment Category */}
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="1" id="publication" />
|
||||
<Label htmlFor="publication">Publikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="2" id="amplification" />
|
||||
<Label htmlFor="amplification">Amplifikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="3" id="contra" />
|
||||
<Label htmlFor="contra">Kontra</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Output Tugas</Label>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{Object.keys(taskOutput).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Broadcast </Label>
|
||||
<RadioGroup
|
||||
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
|
||||
onValueChange={(value) => setBroadcastType(value)} // Mengatur nilai saat radio berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="all" id="all" />
|
||||
<Label htmlFor="all">Semua</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="email" id="email" />
|
||||
<Label htmlFor="email">Email Blast</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="whatsapp" id="whatsapp" />
|
||||
<Label htmlFor="whatsapp">WhatsApp Blast</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="naration"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={detail?.narration}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.naration?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.naration.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
<Label>Judul</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="mt-5">
|
||||
<Label>Tujuan Pemilihan Tugas</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
||||
<SelectItem value="approver">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 mt-5 pt-5 ml-3">
|
||||
{Object.keys(unitSelection).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={unitSelection[key as keyof typeof unitSelection]}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Tipe Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={mainType} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setMainType(value)}
|
||||
// value={String(mainType)}
|
||||
// onValueChange={(value) => setMainType(Number(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="1" id="mediahub" />
|
||||
<Label htmlFor="mediahub">Mediahub</Label>
|
||||
<RadioGroupItem value="2" id="medsos-mediahub" />
|
||||
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Tugas </Label>
|
||||
<RadioGroup
|
||||
value={taskType}
|
||||
onValueChange={(value) => setTaskType(String(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="atensi-khusus" id="khusus" />
|
||||
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
||||
<RadioGroupItem value="tugas-harian" id="harian" />
|
||||
<Label htmlFor="tugas-harian">Tugas Harian</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
{/* RadioGroup Assignment Category */}
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={type} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="1" id="publication" />
|
||||
<Label htmlFor="publication">Publikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="2" id="amplification" />
|
||||
<Label htmlFor="amplification">Amplifikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="3" id="contra" />
|
||||
<Label htmlFor="contra">Kontra</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Output Tugas</Label>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{Object.keys(taskOutput).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Broadcast </Label>
|
||||
<RadioGroup
|
||||
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
|
||||
onValueChange={(value) => setBroadcastType(value)} // Mengatur nilai saat radio berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="all" id="all" />
|
||||
<Label htmlFor="all">Semua</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="email" id="email" />
|
||||
<Label htmlFor="email">Email Blast</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="whatsapp" id="whatsapp" />
|
||||
<Label htmlFor="whatsapp">WhatsApp Blast</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="naration"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.naration?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.naration.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { title } from "process";
|
||||
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
|
||||
import { postAPIInterceptor } from "@/config/api";
|
||||
import { getAPIInterceptor, postAPIInterceptor } from "@/config/api";
|
||||
|
||||
export async function paginationBlog(
|
||||
size: number,
|
||||
|
|
@ -16,3 +16,8 @@ export async function postBlog(data: any) {
|
|||
const url = "blog";
|
||||
return postAPIInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getBlog(id: any) {
|
||||
const url = `blog/${id}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { getAPIInterceptor } from "@/config/api";
|
||||
import {
|
||||
httpGetInterceptor,
|
||||
httpPostInterceptor,
|
||||
|
|
@ -17,3 +18,8 @@ export async function createTask(data: any) {
|
|||
const url = "assignment";
|
||||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getContestById(id: any, pages = 0) {
|
||||
const url = `contest?id=${id}&page=${pages}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,15 @@ 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, page: number, type: any, title: string = "") {
|
||||
return await httpGetInterceptor(`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`);
|
||||
export async function paginationSchedule(
|
||||
size: number,
|
||||
page: number,
|
||||
type: any,
|
||||
title: string = ""
|
||||
) {
|
||||
return await httpGetInterceptor(
|
||||
`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function postSchedule(data: any) {
|
||||
|
|
@ -14,7 +21,7 @@ export async function postSchedule(data: any) {
|
|||
|
||||
export async function detailSchedule(id: any) {
|
||||
const url = `public/schedule?id=${id}`;
|
||||
return getAPIInterceptor({ url });
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
||||
export async function listScheduleTodayPublic(group = null) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue