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 className="flex-none">
|
||||
<Link href={"/contributor/blog/create"}>
|
||||
<Button fullWidth size="md" color="primary">
|
||||
<Button fullWidth color="primary">
|
||||
<Plus className="w-6 h-6 me-1.5" />
|
||||
Add Index
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -91,15 +92,18 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -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 { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -91,14 +92,15 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="flex justify-between items-center px-5">
|
||||
<div className="flex justify-between items-center px-5 mt-3">
|
||||
<div>
|
||||
<InputGroup merged>
|
||||
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -111,10 +112,12 @@ const columns: ColumnDef<any>[] = [
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import PressConferenceTable from "../contributor/schedule/press-release/componen
|
|||
import BlogTable from "../contributor/blog/components/blog-table";
|
||||
import ContentTable from "./routine-task/components/content-table";
|
||||
import RecentActivity from "./routine-task/components/recent-activity";
|
||||
import { Link } from "@/components/navigation";
|
||||
|
||||
const DashboardPage = () => {
|
||||
const t = useTranslations("AnalyticsDashboard");
|
||||
|
|
@ -110,14 +111,16 @@ const DashboardPage = () => {
|
|||
Table Penugasan
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
</Button>
|
||||
<Link href={"/contributor/task/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Buat Penugasan
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 mt-3">
|
||||
<TaskTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -128,7 +131,7 @@ const DashboardPage = () => {
|
|||
<div className="grid grid-cols-12 gap-5">
|
||||
<div className="lg:col-span-12 col-span-12">
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 ">
|
||||
<PressConferenceTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -145,14 +148,16 @@ const DashboardPage = () => {
|
|||
Table Indeks
|
||||
</div>
|
||||
<div>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Tambah Indeks
|
||||
</Button>
|
||||
<Link href={"/contributor/blog/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon />
|
||||
Tambah Indeks
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<CardContent className="p-0">
|
||||
<CardContent className="p-0 mt-3">
|
||||
<BlogTable />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ const AudioSliderPage = () => {
|
|||
<div className="mx-3 px-5">
|
||||
<div className=" grid grid-cols-1 gap-6 ">
|
||||
{displayAudio?.map((audio: any) => (
|
||||
<a
|
||||
href="#"
|
||||
<Link
|
||||
href={`/shared/curated-content//giat-routine/audio/detail/${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"
|
||||
>
|
||||
|
|
@ -118,7 +118,7 @@ const AudioSliderPage = () => {
|
|||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</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=" grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{displayDocument?.map((document: any) => (
|
||||
<a
|
||||
href="#"
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/document/detail/${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"
|
||||
>
|
||||
|
|
@ -105,7 +105,7 @@ const TeksSliderPage = () => {
|
|||
Download Dokumen
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||
import * as z from "zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -17,25 +17,26 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import JoditEditor from "jodit-react";
|
||||
import { register } from "module";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import Cookies from "js-cookie";
|
||||
import { createTask } from "@/config/api";
|
||||
import {
|
||||
createMedia,
|
||||
getTagsBySubCategoryId,
|
||||
listEnableCategory,
|
||||
} from "@/service/content/content";
|
||||
import { postBlog } from "@/service/blog/blog";
|
||||
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" }),
|
||||
slug: 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()
|
||||
|
|
@ -45,130 +46,151 @@ const taskSchema = z.object({
|
|||
|
||||
type Category = {
|
||||
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",
|
||||
name: "Giat Polri",
|
||||
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",
|
||||
name: "Giat Pimpinan",
|
||||
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",
|
||||
name: "Liputan Kegiatan",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "Seputar Prestasi",
|
||||
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 router = useRouter();
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
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 [categories] = useState<Category[]>(initialCategories); // State untuk kategori
|
||||
const [selectedTarget, setSelectedTarget] = useState("");
|
||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [isDraft, setIsDraft] = useState(false);
|
||||
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
allUnit: false,
|
||||
mabes: false,
|
||||
polda: false,
|
||||
polres: false,
|
||||
});
|
||||
|
||||
let fileTypeId = "1";
|
||||
// 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<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
} = useForm<DetailSchema>({
|
||||
resolver: zodResolver(detailSchema),
|
||||
});
|
||||
|
||||
const handleRemoveTag = (index: any) => {
|
||||
setTags((prevTags) => prevTags.filter((_, i) => i !== index));
|
||||
const [commentsData, setCommentsData] = useState(initialComments);
|
||||
const [replyText, setReplyText] = useState("");
|
||||
const [replyingTo, setReplyingTo] = useState<number | null>(null);
|
||||
|
||||
const handleReply = (commentId: number) => {
|
||||
setReplyingTo(commentId);
|
||||
};
|
||||
|
||||
const handleImageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files) {
|
||||
const files = Array.from(event.target.files);
|
||||
setSelectedFiles((prevImages: any) => [...prevImages, ...files]);
|
||||
console.log("DATAFILE::", selectedFiles);
|
||||
const 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);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveImage = (index: number) => {
|
||||
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
||||
};
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (id) {
|
||||
const response = await detailMedia(id);
|
||||
const details = response.data?.data;
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
categoryId: selectedTarget,
|
||||
slug: data.slug,
|
||||
metadata: data.meta,
|
||||
// tags: data.tags,
|
||||
isDraft,
|
||||
};
|
||||
|
||||
const response = await postBlog(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/contributor/blog");
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
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 (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="flex gap-10">
|
||||
<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-5">
|
||||
<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">
|
||||
|
|
@ -183,6 +205,7 @@ export default function DetailImage() {
|
|||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
defaultValue={detail.title}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -195,27 +218,20 @@ export default function DetailImage() {
|
|||
<div className="flex items-center">
|
||||
<div className="py-3 w-full">
|
||||
<Label>Kategori</Label>
|
||||
<Select
|
||||
value={selectedTarget} // Ensure selectedTarget is updated correctly
|
||||
onValueChange={(value) => {
|
||||
console.log("Selected Category ID:", value);
|
||||
setSelectedTarget(value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{categories.map((category) => (
|
||||
<SelectItem
|
||||
key={category.id}
|
||||
value={category.name}
|
||||
>
|
||||
{category.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<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">
|
||||
|
|
@ -223,18 +239,19 @@ export default function DetailImage() {
|
|||
<Label>Description</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="meta"
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
value={field.value}
|
||||
value={detail.description}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Meta"
|
||||
cols={5}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.meta?.message && (
|
||||
{errors.description?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.meta.message}
|
||||
{errors.description.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -271,29 +288,18 @@ export default function DetailImage() {
|
|||
<div className=" py-3">
|
||||
<div className="space-y-2">
|
||||
<Label>Tag</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="slug"
|
||||
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>
|
||||
)}
|
||||
<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>Kontributor</Label>
|
||||
<Label>
|
||||
{" "}
|
||||
{detail?.uploadedBy?.fullname ||
|
||||
"Data tidak tersedia"}
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className=" py-3">
|
||||
|
|
@ -314,24 +320,46 @@ export default function DetailImage() {
|
|||
<div className="gap-5 mb-5">
|
||||
<div className="space-y-2 py-3">
|
||||
<Label className="text-xl text-black">File Media</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.title.message}
|
||||
</p>
|
||||
)}
|
||||
<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}>
|
||||
<img
|
||||
className="object-fill h-full w-full"
|
||||
src={data}
|
||||
alt={` ${data.id}`}
|
||||
/>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</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>
|
||||
|
|
@ -346,14 +374,170 @@ export default function DetailImage() {
|
|||
<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>
|
||||
</form>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const VideoSliderPage = () => {
|
||||
|
|
@ -53,32 +55,36 @@ const VideoSliderPage = () => {
|
|||
key={video?.id}
|
||||
className="hover:scale-110 transition-transform duration-300"
|
||||
>
|
||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
||||
/>
|
||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||
{video?.timezone || "WIB"} |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{video?.clickCount}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
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"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<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
|
||||
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
||||
>
|
||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
||||
/>
|
||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||
{video?.timezone || "WIB"} |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{video?.clickCount}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
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"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<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>
|
||||
))}
|
||||
</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";
|
||||
import React, { useRef, useState } from "react";
|
||||
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";
|
||||
|
|
@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||
import * as z from "zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -20,7 +20,7 @@ import {
|
|||
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 { createTask, getTask } from "@/service/task";
|
||||
|
||||
const taskSchema = z.object({
|
||||
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() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
|
||||
// State for various form fields
|
||||
const [taskOutput, setTaskOutput] = useState({
|
||||
|
|
@ -46,11 +67,13 @@ export default function FormTask() {
|
|||
|
||||
// const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
// 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 [broadcastType, setBroadcastType] = useState<string>("all"); // untuk Tipe Penugasan
|
||||
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
|
||||
const [type, setType] = useState<string>("1");
|
||||
const [selectedTarget, setSelectedTarget] = useState("all");
|
||||
const [detail, setDetail] = useState<taskDetail>();
|
||||
const [refresh] = useState(false);
|
||||
|
||||
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
|
|
@ -68,12 +91,57 @@ export default function FormTask() {
|
|||
resolver: zodResolver(taskSchema),
|
||||
});
|
||||
|
||||
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedValue = Number(event.target.value);
|
||||
setMainType(selectedValue);
|
||||
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const selectedValue = Number(event.target.value);
|
||||
// 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 fileTypeMapping = {
|
||||
|
|
@ -144,172 +212,184 @@ export default function FormTask() {
|
|||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">Form Penugasan</p>
|
||||
<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={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
{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>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row items-center">
|
||||
</div>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="mt-5">
|
||||
<Label>Tujuan Pemilihan Tugas</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
||||
<SelectItem value="approver">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 mt-5 pt-5 ml-3">
|
||||
{Object.keys(unitSelection).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={
|
||||
unitSelection[key as keyof typeof unitSelection]
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Tujuan Pemilihan Tugas</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="contributor">Kontributor</SelectItem>
|
||||
<SelectItem value="approver">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Label>Tipe Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentMainType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setMainType(value)}
|
||||
// value={String(mainType)}
|
||||
// onValueChange={(value) => setMainType(Number(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="1" id="mediahub" />
|
||||
<Label htmlFor="mediahub">Mediahub</Label>
|
||||
<RadioGroupItem value="2" id="medsos-mediahub" />
|
||||
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="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 className="mt-5">
|
||||
<Label>Jenis Tugas </Label>
|
||||
<RadioGroup
|
||||
value={detail.taskType.toString()}
|
||||
onValueChange={(value) => setTaskType(String(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="atensi-khusus" id="khusus" />
|
||||
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
|
||||
<RadioGroupItem value="tugas-harian" id="harian" />
|
||||
<Label htmlFor="tugas-harian">Tugas Harian</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
{/* RadioGroup Assignment Category */}
|
||||
<div className="mt-5">
|
||||
<Label>Jenis Penugasan</Label>
|
||||
<RadioGroup
|
||||
value={detail.assignmentType.id.toString()} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="1" id="publication" />
|
||||
<Label htmlFor="publication">Publikasi</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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 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>
|
||||
<div className="mt-5">
|
||||
<Label>Broadcast </Label>
|
||||
<RadioGroup
|
||||
value={String(broadcastType)}
|
||||
onValueChange={(value) => setBroadcastType(String(value))}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<RadioGroupItem value="all" id="mediahub" />
|
||||
<Label htmlFor="all">Semua</Label>
|
||||
<RadioGroupItem value="email" id="medsos-mediahub" />
|
||||
<Label htmlFor="email-blast">Email Blast</Label>
|
||||
<RadioGroupItem value="whatsapp" id="medsos-mediahub" />
|
||||
<Label htmlFor="whatsapp-blast">WhatsApp Blast</Label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="naration"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
<div className="mt-5">
|
||||
<Label>Output Tugas</Label>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{Object.keys(taskOutput).map((key) => (
|
||||
<div className="flex items-center gap-2" key={key}>
|
||||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Broadcast </Label>
|
||||
<RadioGroup
|
||||
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
|
||||
onValueChange={(value) => setBroadcastType(value)} // Mengatur nilai saat radio berubah
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="all" id="all" />
|
||||
<Label htmlFor="all">Semua</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="email" id="email" />
|
||||
<Label htmlFor="email">Email Blast</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="whatsapp" id="whatsapp" />
|
||||
<Label htmlFor="whatsapp">WhatsApp Blast</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="naration"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={detail?.narration}
|
||||
onChange={onChange}
|
||||
className="dark:text-black"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.naration?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.naration.message}
|
||||
</p>
|
||||
)}
|
||||
/>
|
||||
{errors.naration?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.naration.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
{/* Submit Button */}
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
</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";
|
||||
|
||||
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}`
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
const url = `/assignment?id=${id}`;
|
||||
return getAPIInterceptor({ url });
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
||||
export async function forwardTask(data: any) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue