[QUDO-97,QUDO-98,QUDO-92] feat:check emergency issue,escalation,collaboration

This commit is contained in:
Anang Yusman 2025-05-26 08:44:34 +08:00
parent bc0e169821
commit 706246b013
7 changed files with 156 additions and 100 deletions

View File

@ -96,7 +96,7 @@ const columns: ColumnDef<any>[] = [
<DropdownMenuItem <DropdownMenuItem
onClick={() => onClick={() =>
router.push( router.push(
`/supervisor/communications/forward/detail/${row.original.id}` `/supervisor/communications/collaboration/detail/${row.original.id}`
) )
} }
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center" className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center"

View File

@ -146,8 +146,8 @@ export default function CollaborationPage() {
<Separator className="my-2" /> <Separator className="my-2" />
<div className="flex flex-col gap-2 max-h-[360px]"> <div className="flex flex-col gap-2 max-h-[360px]">
{listDiscussion?.length > 1 ? ( {listDiscussion?.length > 0 ? (
listDiscussion?.map((data: any) => ( listDiscussion.map((data: any) => (
<div key={data?.id} className="flex flex-col "> <div key={data?.id} className="flex flex-col ">
<div className="flex flex-row gap-2 items-center"> <div className="flex flex-row gap-2 items-center">
<Icon icon="qlementine-icons:user-16" width={36} /> <Icon icon="qlementine-icons:user-16" width={36} />

View File

@ -93,7 +93,7 @@ const columns: ColumnDef<any>[] = [
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end"> <DropdownMenuContent className="p-0" align="end">
<Link <Link
href={`/supervisor/communications/forward/detail/${row.original.id}`} href={`/supervisor/communications/escalation/forward/${row.original.id}`}
> >
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"> <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<Eye className="w-4 h-4 me-1.5" /> <Eye className="w-4 h-4 me-1.5" />

View File

@ -71,13 +71,15 @@ export default function FormCollaboration() {
const [mainType, setMainType] = useState<number>(1); // untuk Tipe Penugasan const [mainType, setMainType] = useState<number>(1); // untuk Tipe Penugasan
const [type, setType] = useState<string>("1"); const [type, setType] = useState<string>("1");
const [options, setOptions] = useState<Option[]>([]); const [options, setOptions] = useState<Option[]>([]);
const [ticketPriority, setTicketPriority] = useState([]); const [ticketPriority, setTicketPriority] = useState<
{ value: number; label: string }[]
>([]);
const [selectedOption, setSelectedOption] = useState<Option | undefined>( const [selectedOption, setSelectedOption] = useState<Option | undefined>(
undefined undefined
); );
const animatedComponent = makeAnimated(); const animatedComponent = makeAnimated();
const [platformTypeVisible, setPlatformTypeVisible] = useState(false); const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
const [selectedTarget, setSelectedTarget] = useState(""); const [selectedTarget, setSelectedTarget] = useState<number | null>(null);
// Opsi untuk dropdown // Opsi untuk dropdown
const priority = [ const priority = [
@ -131,7 +133,14 @@ export default function FormCollaboration() {
if (res?.data !== null) { if (res?.data !== null) {
const rawData = res?.data?.data; const rawData = res?.data?.data;
setTicketPriority(rawData);
// Ubah ke format Select { value: number, label: string }
const priorityOptions = rawData.map((item: any) => ({
value: item.id, // value dikirim ke API (number)
label: item.name, // label yang ditampilkan ke user
}));
setTicketPriority(priorityOptions); // ← ini akan dipakai di komponen Select
} }
} }
@ -159,12 +168,14 @@ export default function FormCollaboration() {
const save = async (data: TaskSchema) => { const save = async (data: TaskSchema) => {
const requestData = { const requestData = {
title: data.title, title: data.title,
narration: data.naration, typeId: 11,
target: selectedTarget, statusId: 1,
message: data.naration,
priorityId: selectedTarget,
isCollaboration: true, isCollaboration: true,
isEscalation: true, isEscalation: true,
isCollaborationWithNoneTicket: true, isCollaborationWithNoneTicket: true,
sendToId: selectedOption?.id, // This should work now without the error operatorTeam: selectedOption?.id, // This should work now without the error
}; };
const response = await saveTicketing(requestData); const response = await saveTicketing(requestData);
@ -179,7 +190,7 @@ export default function FormCollaboration() {
confirmButtonColor: "#3085d6", confirmButtonColor: "#3085d6",
confirmButtonText: "OK", confirmButtonText: "OK",
}).then(() => { }).then(() => {
router.push("/contributor/communication"); router.push("/in/supervisor/communications/collaboration");
}); });
}; };
@ -232,15 +243,15 @@ export default function FormCollaboration() {
</Label> </Label>
<Select <Select
id="target-select" id="target-select"
options={priority} options={ticketPriority}
onChange={(selectedOption) => onChange={(selectedOption) =>
setSelectedTarget(selectedOption?.value || "") setSelectedTarget(Number(selectedOption?.value))
} }
placeholder="Pilih" placeholder="Pilih"
styles={{ styles={{
control: (base) => ({ control: (base) => ({
...base, ...base,
minHeight: "40px", // Ukuran sesuai dengan size="md" minHeight: "40px",
}), }),
}} }}
/> />

View File

@ -95,27 +95,38 @@ export default function FormQuestionsForward() {
resolver: zodResolver(taskSchema), resolver: zodResolver(taskSchema),
}); });
// useEffect(() => {
// async function initState() {
// const response = await getQuestionTicket(id);
// setDetail(response?.data?.data);
// if (response?.data !== null) {
// setDetailTickets(response?.data?.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();
// }, [id, reset]);
useEffect(() => { useEffect(() => {
async function initState() { async function initState() {
const response = await getQuestionTicket(id); if (id) {
setDetail(response?.data?.data); const response = await getTicketingDetail(id);
setDetail(response?.data?.data);
if (response?.data !== null) {
setDetailTickets(response?.data?.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(); initState();
getTicketReply(); getTicketReply();
}, [id, reset]); }, [id]);
async function getTicketReply() { async function getTicketReply() {
const res = await getTicketingInternalDiscussion(id); const res = await getTicketingInternalDiscussion(id);
@ -217,74 +228,107 @@ export default function FormQuestionsForward() {
)} )}
</div> </div>
</div> </div>
{detailTickets && ( {detail !== undefined && (
<form onSubmit={handleSubmit(onSubmit)}> <div className="gap-5 mb-5 w-full border mt-3 rounded-md bg-white">
<div className="gap-5 mb-5 w-[100%] lg:w-auto border bg-white rounded-md"> <div className="space-y-2 px-3 mt-3">
<p className="mx-3 mt-3">Properties</p> <Label>Judul</Label>
<div className="space-y-2 px-3"> <Controller
<Label>Judul</Label> control={control}
<Controller name="title"
control={control} render={({ field }) => (
name="title" <Input
render={({ field }) => ( size="md"
<Input type="text"
size="md" value={detail?.title}
type="text" onChange={field.onChange}
{...field} placeholder="Enter Title"
placeholder="Masukkan judul" />
/> )}
)} />
/> {/* {errors.title?.message && (
</div> <p className="text-red-400 text-sm">
{errors.title.message}
<div className="mt-5 px-3"> </p>
<Label>Prioritas</Label> )} */}
<Select </div>
onValueChange={setSelectedPriority} <div className="mt-5 px-3">
value={selectedPriority} <Label>Prioritas</Label>
> <Select
<SelectTrigger size="md"> onValueChange={setSelectedPriority}
<SelectValue placeholder="Pilih Prioritas" /> value={detail?.priority?.name}
</SelectTrigger> >
<SelectContent> <SelectTrigger size="md" className="w-3/12">
<SelectItem value="1">Low</SelectItem> <SelectValue placeholder="Pilih" />
<SelectItem value="2">Medium</SelectItem> </SelectTrigger>
<SelectItem value="3">High</SelectItem> <SelectContent>
</SelectContent> <SelectItem value="Low">Low</SelectItem>
</Select> <SelectItem value="Medium">Medium</SelectItem>
</div> <SelectItem value="High">High</SelectItem>
</SelectContent>
<div className="mt-5 px-3 mb-3"> </Select>
<Label>Status</Label> </div>
<Select onValueChange={setSelectedStatus} value={selectedStatus}> <div className="space-y-2 px-3 mt-3">
<SelectTrigger size="md"> <Label>Description</Label>
<SelectValue placeholder="Pilih Status" /> <Controller
</SelectTrigger> control={control}
<SelectContent> name="title"
<SelectItem value="1">Open</SelectItem> render={({ field }) => (
<SelectItem value="2">Close</SelectItem> <Textarea
</SelectContent> value={detail?.description}
</Select> onChange={field.onChange}
</div> placeholder="Enter Title"
/>
<div className="space-y-2 px-3 py-3"> )}
<Label>Deskripsi</Label> />
<Controller {/* {errors.title?.message && (
control={control} <p className="text-red-400 text-sm">
name="description" {errors.title.message}
render={({ field }) => ( </p>
<Textarea {...field} placeholder="Masukkan description" /> )} */}
)} </div>
/> <div className="mx-3 my-3">
</div> <h3 className="text-gray-700 font-medium">Tanggapan</h3>
<div className="space-y-4">
<div className="flex justify-end mt-3 mr-3 py-3"> {replies.map((reply) => (
<Button type="submit" color="primary"> <div key={reply.id} className="border-b pb-2">
Simpan <p className="font-semibold text-gray-800">{reply.name}</p>
</Button> <p className="text-gray-600">{reply.message}</p>
<p className="text-sm text-gray-400">{reply.timestamp}</p>
</div>
))}
</div> </div>
</div> </div>
</form>
<div className="mx-3">
<label
htmlFor="replyMessage"
className="block text-gray-700 font-medium mb-2"
>
Tulis Tanggapan Anda
</label>
<textarea
id="replyMessage"
className="w-full h-24 border border-gray-300 rounded-md p-2"
value={replyMessage}
onChange={(e) => setReplyMessage(e.target.value)}
placeholder="Tulis tanggapan anda di sini..."
/>
<div className="flex justify-end gap-3 mt-2 mb-3">
<button
onClick={() => setReplyMessage("")}
className="px-4 py-2 bg-gray-200 text-gray-800 rounded-md"
>
Batal
</button>
<button
onClick={handleSendReply}
className="px-4 py-2 bg-blue-600 text-white rounded-md"
>
Kirim Pesan
</button>
</div>
</div>
</div>
)} )}
</div> </div>
); );

View File

@ -91,7 +91,6 @@ const HeroModal = ({
}, []); }, []);
const initFetch = async () => { const initFetch = async () => {
// Ambil data banner dari API listStaticBanner
const response = await listStaticBanner( const response = await listStaticBanner(
group === "mabes" group === "mabes"
? "" ? ""
@ -102,7 +101,6 @@ const HeroModal = ({
: "" : ""
); );
// Ambil dan bersihkan data media dari response
const banners = const banners =
response?.data?.data?.map((item: any) => { response?.data?.data?.map((item: any) => {
const media = item?.mediaUpload; const media = item?.mediaUpload;
@ -113,7 +111,7 @@ const HeroModal = ({
}) || []; }) || [];
console.log("banner Modal", banners); console.log("banner Modal", banners);
setHeroData(banners); // hanya data dari listStaticBanner setHeroData(banners);
}; };
return ( return (
<div className="fixed inset-0 flex items-center justify-center backdrop-brightness-50 z-50 "> <div className="fixed inset-0 flex items-center justify-center backdrop-brightness-50 z-50 ">
@ -328,8 +326,6 @@ const HeroNew = (props: { group?: string }) => {
{showModal && ( {showModal && (
<HeroModal onClose={() => setShowModal(false)} group="mabes" /> <HeroModal onClose={() => setShowModal(false)} group="mabes" />
)} )}
{/* {showFormModal && <FormSurvey />} */}
</div> </div>
{isLoading ? ( {isLoading ? (
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3"> <div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">

View File

@ -137,6 +137,11 @@ export async function deleteQuestion(id: string | number) {
return httpDeleteInterceptor(url); return httpDeleteInterceptor(url);
} }
export async function saveEscalationDiscussion(data: any) {
const url = "ticketing/escalation/discussion";
return httpPostInterceptor(url, data);
}
export async function getEscalationDiscussion(id: any) { export async function getEscalationDiscussion(id: any) {
const url = `ticketing/escalation/discussion?ticketId=${id}`; const url = `ticketing/escalation/discussion?ticketId=${id}`;
return httpGetInterceptor(url); return httpGetInterceptor(url);