+
{children}
diff --git a/src/routes/layout/dashboard-navigation.tsx b/src/routes/layout/dashboard-navigation.tsx
new file mode 100644
index 0000000..9dd3787
--- /dev/null
+++ b/src/routes/layout/dashboard-navigation.tsx
@@ -0,0 +1,48 @@
+import {NavLink} from "react-router-dom";
+import {useMemo} from "react";
+import {useTranslation} from "react-i18next";
+
+import useAuth from "@/hooks/useAuth.ts";
+import {IconQRCode, IconQuery, IconReconciliation} from "@/components/logo";
+
+const AllDashboardMenu = [
+ {
+ key: 'manual',
+ icon:
,
+ path: '/dashboard/manual',
+ },
+ {
+ key: 'bill',
+ icon:
,
+ path: '/dashboard/bill',
+ role: ['root', 'ro', 'fo']
+ },
+ {
+ key: 'check',
+ icon:
,
+ path: '/dashboard/reconciliation',
+ role: ['root', 'ro', 'fo']
+ }
+]
+
+export function DashboardNavigation() {
+ const {t} = useTranslation()
+
+ const {user} = useAuth();
+ const navItems = useMemo(() => {
+ if (!user) return [];
+
+ return AllDashboardMenu.filter(it => {
+ return !it.role || it.role.includes(user.department)
+ });
+ }, [user])
+ return (
+ {navItems.map((it) => (
+
+ {it.icon}
+ {t(`layout.menu.${it.key}`)}
+
+ ))}
+
+ );
+}
\ No newline at end of file
diff --git a/src/service/generate-pdf.ts b/src/service/generate-pdf.ts
new file mode 100644
index 0000000..be5f7c5
--- /dev/null
+++ b/src/service/generate-pdf.ts
@@ -0,0 +1,73 @@
+import JsPDF from "jspdf";
+import autoTable from "jspdf-autotable";
+
+function drawItem(doc: JsPDF, item: {
+ title: string;
+ content?: string
+}, y: number, align: 'left' | 'right' = 'left', fontSize: number = 13) {
+ doc.setFontSize(fontSize);
+ // const width = doc.internal.pageSize.getWidth();
+ doc.text(item.title, align == 'left' ? 20 : 180, y);
+ if (item.content && item.content.length > 0) doc.text(item.content, align == 'left' ? 65 : 230, y, {maxWidth: 150});
+}
+
+export function GeneratePdf(filename: string) {
+ const doc = new JsPDF({
+ orientation: 'landscape',
+ format: 'a4'
+ });
+ // const width = doc.internal.pageSize.getWidth();
+ // const height = doc.internal.pageSize.getHeight();
+ doc.setFont('Helvetica', 'normal', 'bold');
+ doc.setFontSize(20);
+ doc.text('ACKNOWLEDGEMENT RECEIPT', 100, 20, {});
+
+ doc.setFont('Helvetica', 'normal', 'normal');
+ drawItem(doc, {title: 'Student Name:', content: 'BAI ZHONGHONG'}, 40)
+ drawItem(doc, {title: 'Reference Number:', content: '202402655'}, 40, "right")
+ drawItem(doc, {title: 'Student Number:', content: '236171275'}, 48)
+ drawItem(doc, {title: 'Print Date:', content: '2024-05-19'}, 48, "right")
+
+ drawItem(doc, {
+ title: 'Programme:',
+ content: 'MASTER OF SOCIAL SCIENCES IN INTERNATIONAL RELATIONS FOR BELT AND ROAD COUNTRIES'
+ }, 56)
+ drawItem(doc, {title: 'Mode of Study:', content: 'FULL-TIME'}, 70)
+ // draw table
+ autoTable(doc, {
+ startY: 80,
+ theme: 'grid',
+
+ margin: {top: 37, left: 20, right: 20},
+ styles: {
+ fontSize: 13,
+ fillColor: [255, 255, 255],
+ textColor: [0, 0, 0],
+ lineColor: [0, 0, 0],
+ lineWidth: 0.2,
+ minCellHeight: 10,
+ valign: 'middle'
+ },
+ headStyles: {
+ fontSize: 15,
+ },
+ head: [['No.', 'Transaction Date', 'Payment Type', 'Payment Method', 'HK$']],
+ body: [
+ ['#87254', '2024-05-13', 'DOCUMENT FEE ', 'AsiaPay(Wechat Pay)', '100.00'],
+ ['#87255', '2024-05-13', 'VISA FEE', 'AsiaPay(Wechat Pay)', '50.00'],
+ [{
+ colSpan: 3,
+ content: 'TOTAL:',
+ styles: {valign: 'middle', halign: 'right'},
+ }, '150.00'],
+ ],
+ })
+ // draw foot
+ drawItem(doc, {title: 'Remarks:', content: ''}, 155)
+ drawItem(doc, {title: 'Cashier:', content: ''}, 155, "right")
+
+ doc.setFont('Helvetica', 'italic');
+ drawItem(doc, {title: 'Please retain this acknowledgement receipt for your record.'}, 185)
+
+ doc.save(filename);
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index ce1761b..d440bbd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -826,11 +826,6 @@
resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
-"@types/file-saver@^2.0.7":
- version "2.0.7"
- resolved "https://registry.npmmirror.com/@types/file-saver/-/file-saver-2.0.7.tgz#8dbb2f24bdc7486c54aa854eb414940bbd056f7d"
- integrity sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==
-
"@types/lodash@^4.17.1":
version "4.17.4"
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.4.tgz#0303b64958ee070059e3a7184048a55159fe20b7"
@@ -1233,11 +1228,6 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"
-countup.js@^2.8.0:
- version "2.8.0"
- resolved "https://registry.npmmirror.com/countup.js/-/countup.js-2.8.0.tgz#64951f2df3ede28839413d654d8fef28251c32a8"
- integrity sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ==
-
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -1520,11 +1510,6 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
-file-saver@^2.0.5:
- version "2.0.5"
- resolved "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
- integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
-
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@@ -2135,13 +2120,6 @@ raf@^3.4.1:
dependencies:
performance-now "^2.1.0"
-react-countup@^6.5.3:
- version "6.5.3"
- resolved "https://registry.npmmirror.com/react-countup/-/react-countup-6.5.3.tgz#e892aa3eab2d6ba9c3cdba30bf4ed6764826d848"
- integrity sha512-udnqVQitxC7QWADSPDOxVWULkLvKUWrDapn5i53HE4DPRVgs+Y5rr4bo25qEl8jSh+0l2cToJgGMx+clxPM3+w==
- dependencies:
- countup.js "^2.8.0"
-
react-dom@^18.2.0:
version "18.3.1"
resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
@@ -2495,11 +2473,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-use-sync-external-store@1.2.0:
- version "1.2.0"
- resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
- integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
-
utility-types@^3.10.0:
version "3.11.0"
resolved "https://registry.npmmirror.com/utility-types/-/utility-types-3.11.0.tgz#607c40edb4f258915e901ea7995607fdf319424c"
@@ -2559,10 +2532,3 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-
-zustand@^4.5.2:
- version "4.5.2"
- resolved "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz#fddbe7cac1e71d45413b3682cdb47b48034c3848"
- integrity sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==
- dependencies:
- use-sync-external-store "1.2.0"