mediahub-fe/components/form/communication/escalation-forward-form.tsx

501 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
"use client";
import React, { useEffect, 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 } from "next/navigation";
import {
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import {
getCuratorUser,
getEscalationDiscussion,
getQuestionTicket,
getTicketingDetail,
getTicketingInternalDetail,
getTicketingInternalDiscussion,
saveTicketInternalReply,
saveTicketsQuestion,
} from "@/service/communication/communication";
import { Textarea } from "@/components/ui/textarea";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Link } from "@/i18n/routing";
import { loading } from "@/lib/swal";
import { id } from "date-fns/locale";
import { DetailTicket } from "../ticketing/info-lainnya-types";
import { Description } from "@radix-ui/react-toast";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ChevronDownIcon } from "lucide-react";
import { getOperatorUser } from "@/service/management-user/management-user";
import makeAnimated from "react-select/animated";
import Select, { ActionMeta, MultiValue } from "react-select";
import { Checkbox } from "@/components/ui/checkbox";
interface Option {
id: string;
label: string;
value: string;
fullname: string;
userLevel: string;
userLevelId: string;
}
// const taskSchema = z.object({
// title: z.string().optional(),
// description: z.string().min(2, {
// message: "Narasi Penugasan harus lebih dari 2 karakter.",
// }),
// });
const taskSchema = z.object({
title: z.string().optional(),
description: z.string().min(2, {
message: "Narasi Penugasan harus lebih dari 2 karakter.",
}),
});
export type replyDetail = {
id: number;
message: string;
createdAt: string;
messageFrom: {
id: number;
fullname: string;
};
messageTo: {
id: number;
fullname: string;
};
};
const optionsData = [
{ value: "1", label: "Low" },
{ value: "2", label: "Medium" },
{ value: "3", label: "High" },
];
type OptionType = {
value: string;
label: string;
};
export default function FormQuestionsForward() {
const MySwal = withReactContent(Swal);
const { id } = useParams() as { id: string };
const [detail, setDetail] = useState<any>();
const [ticketReply, setTicketReply] = useState<replyDetail[]>([]);
const [replyVisible, setReplyVisible] = useState(false);
const [listDiscussion, setListDiscussion] = useState();
const [message, setMessage] = useState("");
const [detailTickets, setDetailTickets] = useState<DetailTicket | null>(null);
// const [selectedPriority, setSelectedPriority] = useState("");
const [selectedPriority, setSelectedPriority] = useState<OptionType | null>(
null
);
const [replyMessage, setReplyMessage] = useState("");
const [selectedStatus, setSelectedStatus] = useState("");
const [operatorOpt, setOperatorOpt] = useState<
{ id: string; label: string; value: string }[]
>([]);
const [selectedOperator, setSelectedOperator] = useState<string[]>([]);
const [options, setOptions] = useState<Option[]>([]);
const animatedComponent = makeAnimated();
const [isCollaboration, setIsCollaboration] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option[]>([]);
const [replies, setReplies] = useState([
{
id: 1,
name: "Mabes Polri - Approver",
message: "test",
timestamp: "2024-12-20 00:56:10",
},
{
id: 2,
name: "Mabes Polri - Approver",
message: "balas",
timestamp: "2025-01-18 17:42:48",
},
]);
const {
control,
handleSubmit,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(taskSchema),
defaultValues: {
title: "",
description: "",
},
});
useEffect(() => {
async function initState() {
const response = await getQuestionTicket(id);
const data = response?.data?.data;
setDetail(data);
if (data) {
reset({
title: data.message ?? "",
description: data.emergencyIssue?.description ?? "",
});
}
setDetailTickets(data);
if (detailTickets?.emergencyIssue) {
reset({
title: detailTickets.emergencyIssue.title || "",
description: detailTickets.emergencyIssue.description || "",
});
// setSelectedPriority(String(detailTickets.emergencyIssue.urgencyId));
// setSelectedStatus(String(detailTickets.statusId)); // jika ada
}
}
initState();
getTicketReply();
getUser();
}, [id, reset]);
useEffect(() => {
async function getOperator() {
const res = await getOperatorUser(detailTickets?.typeId);
if (res?.data !== null) {
const rawUser = res?.data?.data;
const optionArr = rawUser?.map((option: any) => ({
id: option.id,
label: option.fullName,
value: option.id,
}));
setOperatorOpt(optionArr);
}
}
getOperator();
}, [detailTickets]);
async function getTicketReply() {
const res = await getTicketingInternalDiscussion(id);
if (res?.data !== null) {
setTicketReply(res?.data?.data);
}
}
const onSubmit = async (data: any) => {
try {
const payload = {
id,
title: data.title,
description: data.description,
priorityId: selectedPriority?.value,
statusId: selectedStatus,
typeId: detailTickets?.typeId,
parentCommentId: detailTickets?.feedId,
operatorTeam: selectedOperator.join(","),
isEscalation: true,
communicationTeam: selectedOption.map((item) => item.id).join(","),
isCollaboration: isCollaboration,
};
const response = await saveTicketsQuestion(payload);
MySwal.fire({
title: "Sukses",
text: "Data berhasil diperbarui.",
icon: "success",
}).then(() => {
window.location.href = "/in/supervisor/communications/questions/all";
});
getTicketReply();
} catch (error) {
console.error("Gagal update:", error);
MySwal.fire({
title: "Error",
text: "Terjadi kesalahan saat memperbarui.",
icon: "error",
});
}
};
const handleChange = (
selected: MultiValue<Option>,
_actionMeta: ActionMeta<Option>
) => {
setSelectedOption([...selected]);
};
const formatOptionLabel = (option: Option) => (
<>
<div className="row">
<div className="col">
{option.value} | {option.fullname}
</div>
</div>
<div className="row">
<div className="col">
<b>{option.userLevel}</b>
</div>
</div>
</>
);
async function getUser() {
const res = await getCuratorUser();
if (res?.data !== null) {
const rawUser = res?.data?.data?.content;
console.log("raw user", rawUser);
const optionArr: Option[] = rawUser.map((option: any) => ({
id: option?.id,
label: option?.username + option?.fullname + option?.userLevel?.name,
value: option?.username,
fullname: option?.fullname,
userLevel: option?.userLevel?.name,
userLevelId: option?.userLevel?.id,
}));
setOptions(optionArr);
}
}
const handleSendReply = () => {
if (replyMessage.trim() === "") return;
const newReply = {
id: replies.length + 1,
name: "Mabes Polri - Approver",
message: replyMessage,
timestamp: new Date().toISOString().slice(0, 19).replace("T", " "),
};
setReplies([...replies, newReply]);
setReplyMessage("");
};
return (
<div>
<div className="flex">
<div className="flex flex-col mt-6 w-full mb-3">
{detail !== undefined && (
<div key={detail?.id} className="bg-slate-300 rounded-md">
<p className="p-5 bg-slate-300 rounded-md text-lg font-semibold">
Ticket #{detail.id}
</p>
<div className="flex flex-row gap-3 bg-sky-100 p-5 items-center">
<Icon icon="qlementine-icons:user-16" width={36} />
<div>
<p>
<span className="font-bold">
{detail?.commentFromUserName}
</span>
{` `}
mengirimkan pesan untuk{` `}
<Link
// href={
// detail?.feed
// ? detail?.feed?.permalink_url == undefined
// ? detail?.feedUrl
// : detail?.feed?.permalink_url
// : ""
// }
// target="_blank"
href={detail?.feedUrl}
className="font-bold"
>
{detail?.message}
</Link>
</p>
<p className="text-xs">
{`${new Date(detail?.createdAt).getDate()}-${
new Date(detail?.createdAt).getMonth() + 1
}-${new Date(detail?.createdAt).getFullYear()} ${new Date(
detail?.createdAt
).getHours()}:${new Date(detail?.createdAt).getMinutes()}`}
</p>
</div>
</div>
<p className="p-5 bg-white">{detail.message}</p>
</div>
)}
</div>
</div>
{detailTickets && (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="gap-5 mb-5 w-[100%] lg:w-auto border bg-white rounded-md">
<p className="mx-3 mt-3">Properties</p>
<div className="space-y-2 px-3">
<Label>Judul</Label>
{/* <Controller
control={control}
name="title"
render={({ field }) => (
<Input
size="md"
defaultValue={detailTickets?.message}
type="text"
{...field}
placeholder="Masukkan judul"
/>
)}
/> */}
<Controller
control={control}
name="title"
render={({ field }) => (
<Input
size="md"
type="text"
{...field}
placeholder="Masukkan judul"
/>
)}
/>
</div>
<div className="mt-5 px-3 space-y-3">
<Label>Prioritas</Label>
<Select
options={optionsData}
value={selectedPriority}
onChange={(option) => setSelectedPriority(option)}
placeholder="Pilih Prioritas"
/>
</div>
<div className="mt-5 px-3 mb-3 flex flex-col gap-y-3">
<Label>Operator</Label>
{selectedOperator.length > 0 && (
<div className="flex flex-row gap-2 mb-2">
{selectedOperator.map((id) => {
const label = operatorOpt.find(
(op: any) => op.value === id
)?.label;
return (
<div
key={id}
className="flex items-center justify-between bg-gray-200 px-3 py-1 rounded"
>
<span>{label}</span>
<button
type="button"
onClick={() =>
setSelectedOperator((prev) =>
prev.filter((val) => val !== id)
)
}
className="ml-2 text-gray-500 hover:text-red-600"
>
×
</button>
</div>
);
})}
</div>
)}
{/* Popover Checkbox Dropdown */}
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="w-3/12 justify-between">
Pilih Operator
<ChevronDownIcon className="ml-2 h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full max-h-60 overflow-auto">
<div className="flex flex-col gap-1">
{operatorOpt.map((op: any) => (
<label
key={op.id}
className="flex space-x-2 cursor-pointer px-2 py-1 hover:bg-gray-100 rounded"
>
<input
type="checkbox"
checked={selectedOperator.includes(op.value)}
onChange={(e) => {
if (e.target.checked) {
setSelectedOperator((prev) => [
...prev,
op.value,
]);
} else {
setSelectedOperator((prev) =>
prev.filter((val) => val !== op.value)
);
}
}}
/>
<span>{op.label}</span>
</label>
))}
</div>
</PopoverContent>
</Popover>
</div>
<div className="space-y-2 px-3 py-3">
<div className="">
<Label>
Eskalasi Untuk <span className="text-red-500">*</span>
</Label>
<Select
options={options}
className="w-100"
closeMenuOnSelect={false}
components={animatedComponent}
onChange={handleChange}
formatOptionLabel={formatOptionLabel}
isMulti={true}
/>
</div>
</div>
<div className="space-y-2 px-3 py-3">
<Label>Deskripsi</Label>
<Controller
control={control}
name="description"
render={({ field }) => (
<Textarea {...field} placeholder="Masukkan description" />
)}
/>
</div>
<div className="flex flex-row gap-2 px-3 py-3">
<Label className="">Bagikan Untuk Kolaborasi</Label>
<Checkbox
checked={isCollaboration}
onCheckedChange={(e: boolean) => setIsCollaboration(e)}
/>
</div>
<div className="flex justify-end mt-3 mr-3 py-3">
<Button type="submit" color="primary">
Simpan
</Button>
</div>
</div>
</form>
)}
</div>
);
}