feat:curated-content page,detail, detail planning, detail task
This commit is contained in:
parent
ace0fc2200
commit
fa35e4d2f5
|
|
@ -19,7 +19,7 @@ const BlogPage = async () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-none">
|
<div className="flex-none">
|
||||||
<Link href={"/contributor/blog/create"}>
|
<Link href={"/contributor/blog/create"}>
|
||||||
<Button fullWidth size="md" color="primary">
|
<Button fullWidth color="primary">
|
||||||
<Plus className="w-6 h-6 me-1.5" />
|
<Plus className="w-6 h-6 me-1.5" />
|
||||||
Add Index
|
Add Index
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import { Link } from "@/components/navigation";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const columns: ColumnDef<any>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -91,15 +92,18 @@ const columns: ColumnDef<any>[] = [
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<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
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||||
View
|
>
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
<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" />
|
||||||
<SquarePen className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
Edit
|
</DropdownMenuItem>
|
||||||
</DropdownMenuItem>
|
</Link>
|
||||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
<DropdownMenuItem
|
||||||
|
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||||
|
// onClick={() => deletePlan(row.id)}
|
||||||
|
>
|
||||||
<Trash2 className="w-4 h-4 me-1.5" />
|
<Trash2 className="w-4 h-4 me-1.5" />
|
||||||
Delete
|
Delete
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||||
|
import FormTask from "@/components/form/task/task-form";
|
||||||
|
import PublishMediahub from "@/components/form/planning/mediahub-publish";
|
||||||
|
|
||||||
|
const MediahubPublishPage = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SiteBreadcrumb />
|
||||||
|
<div className="space-y-4">
|
||||||
|
<PublishMediahub />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MediahubPublishPage;
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import { Link } from "@/components/navigation";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const columns: ColumnDef<any>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -91,14 +92,15 @@ const columns: ColumnDef<any>[] = [
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<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
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||||
View
|
>
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
<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" />
|
||||||
<SquarePen className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
Edit
|
</DropdownMenuItem>
|
||||||
</DropdownMenuItem>
|
</Link>
|
||||||
|
|
||||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
<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" />
|
<Trash2 className="w-4 h-4 me-1.5" />
|
||||||
Delete
|
Delete
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||||
|
import PublishMedsos from "@/components/form/planning/medsos-publish";
|
||||||
|
|
||||||
|
const MedsosPublishPage = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SiteBreadcrumb />
|
||||||
|
<div className="space-y-4">
|
||||||
|
<PublishMedsos />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MedsosPublishPage;
|
||||||
|
|
@ -124,7 +124,7 @@ const PressReleaseTable = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full overflow-x-auto">
|
<div className="w-full overflow-x-auto">
|
||||||
<div className="flex justify-between items-center px-5">
|
<div className="flex justify-between items-center px-5 mt-3">
|
||||||
<div>
|
<div>
|
||||||
<InputGroup merged>
|
<InputGroup merged>
|
||||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import { Link } from "@/components/navigation";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const columns: ColumnDef<any>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -111,10 +112,12 @@ const columns: ColumnDef<any>[] = [
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<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/task/detail/${row.original.id}`}>
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
View
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
</DropdownMenuItem>
|
View
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</Link>
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
<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" />
|
<SquarePen className="w-4 h-4 me-1.5" />
|
||||||
Edit
|
Edit
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import PressConferenceTable from "../contributor/schedule/press-release/componen
|
||||||
import BlogTable from "../contributor/blog/components/blog-table";
|
import BlogTable from "../contributor/blog/components/blog-table";
|
||||||
import ContentTable from "./routine-task/components/content-table";
|
import ContentTable from "./routine-task/components/content-table";
|
||||||
import RecentActivity from "./routine-task/components/recent-activity";
|
import RecentActivity from "./routine-task/components/recent-activity";
|
||||||
|
import { Link } from "@/components/navigation";
|
||||||
|
|
||||||
const DashboardPage = () => {
|
const DashboardPage = () => {
|
||||||
const t = useTranslations("AnalyticsDashboard");
|
const t = useTranslations("AnalyticsDashboard");
|
||||||
|
|
@ -110,14 +111,16 @@ const DashboardPage = () => {
|
||||||
Table Penugasan
|
Table Penugasan
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button color="primary" className="text-white">
|
<Link href={"/contributor/task/create"}>
|
||||||
<UploadIcon />
|
<Button color="primary" className="text-white">
|
||||||
Buat Penugasan
|
<UploadIcon />
|
||||||
</Button>
|
Buat Penugasan
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0 mt-3">
|
||||||
<TaskTable />
|
<TaskTable />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -128,7 +131,7 @@ const DashboardPage = () => {
|
||||||
<div className="grid grid-cols-12 gap-5">
|
<div className="grid grid-cols-12 gap-5">
|
||||||
<div className="lg:col-span-12 col-span-12">
|
<div className="lg:col-span-12 col-span-12">
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0 ">
|
||||||
<PressConferenceTable />
|
<PressConferenceTable />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -145,14 +148,16 @@ const DashboardPage = () => {
|
||||||
Table Indeks
|
Table Indeks
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button color="primary" className="text-white">
|
<Link href={"/contributor/blog/create"}>
|
||||||
<UploadIcon />
|
<Button color="primary" className="text-white">
|
||||||
Tambah Indeks
|
<UploadIcon />
|
||||||
</Button>
|
Tambah Indeks
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0 mt-3">
|
||||||
<BlogTable />
|
<BlogTable />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ const AudioSliderPage = () => {
|
||||||
<div className="mx-3 px-5">
|
<div className="mx-3 px-5">
|
||||||
<div className=" grid grid-cols-1 gap-6 ">
|
<div className=" grid grid-cols-1 gap-6 ">
|
||||||
{displayAudio?.map((audio: any) => (
|
{displayAudio?.map((audio: any) => (
|
||||||
<a
|
<Link
|
||||||
href="#"
|
href={`/shared/curated-content//giat-routine/audio/detail/${audio.id}`}
|
||||||
key={audio?.id}
|
key={audio?.id}
|
||||||
className="flex flex-col sm:flex-row items-center hover:scale-110 transition-transform duration-300 bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
className="flex flex-col sm:flex-row items-center hover:scale-110 transition-transform duration-300 bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||||
>
|
>
|
||||||
|
|
@ -118,7 +118,7 @@ const AudioSliderPage = () => {
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,549 @@
|
||||||
|
"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, CardContent } 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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { postBlog } from "@/service/blog/blog";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react";
|
||||||
|
import { detailMedia } from "@/service/curated-content/curated-content";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/free-mode";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/thumbs";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules";
|
||||||
|
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||||
|
|
||||||
|
const detailSchema = z.object({
|
||||||
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
categoryName: 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." }),
|
||||||
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Category = {
|
||||||
|
id: string;
|
||||||
|
categoryName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type curationDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
categoryName: string;
|
||||||
|
description: string;
|
||||||
|
uploadedBy: {
|
||||||
|
id: number;
|
||||||
|
fullname: string;
|
||||||
|
username: string | null;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
isInternational: boolean;
|
||||||
|
userLevel: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
aliasName: string;
|
||||||
|
userGroupId: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tags: string;
|
||||||
|
provinceId: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialComments = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
username: "Esther Howard",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Tolong untuk narasinya mengikuti 5W + 1H!",
|
||||||
|
avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
username: "Brooklyn Simmons",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏",
|
||||||
|
avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
username: "Leslie Alexander",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Sangat berguna. Terima Kasih!",
|
||||||
|
avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DetailAudio() {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { id } = useParams() as { id: string };
|
||||||
|
console.log(id);
|
||||||
|
const editor = useRef(null);
|
||||||
|
type DetailSchema = z.infer<typeof detailSchema>;
|
||||||
|
|
||||||
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
|
const taskId = Cookies.get("taskId");
|
||||||
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
|
// const [detail, setDetail] = useState({
|
||||||
|
// title: null,
|
||||||
|
// tags: null,
|
||||||
|
// files: [],
|
||||||
|
// fileType: null,
|
||||||
|
// });
|
||||||
|
const [detail, setDetail] = useState<curationDetail>();
|
||||||
|
const [refresh] = useState(false);
|
||||||
|
const [detailThumb, setDetailThumb] = useState<any>([]);
|
||||||
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<DetailSchema>({
|
||||||
|
resolver: zodResolver(detailSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const [commentsData, setCommentsData] = useState(initialComments);
|
||||||
|
const [replyText, setReplyText] = useState("");
|
||||||
|
const [replyingTo, setReplyingTo] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleReply = (commentId: number) => {
|
||||||
|
setReplyingTo(commentId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addReply = (commentId: number) => {
|
||||||
|
if (replyText.trim()) {
|
||||||
|
const newCommentData = commentsData.map((comment: any) => {
|
||||||
|
if (comment.id === commentId) {
|
||||||
|
return {
|
||||||
|
...comment,
|
||||||
|
replies: [
|
||||||
|
...comment.replies,
|
||||||
|
{
|
||||||
|
text: replyText,
|
||||||
|
username: "You",
|
||||||
|
date: new Date().toLocaleString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
setCommentsData(newCommentData);
|
||||||
|
setReplyText("");
|
||||||
|
setReplyingTo(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function initState() {
|
||||||
|
if (id) {
|
||||||
|
const response = await detailMedia(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
|
setDetail(details);
|
||||||
|
const filesData = details.files || [];
|
||||||
|
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) =>
|
||||||
|
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg"
|
||||||
|
);
|
||||||
|
setDetailThumb(fileUrls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-10">
|
||||||
|
{detail !== undefined ? (
|
||||||
|
<Card className="w-full ">
|
||||||
|
<div className="px-6 py-6">
|
||||||
|
<p className="text-lg font-semibold mb-3">Kurasi Detail</p>
|
||||||
|
<CardContent className="border rounded-md">
|
||||||
|
<div className="flex flex-row gap-10">
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label>Judul</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="title"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.title?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.title.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="py-3 w-full">
|
||||||
|
<Label>Kategori</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="categoryName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.categoryName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Description</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Textarea
|
||||||
|
value={detail.description}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Meta"
|
||||||
|
cols={5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<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="umum">Umum</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="2" id="amplification" />
|
||||||
|
<Label htmlFor="ksp">Ksp</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="3" id="contra" />
|
||||||
|
<Label htmlFor="journalist">Journalist</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="4" id="contra" />
|
||||||
|
<Label htmlFor="polri">Polri</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Tag</Label>
|
||||||
|
<p className="border rounded-md text-blue-600 px-2 py-2">
|
||||||
|
{detail?.tags}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>
|
||||||
|
{" "}
|
||||||
|
{detail?.uploadedBy?.fullname ||
|
||||||
|
"Data tidak tersedia"}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="flex flex-row items-center gap-2 text-blue-500">
|
||||||
|
<InboxIcon />
|
||||||
|
<p className="text-blue-500">Kotak Saran (0)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button>Content Rewrite</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent className="border rounded-md mt-5">
|
||||||
|
<div className="flex flex-row gap-5">
|
||||||
|
<div className="w-6/12 border px-3 mt-3 rounded-md">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label className="text-xl text-black">File Media</Label>
|
||||||
|
<div className="w-full">
|
||||||
|
<Swiper
|
||||||
|
thumbs={{ swiper: thumbsSwiper }}
|
||||||
|
modules={[FreeMode, Navigation, Thumbs]}
|
||||||
|
navigation={false}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<SwiperSlide key={data.id}>
|
||||||
|
<audio
|
||||||
|
className="w-full"
|
||||||
|
src={data}
|
||||||
|
controls
|
||||||
|
title={`Audio ${data.id}`}
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
<div className="mt-2">
|
||||||
|
<Swiper
|
||||||
|
onSwiper={setThumbsSwiper}
|
||||||
|
slidesPerView={6}
|
||||||
|
spaceBetween={8}
|
||||||
|
pagination={{
|
||||||
|
clickable: true,
|
||||||
|
}}
|
||||||
|
modules={[Pagination, Thumbs]}
|
||||||
|
>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<SwiperSlide key={data.id}>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span className="text-sm text-gray-700">
|
||||||
|
Audio {data.id}
|
||||||
|
</span>
|
||||||
|
<audio
|
||||||
|
className="h-[24px] w-[80px]"
|
||||||
|
src={data}
|
||||||
|
controls
|
||||||
|
title={`Audio ${data.id}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12 border px-3 rounded-md mt-3">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">
|
||||||
|
Penempatan File
|
||||||
|
</Label>
|
||||||
|
<div className="flex flex-row justify-between items-center">
|
||||||
|
<p>file</p>
|
||||||
|
<p>Penempatan</p>
|
||||||
|
</div>
|
||||||
|
<p className="bg-black h-1 w-full rounded-lg"></p>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<div
|
||||||
|
key={data.id}
|
||||||
|
className="flex items-center gap-3 mt-2"
|
||||||
|
>
|
||||||
|
{/* <img
|
||||||
|
className="object-cover w-20 h-20"
|
||||||
|
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||||
|
alt={`Thumbnail ${index}`}
|
||||||
|
/> */}
|
||||||
|
<img
|
||||||
|
className="object-cover w-36 h-32"
|
||||||
|
src={data}
|
||||||
|
alt={`Article ${data.id}`}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-row gap-3 items-center">
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Nasional"
|
||||||
|
/>
|
||||||
|
Nasional
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Wilayah"
|
||||||
|
/>
|
||||||
|
Wilayah
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="International"
|
||||||
|
/>
|
||||||
|
International
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Berikan Komentar</Label>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="/images/avatar/avatar-1.png"
|
||||||
|
alt="@shadcn"
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="flex-grow p-2 border rounded-lg focus:outline-none focus:border-yellow-400"
|
||||||
|
placeholder="Tuliskan komentar Anda di sini.."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-2 gap-3">
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<PaperclipIcon className="w-5 h-5" />
|
||||||
|
Lampirkan
|
||||||
|
</button>
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<SmileIcon className="w-5 h-5" />
|
||||||
|
Emoticon
|
||||||
|
</button>
|
||||||
|
<button className="ml-auto px-4 py-1 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600">
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Komentar</Label>
|
||||||
|
{commentsData.map((comment) => (
|
||||||
|
<div
|
||||||
|
key={comment.id}
|
||||||
|
className="flex items-start gap-3 mt-2"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src={comment.avatar}
|
||||||
|
alt={`@${comment.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{comment.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{comment.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">{comment.text}</p>
|
||||||
|
<div
|
||||||
|
className="flex items-center mt-1 text-blue-500 cursor-pointer"
|
||||||
|
onClick={() => handleReply(comment.id)}
|
||||||
|
>
|
||||||
|
<DotSquare className="w-4 h-4" />
|
||||||
|
<span className="ml-1">Balas</span>
|
||||||
|
</div>
|
||||||
|
{comment.replies.length > 0 && (
|
||||||
|
<div className="ml-8 mt-2">
|
||||||
|
{comment.replies.map((reply: any, index: any) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-start gap-3 mt-1"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="https://github.com/shadcn.png"
|
||||||
|
alt={`@${reply.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{reply.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{reply.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">
|
||||||
|
{reply.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{replyingTo !== null && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md"
|
||||||
|
rows={3}
|
||||||
|
placeholder="Tulis balasan..."
|
||||||
|
value={replyText}
|
||||||
|
onChange={(e) => setReplyText(e.target.value)}
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
className="mt-2 bg-yellow-500 text-white px-4 py-2 rounded-md"
|
||||||
|
onClick={() => addReply(replyingTo)}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,518 @@
|
||||||
|
"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, CardContent } 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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { postBlog } from "@/service/blog/blog";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react";
|
||||||
|
import { detailMedia } from "@/service/curated-content/curated-content";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/free-mode";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/thumbs";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules";
|
||||||
|
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||||
|
import JoditEditor from "jodit-react";
|
||||||
|
|
||||||
|
const detailSchema = z.object({
|
||||||
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
categoryName: 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." }),
|
||||||
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Category = {
|
||||||
|
id: string;
|
||||||
|
categoryName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type curationDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
categoryName: string;
|
||||||
|
description: string;
|
||||||
|
uploadedBy: {
|
||||||
|
id: number;
|
||||||
|
fullname: string;
|
||||||
|
username: string | null;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
isInternational: boolean;
|
||||||
|
userLevel: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
aliasName: string;
|
||||||
|
userGroupId: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tags: string;
|
||||||
|
provinceId: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialComments = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
username: "Esther Howard",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Tolong untuk narasinya mengikuti 5W + 1H!",
|
||||||
|
avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
username: "Brooklyn Simmons",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏",
|
||||||
|
avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
username: "Leslie Alexander",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Sangat berguna. Terima Kasih!",
|
||||||
|
avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DetailDocument() {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { id } = useParams() as { id: string };
|
||||||
|
console.log(id);
|
||||||
|
const editor = useRef(null);
|
||||||
|
type DetailSchema = z.infer<typeof detailSchema>;
|
||||||
|
|
||||||
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
|
const taskId = Cookies.get("taskId");
|
||||||
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
|
// const [detail, setDetail] = useState({
|
||||||
|
// title: null,
|
||||||
|
// tags: null,
|
||||||
|
// files: [],
|
||||||
|
// fileType: null,
|
||||||
|
// });
|
||||||
|
const [detail, setDetail] = useState<curationDetail>();
|
||||||
|
const [refresh] = useState(false);
|
||||||
|
const [detailThumb, setDetailThumb] = useState<any>([]);
|
||||||
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<DetailSchema>({
|
||||||
|
resolver: zodResolver(detailSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const [commentsData, setCommentsData] = useState(initialComments);
|
||||||
|
const [replyText, setReplyText] = useState("");
|
||||||
|
const [replyingTo, setReplyingTo] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleReply = (commentId: number) => {
|
||||||
|
setReplyingTo(commentId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addReply = (commentId: number) => {
|
||||||
|
if (replyText.trim()) {
|
||||||
|
const newCommentData = commentsData.map((comment: any) => {
|
||||||
|
if (comment.id === commentId) {
|
||||||
|
return {
|
||||||
|
...comment,
|
||||||
|
replies: [
|
||||||
|
...comment.replies,
|
||||||
|
{
|
||||||
|
text: replyText,
|
||||||
|
username: "You",
|
||||||
|
date: new Date().toLocaleString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
setCommentsData(newCommentData);
|
||||||
|
setReplyText("");
|
||||||
|
setReplyingTo(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function initState() {
|
||||||
|
if (id) {
|
||||||
|
const response = await detailMedia(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
|
setDetail(details);
|
||||||
|
const filesData = details.files || [];
|
||||||
|
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) =>
|
||||||
|
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg"
|
||||||
|
);
|
||||||
|
setDetailThumb(fileUrls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-10">
|
||||||
|
{detail !== undefined ? (
|
||||||
|
<Card className="w-full ">
|
||||||
|
<div className="px-6 py-6">
|
||||||
|
<p className="text-lg font-semibold mb-3">Kurasi Detail</p>
|
||||||
|
<CardContent className="border rounded-md">
|
||||||
|
<div className="flex flex-row gap-10">
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label>Judul</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="title"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.title?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.title.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="py-3 w-full">
|
||||||
|
<Label>Kategori</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="categoryName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.categoryName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Description</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Textarea
|
||||||
|
value={detail.description}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Meta"
|
||||||
|
cols={5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<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="umum">Umum</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="2" id="amplification" />
|
||||||
|
<Label htmlFor="ksp">Ksp</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="3" id="contra" />
|
||||||
|
<Label htmlFor="journalist">Journalist</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="4" id="contra" />
|
||||||
|
<Label htmlFor="polri">Polri</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Tag</Label>
|
||||||
|
<p className="border rounded-md text-blue-600 px-2 py-2">
|
||||||
|
{detail?.tags}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>
|
||||||
|
{" "}
|
||||||
|
{detail?.uploadedBy?.fullname ||
|
||||||
|
"Data tidak tersedia"}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="flex flex-row items-center gap-2 text-blue-500">
|
||||||
|
<InboxIcon />
|
||||||
|
<p className="text-blue-500">Kotak Saran (0)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button>Content Rewrite</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent className="border rounded-md mt-5">
|
||||||
|
<div className="flex flex-row gap-5">
|
||||||
|
<div className="w-6/12 border px-3 mt-3 rounded-md">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label className="text-xl text-black">File Media</Label>
|
||||||
|
<div className="w-full ">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="description"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<JoditEditor
|
||||||
|
ref={editor}
|
||||||
|
value={detail?.description}
|
||||||
|
onChange={onChange}
|
||||||
|
className="dark:text-black"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12 border px-3 rounded-md mt-3">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">
|
||||||
|
Penempatan File
|
||||||
|
</Label>
|
||||||
|
<div className="flex flex-row justify-between items-center">
|
||||||
|
<p>file</p>
|
||||||
|
<p>Penempatan</p>
|
||||||
|
</div>
|
||||||
|
<p className="bg-black h-1 w-full rounded-lg"></p>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<div
|
||||||
|
key={data.id}
|
||||||
|
className="flex items-center gap-3 mt-2"
|
||||||
|
>
|
||||||
|
{/* <img
|
||||||
|
className="object-cover w-20 h-20"
|
||||||
|
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||||
|
alt={`Thumbnail ${index}`}
|
||||||
|
/> */}
|
||||||
|
<img
|
||||||
|
className="object-cover w-36 h-32"
|
||||||
|
src={data}
|
||||||
|
alt={` ${data.id}`}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-row gap-3 items-center">
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Nasional"
|
||||||
|
/>
|
||||||
|
Nasional
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Wilayah"
|
||||||
|
/>
|
||||||
|
Wilayah
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="International"
|
||||||
|
/>
|
||||||
|
International
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Berikan Komentar</Label>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="/images/avatar/avatar-1.png"
|
||||||
|
alt="@shadcn"
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="flex-grow p-2 border rounded-lg focus:outline-none focus:border-yellow-400"
|
||||||
|
placeholder="Tuliskan komentar Anda di sini.."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-2 gap-3">
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<PaperclipIcon className="w-5 h-5" />
|
||||||
|
Lampirkan
|
||||||
|
</button>
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<SmileIcon className="w-5 h-5" />
|
||||||
|
Emoticon
|
||||||
|
</button>
|
||||||
|
<button className="ml-auto px-4 py-1 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600">
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Komentar</Label>
|
||||||
|
{commentsData.map((comment) => (
|
||||||
|
<div
|
||||||
|
key={comment.id}
|
||||||
|
className="flex items-start gap-3 mt-2"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src={comment.avatar}
|
||||||
|
alt={`@${comment.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{comment.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{comment.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">{comment.text}</p>
|
||||||
|
<div
|
||||||
|
className="flex items-center mt-1 text-blue-500 cursor-pointer"
|
||||||
|
onClick={() => handleReply(comment.id)}
|
||||||
|
>
|
||||||
|
<DotSquare className="w-4 h-4" />
|
||||||
|
<span className="ml-1">Balas</span>
|
||||||
|
</div>
|
||||||
|
{comment.replies.length > 0 && (
|
||||||
|
<div className="ml-8 mt-2">
|
||||||
|
{comment.replies.map((reply: any, index: any) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-start gap-3 mt-1"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="https://github.com/shadcn.png"
|
||||||
|
alt={`@${reply.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{reply.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{reply.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">
|
||||||
|
{reply.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{replyingTo !== null && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md"
|
||||||
|
rows={3}
|
||||||
|
placeholder="Tulis balasan..."
|
||||||
|
value={replyText}
|
||||||
|
onChange={(e) => setReplyText(e.target.value)}
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
className="mt-2 bg-yellow-500 text-white px-4 py-2 rounded-md"
|
||||||
|
onClick={() => addReply(replyingTo)}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -61,8 +61,8 @@ const TeksSliderPage = () => {
|
||||||
<div className="mx-3 px-5">
|
<div className="mx-3 px-5">
|
||||||
<div className=" grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className=" grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
{displayDocument?.map((document: any) => (
|
{displayDocument?.map((document: any) => (
|
||||||
<a
|
<Link
|
||||||
href="#"
|
href={`/shared/curated-content/giat-routine/document/detail/${document.id}`}
|
||||||
key={document?.id}
|
key={document?.id}
|
||||||
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||||
>
|
>
|
||||||
|
|
@ -105,7 +105,7 @@ const TeksSliderPage = () => {
|
||||||
Download Dokumen
|
Download Dokumen
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -17,25 +17,26 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
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 Cookies from "js-cookie";
|
||||||
import { createTask } from "@/config/api";
|
|
||||||
import {
|
|
||||||
createMedia,
|
|
||||||
getTagsBySubCategoryId,
|
|
||||||
listEnableCategory,
|
|
||||||
} from "@/service/content/content";
|
|
||||||
import { postBlog } from "@/service/blog/blog";
|
import { postBlog } from "@/service/blog/blog";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { InboxIcon } from "lucide-react";
|
import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react";
|
||||||
|
import { detailMedia } from "@/service/curated-content/curated-content";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/free-mode";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/thumbs";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules";
|
||||||
|
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||||
|
|
||||||
const taskSchema = z.object({
|
const detailSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
slug: z.string().min(1, { message: "Judul diperlukan" }),
|
categoryName: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
meta: z.string().min(1, { message: "Judul diperlukan" }),
|
meta: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z
|
||||||
.string()
|
.string()
|
||||||
|
|
@ -45,130 +46,151 @@ const taskSchema = z.object({
|
||||||
|
|
||||||
type Category = {
|
type Category = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
categoryName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialCategories: Category[] = [
|
export type curationDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
categoryName: string;
|
||||||
|
description: string;
|
||||||
|
uploadedBy: {
|
||||||
|
id: number;
|
||||||
|
fullname: string;
|
||||||
|
username: string | null;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
isInternational: boolean;
|
||||||
|
userLevel: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
aliasName: string;
|
||||||
|
userGroupId: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tags: string;
|
||||||
|
provinceId: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialComments = [
|
||||||
{
|
{
|
||||||
id: "1",
|
id: 1,
|
||||||
name: "Giat Polri",
|
username: "Esther Howard",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Tolong untuk narasinya mengikuti 5W + 1H!",
|
||||||
|
avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "2",
|
id: 2,
|
||||||
name: "Giat Pimpinan",
|
username: "Brooklyn Simmons",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏",
|
||||||
|
avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "3",
|
id: 3,
|
||||||
name: "Liputan Kegiatan",
|
username: "Leslie Alexander",
|
||||||
},
|
date: "07-04-2023 20:00 WIB",
|
||||||
{
|
text: "Sangat berguna. Terima Kasih!",
|
||||||
id: "4",
|
avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna
|
||||||
name: "Seputar Prestasi",
|
replies: [], // Komentar balasan
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function DetailImage() {
|
export default function DetailImage() {
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const router = useRouter();
|
const { id } = useParams() as { id: string };
|
||||||
|
console.log(id);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type TaskSchema = z.infer<typeof taskSchema>;
|
type DetailSchema = z.infer<typeof detailSchema>;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
|
|
||||||
const [categories] = useState<Category[]>(initialCategories); // State untuk kategori
|
|
||||||
const [selectedTarget, setSelectedTarget] = useState("");
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
// const [detail, setDetail] = useState({
|
||||||
const [tags, setTags] = useState<any[]>([]);
|
// title: null,
|
||||||
const [isDraft, setIsDraft] = useState(false);
|
// tags: null,
|
||||||
|
// files: [],
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
// fileType: null,
|
||||||
allUnit: false,
|
// });
|
||||||
mabes: false,
|
const [detail, setDetail] = useState<curationDetail>();
|
||||||
polda: false,
|
const [refresh] = useState(false);
|
||||||
polres: false,
|
const [detailThumb, setDetailThumb] = useState<any>([]);
|
||||||
});
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
|
|
||||||
let fileTypeId = "1";
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
setValue,
|
setValue,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<TaskSchema>({
|
} = useForm<DetailSchema>({
|
||||||
resolver: zodResolver(taskSchema),
|
resolver: zodResolver(detailSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRemoveTag = (index: any) => {
|
const [commentsData, setCommentsData] = useState(initialComments);
|
||||||
setTags((prevTags) => prevTags.filter((_, i) => i !== index));
|
const [replyText, setReplyText] = useState("");
|
||||||
|
const [replyingTo, setReplyingTo] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleReply = (commentId: number) => {
|
||||||
|
setReplyingTo(commentId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const addReply = (commentId: number) => {
|
||||||
if (event.target.files) {
|
if (replyText.trim()) {
|
||||||
const files = Array.from(event.target.files);
|
const newCommentData = commentsData.map((comment: any) => {
|
||||||
setSelectedFiles((prevImages: any) => [...prevImages, ...files]);
|
if (comment.id === commentId) {
|
||||||
console.log("DATAFILE::", selectedFiles);
|
return {
|
||||||
|
...comment,
|
||||||
|
replies: [
|
||||||
|
...comment.replies,
|
||||||
|
{
|
||||||
|
text: replyText,
|
||||||
|
username: "You",
|
||||||
|
date: new Date().toLocaleString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
setCommentsData(newCommentData);
|
||||||
|
setReplyText("");
|
||||||
|
setReplyingTo(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveImage = (index: number) => {
|
useEffect(() => {
|
||||||
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
async function initState() {
|
||||||
};
|
if (id) {
|
||||||
|
const response = await detailMedia(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
const save = async (data: TaskSchema) => {
|
setDetail(details);
|
||||||
const requestData = {
|
const filesData = details.files || [];
|
||||||
...data,
|
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) =>
|
||||||
title: data.title,
|
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg"
|
||||||
description: data.description,
|
);
|
||||||
categoryId: selectedTarget,
|
setDetailThumb(fileUrls);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
};
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<div className="flex gap-10">
|
||||||
<div className="flex gap-10">
|
{detail !== undefined ? (
|
||||||
<Card className="w-full ">
|
<Card className="w-full ">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Kurasi Detail</p>
|
<p className="text-lg font-semibold mb-3">Kurasi Detail</p>
|
||||||
<CardContent className="border rounded-md">
|
<CardContent className="border rounded-md">
|
||||||
<div className="flex flex-row gap-5">
|
<div className="flex flex-row gap-10">
|
||||||
<div className="w-6/12">
|
<div className="w-6/12">
|
||||||
<div className="gap-5 mb-5">
|
<div className="gap-5 mb-5">
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
|
|
@ -183,6 +205,7 @@ export default function DetailImage() {
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
placeholder="Enter Title"
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.title}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -195,27 +218,20 @@ export default function DetailImage() {
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="py-3 w-full">
|
<div className="py-3 w-full">
|
||||||
<Label>Kategori</Label>
|
<Label>Kategori</Label>
|
||||||
<Select
|
<Controller
|
||||||
value={selectedTarget} // Ensure selectedTarget is updated correctly
|
control={control}
|
||||||
onValueChange={(value) => {
|
name="categoryName"
|
||||||
console.log("Selected Category ID:", value);
|
render={({ field }) => (
|
||||||
setSelectedTarget(value);
|
<Input
|
||||||
}}
|
size="md"
|
||||||
>
|
type="text"
|
||||||
<SelectTrigger size="md">
|
value={field.value}
|
||||||
<SelectValue placeholder="Pilih" />
|
onChange={field.onChange}
|
||||||
</SelectTrigger>
|
placeholder="Enter Title"
|
||||||
<SelectContent>
|
defaultValue={detail.categoryName}
|
||||||
{categories.map((category) => (
|
/>
|
||||||
<SelectItem
|
)}
|
||||||
key={category.id}
|
/>
|
||||||
value={category.name}
|
|
||||||
>
|
|
||||||
{category.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className=" py-3">
|
<div className=" py-3">
|
||||||
|
|
@ -223,18 +239,19 @@ export default function DetailImage() {
|
||||||
<Label>Description</Label>
|
<Label>Description</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="meta"
|
name="description"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Textarea
|
<Textarea
|
||||||
value={field.value}
|
value={detail.description}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
placeholder="Enter Meta"
|
placeholder="Enter Meta"
|
||||||
|
cols={5}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{errors.meta?.message && (
|
{errors.description?.message && (
|
||||||
<p className="text-red-400 text-sm">
|
<p className="text-red-400 text-sm">
|
||||||
{errors.meta.message}
|
{errors.description.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -271,29 +288,18 @@ export default function DetailImage() {
|
||||||
<div className=" py-3">
|
<div className=" py-3">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Tag</Label>
|
<Label>Tag</Label>
|
||||||
<Controller
|
<p className="border rounded-md text-blue-600 px-2 py-2">
|
||||||
control={control}
|
{detail?.tags}
|
||||||
name="slug"
|
</p>
|
||||||
render={({ field }) => (
|
|
||||||
<Input
|
|
||||||
size="md"
|
|
||||||
type="text"
|
|
||||||
value={field.value}
|
|
||||||
onChange={field.onChange}
|
|
||||||
placeholder="Enter Slug"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{errors.slug?.message && (
|
|
||||||
<p className="text-red-400 text-sm">
|
|
||||||
{errors.slug.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className=" py-3">
|
<div className=" py-3">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Kontributor</Label>
|
<Label>
|
||||||
|
{" "}
|
||||||
|
{detail?.uploadedBy?.fullname ||
|
||||||
|
"Data tidak tersedia"}
|
||||||
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className=" py-3">
|
<div className=" py-3">
|
||||||
|
|
@ -314,24 +320,46 @@ export default function DetailImage() {
|
||||||
<div className="gap-5 mb-5">
|
<div className="gap-5 mb-5">
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<Label className="text-xl text-black">File Media</Label>
|
<Label className="text-xl text-black">File Media</Label>
|
||||||
<Controller
|
<div className="w-full ">
|
||||||
control={control}
|
<Swiper
|
||||||
name="title"
|
thumbs={{ swiper: thumbsSwiper }}
|
||||||
render={({ field }) => (
|
modules={[FreeMode, Navigation, Thumbs]}
|
||||||
<Input
|
navigation={false}
|
||||||
size="md"
|
className="w-full"
|
||||||
type="text"
|
>
|
||||||
value={field.value}
|
{detailThumb?.map((data: any) => (
|
||||||
onChange={field.onChange}
|
<SwiperSlide key={data.id}>
|
||||||
placeholder="Enter Title"
|
<img
|
||||||
/>
|
className="object-fill h-full w-full"
|
||||||
)}
|
src={data}
|
||||||
/>
|
alt={` ${data.id}`}
|
||||||
{errors.title?.message && (
|
/>
|
||||||
<p className="text-red-400 text-sm">
|
</SwiperSlide>
|
||||||
{errors.title.message}
|
))}
|
||||||
</p>
|
</Swiper>
|
||||||
)}
|
<div className=" mt-2 ">
|
||||||
|
<Swiper
|
||||||
|
onSwiper={setThumbsSwiper}
|
||||||
|
slidesPerView={6}
|
||||||
|
spaceBetween={8}
|
||||||
|
pagination={{
|
||||||
|
clickable: true,
|
||||||
|
}}
|
||||||
|
modules={[Pagination, Thumbs]}
|
||||||
|
// className="mySwiper2"
|
||||||
|
>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<SwiperSlide key={data.id}>
|
||||||
|
<img
|
||||||
|
className="object-cover h-[60px] w-[80px]"
|
||||||
|
src={data}
|
||||||
|
alt={` ${data.id}`}
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -346,14 +374,170 @@ export default function DetailImage() {
|
||||||
<p>Penempatan</p>
|
<p>Penempatan</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="bg-black h-1 w-full rounded-lg"></p>
|
<p className="bg-black h-1 w-full rounded-lg"></p>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<div
|
||||||
|
key={data.id}
|
||||||
|
className="flex items-center gap-3 mt-2"
|
||||||
|
>
|
||||||
|
{/* <img
|
||||||
|
className="object-cover w-20 h-20"
|
||||||
|
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||||
|
alt={`Thumbnail ${index}`}
|
||||||
|
/> */}
|
||||||
|
<img
|
||||||
|
className="object-cover w-36 h-32"
|
||||||
|
src={data}
|
||||||
|
alt={`Article ${data.id}`}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-row gap-3 items-center">
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Nasional"
|
||||||
|
/>
|
||||||
|
Nasional
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Wilayah"
|
||||||
|
/>
|
||||||
|
Wilayah
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="International"
|
||||||
|
/>
|
||||||
|
International
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Berikan Komentar</Label>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="/images/avatar/avatar-1.png"
|
||||||
|
alt="@shadcn"
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="flex-grow p-2 border rounded-lg focus:outline-none focus:border-yellow-400"
|
||||||
|
placeholder="Tuliskan komentar Anda di sini.."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-2 gap-3">
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<PaperclipIcon className="w-5 h-5" />
|
||||||
|
Lampirkan
|
||||||
|
</button>
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<SmileIcon className="w-5 h-5" />
|
||||||
|
Emoticon
|
||||||
|
</button>
|
||||||
|
<button className="ml-auto px-4 py-1 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600">
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Komentar</Label>
|
||||||
|
{commentsData.map((comment) => (
|
||||||
|
<div
|
||||||
|
key={comment.id}
|
||||||
|
className="flex items-start gap-3 mt-2"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src={comment.avatar}
|
||||||
|
alt={`@${comment.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{comment.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{comment.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">{comment.text}</p>
|
||||||
|
<div
|
||||||
|
className="flex items-center mt-1 text-blue-500 cursor-pointer"
|
||||||
|
onClick={() => handleReply(comment.id)}
|
||||||
|
>
|
||||||
|
<DotSquare className="w-4 h-4" />
|
||||||
|
<span className="ml-1">Balas</span>
|
||||||
|
</div>
|
||||||
|
{comment.replies.length > 0 && (
|
||||||
|
<div className="ml-8 mt-2">
|
||||||
|
{comment.replies.map((reply: any, index: any) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-start gap-3 mt-1"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="https://github.com/shadcn.png"
|
||||||
|
alt={`@${reply.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{reply.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{reply.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">
|
||||||
|
{reply.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{replyingTo !== null && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md"
|
||||||
|
rows={3}
|
||||||
|
placeholder="Tulis balasan..."
|
||||||
|
value={replyText}
|
||||||
|
onChange={(e) => setReplyText(e.target.value)}
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
className="mt-2 bg-yellow-500 text-white px-4 py-2 rounded-md"
|
||||||
|
onClick={() => addReply(replyingTo)}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
) : (
|
||||||
</form>
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { Link } from "@/components/navigation";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { getListContent } from "@/service/landing/landing";
|
import { getListContent } from "@/service/landing/landing";
|
||||||
import { formatDateToIndonesian } from "@/utils/globals";
|
import { formatDateToIndonesian } from "@/utils/globals";
|
||||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||||
|
import image from "next/image";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
const VideoSliderPage = () => {
|
const VideoSliderPage = () => {
|
||||||
|
|
@ -53,32 +55,36 @@ const VideoSliderPage = () => {
|
||||||
key={video?.id}
|
key={video?.id}
|
||||||
className="hover:scale-110 transition-transform duration-300"
|
className="hover:scale-110 transition-transform duration-300"
|
||||||
>
|
>
|
||||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
<Link
|
||||||
<img
|
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
||||||
src={video?.thumbnailLink}
|
>
|
||||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||||
/>
|
<img
|
||||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
src={video?.thumbnailLink}
|
||||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
||||||
{video?.timezone || "WIB"} |
|
/>
|
||||||
<Icon icon="formkit:eye" width="15" height="15" />
|
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||||
{video?.clickCount}
|
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||||
<svg
|
{video?.timezone || "WIB"} |
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<Icon icon="formkit:eye" width="15" height="15" />
|
||||||
width="1em"
|
{video?.clickCount}
|
||||||
height="1em"
|
<svg
|
||||||
viewBox="0 0 20 20"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
width="1em"
|
||||||
<path
|
height="1em"
|
||||||
fill="#f00"
|
viewBox="0 0 20 20"
|
||||||
d="M7.707 10.293a1 1 0 1 0-1.414 1.414l3 3a1 1 0 0 0 1.414 0l3-3a1 1 0 0 0-1.414-1.414L11 11.586V6h5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5v5.586zM9 4a1 1 0 0 1 2 0v2H9z"
|
>
|
||||||
/>
|
<path
|
||||||
</svg>
|
fill="#f00"
|
||||||
</div>
|
d="M7.707 10.293a1 1 0 1 0-1.414 1.414l3 3a1 1 0 0 0 1.414 0l3-3a1 1 0 0 0-1.414-1.414L11 11.586V6h5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5v5.586zM9 4a1 1 0 0 1 2 0v2H9z"
|
||||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
/>
|
||||||
{video?.title}
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
||||||
|
{video?.title}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Link>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,551 @@
|
||||||
|
"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, CardContent } 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 { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { postBlog } from "@/service/blog/blog";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react";
|
||||||
|
import { detailMedia } from "@/service/curated-content/curated-content";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/free-mode";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/thumbs";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules";
|
||||||
|
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||||
|
|
||||||
|
const detailSchema = z.object({
|
||||||
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
categoryName: 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." }),
|
||||||
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Category = {
|
||||||
|
id: string;
|
||||||
|
categoryName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type curationDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
categoryName: string;
|
||||||
|
description: string;
|
||||||
|
uploadedBy: {
|
||||||
|
id: number;
|
||||||
|
fullname: string;
|
||||||
|
username: string | null;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
isInternational: boolean;
|
||||||
|
userLevel: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
aliasName: string;
|
||||||
|
userGroupId: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tags: string;
|
||||||
|
provinceId: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialComments = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
username: "Esther Howard",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Tolong untuk narasinya mengikuti 5W + 1H!",
|
||||||
|
avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
username: "Brooklyn Simmons",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏",
|
||||||
|
avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
username: "Leslie Alexander",
|
||||||
|
date: "07-04-2023 20:00 WIB",
|
||||||
|
text: "Sangat berguna. Terima Kasih!",
|
||||||
|
avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna
|
||||||
|
replies: [], // Komentar balasan
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DetailImage() {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { id } = useParams() as { id: string };
|
||||||
|
console.log(id);
|
||||||
|
const editor = useRef(null);
|
||||||
|
type DetailSchema = z.infer<typeof detailSchema>;
|
||||||
|
|
||||||
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
|
const taskId = Cookies.get("taskId");
|
||||||
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
|
// const [detail, setDetail] = useState({
|
||||||
|
// title: null,
|
||||||
|
// tags: null,
|
||||||
|
// files: [],
|
||||||
|
// fileType: null,
|
||||||
|
// });
|
||||||
|
const [detail, setDetail] = useState<curationDetail>();
|
||||||
|
const [refresh] = useState(false);
|
||||||
|
const [detailVideo, setDetailVideo] = useState<any>([]);
|
||||||
|
const [detailThumb, setDetailThumb] = useState<any>([]);
|
||||||
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<DetailSchema>({
|
||||||
|
resolver: zodResolver(detailSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const [commentsData, setCommentsData] = useState(initialComments);
|
||||||
|
const [replyText, setReplyText] = useState("");
|
||||||
|
const [replyingTo, setReplyingTo] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleReply = (commentId: number) => {
|
||||||
|
setReplyingTo(commentId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addReply = (commentId: number) => {
|
||||||
|
if (replyText.trim()) {
|
||||||
|
const newCommentData = commentsData.map((comment: any) => {
|
||||||
|
if (comment.id === commentId) {
|
||||||
|
return {
|
||||||
|
...comment,
|
||||||
|
replies: [
|
||||||
|
...comment.replies,
|
||||||
|
{
|
||||||
|
text: replyText,
|
||||||
|
username: "You",
|
||||||
|
date: new Date().toLocaleString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
setCommentsData(newCommentData);
|
||||||
|
setReplyText("");
|
||||||
|
setReplyingTo(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function initState() {
|
||||||
|
if (id) {
|
||||||
|
const response = await detailMedia(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
|
setDetail(details);
|
||||||
|
const filesData = details.files || [];
|
||||||
|
const fileUrls = filesData.map((file: { url: string }) =>
|
||||||
|
file.url ? file.url : "default-image.jpg"
|
||||||
|
);
|
||||||
|
setDetailVideo(fileUrls);
|
||||||
|
const filesDataThumbnail = details.files || [];
|
||||||
|
const fileUrlsThumbnail = filesDataThumbnail.map(
|
||||||
|
(file: { thumbnailFileUrl: string }) =>
|
||||||
|
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg"
|
||||||
|
);
|
||||||
|
setDetailThumb(fileUrlsThumbnail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-10">
|
||||||
|
{detail !== undefined ? (
|
||||||
|
<Card className="w-full ">
|
||||||
|
<div className="px-6 py-6">
|
||||||
|
<p className="text-lg font-semibold mb-3">Kurasi Detail</p>
|
||||||
|
<CardContent className="border rounded-md">
|
||||||
|
<div className="flex flex-row gap-10">
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label>Judul</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="title"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.title?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.title.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="py-3 w-full">
|
||||||
|
<Label>Kategori</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="categoryName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
size="md"
|
||||||
|
type="text"
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Title"
|
||||||
|
defaultValue={detail.categoryName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Description</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Textarea
|
||||||
|
value={detail.description}
|
||||||
|
onChange={field.onChange}
|
||||||
|
placeholder="Enter Meta"
|
||||||
|
cols={5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<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="umum">Umum</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="2" id="amplification" />
|
||||||
|
<Label htmlFor="ksp">Ksp</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="3" id="contra" />
|
||||||
|
<Label htmlFor="journalist">Journalist</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="4" id="contra" />
|
||||||
|
<Label htmlFor="polri">Polri</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Tag</Label>
|
||||||
|
<p className="border rounded-md text-blue-600 px-2 py-2">
|
||||||
|
{detail?.tags}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>
|
||||||
|
{" "}
|
||||||
|
{detail?.uploadedBy?.fullname ||
|
||||||
|
"Data tidak tersedia"}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=" py-3">
|
||||||
|
<div className="flex flex-row items-center gap-2 text-blue-500">
|
||||||
|
<InboxIcon />
|
||||||
|
<p className="text-blue-500">Kotak Saran (0)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button>Content Rewrite</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent className="border rounded-md mt-5">
|
||||||
|
<div className="flex flex-row gap-5">
|
||||||
|
<div className="w-6/12 border px-3 mt-3 rounded-md">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="space-y-2 py-3">
|
||||||
|
<Label className="text-xl text-black">File Media</Label>
|
||||||
|
<div className="w-full">
|
||||||
|
<Swiper
|
||||||
|
thumbs={{ swiper: thumbsSwiper }}
|
||||||
|
modules={[FreeMode, Navigation, Thumbs]}
|
||||||
|
navigation={false}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{detailVideo?.map((data: any) => (
|
||||||
|
<SwiperSlide key={data.id}>
|
||||||
|
<video
|
||||||
|
className="object-fill h-full w-full"
|
||||||
|
src={data}
|
||||||
|
controls
|
||||||
|
title={`Video ${data.id}`} // Mengganti alt dengan title
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
<div className="mt-2">
|
||||||
|
<Swiper
|
||||||
|
onSwiper={setThumbsSwiper}
|
||||||
|
slidesPerView={6}
|
||||||
|
spaceBetween={8}
|
||||||
|
pagination={{
|
||||||
|
clickable: true,
|
||||||
|
}}
|
||||||
|
modules={[Pagination, Thumbs]}
|
||||||
|
>
|
||||||
|
{detailVideo?.map((data: any) => (
|
||||||
|
<SwiperSlide key={data.id}>
|
||||||
|
<video
|
||||||
|
className="object-cover h-[60px] w-[80px]"
|
||||||
|
src={data}
|
||||||
|
muted
|
||||||
|
title={`Video ${data.id}`} // Mengganti alt dengan title
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12 border px-3 rounded-md mt-3">
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">
|
||||||
|
Penempatan File
|
||||||
|
</Label>
|
||||||
|
<div className="flex flex-row justify-between items-center">
|
||||||
|
<p>file</p>
|
||||||
|
<p>Penempatan</p>
|
||||||
|
</div>
|
||||||
|
<p className="bg-black h-1 w-full rounded-lg"></p>
|
||||||
|
{detailThumb?.map((data: any) => (
|
||||||
|
<div
|
||||||
|
key={data.id}
|
||||||
|
className="flex items-center gap-3 mt-2"
|
||||||
|
>
|
||||||
|
{/* <img
|
||||||
|
className="object-cover w-20 h-20"
|
||||||
|
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||||
|
alt={`Thumbnail ${index}`}
|
||||||
|
/> */}
|
||||||
|
<img
|
||||||
|
className="object-cover w-36 h-32"
|
||||||
|
src={data}
|
||||||
|
alt={` ${data.id}`}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-row gap-3 items-center">
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Nasional"
|
||||||
|
/>
|
||||||
|
Nasional
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="Wilayah"
|
||||||
|
/>
|
||||||
|
Wilayah
|
||||||
|
</label>
|
||||||
|
<label className="text-blue-500 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="placement"
|
||||||
|
value="International"
|
||||||
|
/>
|
||||||
|
International
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
<div className="gap-5 mb-5">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Berikan Komentar</Label>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="/images/avatar/avatar-1.png"
|
||||||
|
alt="@shadcn"
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="flex-grow p-2 border rounded-lg focus:outline-none focus:border-yellow-400"
|
||||||
|
placeholder="Tuliskan komentar Anda di sini.."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-2 gap-3">
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<PaperclipIcon className="w-5 h-5" />
|
||||||
|
Lampirkan
|
||||||
|
</button>
|
||||||
|
<button className="flex items-center text-gray-600 hover:text-gray-800">
|
||||||
|
<SmileIcon className="w-5 h-5" />
|
||||||
|
Emoticon
|
||||||
|
</button>
|
||||||
|
<button className="ml-auto px-4 py-1 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600">
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label className="text-xl text-black">Komentar</Label>
|
||||||
|
{commentsData.map((comment) => (
|
||||||
|
<div
|
||||||
|
key={comment.id}
|
||||||
|
className="flex items-start gap-3 mt-2"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src={comment.avatar}
|
||||||
|
alt={`@${comment.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{comment.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{comment.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">{comment.text}</p>
|
||||||
|
<div
|
||||||
|
className="flex items-center mt-1 text-blue-500 cursor-pointer"
|
||||||
|
onClick={() => handleReply(comment.id)}
|
||||||
|
>
|
||||||
|
<DotSquare className="w-4 h-4" />
|
||||||
|
<span className="ml-1">Balas</span>
|
||||||
|
</div>
|
||||||
|
{comment.replies.length > 0 && (
|
||||||
|
<div className="ml-8 mt-2">
|
||||||
|
{comment.replies.map((reply: any, index: any) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-start gap-3 mt-1"
|
||||||
|
>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage
|
||||||
|
src="https://github.com/shadcn.png"
|
||||||
|
alt={`@${reply.username}`}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-gray-700 font-semibold">
|
||||||
|
{reply.username}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-500 text-sm">
|
||||||
|
{reply.date}
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-800 mt-1">
|
||||||
|
{reply.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{replyingTo !== null && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md"
|
||||||
|
rows={3}
|
||||||
|
placeholder="Tulis balasan..."
|
||||||
|
value={replyText}
|
||||||
|
onChange={(e) => setReplyText(e.target.value)}
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
className="mt-2 bg-yellow-500 text-white px-4 py-2 rounded-md"
|
||||||
|
onClick={() => addReply(replyingTo)}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,352 @@
|
||||||
|
"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 } from "@/service/task";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
import { CalendarIcon } from "lucide-react";
|
||||||
|
import { id } from "date-fns/locale";
|
||||||
|
import { getPlanningById } from "@/service/planning/planning";
|
||||||
|
|
||||||
|
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 mediahubDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
fileTypeOutput: string;
|
||||||
|
assignedToTopLevel: string;
|
||||||
|
assignmentType: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
date: string;
|
||||||
|
description: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PublishMediahub() {
|
||||||
|
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);
|
||||||
|
const [taskOutput, setTaskOutput] = useState({
|
||||||
|
all: false,
|
||||||
|
video: false,
|
||||||
|
audio: false,
|
||||||
|
image: false,
|
||||||
|
text: false,
|
||||||
|
});
|
||||||
|
const [mainType, setMainType] = useState<number>(1);
|
||||||
|
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||||
|
const [broadcastType, setBroadcastType] = useState<string>("all"); // untuk Tipe Penugasan
|
||||||
|
const [type, setType] = useState<string>("1");
|
||||||
|
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||||
|
const [startDate, setStartDate] = useState<Date>(new Date());
|
||||||
|
const [detail, setDetail] = useState<mediahubDetail>();
|
||||||
|
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 getPlanningById(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
|
setDetail(details);
|
||||||
|
if (details?.date) {
|
||||||
|
setStartDate(new Date(details.date)); // Konversi string tanggal ke objek Date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
|
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)
|
||||||
|
); // Membagi string ke dalam array dan mengonversi ke nomor
|
||||||
|
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">Perencanaan Mediahub</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="mt-5">
|
||||||
|
<Label>Output Tugas</Label>
|
||||||
|
<div className="flex flex-wrap gap-3 mt-1">
|
||||||
|
{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-row items-center">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label>Pelaksana Tugas</Label>
|
||||||
|
<div className="flex flex-wrap mt-1 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>
|
||||||
|
<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">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Label>Date</Label>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
value={detail.date}
|
||||||
|
variant="outline"
|
||||||
|
size="md"
|
||||||
|
className={cn(
|
||||||
|
" justify-between text-left font-normal border-default-200 text-default-600 md:px-4 w-3/12",
|
||||||
|
!startDate && "text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{startDate ? (
|
||||||
|
format(startDate, "PP")
|
||||||
|
) : (
|
||||||
|
<span>Pick a date</span>
|
||||||
|
)}
|
||||||
|
<CalendarIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label>Narasi Penugasan</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="naration"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<JoditEditor
|
||||||
|
ref={editor}
|
||||||
|
value={detail?.description}
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,352 @@
|
||||||
|
"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 } from "@/service/task";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
import { CalendarIcon } from "lucide-react";
|
||||||
|
import { id } from "date-fns/locale";
|
||||||
|
import { getPlanningById } from "@/service/planning/planning";
|
||||||
|
|
||||||
|
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 medsosDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
fileTypeOutput: string;
|
||||||
|
assignedToTopLevel: string;
|
||||||
|
assignmentType: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
date: string;
|
||||||
|
description: string;
|
||||||
|
is_active: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PublishMedsos() {
|
||||||
|
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);
|
||||||
|
const [taskOutput, setTaskOutput] = useState({
|
||||||
|
all: false,
|
||||||
|
video: false,
|
||||||
|
audio: false,
|
||||||
|
image: false,
|
||||||
|
text: false,
|
||||||
|
});
|
||||||
|
const [mainType, setMainType] = useState<number>(1);
|
||||||
|
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||||
|
const [broadcastType, setBroadcastType] = useState<string>("all"); // untuk Tipe Penugasan
|
||||||
|
const [type, setType] = useState<string>("1");
|
||||||
|
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||||
|
const [startDate, setStartDate] = useState<Date>(new Date());
|
||||||
|
const [detail, setDetail] = useState<medsosDetail>();
|
||||||
|
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 getPlanningById(id);
|
||||||
|
const details = response.data?.data;
|
||||||
|
|
||||||
|
setDetail(details);
|
||||||
|
if (details?.date) {
|
||||||
|
setStartDate(new Date(details.date)); // Konversi string tanggal ke objek Date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initState();
|
||||||
|
}, [id, refresh]);
|
||||||
|
|
||||||
|
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)
|
||||||
|
); // Membagi string ke dalam array dan mengonversi ke nomor
|
||||||
|
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">Perencanaan Mediahub</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="mt-5">
|
||||||
|
<Label>Output Tugas</Label>
|
||||||
|
<div className="flex flex-wrap gap-3 mt-1">
|
||||||
|
{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-row items-center">
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label>Pelaksana Tugas</Label>
|
||||||
|
<div className="flex flex-wrap mt-1 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>
|
||||||
|
<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">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Label>Date</Label>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
value={detail.date}
|
||||||
|
variant="outline"
|
||||||
|
size="md"
|
||||||
|
className={cn(
|
||||||
|
" justify-between text-left font-normal border-default-200 text-default-600 md:px-4 w-3/12",
|
||||||
|
!startDate && "text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{startDate ? (
|
||||||
|
format(startDate, "PP")
|
||||||
|
) : (
|
||||||
|
<span>Pick a date</span>
|
||||||
|
)}
|
||||||
|
<CalendarIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-5">
|
||||||
|
<Label>Narasi Penugasan</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="naration"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<JoditEditor
|
||||||
|
ref={editor}
|
||||||
|
value={detail?.description}
|
||||||
|
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,5 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -20,7 +20,7 @@ import {
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
import JoditEditor from "jodit-react";
|
import JoditEditor from "jodit-react";
|
||||||
import { createTask } from "@/service/task";
|
import { createTask, getTask } from "@/service/task";
|
||||||
|
|
||||||
const taskSchema = z.object({
|
const taskSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
|
@ -29,11 +29,32 @@ const taskSchema = z.object({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 FormTask() {
|
export default function FormTask() {
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type TaskSchema = z.infer<typeof taskSchema>;
|
type TaskSchema = z.infer<typeof taskSchema>;
|
||||||
|
const { id } = useParams() as { id: string };
|
||||||
|
console.log(id);
|
||||||
|
|
||||||
// State for various form fields
|
// State for various form fields
|
||||||
const [taskOutput, setTaskOutput] = useState({
|
const [taskOutput, setTaskOutput] = useState({
|
||||||
|
|
@ -46,11 +67,13 @@ export default function FormTask() {
|
||||||
|
|
||||||
// const [assignmentType, setAssignmentType] = useState("mediahub");
|
// const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||||
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||||
const [mainType, setMainType] = useState<number>(1);
|
const [mainType, setMainType] = useState<string>("1");
|
||||||
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||||
const [broadcastType, setBroadcastType] = useState<string>("all"); // untuk Tipe Penugasan
|
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
|
||||||
const [type, setType] = useState<string>("1");
|
const [type, setType] = useState<string>("1");
|
||||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||||
|
const [detail, setDetail] = useState<taskDetail>();
|
||||||
|
const [refresh] = useState(false);
|
||||||
|
|
||||||
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
|
|
@ -68,12 +91,57 @@ export default function FormTask() {
|
||||||
resolver: zodResolver(taskSchema),
|
resolver: zodResolver(taskSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const selectedValue = Number(event.target.value);
|
// const selectedValue = Number(event.target.value);
|
||||||
setMainType(selectedValue);
|
// setMainType(selectedValue);
|
||||||
|
|
||||||
setPlatformTypeVisible(selectedValue === 2);
|
// 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 save = async (data: TaskSchema) => {
|
||||||
const fileTypeMapping = {
|
const fileTypeMapping = {
|
||||||
|
|
@ -144,172 +212,184 @@ export default function FormTask() {
|
||||||
<Card>
|
<Card>
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Form Penugasan</p>
|
<p className="text-lg font-semibold mb-3">Form Penugasan</p>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
{detail !== undefined ? (
|
||||||
<div className="gap-5 mb-5">
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
{/* Input Title */}
|
<div className="gap-5 mb-5">
|
||||||
<div className="space-y-2">
|
{/* Input Title */}
|
||||||
<Label>Judul</Label>
|
<div className="space-y-2">
|
||||||
<Controller
|
<Label>Judul</Label>
|
||||||
control={control}
|
<Controller
|
||||||
name="title"
|
control={control}
|
||||||
render={({ field }) => (
|
name="title"
|
||||||
<Input
|
render={({ field }) => (
|
||||||
size="md"
|
<Input
|
||||||
type="text"
|
size="md"
|
||||||
value={field.value}
|
type="text"
|
||||||
onChange={field.onChange}
|
value={detail?.title}
|
||||||
placeholder="Enter Title"
|
onChange={field.onChange}
|
||||||
/>
|
placeholder="Enter Title"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.title?.message && (
|
||||||
|
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||||
)}
|
)}
|
||||||
/>
|
</div>
|
||||||
{errors.title?.message && (
|
<div className="flex flex-row items-center">
|
||||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
<div className="mt-5">
|
||||||
)}
|
<Label>Tujuan Pemilihan Tugas</Label>
|
||||||
</div>
|
<Select onValueChange={setSelectedTarget}>
|
||||||
<div className="flex flex-row items-center">
|
<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">
|
<div className="mt-5">
|
||||||
<Label>Tujuan Pemilihan Tugas</Label>
|
<Label>Tipe Penugasan</Label>
|
||||||
<Select onValueChange={setSelectedTarget}>
|
<RadioGroup
|
||||||
<SelectTrigger size="md">
|
value={detail.assignmentMainType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||||
<SelectValue placeholder="Pilih" />
|
onValueChange={(value) => setMainType(value)}
|
||||||
</SelectTrigger>
|
// value={String(mainType)}
|
||||||
<SelectContent>
|
// onValueChange={(value) => setMainType(Number(value))}
|
||||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
className="flex flex-wrap gap-3"
|
||||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
>
|
||||||
<SelectItem value="approver">Approver</SelectItem>
|
<RadioGroupItem value="1" id="mediahub" />
|
||||||
</SelectContent>
|
<Label htmlFor="mediahub">Mediahub</Label>
|
||||||
</Select>
|
<RadioGroupItem value="2" id="medsos-mediahub" />
|
||||||
|
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
|
||||||
|
</RadioGroup>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-3 mt-5 pt-5 ml-3">
|
<div className="mt-5">
|
||||||
{Object.keys(unitSelection).map((key) => (
|
<Label>Jenis Tugas </Label>
|
||||||
<div className="flex items-center gap-2" key={key}>
|
<RadioGroup
|
||||||
<Checkbox
|
value={detail.taskType.toString()}
|
||||||
id={key}
|
onValueChange={(value) => setTaskType(String(value))}
|
||||||
checked={unitSelection[key as keyof typeof unitSelection]}
|
className="flex flex-wrap gap-3"
|
||||||
onCheckedChange={(value) =>
|
>
|
||||||
setUnitSelection({ ...unitSelection, [key]: value })
|
<RadioGroupItem value="atensi-khusus" id="khusus" />
|
||||||
}
|
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
||||||
/>
|
<RadioGroupItem value="tugas-harian" id="harian" />
|
||||||
<Label htmlFor={key}>
|
<Label htmlFor="tugas-harian">Tugas Harian</Label>
|
||||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
</RadioGroup>
|
||||||
</Label>
|
</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>
|
||||||
))}
|
<div className="flex items-center gap-2">
|
||||||
</div>
|
<RadioGroupItem value="2" id="amplification" />
|
||||||
</div>
|
<Label htmlFor="amplification">Amplifikasi</Label>
|
||||||
|
|
||||||
<div className="mt-5">
|
|
||||||
<Label>Tipe Penugasan</Label>
|
|
||||||
<RadioGroup
|
|
||||||
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={String(taskType)}
|
|
||||||
onValueChange={(value) => setTaskType(String(value))}
|
|
||||||
className="flex flex-wrap gap-3"
|
|
||||||
>
|
|
||||||
<RadioGroupItem value="atensi-khusus" id="mediahub" />
|
|
||||||
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
|
||||||
<RadioGroupItem value="tugas-harian" id="medsos-mediahub" />
|
|
||||||
<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 className="flex items-center gap-2">
|
||||||
|
<RadioGroupItem value="3" id="contra" />
|
||||||
|
<Label htmlFor="contra">Kontra</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="mt-5">
|
||||||
<div className="mt-5">
|
<Label>Output Tugas</Label>
|
||||||
<Label>Broadcast </Label>
|
<div className="flex flex-wrap gap-3">
|
||||||
<RadioGroup
|
{Object.keys(taskOutput).map((key) => (
|
||||||
value={String(broadcastType)}
|
<div className="flex items-center gap-2" key={key}>
|
||||||
onValueChange={(value) => setBroadcastType(String(value))}
|
<Checkbox
|
||||||
className="flex flex-wrap gap-3"
|
id={key}
|
||||||
>
|
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||||
<RadioGroupItem value="all" id="mediahub" />
|
onCheckedChange={(value) =>
|
||||||
<Label htmlFor="all">Semua</Label>
|
setTaskOutput({ ...taskOutput, [key]: value })
|
||||||
<RadioGroupItem value="email" id="medsos-mediahub" />
|
}
|
||||||
<Label htmlFor="email-blast">Email Blast</Label>
|
/>
|
||||||
<RadioGroupItem value="whatsapp" id="medsos-mediahub" />
|
<Label htmlFor={key}>
|
||||||
<Label htmlFor="whatsapp-blast">WhatsApp Blast</Label>
|
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||||
</RadioGroup>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
))}
|
||||||
<Label>Narasi Penugasan</Label>
|
</div>
|
||||||
<Controller
|
</div>
|
||||||
control={control}
|
<div className="mt-5">
|
||||||
name="naration"
|
<Label>Broadcast </Label>
|
||||||
render={({ field: { onChange, value } }) => (
|
<RadioGroup
|
||||||
<JoditEditor
|
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
|
||||||
ref={editor}
|
onValueChange={(value) => setBroadcastType(value)} // Mengatur nilai saat radio berubah
|
||||||
value={value}
|
className="flex flex-wrap gap-3"
|
||||||
onChange={onChange}
|
>
|
||||||
className="dark:text-black"
|
<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>
|
||||||
{errors.naration?.message && (
|
|
||||||
<p className="text-red-400 text-sm">
|
|
||||||
{errors.naration.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<Button type="submit" color="primary">
|
<Button type="submit" color="primary">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { getAPIInterceptor } from "@/config/api";
|
||||||
|
|
||||||
|
export async function detailMedia(id: any) {
|
||||||
|
const url = `media?id=${id}`;
|
||||||
|
return getAPIInterceptor(url);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { getAPIInterceptor } from "@/config/api";
|
||||||
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
|
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
|
||||||
|
|
||||||
export async function getPlanningSentPagination(
|
export async function getPlanningSentPagination(
|
||||||
|
|
@ -10,3 +11,8 @@ export async function getPlanningSentPagination(
|
||||||
`planning/pagination/sent?enablePage=1&size=${size}&page=${page}&typeId=${typeId}&title=${title}`
|
`planning/pagination/sent?enablePage=1&size=${size}&page=${page}&typeId=${typeId}&title=${title}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getPlanningById(id: any) {
|
||||||
|
const url = `planning?id=${id}`;
|
||||||
|
return getAPIInterceptor(url);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export async function createTask(data: any) {
|
||||||
|
|
||||||
export async function getTask(id: any) {
|
export async function getTask(id: any) {
|
||||||
const url = `/assignment?id=${id}`;
|
const url = `/assignment?id=${id}`;
|
||||||
return getAPIInterceptor({ url });
|
return getAPIInterceptor(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function forwardTask(data: any) {
|
export async function forwardTask(data: any) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue