feat: add print to pdf feature

This commit is contained in:
Sukma Gladys 2024-11-05 20:42:12 +07:00
parent d87b98d828
commit c495a1257c
6 changed files with 1695 additions and 129 deletions

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"hono": "^4.4.6", "hono": "^4.4.6",
"html2pdf.js": "^0.10.2",
"lucide-react": "^0.414.0", "lucide-react": "^0.414.0",
"mantine-form-zod-resolver": "^1.1.0", "mantine-form-zod-resolver": "^1.1.0",
"react": "^18.3.1", "react": "^18.3.1",

View File

@ -13,12 +13,19 @@ import { createFileRoute } from '@tanstack/react-router'
// Import Routes // Import Routes
import { Route as rootRoute } from './routes/__root' import { Route as rootRoute } from './routes/__root'
import { Route as VerifyingLayoutImport } from './routes/_verifyingLayout'
import { Route as DashboardLayoutImport } from './routes/_dashboardLayout' import { Route as DashboardLayoutImport } from './routes/_dashboardLayout'
import { Route as AssessmentLayoutImport } from './routes/_assessmentLayout'
import { Route as VerifyingLayoutVerifyingIndexImport } from './routes/_verifyingLayout/verifying/index'
import { Route as DashboardLayoutUsersIndexImport } from './routes/_dashboardLayout/users/index' import { Route as DashboardLayoutUsersIndexImport } from './routes/_dashboardLayout/users/index'
import { Route as DashboardLayoutTimetableIndexImport } from './routes/_dashboardLayout/timetable/index' import { Route as DashboardLayoutTimetableIndexImport } from './routes/_dashboardLayout/timetable/index'
import { Route as DashboardLayoutDashboardIndexImport } from './routes/_dashboardLayout/dashboard/index' import { Route as DashboardLayoutQuestionsIndexImport } from './routes/_dashboardLayout/questions/index'
import { Route as DashboardLayoutAssessmentResultsManagementIndexImport } from './routes/_dashboardLayout/assessmentResultsManagement/index'
import { Route as DashboardLayoutAssessmentResultIndexImport } from './routes/_dashboardLayout/assessmentResult/index'
import { Route as DashboardLayoutAssessmentRequestManagementsIndexImport } from './routes/_dashboardLayout/assessmentRequestManagements/index'
import { Route as DashboardLayoutAssessmentRequestIndexImport } from './routes/_dashboardLayout/assessmentRequest/index' import { Route as DashboardLayoutAssessmentRequestIndexImport } from './routes/_dashboardLayout/assessmentRequest/index'
import { Route as DashboardLayoutAspectIndexImport } from './routes/_dashboardLayout/aspect/index' import { Route as DashboardLayoutAspectIndexImport } from './routes/_dashboardLayout/aspect/index'
import { Route as AssessmentLayoutAssessmentIndexImport } from './routes/_assessmentLayout/assessment/index'
// Create Virtual Routes // Create Virtual Routes
@ -33,11 +40,21 @@ const ForgotPasswordVerifyLazyImport = createFileRoute(
// Create/Update Routes // Create/Update Routes
const VerifyingLayoutRoute = VerifyingLayoutImport.update({
id: '/_verifyingLayout',
getParentRoute: () => rootRoute,
} as any)
const DashboardLayoutRoute = DashboardLayoutImport.update({ const DashboardLayoutRoute = DashboardLayoutImport.update({
id: '/_dashboardLayout', id: '/_dashboardLayout',
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
} as any) } as any)
const AssessmentLayoutRoute = AssessmentLayoutImport.update({
id: '/_assessmentLayout',
getParentRoute: () => rootRoute,
} as any)
const IndexLazyRoute = IndexLazyImport.update({ const IndexLazyRoute = IndexLazyImport.update({
path: '/', path: '/',
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
@ -74,6 +91,16 @@ const ForgotPasswordVerifyLazyRoute = ForgotPasswordVerifyLazyImport.update({
import('./routes/forgot-password/verify.lazy').then((d) => d.Route), import('./routes/forgot-password/verify.lazy').then((d) => d.Route),
) )
const VerifyingLayoutVerifyingIndexRoute =
VerifyingLayoutVerifyingIndexImport.update({
path: '/verifying/',
getParentRoute: () => VerifyingLayoutRoute,
} as any).lazy(() =>
import('./routes/_verifyingLayout/verifying/index.lazy').then(
(d) => d.Route,
),
)
const DashboardLayoutUsersIndexRoute = DashboardLayoutUsersIndexImport.update({ const DashboardLayoutUsersIndexRoute = DashboardLayoutUsersIndexImport.update({
path: '/users/', path: '/users/',
getParentRoute: () => DashboardLayoutRoute, getParentRoute: () => DashboardLayoutRoute,
@ -87,11 +114,45 @@ const DashboardLayoutTimetableIndexRoute =
getParentRoute: () => DashboardLayoutRoute, getParentRoute: () => DashboardLayoutRoute,
} as any) } as any)
const DashboardLayoutDashboardIndexRoute = const DashboardLayoutQuestionsIndexRoute =
DashboardLayoutDashboardIndexImport.update({ DashboardLayoutQuestionsIndexImport.update({
path: '/dashboard/', path: '/questions/',
getParentRoute: () => DashboardLayoutRoute, getParentRoute: () => DashboardLayoutRoute,
} as any) } as any).lazy(() =>
import('./routes/_dashboardLayout/questions/index.lazy').then(
(d) => d.Route,
),
)
const DashboardLayoutAssessmentResultsManagementIndexRoute =
DashboardLayoutAssessmentResultsManagementIndexImport.update({
path: '/assessmentResultsManagement/',
getParentRoute: () => DashboardLayoutRoute,
} as any).lazy(() =>
import(
'./routes/_dashboardLayout/assessmentResultsManagement/index.lazy'
).then((d) => d.Route),
)
const DashboardLayoutAssessmentResultIndexRoute =
DashboardLayoutAssessmentResultIndexImport.update({
path: '/assessmentResult/',
getParentRoute: () => DashboardLayoutRoute,
} as any).lazy(() =>
import('./routes/_dashboardLayout/assessmentResult/index.lazy').then(
(d) => d.Route,
),
)
const DashboardLayoutAssessmentRequestManagementsIndexRoute =
DashboardLayoutAssessmentRequestManagementsIndexImport.update({
path: '/assessmentRequestManagements/',
getParentRoute: () => DashboardLayoutRoute,
} as any).lazy(() =>
import(
'./routes/_dashboardLayout/assessmentRequestManagements/index.lazy'
).then((d) => d.Route),
)
const DashboardLayoutAssessmentRequestIndexRoute = const DashboardLayoutAssessmentRequestIndexRoute =
DashboardLayoutAssessmentRequestIndexImport.update({ DashboardLayoutAssessmentRequestIndexImport.update({
@ -112,6 +173,16 @@ const DashboardLayoutAspectIndexRoute = DashboardLayoutAspectIndexImport.update(
import('./routes/_dashboardLayout/aspect/index.lazy').then((d) => d.Route), import('./routes/_dashboardLayout/aspect/index.lazy').then((d) => d.Route),
) )
const AssessmentLayoutAssessmentIndexRoute =
AssessmentLayoutAssessmentIndexImport.update({
path: '/assessment/',
getParentRoute: () => AssessmentLayoutRoute,
} as any).lazy(() =>
import('./routes/_assessmentLayout/assessment/index.lazy').then(
(d) => d.Route,
),
)
// Populate the FileRoutesByPath interface // Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
@ -123,6 +194,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexLazyImport preLoaderRoute: typeof IndexLazyImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/_assessmentLayout': {
id: '/_assessmentLayout'
path: ''
fullPath: ''
preLoaderRoute: typeof AssessmentLayoutImport
parentRoute: typeof rootRoute
}
'/_dashboardLayout': { '/_dashboardLayout': {
id: '/_dashboardLayout' id: '/_dashboardLayout'
path: '' path: ''
@ -130,6 +208,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardLayoutImport preLoaderRoute: typeof DashboardLayoutImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/_verifyingLayout': {
id: '/_verifyingLayout'
path: ''
fullPath: ''
preLoaderRoute: typeof VerifyingLayoutImport
parentRoute: typeof rootRoute
}
'/forgot-password/verify': { '/forgot-password/verify': {
id: '/forgot-password/verify' id: '/forgot-password/verify'
path: '/forgot-password/verify' path: '/forgot-password/verify'
@ -165,6 +250,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof RegisterIndexLazyImport preLoaderRoute: typeof RegisterIndexLazyImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/_assessmentLayout/assessment/': {
id: '/_assessmentLayout/assessment/'
path: '/assessment'
fullPath: '/assessment'
preLoaderRoute: typeof AssessmentLayoutAssessmentIndexImport
parentRoute: typeof AssessmentLayoutImport
}
'/_dashboardLayout/aspect/': { '/_dashboardLayout/aspect/': {
id: '/_dashboardLayout/aspect/' id: '/_dashboardLayout/aspect/'
path: '/aspect' path: '/aspect'
@ -179,11 +271,32 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardLayoutAssessmentRequestIndexImport preLoaderRoute: typeof DashboardLayoutAssessmentRequestIndexImport
parentRoute: typeof DashboardLayoutImport parentRoute: typeof DashboardLayoutImport
} }
'/_dashboardLayout/dashboard/': { '/_dashboardLayout/assessmentRequestManagements/': {
id: '/_dashboardLayout/dashboard/' id: '/_dashboardLayout/assessmentRequestManagements/'
path: '/dashboard' path: '/assessmentRequestManagements'
fullPath: '/dashboard' fullPath: '/assessmentRequestManagements'
preLoaderRoute: typeof DashboardLayoutDashboardIndexImport preLoaderRoute: typeof DashboardLayoutAssessmentRequestManagementsIndexImport
parentRoute: typeof DashboardLayoutImport
}
'/_dashboardLayout/assessmentResult/': {
id: '/_dashboardLayout/assessmentResult/'
path: '/assessmentResult'
fullPath: '/assessmentResult'
preLoaderRoute: typeof DashboardLayoutAssessmentResultIndexImport
parentRoute: typeof DashboardLayoutImport
}
'/_dashboardLayout/assessmentResultsManagement/': {
id: '/_dashboardLayout/assessmentResultsManagement/'
path: '/assessmentResultsManagement'
fullPath: '/assessmentResultsManagement'
preLoaderRoute: typeof DashboardLayoutAssessmentResultsManagementIndexImport
parentRoute: typeof DashboardLayoutImport
}
'/_dashboardLayout/questions/': {
id: '/_dashboardLayout/questions/'
path: '/questions'
fullPath: '/questions'
preLoaderRoute: typeof DashboardLayoutQuestionsIndexImport
parentRoute: typeof DashboardLayoutImport parentRoute: typeof DashboardLayoutImport
} }
'/_dashboardLayout/timetable/': { '/_dashboardLayout/timetable/': {
@ -200,6 +313,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardLayoutUsersIndexImport preLoaderRoute: typeof DashboardLayoutUsersIndexImport
parentRoute: typeof DashboardLayoutImport parentRoute: typeof DashboardLayoutImport
} }
'/_verifyingLayout/verifying/': {
id: '/_verifyingLayout/verifying/'
path: '/verifying'
fullPath: '/verifying'
preLoaderRoute: typeof VerifyingLayoutVerifyingIndexImport
parentRoute: typeof VerifyingLayoutImport
}
} }
} }
@ -207,13 +327,22 @@ declare module '@tanstack/react-router' {
export const routeTree = rootRoute.addChildren({ export const routeTree = rootRoute.addChildren({
IndexLazyRoute, IndexLazyRoute,
AssessmentLayoutRoute: AssessmentLayoutRoute.addChildren({
AssessmentLayoutAssessmentIndexRoute,
}),
DashboardLayoutRoute: DashboardLayoutRoute.addChildren({ DashboardLayoutRoute: DashboardLayoutRoute.addChildren({
DashboardLayoutAspectIndexRoute, DashboardLayoutAspectIndexRoute,
DashboardLayoutAssessmentRequestIndexRoute, DashboardLayoutAssessmentRequestIndexRoute,
DashboardLayoutDashboardIndexRoute, DashboardLayoutAssessmentRequestManagementsIndexRoute,
DashboardLayoutAssessmentResultIndexRoute,
DashboardLayoutAssessmentResultsManagementIndexRoute,
DashboardLayoutQuestionsIndexRoute,
DashboardLayoutTimetableIndexRoute, DashboardLayoutTimetableIndexRoute,
DashboardLayoutUsersIndexRoute, DashboardLayoutUsersIndexRoute,
}), }),
VerifyingLayoutRoute: VerifyingLayoutRoute.addChildren({
VerifyingLayoutVerifyingIndexRoute,
}),
ForgotPasswordVerifyLazyRoute, ForgotPasswordVerifyLazyRoute,
ForgotPasswordIndexLazyRoute, ForgotPasswordIndexLazyRoute,
LoginIndexLazyRoute, LoginIndexLazyRoute,
@ -230,7 +359,9 @@ export const routeTree = rootRoute.addChildren({
"filePath": "__root.tsx", "filePath": "__root.tsx",
"children": [ "children": [
"/", "/",
"/_assessmentLayout",
"/_dashboardLayout", "/_dashboardLayout",
"/_verifyingLayout",
"/forgot-password/verify", "/forgot-password/verify",
"/forgot-password/", "/forgot-password/",
"/login/", "/login/",
@ -241,16 +372,31 @@ export const routeTree = rootRoute.addChildren({
"/": { "/": {
"filePath": "index.lazy.tsx" "filePath": "index.lazy.tsx"
}, },
"/_assessmentLayout": {
"filePath": "_assessmentLayout.tsx",
"children": [
"/_assessmentLayout/assessment/"
]
},
"/_dashboardLayout": { "/_dashboardLayout": {
"filePath": "_dashboardLayout.tsx", "filePath": "_dashboardLayout.tsx",
"children": [ "children": [
"/_dashboardLayout/aspect/", "/_dashboardLayout/aspect/",
"/_dashboardLayout/assessmentRequest/", "/_dashboardLayout/assessmentRequest/",
"/_dashboardLayout/dashboard/", "/_dashboardLayout/assessmentRequestManagements/",
"/_dashboardLayout/assessmentResult/",
"/_dashboardLayout/assessmentResultsManagement/",
"/_dashboardLayout/questions/",
"/_dashboardLayout/timetable/", "/_dashboardLayout/timetable/",
"/_dashboardLayout/users/" "/_dashboardLayout/users/"
] ]
}, },
"/_verifyingLayout": {
"filePath": "_verifyingLayout.tsx",
"children": [
"/_verifyingLayout/verifying/"
]
},
"/forgot-password/verify": { "/forgot-password/verify": {
"filePath": "forgot-password/verify.lazy.tsx" "filePath": "forgot-password/verify.lazy.tsx"
}, },
@ -266,6 +412,10 @@ export const routeTree = rootRoute.addChildren({
"/register/": { "/register/": {
"filePath": "register/index.lazy.tsx" "filePath": "register/index.lazy.tsx"
}, },
"/_assessmentLayout/assessment/": {
"filePath": "_assessmentLayout/assessment/index.tsx",
"parent": "/_assessmentLayout"
},
"/_dashboardLayout/aspect/": { "/_dashboardLayout/aspect/": {
"filePath": "_dashboardLayout/aspect/index.tsx", "filePath": "_dashboardLayout/aspect/index.tsx",
"parent": "/_dashboardLayout" "parent": "/_dashboardLayout"
@ -274,8 +424,20 @@ export const routeTree = rootRoute.addChildren({
"filePath": "_dashboardLayout/assessmentRequest/index.tsx", "filePath": "_dashboardLayout/assessmentRequest/index.tsx",
"parent": "/_dashboardLayout" "parent": "/_dashboardLayout"
}, },
"/_dashboardLayout/dashboard/": { "/_dashboardLayout/assessmentRequestManagements/": {
"filePath": "_dashboardLayout/dashboard/index.tsx", "filePath": "_dashboardLayout/assessmentRequestManagements/index.tsx",
"parent": "/_dashboardLayout"
},
"/_dashboardLayout/assessmentResult/": {
"filePath": "_dashboardLayout/assessmentResult/index.tsx",
"parent": "/_dashboardLayout"
},
"/_dashboardLayout/assessmentResultsManagement/": {
"filePath": "_dashboardLayout/assessmentResultsManagement/index.tsx",
"parent": "/_dashboardLayout"
},
"/_dashboardLayout/questions/": {
"filePath": "_dashboardLayout/questions/index.tsx",
"parent": "/_dashboardLayout" "parent": "/_dashboardLayout"
}, },
"/_dashboardLayout/timetable/": { "/_dashboardLayout/timetable/": {
@ -285,6 +447,10 @@ export const routeTree = rootRoute.addChildren({
"/_dashboardLayout/users/": { "/_dashboardLayout/users/": {
"filePath": "_dashboardLayout/users/index.tsx", "filePath": "_dashboardLayout/users/index.tsx",
"parent": "/_dashboardLayout" "parent": "/_dashboardLayout"
},
"/_verifyingLayout/verifying/": {
"filePath": "_verifyingLayout/verifying/index.tsx",
"parent": "/_verifyingLayout"
} }
} }
} }

View File

@ -1,4 +1,5 @@
import { SetStateAction, useEffect, useState } from "react"; import { SetStateAction, useEffect, useRef, useState } from "react";
import html2pdf from "html2pdf.js";
import useAuth from "@/hooks/useAuth"; import useAuth from "@/hooks/useAuth";
import { createLazyFileRoute } from "@tanstack/react-router"; import { createLazyFileRoute } from "@tanstack/react-router";
import { getAllAspectsAverageScore, getAllSubAspectsAverageScore, getAllVerifiedAspectsAverageScore, getAllVerifiedSubAspectsAverageScore } from "@/modules/assessmentResult/queries/assessmentResultQueries"; import { getAllAspectsAverageScore, getAllSubAspectsAverageScore, getAllVerifiedAspectsAverageScore, getAllVerifiedSubAspectsAverageScore } from "@/modules/assessmentResult/queries/assessmentResultQueries";
@ -185,13 +186,10 @@ export default function AssessmentResultPage() {
}; };
const handleItemClick = () => { const handleItemClick = () => {
// Mengubah antara "Hasil Sementara" dan "Hasil Terverifikasi" setSelectedItem(prev =>
if (selectedItem === 'Hasil Sementara') { prev === 'Hasil Sementara' ? 'Hasil Terverifikasi' : 'Hasil Sementara'
setSelectedItem('Hasil Terverifikasi'); // Mengubah teks dropdown );
} else { setIsOpen(false); // Tutup dropdown setelah klik item
setSelectedItem('Hasil Sementara'); // Mengubah kembali ke teks awal
}
setIsOpen(false); // Menutup dropdown setelah item dipilih
}; };
// Pie Chart Component // Pie Chart Component
@ -349,11 +347,64 @@ export default function AssessmentResultPage() {
); );
} }
const cardRef = useRef<HTMLDivElement | null>(null); // Create a ref for your component
const handlePrintPDF = async () => {
const element = cardRef.current;
if (element) {
// Sembunyikan elemen yang tidak ingin dicetak
const noPrint = document.getElementById("no-print");
if (noPrint) noPrint.style.visibility = 'hidden'; // Menggunakan visibility untuk tetap menjaga ruang
// Pastikan elemen memiliki lebar 100%
element.style.width = '100%'; // Mengatur lebar konten
const options = {
margin: [0.4, 0.5, 0.4, 0], // Margin kecil untuk mengurangi ruang kosong
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2, // Mengatur scale agar kualitas tinggi
width: element.scrollWidth,
height: element.scrollHeight,
},
jsPDF: {
unit: 'in',
format: 'a4',
orientation: 'landscape',
}
};
try {
const pdfBlob: Blob = await html2pdf()
.set(options)
.from(element)
.toPdf()
.get('pdf')
.then((pdf: any) => {
pdf.setProperties({
title: 'Hasil_Asesemen_Level_Maturitas',
});
return pdf.output('blob'); // Menghasilkan PDF sebagai blob dengan title
});
// Buat URL dari Blob dan buka di tab baru untuk pratinjau
const pdfURL = URL.createObjectURL(pdfBlob);
window.open(pdfURL, '_blank'); // Pratinjau di tab baru tanpa unduh
} catch (err) {
console.error("Error generating PDF:", err);
} finally {
// Tampilkan kembali elemen yang disembunyikan
if (noPrint) noPrint.style.visibility = 'visible'; // Mengembalikan visibility
element.style.width = ""; // Reset lebar setelah selesai
}
}
};
return ( return (
<Card className="flex flex-row w-full h-full border-none shadow-none"> <Card ref={cardRef} className="flex flex-row w-full h-full border-none shadow-none">
<div className="flex flex-col w-fit min-h-fit border-none shadow-none -ml-1 -pr-2"> <div className="flex flex-col w-fit h-fit border-none shadow-none -ml-1 -pr-2">
<p className="font-bold mt-2">Tingkatan Level Maturitas</p> <p className="font-bold mt-2 ml-2">Tingkatan Level Maturitas</p>
<div className="flex flex-col mr-5 -ml-5 h-full"> <div className="flex flex-col mr-5 -ml-5 h-full">
{[ {[
{ level: 5, colorVar: '--levelFive-color', title: 'Implementasi Optimal', details: ['Otomatisasi', 'Terintegrasi', 'Membudaya'], textColor: 'white' }, { level: 5, colorVar: '--levelFive-color', title: 'Implementasi Optimal', details: ['Otomatisasi', 'Terintegrasi', 'Membudaya'], textColor: 'white' },
@ -403,8 +454,14 @@ export default function AssessmentResultPage() {
</div> </div>
)} )}
{/* Dropdown */} <div className="flex flex-row gap-2" id="no-print">
<div className="fixed right-9"> <button
onClick={handlePrintPDF}
className="bg-blue-600 text-white flex w-fit p-2 rounded-sm text-sm items-start justify-between outline-none ring-offset-0"
>
Cetak ke PDF
</button>
<div className="flex">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger <DropdownMenuTrigger
className="bg-blue-600 text-white flex w-44 p-2 pl-4 rounded-sm text-sm items-start justify-between outline-none ring-offset-0" className="bg-blue-600 text-white flex w-44 p-2 pl-4 rounded-sm text-sm items-start justify-between outline-none ring-offset-0"
@ -428,6 +485,7 @@ export default function AssessmentResultPage() {
</div> </div>
</div> </div>
</div> </div>
</div>
{isSuperAdmin && {isSuperAdmin &&
<Card className="flex flex-col w-full h-full mb-6 justify-center items-start"> <Card className="flex flex-col w-full h-full mb-6 justify-center items-start">
@ -505,10 +563,10 @@ export default function AssessmentResultPage() {
<> <>
{/* Score Table */} {/* Score Table */}
<p className="text-lg font-bold">Tabel Level Maturitas</p> <p className="text-lg font-bold">Tabel Level Maturitas</p>
<Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden border-y"> <Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden text-center">
<div className="flex flex-row"> <div className="flex flex-row w-full">
{aspectsData?.data?.map((aspect) => ( {aspectsData?.data?.map((aspect) => (
<div key={aspect.id} className="flex-col bg-white w-full h-full border-x border-t"> <div key={aspect.id} className="flex-col bg-white w-full h-full border-t border-x">
<div className="flex flex-col font-bold items-center justify-center p-2 h-full w-full border-b" style={getScoreStyleClass(getAspectScore(aspect.id))}> <div className="flex flex-col font-bold items-center justify-center p-2 h-full w-full border-b" style={getScoreStyleClass(getAspectScore(aspect.id))}>
<p className="text-sm text-black">{aspect.name}</p> <p className="text-sm text-black">{aspect.name}</p>
<span className="text-2xl">{formatScore(getAspectScore(aspect.id))}</span> <span className="text-2xl">{formatScore(getAspectScore(aspect.id))}</span>
@ -516,7 +574,7 @@ export default function AssessmentResultPage() {
{aspect.subAspects.map((subAspect) => ( {aspect.subAspects.map((subAspect) => (
<div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full"> <div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full">
<div className="flex flex-row gap-2 justify-between h-full w-full"> <div className="flex flex-row gap-2 justify-between h-full w-full">
<p className="text-xs text-muted-foreground">{subAspect.name}</p> <p className="text-xs text-muted-foreground text-left">{subAspect.name}</p>
<span className="text-xs font-bold">{formatScore(getSubAspectScore(subAspect.id))}</span> <span className="text-xs font-bold">{formatScore(getSubAspectScore(subAspect.id))}</span>
</div> </div>
</div> </div>
@ -526,8 +584,8 @@ export default function AssessmentResultPage() {
</div> </div>
{/* Total score */} {/* Total score */}
<div className="flex flex-row w-full h-14 gap-2 items-center justify-center font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}> <div className="flex flex-row w-full h-fit p-3 justify-center gap-2 font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}>
<p>Level Maturitas:</p> <p className="text-center">Level Maturitas:</p>
<span>{totalScore}</span> <span>{totalScore}</span>
</div> </div>
</Card> </Card>
@ -536,7 +594,7 @@ export default function AssessmentResultPage() {
<> <>
{/* Verified Result Table */} {/* Verified Result Table */}
<p className="text-lg font-bold">Tabel Level Maturitas Terverifikasi</p> <p className="text-lg font-bold">Tabel Level Maturitas Terverifikasi</p>
<Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden border-y"> <Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden border-y text-center">
<div className="flex flex-row"> <div className="flex flex-row">
{aspectsData?.data?.map((aspect) => ( {aspectsData?.data?.map((aspect) => (
<div key={aspect.id} className="flex-col bg-white w-full h-full border-x border-t"> <div key={aspect.id} className="flex-col bg-white w-full h-full border-x border-t">
@ -547,7 +605,7 @@ export default function AssessmentResultPage() {
{aspect.subAspects.map((subAspect) => ( {aspect.subAspects.map((subAspect) => (
<div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full"> <div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full">
<div className="flex flex-row gap-2 justify-between h-full w-full"> <div className="flex flex-row gap-2 justify-between h-full w-full">
<p className="text-xs text-muted-foreground">{subAspect.name}</p> <p className="text-xs text-muted-foreground text-left">{subAspect.name}</p>
<span className="text-xs font-bold">{formatScore(getVerifiedSubAspectScore(subAspect.id))}</span> <span className="text-xs font-bold">{formatScore(getVerifiedSubAspectScore(subAspect.id))}</span>
</div> </div>
</div> </div>
@ -557,18 +615,17 @@ export default function AssessmentResultPage() {
</div> </div>
{/* Total verified score */} {/* Total verified score */}
<div className="flex flex-row w-full h-14 gap-2 items-center justify-center font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}> <div className="flex flex-row w-full h-fit p-3 justify-center gap-2 font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}>
<p>Level Maturitas:</p> <p className="text-center">Level Maturitas:</p>
<span>{totalVerifiedScore}</span> <span>{totalVerifiedScore}</span>
</div> </div>
</Card> </Card>
</> </>
)} )}
<Card className="flex flex-col lg:flex-row gap-8 border-none shadow-none"> <Card className="flex flex-col lg:flex-row gap-8 border-none shadow-none w-full">
{/* Pie Chart */} {/* Pie Chart */}
{selectedItem === 'Hasil Sementara' ? ( {selectedItem === 'Hasil Sementara' ? (
<>
<Card className="flex flex-col w-full"> <Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0"> <CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Lingkaran</CardTitle> <CardTitle className="text-lg">Diagram Lingkaran</CardTitle>
@ -581,9 +638,7 @@ export default function AssessmentResultPage() {
/> />
</CardContent> </CardContent>
</Card> </Card>
</>
) : ( ) : (
<>
<Card className="flex flex-col w-full"> <Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0"> <CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Lingkaran Terverifikasi</CardTitle> <CardTitle className="text-lg">Diagram Lingkaran Terverifikasi</CardTitle>
@ -596,12 +651,11 @@ export default function AssessmentResultPage() {
/> />
</CardContent> </CardContent>
</Card> </Card>
</>
)} )}
{/* Radar Chart */} {/* Radar Chart */}
{selectedItem === 'Hasil Sementara' ? ( {selectedItem === 'Hasil Sementara' ? (
<> <Card className="flex flex-col w-full">
<Card className="flex flex-col w-full mb-4">
<CardHeader className="items-start pb-0"> <CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Radar</CardTitle> <CardTitle className="text-lg">Diagram Radar</CardTitle>
</CardHeader> </CardHeader>
@ -609,10 +663,8 @@ export default function AssessmentResultPage() {
<RadarChartComponent chartData={chartData} chartConfig={chartConfig} /> <RadarChartComponent chartData={chartData} chartConfig={chartConfig} />
</CardContent> </CardContent>
</Card> </Card>
</>
) : ( ) : (
<> <Card className="flex flex-col w-full">
<Card className="flex flex-col w-full mb-4">
<CardHeader className="items-start pb-0"> <CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Radar Terverifikasi</CardTitle> <CardTitle className="text-lg">Diagram Radar Terverifikasi</CardTitle>
</CardHeader> </CardHeader>
@ -620,7 +672,6 @@ export default function AssessmentResultPage() {
<RadarChartComponent chartData={verifiedChartData} chartConfig={chartConfig} /> <RadarChartComponent chartData={verifiedChartData} chartConfig={chartConfig} />
</CardContent> </CardContent>
</Card> </Card>
</>
)} )}
</Card> </Card>

1
apps/frontend/src/types/html2pdf.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'html2pdf.js';

View File

@ -168,6 +168,9 @@ importers:
hono: hono:
specifier: ^4.4.6 specifier: ^4.4.6
version: 4.4.6 version: 4.4.6
html2pdf.js:
specifier: ^0.10.2
version: 0.10.2
lucide-react: lucide-react:
specifier: ^0.414.0 specifier: ^0.414.0
version: 0.414.0(react@18.3.1) version: 0.414.0(react@18.3.1)
@ -2400,6 +2403,9 @@ packages:
'@types/prop-types@15.7.5': '@types/prop-types@15.7.5':
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
'@types/raf@3.4.3':
resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
'@types/react-dom@18.2.19': '@types/react-dom@18.2.19':
resolution: {integrity: sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==} resolution: {integrity: sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==}
@ -2837,6 +2843,11 @@ packages:
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
engines: {node: '>=4'} engines: {node: '>=4'}
atob@2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
engines: {node: '>= 4.5.0'}
hasBin: true
autoprefixer@10.4.19: autoprefixer@10.4.19:
resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -2887,6 +2898,10 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@ -2932,6 +2947,11 @@ packages:
bser@2.1.1: bser@2.1.1:
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
btoa@1.2.1:
resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==}
engines: {node: '>= 0.4.0'}
hasBin: true
buffer-equal-constant-time@1.0.1: buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
@ -2980,6 +3000,10 @@ packages:
caniuse-lite@1.0.30001667: caniuse-lite@1.0.30001667:
resolution: {integrity: sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==} resolution: {integrity: sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==}
canvg@3.0.10:
resolution: {integrity: sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==}
engines: {node: '>=10.0.0'}
chalk@2.4.2: chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3113,6 +3137,9 @@ packages:
core-js-pure@3.32.1: core-js-pure@3.32.1:
resolution: {integrity: sha512-f52QZwkFVDPf7UEQZGHKx6NYxsxmVGJe5DIvbzOdRMJlmT6yv0KDjR8rmy3ngr/t5wU54c7Sp/qIJH0ppbhVpQ==} resolution: {integrity: sha512-f52QZwkFVDPf7UEQZGHKx6NYxsxmVGJe5DIvbzOdRMJlmT6yv0KDjR8rmy3ngr/t5wU54c7Sp/qIJH0ppbhVpQ==}
core-js@3.39.0:
resolution: {integrity: sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==}
cosmiconfig@7.1.0: cosmiconfig@7.1.0:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -3129,6 +3156,9 @@ packages:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
cssesc@3.0.0: cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3341,6 +3371,9 @@ packages:
dom-helpers@5.2.1: dom-helpers@5.2.1:
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
dompurify@2.5.7:
resolution: {integrity: sha512-2q4bEI+coQM8f5ez7kt2xclg1XsecaV9ASJk/54vwlfRRNQfDqJz2pzQ8t0Ix/ToBpXlVjrRIx7pFC/o8itG2Q==}
dot-case@2.1.1: dot-case@2.1.1:
resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==}
@ -3499,6 +3532,9 @@ packages:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es6-promise@4.2.8:
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
esbuild-register@3.5.0: esbuild-register@3.5.0:
resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==}
peerDependencies: peerDependencies:
@ -3794,6 +3830,9 @@ packages:
fb-watchman@2.0.2: fb-watchman@2.0.2:
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
fflate@0.8.2:
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
figures@3.2.0: figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -4047,6 +4086,13 @@ packages:
html-escaper@2.0.2: html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
html2pdf.js@0.10.2:
resolution: {integrity: sha512-WyHVeMb18Bp7vYTmBv1GVsThH//K7SRfHdSdhHPkl4JvyQarNQXnailkYn0QUbRRmnN5rdbbmSIGEsPZtzPy2Q==}
http-proxy-agent@7.0.0: http-proxy-agent@7.0.0:
resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
@ -4511,6 +4557,9 @@ packages:
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
engines: {node: '>=12', npm: '>=6'} engines: {node: '>=12', npm: '>=6'}
jspdf@2.5.2:
resolution: {integrity: sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==}
jsx-ast-utils@3.3.5: jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@ -4941,6 +4990,9 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'} engines: {node: '>=8'}
performance-now@2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
pg-cloudflare@1.1.1: pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
@ -5128,6 +5180,9 @@ packages:
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
raf@3.4.1:
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
rc@1.2.8: rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true hasBin: true
@ -5273,6 +5328,9 @@ packages:
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
regenerator-runtime@0.14.0: regenerator-runtime@0.14.0:
resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
@ -5340,6 +5398,10 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'} engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
rgbcolor@1.0.1:
resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
engines: {node: '>= 0.8.15'}
rimraf@3.0.2: rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported deprecated: Rimraf versions prior to v4 are no longer supported
@ -5518,6 +5580,10 @@ packages:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
stackblur-canvas@2.7.0:
resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==}
engines: {node: '>=0.1.14'}
string-length@4.0.2: string-length@4.0.2:
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -5610,6 +5676,10 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
svg-pathdata@6.0.3:
resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
engines: {node: '>=12.0.0'}
swap-case@1.1.2: swap-case@1.1.2:
resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==}
@ -5645,6 +5715,9 @@ packages:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'} engines: {node: '>=8'}
text-segmentation@1.0.3:
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
text-table@0.2.0: text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@ -5916,6 +5989,9 @@ packages:
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
v8-compile-cache-lib@3.0.1: v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@ -8242,6 +8318,9 @@ snapshots:
'@types/prop-types@15.7.5': {} '@types/prop-types@15.7.5': {}
'@types/raf@3.4.3':
optional: true
'@types/react-dom@18.2.19': '@types/react-dom@18.2.19':
dependencies: dependencies:
'@types/react': 18.2.61 '@types/react': 18.2.61
@ -8834,6 +8913,8 @@ snapshots:
dependencies: dependencies:
tslib: 2.6.3 tslib: 2.6.3
atob@2.1.2: {}
autoprefixer@10.4.19(postcss@8.4.38): autoprefixer@10.4.19(postcss@8.4.38):
dependencies: dependencies:
browserslist: 4.23.1 browserslist: 4.23.1
@ -8922,6 +9003,8 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
base64-arraybuffer@1.0.2: {}
base64-js@1.5.1: {} base64-js@1.5.1: {}
basic-ftp@5.0.3: {} basic-ftp@5.0.3: {}
@ -8979,6 +9062,8 @@ snapshots:
node-int64: 0.4.0 node-int64: 0.4.0
optional: true optional: true
btoa@1.2.1: {}
buffer-equal-constant-time@1.0.1: {} buffer-equal-constant-time@1.0.1: {}
buffer-from@1.1.2: {} buffer-from@1.1.2: {}
@ -9024,6 +9109,18 @@ snapshots:
caniuse-lite@1.0.30001667: caniuse-lite@1.0.30001667:
optional: true optional: true
canvg@3.0.10:
dependencies:
'@babel/runtime': 7.24.7
'@types/raf': 3.4.3
core-js: 3.39.0
raf: 3.4.1
regenerator-runtime: 0.13.11
rgbcolor: 1.0.1
stackblur-canvas: 2.7.0
svg-pathdata: 6.0.3
optional: true
chalk@2.4.2: chalk@2.4.2:
dependencies: dependencies:
ansi-styles: 3.2.1 ansi-styles: 3.2.1
@ -9165,6 +9262,9 @@ snapshots:
core-js-pure@3.32.1: {} core-js-pure@3.32.1: {}
core-js@3.39.0:
optional: true
cosmiconfig@7.1.0: cosmiconfig@7.1.0:
dependencies: dependencies:
'@types/parse-json': 4.0.2 '@types/parse-json': 4.0.2
@ -9197,6 +9297,10 @@ snapshots:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
css-line-break@2.1.0:
dependencies:
utrie: 1.0.2
cssesc@3.0.0: {} cssesc@3.0.0: {}
csstype@3.1.2: {} csstype@3.1.2: {}
@ -9371,6 +9475,9 @@ snapshots:
'@babel/runtime': 7.24.7 '@babel/runtime': 7.24.7
csstype: 3.1.3 csstype: 3.1.3
dompurify@2.5.7:
optional: true
dot-case@2.1.1: dot-case@2.1.1:
dependencies: dependencies:
no-case: 2.3.2 no-case: 2.3.2
@ -9513,6 +9620,8 @@ snapshots:
is-date-object: 1.0.5 is-date-object: 1.0.5
is-symbol: 1.0.4 is-symbol: 1.0.4
es6-promise@4.2.8: {}
esbuild-register@3.5.0(esbuild@0.19.12): esbuild-register@3.5.0(esbuild@0.19.12):
dependencies: dependencies:
debug: 4.3.5 debug: 4.3.5
@ -10019,6 +10128,8 @@ snapshots:
bser: 2.1.1 bser: 2.1.1
optional: true optional: true
fflate@0.8.2: {}
figures@3.2.0: figures@3.2.0:
dependencies: dependencies:
escape-string-regexp: 1.0.5 escape-string-regexp: 1.0.5
@ -10299,6 +10410,17 @@ snapshots:
html-escaper@2.0.2: html-escaper@2.0.2:
optional: true optional: true
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
html2pdf.js@0.10.2:
dependencies:
es6-promise: 4.2.8
html2canvas: 1.4.1
jspdf: 2.5.2
http-proxy-agent@7.0.0: http-proxy-agent@7.0.0:
dependencies: dependencies:
agent-base: 7.1.0 agent-base: 7.1.0
@ -10993,6 +11115,18 @@ snapshots:
ms: 2.1.3 ms: 2.1.3
semver: 7.6.2 semver: 7.6.2
jspdf@2.5.2:
dependencies:
'@babel/runtime': 7.24.7
atob: 2.1.2
btoa: 1.2.1
fflate: 0.8.2
optionalDependencies:
canvg: 3.0.10
core-js: 3.39.0
dompurify: 2.5.7
html2canvas: 1.4.1
jsx-ast-utils@3.3.5: jsx-ast-utils@3.3.5:
dependencies: dependencies:
array-includes: 3.1.8 array-includes: 3.1.8
@ -11431,6 +11565,9 @@ snapshots:
path-type@4.0.0: {} path-type@4.0.0: {}
performance-now@2.1.0:
optional: true
pg-cloudflare@1.1.1: pg-cloudflare@1.1.1:
optional: true optional: true
@ -11606,6 +11743,11 @@ snapshots:
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
raf@3.4.1:
dependencies:
performance-now: 2.1.0
optional: true
rc@1.2.8: rc@1.2.8:
dependencies: dependencies:
deep-extend: 0.6.0 deep-extend: 0.6.0
@ -11777,6 +11919,9 @@ snapshots:
globalthis: 1.0.4 globalthis: 1.0.4
which-builtin-type: 1.1.3 which-builtin-type: 1.1.3
regenerator-runtime@0.13.11:
optional: true
regenerator-runtime@0.14.0: {} regenerator-runtime@0.14.0: {}
regenerator-runtime@0.14.1: {} regenerator-runtime@0.14.1: {}
@ -11845,6 +11990,9 @@ snapshots:
reusify@1.0.4: {} reusify@1.0.4: {}
rgbcolor@1.0.1:
optional: true
rimraf@3.0.2: rimraf@3.0.2:
dependencies: dependencies:
glob: 7.2.3 glob: 7.2.3
@ -12069,6 +12217,9 @@ snapshots:
escape-string-regexp: 2.0.0 escape-string-regexp: 2.0.0
optional: true optional: true
stackblur-canvas@2.7.0:
optional: true
string-length@4.0.2: string-length@4.0.2:
dependencies: dependencies:
char-regex: 1.0.2 char-regex: 1.0.2
@ -12179,6 +12330,9 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
svg-pathdata@6.0.3:
optional: true
swap-case@1.1.2: swap-case@1.1.2:
dependencies: dependencies:
lower-case: 1.1.4 lower-case: 1.1.4
@ -12242,6 +12396,10 @@ snapshots:
minimatch: 3.1.2 minimatch: 3.1.2
optional: true optional: true
text-segmentation@1.0.3:
dependencies:
utrie: 1.0.2
text-table@0.2.0: {} text-table@0.2.0: {}
thenify-all@1.6.0: thenify-all@1.6.0:
@ -12515,6 +12673,10 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
utrie@1.0.2:
dependencies:
base64-arraybuffer: 1.0.2
v8-compile-cache-lib@3.0.1: {} v8-compile-cache-lib@3.0.1: {}
v8-to-istanbul@9.3.0: v8-to-istanbul@9.3.0: