feat:kotak saran

This commit is contained in:
Rama Priyanto 2025-06-05 22:47:52 +07:00
parent 9231546780
commit 2e6a2beb5c
4 changed files with 291 additions and 5 deletions

View File

@ -49,6 +49,7 @@ import {
Dialog,
DialogContent,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Textarea } from "@/components/ui/textarea";
import { close, loading, successCallback } from "@/config/swal";
@ -59,6 +60,7 @@ import dynamic from "next/dynamic";
import { useRouter } from "@/i18n/routing";
import { useTranslations } from "next-intl";
import { UnitMapping } from "@/app/[locale]/(protected)/contributor/agenda-setting/unit-mapping";
import SuggestionModal from "@/components/modal/suggestions-modal";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -628,10 +630,11 @@ export default function FormImageDetail() {
</div>
</div>
</div>
<div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm">
<MailIcon />
<p className="">{t("suggestion-box")} (0)</p>
</div>
<SuggestionModal
id={Number(id)}
numberOfSuggestion={detail?.numberOfSuggestion}
/>
<div className="px-3 py-3 border mx-3">
<p>{t("information")}:</p>
<p className="text-sm text-slate-400">{detail?.statusName}</p>

View File

@ -87,7 +87,6 @@ export default function FormDetailLiveReport() {
const roleId = getCookiesDecrypt("urie");
const userLevelNumber = getCookiesDecrypt("ulne");
console.log("cookie", userId, userLevelId, roleId, userLevelNumber);
const [startTime, setStartTime] = useState("08:00");
const [endTime, setEndTime] = useState("09:00");
const [date, setDate] = useState<DateRange | undefined>();

View File

@ -0,0 +1,269 @@
"use client";
import { MailIcon, UserIcon } from "lucide-react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTrigger,
} from "../ui/dialog";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { useTranslations } from "next-intl";
import { Input } from "../ui/input";
import { getCookiesDecrypt } from "@/lib/utils";
import { close, error, loading } from "@/config/swal";
import {
createSuggestion,
deleteSuggestion,
getSuggestionList,
} from "@/service/curated-content/curated-content";
import { formatDateToIndonesian } from "@/utils/globals";
export default function SuggestionModal(props: {
id: number;
numberOfSuggestion: number;
}) {
const { id, numberOfSuggestion } = props;
const t = useTranslations("Form");
const [suggestionValue, setSuggestionValue] = useState("");
const userId = getCookiesDecrypt("uie");
const [listData, setListData] = useState([]);
const [replyId, setReplyId] = useState(0);
const [replyValue, setReplyValue] = useState("");
useEffect(() => {
initState();
}, [id]);
async function initState() {
loading();
const response = await getSuggestionList(id);
setListData(response?.data?.data);
close();
}
const saveSuggestion = async (parentId?: number) => {
console.log("suggestion vval", suggestionValue);
const data = {
mediaUploadId: Number(id),
message: parentId ? replyValue : suggestionValue,
parentId: parentId ? parentId : null,
};
loading();
const response = await createSuggestion(data);
if (response?.error) {
error(response?.message);
return false;
}
close();
setSuggestionValue("");
setReplyValue("");
initState();
};
const handleDeleteSuggestion = async (id: number) => {
loading();
const response = await deleteSuggestion(id);
if (response?.error) {
error(response?.message);
return false;
}
close();
initState();
};
return (
<Dialog>
<DialogTrigger>
<a className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm cursor-pointer">
<MailIcon />
<p className="">
{t("suggestion-box")} ({numberOfSuggestion || 0})
</p>
</a>
</DialogTrigger>
<DialogContent size="md" className="px-1 lg:px-4">
<DialogHeader>Suggestions</DialogHeader>
<div className="flex flex-row items-center justify-center">
<Input
value={suggestionValue}
onChange={(e) => setSuggestionValue(e.target.value)}
/>
<Button size="sm" onClick={() => saveSuggestion()}>
{t("submit")}
</Button>
</div>
<div className="flex flex-col gap-2">
{listData?.length > 0 &&
listData?.map((data: any) => (
<div key={data?.id} className="flex flex-col gap-1 w-full">
<div className="flex flex-row gap-2">
<div className="mt-2 w-[24px] h-[24px] md:w-[50px] md:h-[50px] border-2 flex items-center justify-center rounded-full bg-stone-200 border-stone-300">
<UserIcon size={36} />
</div>
<div className="flex flex-col gap-2 w-full">
<div className="flex justify-between bg-stone-200 px-2 lg:px-4 py-2 w-full rounded-lg">
<div className="flex flex-col gap-1">
<b className="text-sm md:text-base">
{data.suggestionFrom?.fullname}
</b>
<p className="text-xs md:text-sm">{data.message}</p>
</div>
<div className="flex flex-col gap-1">
<p className="text-xs md:text-sm text-right">
{formatDateToIndonesian(data.createdAt)}
</p>
<div className="flex flex-col items-end md:flex-row gap-2 text-xs md:text-sm justify-end">
<a
className="text-primary cursor-pointer"
onClick={() => {
setReplyId(replyId === data?.id ? 0 : data?.id);
setReplyValue("");
}}
>
Balas
</a>
<a
onClick={() => handleDeleteSuggestion(data?.id)}
className="text-destructive cursor-pointer"
>
Hapus
</a>
</div>
</div>
</div>
{replyId === data?.id && (
<div className="flex flex-row items-center justify-center">
<Input
value={replyValue}
onChange={(e) => setReplyValue(e.target.value)}
/>
<Button
size="sm"
onClick={() => saveSuggestion(data?.id)}
>
{t("submit")}
</Button>
</div>
)}
</div>
</div>
{data?.children.length > 0 &&
data?.children.map((child: any) => (
<div key={child.id} className="flex flex-row gap-2">
<div className="w-[50px]"></div>
<div className="flex flex-col w-full gap-2">
<div className="flex flex-row gap-2 w-full">
<div className="mt-2 w-[24px] h-[24px] md:w-[50px] md:h-[50px] border-2 flex items-center justify-center rounded-full bg-stone-200 border-stone-300">
<UserIcon size={36} />
</div>
<div className="flex flex-col gap-2 w-full">
<div className="flex justify-between bg-stone-100 px-2 lg:px-4 py-2 w-full rounded-lg">
<div className="flex flex-col gap-1">
<b className="text-xs md:text-base">
{child.suggestionFrom?.fullname}
</b>
<p className="text-xs md:text-sm">
{child.message}
</p>
</div>
<div className="flex flex-col gap-1">
<p className="text-xs md:text-sm text-right">
{formatDateToIndonesian(child.createdAt)}
</p>
<div className="flex flex-col items-end md:flex-row gap-2 text-xs md:text-sm justify-end">
<a
className="text-primary cursor-pointer"
onClick={() => {
setReplyId(
replyId === child?.id ? 0 : child?.id
);
setReplyValue("");
}}
>
Balas
</a>
<a
onClick={() =>
handleDeleteSuggestion(child?.id)
}
className="text-destructive cursor-pointer"
>
Hapus
</a>
</div>
</div>
</div>
{replyId === child?.id && (
<div className="flex flex-row items-center justify-center">
<Input
value={replyValue}
onChange={(e) =>
setReplyValue(e.target.value)
}
/>
<Button
size="sm"
onClick={() => saveSuggestion(child?.id)}
>
{t("submit")}
</Button>
</div>
)}
</div>
</div>
{child?.children.length > 0 &&
child?.children.map((items: any) => (
<div key={items.id} className="flex flex-row gap-2">
<div className="w-[50px]"></div>
<div className="flex flex-row gap-2 w-full">
<div className="mt-2 w-[24px] h-[24px] md:w-[50px] md:h-[50px] border-2 flex items-center justify-center rounded-full bg-stone-200 border-stone-300">
<UserIcon size={36} />
</div>
<div className="flex flex-col gap-2 w-full">
<div className="flex justify-between bg-stone-50 px-2 lg:px-4 py-2 w-full rounded-lg">
<div className="flex flex-col gap-1">
<b className="text-xs md:text-base">
{items.suggestionFrom?.fullname}
</b>
<p className="text-xs md:text-sm">
{items.message}
</p>
</div>
<div className="flex flex-col gap-1">
<p className="text-xs md:text-sm text-right">
{formatDateToIndonesian(
items.createdAt
)}
</p>
<div className="flex flex-col items-end md:flex-row gap-2 text-xs md:text-sm justify-end">
<a
onClick={() =>
handleDeleteSuggestion(items?.id)
}
className="text-destructive cursor-pointer"
>
Hapus
</a>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
))}
</div>
))}
</div>
</DialogContent>
</Dialog>
);
}

View File

@ -35,3 +35,18 @@ export async function deleteMediaCurationMessage(id: any) {
const url = `media/curation/message?id=${id}`;
return httpDeleteInterceptor(url);
}
export async function getSuggestionList(id: number | string) {
const url = `media/suggestion?mediaId=${id}`;
return httpGetInterceptor(url);
}
export async function createSuggestion(data: any) {
const url = "media/suggestion";
return httpPostInterceptor(url, data);
}
export async function deleteSuggestion(id: number | string) {
const url = `media/suggestion?id=${id}`;
return httpDeleteInterceptor(url);
}