Update : using component Shadcn, create Modal for actions with redirect

This commit is contained in:
percyfikri 2024-10-07 10:58:38 +07:00
parent 0fccc638fe
commit 8ff729a7ab
5 changed files with 177 additions and 105 deletions

View File

@ -0,0 +1,34 @@
import { Modal, Text, Flex } from "@mantine/core";
import { Button } from "@/shadcn/components/ui/button";
interface StartAssessmentModalProps {
assessmentId: string;
isOpen: boolean;
onClose: () => void;
onConfirm: (assessmentId: string) => void;
}
export default function StartAssessmentModal({
assessmentId,
isOpen,
onClose,
onConfirm,
}: StartAssessmentModalProps) {
return (
<Modal opened={isOpen} onClose={onClose} title="Konfirmasi Mulai Asesmen">
<Text>Apakah Anda yakin ingin memulai asesmen ini?</Text>
<Flex gap="sm" justify="flex-end" mt="md">
<Button variant="outline" onClick={onClose}>
Batal
</Button>
<Button
onClick={() => {
onConfirm(assessmentId); // Menggunakan assessmentId saat konfirmasi
}}
>
Mulai Asesmen
</Button>
</Flex>
</Modal>
);
}

View File

@ -25,9 +25,7 @@ import { assessmentRequestQueryOptions, createAssessmentRequest } from "../queri
const routeApi = getRouteApi("/_dashboardLayout/assessmentRequest/"); const routeApi = getRouteApi("/_dashboardLayout/assessmentRequest/");
export default function UserFormModal() { export default function UserFormModal() {
/**
* DON'T CHANGE FOLLOWING:
*/
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const navigate = routeApi.useNavigate(); const navigate = routeApi.useNavigate();
@ -38,16 +36,9 @@ export default function UserFormModal() {
const formType = "create"; const formType = "create";
/**
* CHANGE FOLLOWING:
*/
const userQuery = useQuery(assessmentRequestQueryOptions(0, 10)); const userQuery = useQuery(assessmentRequestQueryOptions(0, 10));
const modalTitle = const modalTitle = <b>Konfirmasi</b>
<b>
Konfirmasi
</b>
const form = useForm({ const form = useForm({
initialValues: { initialValues: {
@ -82,8 +73,9 @@ export default function UserFormModal() {
return await createAssessmentRequest(options.data); return await createAssessmentRequest(options.data);
} }
}, },
// auto refresh after mutation
onSuccess: () => { onSuccess: () => {
// Ini akan memaksa react-query untuk mengambil data terbaru // force a query-reaction to retrieve the latest data
queryClient.invalidateQueries({ queryKey: ["assessmentRequest"] }); queryClient.invalidateQueries({ queryKey: ["assessmentRequest"] });
notifications.show({ notifications.show({
@ -91,7 +83,7 @@ export default function UserFormModal() {
color: "green", color: "green",
}); });
// Menutup modal // close modal
navigate({ search: {} }); navigate({ search: {} });
}, },
onError: (error: unknown) => { onError: (error: unknown) => {
@ -111,6 +103,7 @@ export default function UserFormModal() {
}, },
}); });
// Handle submit form, mutate data to server and close modal after success
const handleSubmit = async (values: typeof form.values) => { const handleSubmit = async (values: typeof form.values) => {
if (formType === "create") { if (formType === "create") {
@ -142,7 +135,7 @@ export default function UserFormModal() {
<Text>Apakah anda yakin ingin membuat Permohonan Asesmen Baru?</Text> <Text>Apakah anda yakin ingin membuat Permohonan Asesmen Baru?</Text>
{/* Fields to display data will be sent */} {/* Fields to display data will be sent but only respondentId */}
{createInputComponents({ {createInputComponents({
disableAll: mutation.isPending, disableAll: mutation.isPending,
readonlyAll: formType === "create", readonlyAll: formType === "create",
@ -171,7 +164,7 @@ export default function UserFormModal() {
})} })}
{/* Buttons */} {/* Buttons */}
<Flex justify="flex-end" align="center" gap="lg" mt="lg"> <Flex justify="flex-end" align="center" gap="sm" mt="lg">
<Button <Button
variant="outline" variant="outline"
type="button" type="button"
@ -184,7 +177,7 @@ export default function UserFormModal() {
type="submit" type="submit"
isLoading={mutation.isPending} isLoading={mutation.isPending}
> >
Ya Buat Permohonan
</Button> </Button>
</Flex> </Flex>
</form> </form>

View File

@ -1,11 +1,14 @@
import { useState } from "react";
import { assessmentRequestQueryOptions } from "@/modules/assessmentRequestManagement/queries/assessmentRequestQueries"; import { assessmentRequestQueryOptions } from "@/modules/assessmentRequestManagement/queries/assessmentRequestQueries";
import PageTemplate from "@/components/PageTemplate"; import PageTemplate from "@/components/PageTemplate";
import { createLazyFileRoute } from "@tanstack/react-router"; import { createLazyFileRoute } from "@tanstack/react-router";
import FormModal from "@/modules/assessmentRequestManagement/modals/FormModal"; import FormModal from "@/modules/assessmentRequestManagement/modals/CreateAssessmentRequestModal";
import ExtractQueryDataType from "@/types/ExtractQueryDataType"; import ExtractQueryDataType from "@/types/ExtractQueryDataType";
import { createColumnHelper } from "@tanstack/react-table"; import { createColumnHelper } from "@tanstack/react-table";
import { Badge, Flex } from "@mantine/core"; import { Flex } from "@mantine/core";
import { Badge } from "@/shadcn/components/ui/badge";
import { Button } from "@/shadcn/components/ui/button"; import { Button } from "@/shadcn/components/ui/button";
import StartAssessmentModal from "@/modules/assessmentRequestManagement/modals/ConfirmModal";
export const Route = createLazyFileRoute("/_dashboardLayout/assessmentRequest/")({ export const Route = createLazyFileRoute("/_dashboardLayout/assessmentRequest/")({
component: UsersPage, component: UsersPage,
@ -16,101 +19,137 @@ type DataType = ExtractQueryDataType<typeof assessmentRequestQueryOptions>;
const columnHelper = createColumnHelper<DataType>(); const columnHelper = createColumnHelper<DataType>();
export default function UsersPage() { export default function UsersPage() {
const [modalOpen, setModalOpen] = useState(false);
const [selectedAssessmentId, setSelectedAssessmentId] = useState<string | null>(null);
const handleStartAssessment = (assessmentId: string) => { /**
const userConfirmed = window.confirm("Apakah anda yakin untuk memulai asesmen?"); * Fungsi untuk membuka modal konfirmasi mulai asesmen
* @param {string} assessmentId ID asesmen yang akan di mulai
*/
const handleOpenModal = (assessmentId: string) => {
if (!assessmentId) {
console.error("Assessment ID is missing");
return;
}
if (userConfirmed) { setSelectedAssessmentId(assessmentId);
// Redirect ke URL baru di tab baru setModalOpen(true);
const assessmentUrl = `/assessment?id=${assessmentId}`;
window.open(assessmentUrl, "_blank");
}
}; };
/**
* Fungsi untuk membuka halaman asesmen di tab baru
* @param {string} assessmentId ID asesmen yang akan di buka
*/
const handleStartAssessment = (assessmentId: string) => {
// Redirect ke URL baru di tab baru
const assessmentUrl = `/assessment?id=${assessmentId}`;
window.open(assessmentUrl, "_blank");
setModalOpen(false);
};
/**
* Fungsi untuk membuka halaman hasil asesmen berdasarkan ID yang valid
* Digunakan ketika tombol "Lihat Hasil" diklik
* @param {string} assessmentId ID asesmen yang akan di buka
*/
const handleViewResult = (assessmentId: string) => {
// Make sure assessmentId is valid and not null
if (!assessmentId) {
console.error("Assessment ID is missing");
return;
}
const resultUrl = `/assessmentResult/${assessmentId}`;
window.location.href = resultUrl;
};
return ( return (
<PageTemplate <>
title="Permohonan Asesmen" <PageTemplate
queryOptions={assessmentRequestQueryOptions} title="Permohonan Asesmen"
modals={[<FormModal />]} queryOptions={assessmentRequestQueryOptions}
columnDefs={[ modals={[<FormModal />]}
columnHelper.display({ columnDefs={[
header: "No", columnHelper.display({
cell: (props) => props.row.index + 1, header: "No",
}), cell: (props) => props.row.index + 1,
columnHelper.display({ }),
header: "Tanggal", columnHelper.display({
cell: (props) => header: "Tanggal",
props.row.original.createdAt cell: (props) =>
? new Intl.DateTimeFormat("ID", { props.row.original.createdAt
year: "numeric", ? new Intl.DateTimeFormat("ID", {
month: "long", year: "numeric",
day: "2-digit", month: "long",
hour: "2-digit", day: "2-digit",
minute: "2-digit", hour: "2-digit",
hour12: true, minute: "2-digit",
}).format(new Date(props.row.original.createdAt)) hour12: true,
: 'N/A', }).format(new Date(props.row.original.createdAt))
}), : 'N/A',
}),
columnHelper.display({
header: "Status",
cell: (props) => {
const status = props.row.original.status;
switch (status) {
case "menunggu konfirmasi":
// return <Badge color="yellow">Menunggu Konfirmasi</Badge>;
return <Badge variant={"waiting"}>Menunggu Konfirmasi</Badge>;
case "diterima":
return <Badge variant={"accepted"}>Diterima</Badge>;
case "ditolak":
return <Badge variant={"rejected"}>Ditolak</Badge>;
case "selesai":
return <Badge variant={"completed"}>Selesai</Badge>;
default:
return <Badge variant={"outline"}>Tidak diketahui</Badge>;
}
},
}),
columnHelper.display({
header: "Actions",
cell: (props) => {
const status = props.row.original.status;
const assessmentId = props.row.original.id; // Retrieve the assessmentId from the data row
columnHelper.display({ return (
header: "Status", <Flex gap="xs">
cell: (props) => { {/* Button Create Assessment */}
const status = props.row.original.status; {status === "selesai" ? (
switch (status) {
case "menunggu konfirmasi":
return <Badge color="yellow">Menunggu Konfirmasi</Badge>;
case "diterima":
return <Badge color="green">Diterima</Badge>;
case "ditolak":
return <Badge color="red">Ditolak</Badge>;
case "selesai":
return <Badge color="blue">Selesai</Badge>;
default:
return <Badge color="gray">Tidak diketahui</Badge>;
}
},
}),
columnHelper.display({
header: "Aksi",
cell: (props) => {
const status = props.row.original.status;
const assessmentId = props.row.original.id;
return (
<Flex gap="xs">
{status === "selesai" ? (
<>
<Button disabled>Mulai Asesmen</Button> <Button disabled>Mulai Asesmen</Button>
<Button onClick={() => alert('Lihat Hasil')}>Lihat Hasil</Button> ) : status === "diterima" ? (
</>
) : status === "diterima" ? (
<>
<Button <Button
onClick={() => { onClick={() => handleOpenModal(assessmentId ?? '')}
if (assessmentId) {
handleStartAssessment(assessmentId);
} else {
alert("Assessment ID tidak valid.");
}
}}
> >
Mulai Asesmen Mulai Asesmen
</Button> </Button>
<Button disabled>Lihat Hasil</Button> ) : (
</>
) : status === "menunggu konfirmasi" || status === "ditolak" ? (
<>
<Button disabled>Mulai Asesmen</Button> <Button disabled>Mulai Asesmen</Button>
)}
{/* Button View Result */}
{status === "selesai" ? (
<Button onClick={()=>handleViewResult(assessmentId ?? '')}>Lihat Hasil</Button>
) : (
<Button disabled>Lihat Hasil</Button> <Button disabled>Lihat Hasil</Button>
</> )}
) : null} </Flex>
</Flex> );
); },
}, }),
}), ]}
]} />
/>
{/* Modal Konfirmasi Start Asessment */}
{selectedAssessmentId && (
<StartAssessmentModal
assessmentId={selectedAssessmentId}
isOpen={modalOpen}
onClose={() => setModalOpen(false)}
onConfirm={handleStartAssessment}
/>
)}
</>
); );
} }

View File

@ -15,6 +15,12 @@ const badgeVariants = cva(
destructive: destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground", outline: "text-foreground",
// Custom variants for status
waiting: "border-transparent bg-yellow-500 text-white hover:bg-yellow-600",
accepted: "border-transparent bg-green-500 text-white hover:bg-green-600",
rejected: "border-transparent bg-red-500 text-white hover:bg-red-600",
completed: "border-transparent bg-blue-500 text-white hover:bg-blue-600",
}, },
}, },
defaultVariants: { defaultVariants: {

View File

@ -52,7 +52,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
{...props} {...props}
> >
{isLoading ? ( {isLoading ? (
<TbLoader2 className="mr-2 h-4 w-4 animate-spin" /> // Tampilkan spinner saat loading <TbLoader2 className="mr-2 h-4 w-4 animate-spin" /> // Show spinner when loading
) : ( ) : (
children children
)} )}