feat:add table survey,form survey
This commit is contained in:
parent
72bee46ec5
commit
f474a98a75
|
|
@ -13,6 +13,9 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { format } from "date-fns";
|
||||
import header from "@/components/partials/header";
|
||||
import { date } from "zod";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -23,50 +26,61 @@ const columns: ColumnDef<any>[] = [
|
|||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("createdAt")}</span>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "account-type",
|
||||
accessorKey: "createdByCategory",
|
||||
header: "Jenis Akun",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("account-type")}</span>
|
||||
<span className="normal-case">{row.getValue("createdByCategory")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "userName",
|
||||
accessorKey: "createdByUsername",
|
||||
header: "UserName",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("userName")}</span>
|
||||
<span className="normal-case">{row.getValue("createdByUsername")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "accessMediahub",
|
||||
accessorKey: "accessFrequency",
|
||||
header: "Akses Mediahub",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("accessMediahub")}</span>
|
||||
<span className="normal-case">{row.getValue("accessFrequency")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "desaignWeb",
|
||||
accessorKey: "uiExperienceDesign",
|
||||
header: "Tampilan Desain Web",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("desaignWeb")}</span>
|
||||
<span className="normal-case">{row.getValue("uiExperienceDesign")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "navigation",
|
||||
accessorKey: "uiExperienceNavigation",
|
||||
header: "Kemudahan Navigasi",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("navigation")}</span>
|
||||
<span className="normal-case">
|
||||
{row.getValue("uiExperienceNavigation")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "fastAccess",
|
||||
accessorKey: "uiExperienceSpeed",
|
||||
header: "Kecepatan Akses",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("fastAccess")}</span>
|
||||
<span className="normal-case">{row.getValue("uiExperienceSpeed")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
@ -86,13 +100,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">
|
||||
<Link
|
||||
href={`/admin/broadcast/campaign-list/detail/${row.original.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<Link href={`/admin/survey/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 mt-1" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ import {
|
|||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import { getSurveyData } from "@/service/survey/survey";
|
||||
|
||||
const data = [
|
||||
{
|
||||
|
|
@ -181,7 +182,7 @@ const SurveyListTable = () => {
|
|||
async function fetchData() {
|
||||
try {
|
||||
loading();
|
||||
const res = await getMediaBlastCampaignPage(page - 1);
|
||||
const res = await getSurveyData();
|
||||
const data = res?.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
|
|
@ -249,7 +250,7 @@ const SurveyListTable = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-h-screen p-3">
|
||||
<div className="p-3">
|
||||
<h2 className="text-center font-semibold mb-4">
|
||||
Survei Kepuasan Pengguna MediaHub Polri
|
||||
</h2>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormBlogDetail from "@/components/form/blog/blog--detail-form";
|
||||
import FormSurvey from "@/components/landing-page/survey";
|
||||
import FormSurveyDetail from "@/components/form/survey/survey-detail";
|
||||
|
||||
const SurveyDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormSurveyDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SurveyDetailPage;
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormBlogDetail from "@/components/form/blog/blog--detail-form";
|
||||
import FormSurveyDetailPage from "@/components/form/survey/survey-detail";
|
||||
|
||||
const BlogDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormBlogDetail />
|
||||
<FormSurveyDetailPage />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,264 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { createSurveyData, getSurveyById } from "@/service/survey/survey";
|
||||
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const surveySchema = z.object({
|
||||
accessFrequency: z.string(),
|
||||
uiExperienceDesign: z.string(),
|
||||
uiExperienceNavigation: z.string(),
|
||||
uiExperienceSpeed: z.string(),
|
||||
infoAccuracy: z.string(),
|
||||
infoCompleteness: z.string(),
|
||||
usefulness: z.string(),
|
||||
suggestion: z.string().optional(),
|
||||
});
|
||||
|
||||
type SurveySchema = z.infer<typeof surveySchema>;
|
||||
|
||||
export default function FormSurveyDetailPage() {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [loadingSurvey, setLoadingSurvey] = useState(true);
|
||||
const [detail, setDetail] = useState<any>();
|
||||
const { id } = useParams() as { id: string };
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<SurveySchema>({
|
||||
resolver: zodResolver(surveySchema),
|
||||
defaultValues: {
|
||||
accessFrequency: "",
|
||||
uiExperienceDesign: "",
|
||||
uiExperienceNavigation: "",
|
||||
uiExperienceSpeed: "",
|
||||
infoAccuracy: "",
|
||||
infoCompleteness: "",
|
||||
usefulness: "",
|
||||
suggestion: "",
|
||||
},
|
||||
});
|
||||
|
||||
const options = {
|
||||
accessFrequency: [
|
||||
"Setiap hari",
|
||||
"Beberapa kali seminggu",
|
||||
"Beberapa kali dalam sebulan",
|
||||
"Baru pertama kali",
|
||||
],
|
||||
uiExperienceDesign: ["Sangat baik", "Baik", "Cukup", "Kurang", "Buruk"],
|
||||
uiExperienceNavigation: [
|
||||
"Sangat mudah",
|
||||
"Mudah",
|
||||
"Cukup",
|
||||
"Sulit",
|
||||
"Sangat sulit",
|
||||
],
|
||||
uiExperienceSpeed: [
|
||||
"Sangat cepat",
|
||||
"Cepat",
|
||||
"Cukup",
|
||||
"Lambat",
|
||||
"Sangat lambat",
|
||||
],
|
||||
infoAccuracy: ["Sangat puas", "Puas", "Cukup", "Kurang puas", "Tidak puas"],
|
||||
infoCompleteness: [
|
||||
"Sangat lengkap",
|
||||
"Lengkap",
|
||||
"Cukup",
|
||||
"Kurang lengkap",
|
||||
"Tidak lengkap",
|
||||
],
|
||||
usefulness: [
|
||||
"Sangat membantu",
|
||||
"Membantu",
|
||||
"Cukup membantu",
|
||||
"Kurang membantu",
|
||||
"Tidak membantu",
|
||||
],
|
||||
};
|
||||
|
||||
const renderControllerGroup = (
|
||||
name: keyof SurveySchema,
|
||||
question: string,
|
||||
choices: string[]
|
||||
) => (
|
||||
<div className="space-y-2">
|
||||
<p className="font-medium">{question}</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{choices.map((choice, i) => (
|
||||
<Controller
|
||||
key={i}
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<label className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={field.value === choice}
|
||||
onCheckedChange={() => field.onChange(choice)}
|
||||
/>
|
||||
<span>{choice}</span>
|
||||
</label>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{errors[name] && (
|
||||
<p className="text-red-500 text-sm">
|
||||
{errors[name]?.message as string}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const onSubmit = async (data: SurveySchema) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await createSurveyData(data);
|
||||
console.log("Survey submitted:", response);
|
||||
} catch (error) {
|
||||
console.error("Failed to submit survey:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSurvey = async () => {
|
||||
if (id) {
|
||||
setLoadingSurvey(true);
|
||||
try {
|
||||
const response = await getSurveyById(id);
|
||||
const details = response?.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
|
||||
// Set value dari data detail ke form
|
||||
if (details) {
|
||||
setValue("accessFrequency", details.accessFrequency || "");
|
||||
setValue("uiExperienceDesign", details.uiExperienceDesign || "");
|
||||
setValue(
|
||||
"uiExperienceNavigation",
|
||||
details.uiExperienceNavigation || ""
|
||||
);
|
||||
setValue("uiExperienceSpeed", details.uiExperienceSpeed || "");
|
||||
setValue("infoAccuracy", details.infoAccuracy || "");
|
||||
setValue("infoCompleteness", details.infoCompleteness || "");
|
||||
setValue("usefulness", details.usefulness || "");
|
||||
setValue("suggestion", details.suggestion || "");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch survey detail:", error);
|
||||
} finally {
|
||||
setLoadingSurvey(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchSurvey();
|
||||
}, [id, setValue]);
|
||||
|
||||
if (loadingSurvey) {
|
||||
return <div className="p-6">Loading survey data...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full mx-auto p-6">
|
||||
<h1 className="text-2xl font-bold mb-2">
|
||||
SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI
|
||||
</h1>
|
||||
<p className="text-sm mb-6 text-gray-600">
|
||||
Kami menghargai pendapat Anda! Survei ini bertujuan untuk meningkatkan
|
||||
kualitas layanan MediaHub Polri.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
||||
{renderControllerGroup(
|
||||
"accessFrequency",
|
||||
"1. Seberapa sering Anda mengakses MediaHub Polri?",
|
||||
options.accessFrequency
|
||||
)}
|
||||
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
2. Bagaimana pengalaman Anda dalam mengakses website ini?
|
||||
</p>
|
||||
<div className="space-y-3 mt-2">
|
||||
{renderControllerGroup(
|
||||
"uiExperienceDesign",
|
||||
"a) Tampilan dan desain website",
|
||||
options.uiExperienceDesign
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"uiExperienceNavigation",
|
||||
"b) Kemudahan navigasi",
|
||||
options.uiExperienceNavigation
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"uiExperienceSpeed",
|
||||
"c) Kecepatan akses website",
|
||||
options.uiExperienceSpeed
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
3. Seberapa puas Anda dengan informasi yang tersedia di MediaHub
|
||||
Polri?
|
||||
</p>
|
||||
<div className="space-y-3 mt-2">
|
||||
{renderControllerGroup(
|
||||
"infoAccuracy",
|
||||
"a) Akurat dan terpercaya",
|
||||
options.infoAccuracy
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"infoCompleteness",
|
||||
"b) Kelengkapan berita dan informasi",
|
||||
options.infoCompleteness
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{renderControllerGroup(
|
||||
"usefulness",
|
||||
"4. Apakah Anda merasa website ini membantu dalam mendapatkan informasi terkait Polri?",
|
||||
options.usefulness
|
||||
)}
|
||||
|
||||
<div>
|
||||
<p className="font-medium">5. Apa saran atau masukan Anda?</p>
|
||||
<Controller
|
||||
name="suggestion"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
placeholder="Tulis pesan Anda..."
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button type="submit" disabled={isLoading}>
|
||||
{isLoading ? "Mengirim..." : "Kirim"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ import { Autoplay, Pagination } from "swiper/modules";
|
|||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import "swiper/css";
|
||||
import "swiper/css/pagination";
|
||||
import FormSurvey from "./survey";
|
||||
|
||||
const HeroModal = ({ onClose }: { onClose: () => void }) => {
|
||||
const [heroData, setHeroData] = useState<any>();
|
||||
|
|
@ -206,170 +207,6 @@ const options = {
|
|||
],
|
||||
};
|
||||
|
||||
const SurveyFormModal = ({ onClose }: { onClose: () => void }) => {
|
||||
useEffect(() => {
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => {
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose();
|
||||
}}
|
||||
>
|
||||
<DialogContent className="z-50 min-w-max h-[600px] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-lg font-bold">
|
||||
SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-sm">
|
||||
Kami menghargai pendapat Anda! Survei ini bertujuan untuk
|
||||
meningkatkan kualitas layanan MediaHub Polri. Mohon luangkan waktu
|
||||
beberapa menit untuk mengisi survei ini.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4 mt-4">
|
||||
{/* 1 */}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
1. Seberapa sering Anda mengakses MediaHub Polri?
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2 mt-2">
|
||||
{options.q1.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q1-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 2 */}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
2. Bagaimana pengalaman Anda dalam mengakses website ini?
|
||||
</p>
|
||||
<div className="mt-2 space-y-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
a) Tampilan dan desain website
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-2 mt-1">
|
||||
{options.q2a.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q2a-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
b) Kemudahan navigasi (pencarian informasi, menu, dll)
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-2 mt-1">
|
||||
{options.q2b.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q2b-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
c) Kecepatan akses website
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-2 mt-1">
|
||||
{options.q2c.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q2c-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 3 */}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
3. Seberapa puas Anda dengan informasi yang tersedia di MediaHub
|
||||
Polri?
|
||||
</p>
|
||||
<div className="mt-2 space-y-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium">a) Akurat dan terpercaya</p>
|
||||
<div className="grid grid-cols-3 gap-2 mt-1">
|
||||
{options.q3a.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q3a-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
b) Kelengkapan berita dan informasi
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-2 mt-1">
|
||||
{options.q3b.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q3b-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 4 */}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
5. Apakah Anda merasa website ini membantu dalam mendapatkan
|
||||
informasi terkait Polri?
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2 mt-2">
|
||||
{options.q4.map((item, i) => (
|
||||
<label key={i} className="flex items-center space-x-2">
|
||||
<Checkbox id={`q4-${i}`} />
|
||||
<span>{item}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 5 */}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
6. Apa saran atau masukan Anda untuk meningkatkan layanan MediaHub
|
||||
Polri?
|
||||
</p>
|
||||
<Textarea placeholder="Tulis pesan Anda" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-6">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Batal</Button>
|
||||
</DialogClose>
|
||||
<Button>Kirim</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const ONE_MONTH = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const Hero: React.FC = () => {
|
||||
|
|
@ -399,12 +236,29 @@ const Hero: React.FC = () => {
|
|||
initFetch();
|
||||
}, []);
|
||||
|
||||
// useEffect(() => {
|
||||
// const roleId = Cookies.get("urie");
|
||||
// const lastShown = Cookies.get("surveyLastShown");
|
||||
// const now = new Date().getTime();
|
||||
|
||||
// if (roleId && roleId !== "2") {
|
||||
// if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
|
||||
// setShowSurveyModal(true);
|
||||
// Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
|
||||
// }
|
||||
// }
|
||||
|
||||
// initFetch();
|
||||
// }, []);
|
||||
|
||||
useEffect(() => {
|
||||
const roleId = Cookies.get("urie");
|
||||
const lastShown = Cookies.get("surveyLastShown");
|
||||
const now = new Date().getTime();
|
||||
|
||||
if (roleId && roleId !== "2") {
|
||||
const allowedRoles = ["1", "2", "3"];
|
||||
|
||||
if (roleId && allowedRoles.includes(roleId)) {
|
||||
if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
|
||||
setShowSurveyModal(true);
|
||||
Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
|
||||
|
|
@ -474,9 +328,7 @@ const Hero: React.FC = () => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{showFormModal && (
|
||||
<SurveyFormModal onClose={() => setShowFormModal(false)} />
|
||||
)}
|
||||
{showFormModal && <FormSurvey />}
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,236 @@
|
|||
"use client";
|
||||
|
||||
import { z } from "zod";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "../ui/dialog";
|
||||
import { Checkbox } from "../ui/checkbox";
|
||||
import { Button } from "../ui/button";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { useState } from "react";
|
||||
import { createTaskTa } from "@/service/task";
|
||||
import { createSurveyData } from "@/service/survey/survey";
|
||||
|
||||
// Schema untuk validasi
|
||||
const surveySchema = z.object({
|
||||
accessFrequency: z.string(),
|
||||
uiExperienceDesign: z.string(),
|
||||
uiExperienceNavigation: z.string(),
|
||||
uiExperienceSpeed: z.string(),
|
||||
infoAccuracy: z.string(),
|
||||
infoCompleteness: z.string(),
|
||||
usefulness: z.string(),
|
||||
suggestion: z.string().optional(),
|
||||
});
|
||||
|
||||
type SurveySchema = z.infer<typeof surveySchema>;
|
||||
|
||||
export default function FormSurvey() {
|
||||
const [showSurvey, setShowSurvey] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<SurveySchema>({
|
||||
resolver: zodResolver(surveySchema),
|
||||
mode: "all",
|
||||
defaultValues: {
|
||||
accessFrequency: "",
|
||||
uiExperienceDesign: "",
|
||||
uiExperienceNavigation: "",
|
||||
uiExperienceSpeed: "",
|
||||
infoAccuracy: "",
|
||||
infoCompleteness: "",
|
||||
usefulness: "",
|
||||
suggestion: "",
|
||||
},
|
||||
});
|
||||
|
||||
const options = {
|
||||
accessFrequency: [
|
||||
"Setiap hari",
|
||||
"Beberapa kali seminggu",
|
||||
"Beberapa kali dalam sebulan",
|
||||
"Baru pertama kali",
|
||||
],
|
||||
uiExperienceDesign: ["Sangat baik", "Baik", "Cukup", "Kurang", "Buruk"],
|
||||
uiExperienceNavigation: [
|
||||
"Sangat mudah",
|
||||
"Mudah",
|
||||
"Cukup",
|
||||
"Sulit",
|
||||
"Sangat sulit",
|
||||
],
|
||||
uiExperienceSpeed: [
|
||||
"Sangat cepat",
|
||||
"Cepat",
|
||||
"Cukup",
|
||||
"Lambat",
|
||||
"Sangat lambat",
|
||||
],
|
||||
infoAccuracy: ["Sangat puas", "Puas", "Cukup", "Kurang puas", "Tidak puas"],
|
||||
infoCompleteness: [
|
||||
"Sangat lengkap",
|
||||
"Lengkap",
|
||||
"Cukup",
|
||||
"Kurang lengkap",
|
||||
"Tidak lengkap",
|
||||
],
|
||||
usefulness: [
|
||||
"Sangat membantu",
|
||||
"Membantu",
|
||||
"Cukup membantu",
|
||||
"Kurang membantu",
|
||||
"Tidak membantu",
|
||||
],
|
||||
};
|
||||
|
||||
const renderControllerGroup = (
|
||||
name: keyof SurveySchema,
|
||||
question: string,
|
||||
choices: string[]
|
||||
) => (
|
||||
<div className="space-y-2">
|
||||
<p className="font-medium">{question}</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{choices.map((choice, i) => (
|
||||
<Controller
|
||||
key={i}
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<label className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={field.value === choice}
|
||||
onCheckedChange={() => field.onChange(choice)}
|
||||
/>
|
||||
<span>{choice}</span>
|
||||
</label>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{errors[name] && (
|
||||
<p className="text-red-500 text-sm">
|
||||
{errors[name]?.message as string}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const onSubmit = async (data: SurveySchema) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await createSurveyData(data);
|
||||
console.log("API Response:", response);
|
||||
setShowSurvey(false);
|
||||
} catch (error) {
|
||||
console.error("Error submitting survey:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={showSurvey} onOpenChange={setShowSurvey}>
|
||||
<DialogContent className="z-50 min-w-max h-[600px] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-lg font-bold">
|
||||
SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-sm">
|
||||
Kami menghargai pendapat Anda! Survei ini bertujuan untuk
|
||||
meningkatkan kualitas layanan MediaHub Polri.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 mt-4">
|
||||
{renderControllerGroup(
|
||||
"accessFrequency",
|
||||
"1. Seberapa sering Anda mengakses MediaHub Polri?",
|
||||
options.accessFrequency
|
||||
)}
|
||||
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
2. Bagaimana pengalaman Anda dalam mengakses website ini?
|
||||
</p>
|
||||
<div className="space-y-3 mt-2">
|
||||
{renderControllerGroup(
|
||||
"uiExperienceDesign",
|
||||
"a) Tampilan dan desain website",
|
||||
options.uiExperienceDesign
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"uiExperienceNavigation",
|
||||
"b) Kemudahan navigasi",
|
||||
options.uiExperienceNavigation
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"uiExperienceSpeed",
|
||||
"c) Kecepatan akses website",
|
||||
options.uiExperienceSpeed
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
3. Seberapa puas Anda dengan informasi yang tersedia di MediaHub
|
||||
Polri?
|
||||
</p>
|
||||
<div className="space-y-3 mt-2">
|
||||
{renderControllerGroup(
|
||||
"infoAccuracy",
|
||||
"a) Akurat dan terpercaya",
|
||||
options.infoAccuracy
|
||||
)}
|
||||
{renderControllerGroup(
|
||||
"infoCompleteness",
|
||||
"b) Kelengkapan berita dan informasi",
|
||||
options.infoCompleteness
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{renderControllerGroup(
|
||||
"usefulness",
|
||||
"4. Apakah Anda merasa website ini membantu dalam mendapatkan informasi terkait Polri?",
|
||||
options.usefulness
|
||||
)}
|
||||
|
||||
<div>
|
||||
<p className="font-medium">5. Apa saran atau masukan Anda?</p>
|
||||
<Controller
|
||||
name="suggestion"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
placeholder="Tulis pesan Anda..."
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="outline" onClick={() => setShowSurvey(false)}>
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit" disabled={isLoading}>
|
||||
{isLoading ? "Mengirim..." : "Kirim"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import {
|
||||
httpGetInterceptor,
|
||||
httpPostInterceptor,
|
||||
} from "../http-config/http-interceptor-service";
|
||||
|
||||
export async function createSurveyData(data: any) {
|
||||
const pathUrl = "users/satisfaction-survey";
|
||||
return httpPostInterceptor(pathUrl, data);
|
||||
}
|
||||
|
||||
export async function getSurveyData() {
|
||||
const url = `users/satisfaction-survey/pagination`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getSurveyById(id: any) {
|
||||
const url = `users/satisfaction-survey?id=${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
Loading…
Reference in New Issue