From b9fe4f2ac5a3ae5e3f93c2def107dc2aa58993f4 Mon Sep 17 00:00:00 2001 From: nii-ev Date: Fri, 30 May 2025 14:22:07 +0100 Subject: [PATCH 01/26] Add on features --- package-lock.json | 756 ++++++++++++++---- package.json | 3 +- .../accounts/approve-deposit/page.tsx | 0 .../dashboard/accounts/bills/page.tsx | 3 + .../accountant/dashboard/accounts/layout.tsx | 78 ++ .../accountant/dashboard/accounts/page.tsx | 0 .../accounts/pending-deposit/page.tsx | 0 .../accounts/refund-request/page.tsx | 0 .../accounts/wallet-deposit/page.tsx | 0 .../accounts/wallet-transactions/page.tsx | 0 src/app/accountant/dashboard/page.tsx | 122 +++ src/app/accountant/dashboard/payroll/page.tsx | 0 .../dashboard/payroll/report/page.tsx | 3 + src/app/accountant/dashboard/staff/page.tsx | 0 .../accountant/dashboard/students/page.tsx | 3 + src/app/accountant/page.tsx | 321 ++++++++ src/app/bills/page.tsx | 87 ++ src/app/layout.tsx | 2 +- src/app/teacher/dashboard/page.tsx | 134 ++++ src/middleware.ts | 3 + tsconfig.json | 24 +- 21 files changed, 1395 insertions(+), 144 deletions(-) create mode 100644 src/app/accountant/dashboard/accounts/approve-deposit/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/bills/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/layout.tsx create mode 100644 src/app/accountant/dashboard/accounts/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/pending-deposit/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/refund-request/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/wallet-deposit/page.tsx create mode 100644 src/app/accountant/dashboard/accounts/wallet-transactions/page.tsx create mode 100644 src/app/accountant/dashboard/page.tsx create mode 100644 src/app/accountant/dashboard/payroll/page.tsx create mode 100644 src/app/accountant/dashboard/payroll/report/page.tsx create mode 100644 src/app/accountant/dashboard/staff/page.tsx create mode 100644 src/app/accountant/dashboard/students/page.tsx create mode 100644 src/app/accountant/page.tsx create mode 100644 src/app/bills/page.tsx create mode 100644 src/app/teacher/dashboard/page.tsx diff --git a/package-lock.json b/package-lock.json index 64c85920..f7fdce24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@prisma/client": "^5.19.1", "@types/react-big-calendar": "^1.8.9", "moment": "^2.30.1", - "next": "14.2.5", + "next": "^15.3.3", "next-cloudinary": "^6.13.0", "prisma": "^5.19.1", "react": "^18", @@ -22,6 +22,7 @@ "react-calendar": "^5.0.0", "react-dom": "^18", "react-hook-form": "^7.52.2", + "react-to-print": "^3.1.0", "react-toastify": "^10.0.5", "recharts": "^2.12.7", "zod": "^3.23.8" @@ -52,26 +53,23 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", - "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz", + "integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@clerk/backend": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.9.2.tgz", - "integrity": "sha512-8vCYux8Xbu5TQ2iq9tYuDnNhv3K/XhZ+34QJG+n4ZX4w4FfTTuzwb5OylcmP69vPvYybhoQfjpK57kBOW22deg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.14.1.tgz", + "integrity": "sha512-YlKMpiVo4UITw3sgA+9QrAFRILVOz5hgB1Zw180Y2LEZ5a+MdpX668vJKGh7riSweMN7JQvU2jlsKGRO+1bXDw==", "license": "MIT", "dependencies": { - "@clerk/shared": "2.6.2", - "@clerk/types": "4.19.0", - "cookie": "0.5.0", + "@clerk/shared": "2.9.2", + "@clerk/types": "4.26.0", + "cookie": "0.7.0", "snakecase-keys": "5.4.4", "tslib": "2.4.1" }, @@ -86,13 +84,13 @@ "license": "0BSD" }, "node_modules/@clerk/clerk-react": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.7.0.tgz", - "integrity": "sha512-VCYj/Qhm4P5u0A3X1M+yycod8cz8flFwtpnI8+ajGUDmMdel9iuR5ix01cgsHfyPuamfiuP1a4xNg7F0d+2P7Q==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.12.0.tgz", + "integrity": "sha512-3Lr2QazCm5R6ZLbu7wM+d5YwCElrAoX00OBWcKqjPYaWDJCCmEYN6LJbLzOTYQ8QT1J1ZIed85/lKa+q2aD1aA==", "license": "MIT", "dependencies": { - "@clerk/shared": "2.6.2", - "@clerk/types": "4.19.0", + "@clerk/shared": "2.9.2", + "@clerk/types": "4.26.0", "tslib": "2.4.1" }, "engines": { @@ -139,17 +137,16 @@ } }, "node_modules/@clerk/nextjs": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-5.4.1.tgz", - "integrity": "sha512-rW/UIdsR0hDd90OTy0HS1dk69y8cO24GjnMXX7A2WhN2LmLtvC6K8pIX2w/mOajWNm6MTSBuzTDwLB8rYii9Ww==", + "version": "5.7.5", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-5.7.5.tgz", + "integrity": "sha512-hfH4IiKcDT9LlqSOlNHZoYfX6iF4lBqPXf/KwnILCX/0+MVYaotb30FwWXkcHI2jZgcvumlQTOq8Gv5KugnihA==", "license": "MIT", "dependencies": { - "@clerk/backend": "1.9.2", - "@clerk/clerk-react": "5.7.0", - "@clerk/shared": "2.6.2", - "@clerk/types": "4.19.0", + "@clerk/backend": "1.14.1", + "@clerk/clerk-react": "5.12.0", + "@clerk/shared": "2.9.2", + "@clerk/types": "4.26.0", "crypto-js": "4.2.0", - "path-to-regexp": "6.2.2", "server-only": "0.0.1", "tslib": "2.4.1" }, @@ -169,13 +166,13 @@ "license": "0BSD" }, "node_modules/@clerk/shared": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-2.6.2.tgz", - "integrity": "sha512-RkrNknIr98GPu3srXLhjJViC1Mom1gUsRMNnf1deibX2yvRnndloZGnFb0qxf+pFL/NCkKd3nSHtK3eCJQrVYQ==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-2.9.2.tgz", + "integrity": "sha512-vRMDj13Pv9n8Pf+f8P40AvqJ8QEq348qUxUVIf17vn9R3/toicrQOY/Q6qsrAS8KXY9+ZnyTafJa+VFK+6iEFA==", "hasInstallScript": true, "license": "MIT", "dependencies": { - "@clerk/types": "4.19.0", + "@clerk/types": "4.26.0", "glob-to-regexp": "0.4.1", "js-cookie": "3.0.5", "std-env": "^3.7.0", @@ -198,9 +195,9 @@ } }, "node_modules/@clerk/types": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.19.0.tgz", - "integrity": "sha512-bDN/nRUD5PFCehQ+Kjdcft0I3b9CIyCcY3OBNDSc1L6RQhlXH+J48EtaP/cbRdslb83LJiBPQ2i/gV4VgblzwA==", + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.26.0.tgz", + "integrity": "sha512-VGcrQz/XpCiGbpIIzKVwWw4nLorzKnIP1IAemj1xt/80ULcdEZCncwhas6PoYBBsl1W55A1SwP9B/pEs0nmkCw==", "license": "MIT", "dependencies": { "csstype": "3.1.1" @@ -281,6 +278,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -388,6 +395,402 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz", + "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz", + "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", + "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", + "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", + "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", + "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", + "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", + "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", + "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", + "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", + "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz", + "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz", + "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz", + "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz", + "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz", + "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz", + "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz", + "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz", + "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz", + "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz", + "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -489,9 +892,9 @@ } }, "node_modules/@next/env": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", - "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz", + "integrity": "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -505,9 +908,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", - "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz", + "integrity": "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==", "cpu": [ "arm64" ], @@ -521,9 +924,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", - "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz", + "integrity": "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==", "cpu": [ "x64" ], @@ -537,9 +940,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", - "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz", + "integrity": "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==", "cpu": [ "arm64" ], @@ -553,9 +956,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", - "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz", + "integrity": "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==", "cpu": [ "arm64" ], @@ -569,9 +972,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", - "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", + "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", "cpu": [ "x64" ], @@ -585,9 +988,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", - "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", + "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", "cpu": [ "x64" ], @@ -601,9 +1004,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", - "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz", + "integrity": "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==", "cpu": [ "arm64" ], @@ -616,26 +1019,10 @@ "node": ">= 10" } }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", - "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", - "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz", + "integrity": "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==", "cpu": [ "x64" ], @@ -957,13 +1344,12 @@ "license": "Apache-2.0" }, "node_modules/@swc/helpers": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", - "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", "dependencies": { - "@swc/counter": "^0.1.3", - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@tsconfig/node10": { @@ -1818,11 +2204,25 @@ "node": ">=6" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1835,9 +2235,20 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1856,9 +2267,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.0.tgz", + "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -1872,9 +2283,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -2214,6 +2625,16 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -3383,6 +3804,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -3603,6 +4025,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", @@ -4316,9 +4745,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -4412,9 +4841,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -4437,41 +4866,42 @@ "license": "MIT" }, "node_modules/next": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", - "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/next/-/next-15.3.3.tgz", + "integrity": "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==", "license": "MIT", "dependencies": { - "@next/env": "14.2.5", - "@swc/helpers": "0.5.5", + "@next/env": "15.3.3", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", - "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.1" + "styled-jsx": "5.1.6" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=18.17.0" + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.5", - "@next/swc-darwin-x64": "14.2.5", - "@next/swc-linux-arm64-gnu": "14.2.5", - "@next/swc-linux-arm64-musl": "14.2.5", - "@next/swc-linux-x64-gnu": "14.2.5", - "@next/swc-linux-x64-musl": "14.2.5", - "@next/swc-win32-arm64-msvc": "14.2.5", - "@next/swc-win32-ia32-msvc": "14.2.5", - "@next/swc-win32-x64-msvc": "14.2.5" + "@next/swc-darwin-arm64": "15.3.3", + "@next/swc-darwin-x64": "15.3.3", + "@next/swc-linux-arm64-gnu": "15.3.3", + "@next/swc-linux-arm64-musl": "15.3.3", + "@next/swc-linux-x64-gnu": "15.3.3", + "@next/swc-linux-x64-musl": "15.3.3", + "@next/swc-win32-arm64-msvc": "15.3.3", + "@next/swc-win32-x64-msvc": "15.3.3", + "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { @@ -4481,6 +4911,9 @@ "@playwright/test": { "optional": true }, + "babel-plugin-react-compiler": { + "optional": true + }, "sass": { "optional": true } @@ -4831,12 +5264,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "license": "MIT" - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5280,6 +5707,15 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-to-print": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-3.1.0.tgz", + "integrity": "sha512-hiJZVmJtaRm9EHoUTG2bordyeRxVSGy9oFVV7fSvzOWwctPp6jbz2R6NFkaokaTYBxC7wTM/fMV5eCXsNpEwsA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ~19" + } + }, "node_modules/react-toastify": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", @@ -5386,12 +5822,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -5570,10 +6000,10 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5622,6 +6052,48 @@ "node": ">= 0.4" } }, + "node_modules/sharp": { + "version": "0.34.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz", + "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.4", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.2", + "@img/sharp-darwin-x64": "0.34.2", + "@img/sharp-libvips-darwin-arm64": "1.1.0", + "@img/sharp-libvips-darwin-x64": "1.1.0", + "@img/sharp-libvips-linux-arm": "1.1.0", + "@img/sharp-libvips-linux-arm64": "1.1.0", + "@img/sharp-libvips-linux-ppc64": "1.1.0", + "@img/sharp-libvips-linux-s390x": "1.1.0", + "@img/sharp-libvips-linux-x64": "1.1.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", + "@img/sharp-libvips-linuxmusl-x64": "1.1.0", + "@img/sharp-linux-arm": "0.34.2", + "@img/sharp-linux-arm64": "0.34.2", + "@img/sharp-linux-s390x": "0.34.2", + "@img/sharp-linux-x64": "0.34.2", + "@img/sharp-linuxmusl-arm64": "0.34.2", + "@img/sharp-linuxmusl-x64": "0.34.2", + "@img/sharp-wasm32": "0.34.2", + "@img/sharp-win32-arm64": "0.34.2", + "@img/sharp-win32-ia32": "0.34.2", + "@img/sharp-win32-x64": "0.34.2" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5677,6 +6149,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5981,9 +6463,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -5992,7 +6474,7 @@ "node": ">= 12.0.0" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "peerDependenciesMeta": { "@babel/core": { @@ -6247,9 +6729,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/type-check": { diff --git a/package.json b/package.json index a6793a00..aa582afe 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@prisma/client": "^5.19.1", "@types/react-big-calendar": "^1.8.9", "moment": "^2.30.1", - "next": "14.2.5", + "next": "^15.3.3", "next-cloudinary": "^6.13.0", "prisma": "^5.19.1", "react": "^18", @@ -23,6 +23,7 @@ "react-calendar": "^5.0.0", "react-dom": "^18", "react-hook-form": "^7.52.2", + "react-to-print": "^3.1.0", "react-toastify": "^10.0.5", "recharts": "^2.12.7", "zod": "^3.23.8" diff --git a/src/app/accountant/dashboard/accounts/approve-deposit/page.tsx b/src/app/accountant/dashboard/accounts/approve-deposit/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/accounts/bills/page.tsx b/src/app/accountant/dashboard/accounts/bills/page.tsx new file mode 100644 index 00000000..a3550be8 --- /dev/null +++ b/src/app/accountant/dashboard/accounts/bills/page.tsx @@ -0,0 +1,3 @@ +export default function BillsPage() { + return
Bills Management
; +} \ No newline at end of file diff --git a/src/app/accountant/dashboard/accounts/layout.tsx b/src/app/accountant/dashboard/accounts/layout.tsx new file mode 100644 index 00000000..0f5e6436 --- /dev/null +++ b/src/app/accountant/dashboard/accounts/layout.tsx @@ -0,0 +1,78 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +const menu = [ + { label: "Students", href: "/accountant/dashboard/students" }, + { + label: "Accounts", + submenu: [ + { label: "Bills", href: "/accountant/dashboard/accounts/bills" }, + { label: "Wallet Deposit", href: "/accountant/dashboard/accounts/wallet-deposit" }, + { label: "Wallet Transactions", href: "/accountant/dashboard/accounts/wallet-transactions" }, + { label: "Refund Request", href: "/accountant/dashboard/accounts/refund-request" }, + { label: "Approve Deposit", href: "/accountant/dashboard/accounts/approve-deposit" }, + { label: "Pending Deposit", href: "/accountant/dashboard/accounts/pending-deposit" }, + ], + }, + { label: "Staff", href: "/accountant/dashboard/staff" }, + { + label: "Payroll", + submenu: [ + { label: "Payroll", href: "/accountant/dashboard/payroll" }, + { label: "Payroll Report", href: "/accountant/dashboard/payroll/report" }, + ], + }, +]; + +export default function AccountantDashboardLayout({ children }: { children: React.ReactNode }) { + const pathname = usePathname(); + + return ( +
+ {/* Sidebar */} + + {/* Main Content */} +
{children}
+
+ ); +} \ No newline at end of file diff --git a/src/app/accountant/dashboard/accounts/page.tsx b/src/app/accountant/dashboard/accounts/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/accounts/pending-deposit/page.tsx b/src/app/accountant/dashboard/accounts/pending-deposit/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/accounts/refund-request/page.tsx b/src/app/accountant/dashboard/accounts/refund-request/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/accounts/wallet-deposit/page.tsx b/src/app/accountant/dashboard/accounts/wallet-deposit/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/accounts/wallet-transactions/page.tsx b/src/app/accountant/dashboard/accounts/wallet-transactions/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/page.tsx b/src/app/accountant/dashboard/page.tsx new file mode 100644 index 00000000..2a101795 --- /dev/null +++ b/src/app/accountant/dashboard/page.tsx @@ -0,0 +1,122 @@ +"use client"; + +import { useState } from "react"; + +const menu = [ + { label: "Students", key: "students" }, + { + label: "Accounts", + key: "accounts", + submenu: [ + { label: "Bills", key: "bills" }, + { label: "Wallet Deposit", key: "wallet-deposit" }, + { label: "Wallet Transactions", key: "wallet-transactions" }, + { label: "Refund Request", key: "refund-request" }, + { label: "Approve Deposit", key: "approve-deposit" }, + { label: "Pending Deposit", key: "pending-deposit" }, + ], + }, + { + label: "Staff", + key: "staff", + }, + { + label: "Payroll", + key: "payroll", + submenu: [ + { label: "Payroll", key: "payroll-main" }, + { label: "Payroll Report", key: "payroll-report" }, + ], + }, +]; + +export default function AccountantDashboard() { + const [activeMenu, setActiveMenu] = useState("students"); + const [openMenus, setOpenMenus] = useState<{ [key: string]: boolean }>({}); + + const handleMenuClick = (key: string, hasSubmenu: boolean) => { + if (hasSubmenu) { + setOpenMenus((prev) => ({ ...prev, [key]: !prev[key] })); + } else { + setActiveMenu(key); + } + }; + + const handleSubMenuClick = (key: string) => { + setActiveMenu(key); + }; + + // Placeholder content for each section + const renderContent = () => { + switch (activeMenu) { + case "students": + return
Students List/Management
; + case "bills": + return
Bills Management
; + case "wallet-deposit": + return
Wallet Deposit
; + case "wallet-transactions": + return
Wallet Transactions
; + case "refund-request": + return
Refund Requests
; + case "approve-deposit": + return
Approve Deposit
; + case "pending-deposit": + return
Pending Deposit
; + case "staff": + return
Staff Management
; + case "payroll-main": + return
Payroll Processing
; + case "payroll-report": + return
Payroll Report
; + default: + return
Select a menu item
; + } + }; + + return ( +
+ {/* Sidebar */} + + {/* Main Content */} +
{renderContent()}
+
+ ); +} \ No newline at end of file diff --git a/src/app/accountant/dashboard/payroll/page.tsx b/src/app/accountant/dashboard/payroll/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/payroll/report/page.tsx b/src/app/accountant/dashboard/payroll/report/page.tsx new file mode 100644 index 00000000..afac4f55 --- /dev/null +++ b/src/app/accountant/dashboard/payroll/report/page.tsx @@ -0,0 +1,3 @@ +export default function PayrollReportPage() { + return
Payroll Report
; +} \ No newline at end of file diff --git a/src/app/accountant/dashboard/staff/page.tsx b/src/app/accountant/dashboard/staff/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/accountant/dashboard/students/page.tsx b/src/app/accountant/dashboard/students/page.tsx new file mode 100644 index 00000000..28cdcdf2 --- /dev/null +++ b/src/app/accountant/dashboard/students/page.tsx @@ -0,0 +1,3 @@ +export default function StudentsPage() { + return
Students List/Management
; +} \ No newline at end of file diff --git a/src/app/accountant/page.tsx b/src/app/accountant/page.tsx new file mode 100644 index 00000000..d4785c96 --- /dev/null +++ b/src/app/accountant/page.tsx @@ -0,0 +1,321 @@ +"use client"; + +import { useRef, useState } from "react"; +import ReactToPrint from "react-to-print"; +const ReactToPrintComponent = ReactToPrint as unknown as React.FC; + +// Removed duplicate Transaction type to avoid shadowing the correct one below + +"use client"; + +type Student = { + id: string; + name: string; + totalBill: number; + paid: number; +}; + +type Transaction = { + id: number; + date: string; + account: string; + description: string; + amount: number; + type: "Income" | "Expense"; + studentId?: string; +}; + +const studentsData: Student[] = [ + { id: "1", name: "John Doe", totalBill: 1000, paid: 0 }, + { id: "2", name: "Jane Smith", totalBill: 1200, paid: 0 }, + { id: "3", name: "Alice Johnson", totalBill: 900, paid: 0 }, +]; + +const accounts = [ + "Cash", + "Bank", + "Tuition Fees", + "Salaries", + "Supplies", + "Utilities", + "Other", +]; + +export default function AccountantPage() { + const [students, setStudents] = useState(studentsData); + const [transactions, setTransactions] = useState([]); + const [receipt, setReceipt] = useState(null); + const [voucher, setVoucher] = useState(null); + + // Fee Payment Form + const [paymentForm, setPaymentForm] = useState({ + studentId: "", + amount: "", + date: "", + }); + + // Expense Voucher Form + const [voucherForm, setVoucherForm] = useState({ + account: "", + description: "", + amount: "", + date: "", + }); + + const receiptRef = useRef(null); + + // Example backend endpoint + const BACKEND_URL = "http://localhost:4000/api/transactions"; + + // Update handlePayment to send data to backend + const handlePayment = async (e: React.FormEvent) => { + e.preventDefault(); + const student = students.find((s) => s.id === paymentForm.studentId); + if (!student) return; + + const amountNum = Number(paymentForm.amount); + + // Update student's paid amount locally + setStudents((prev) => + prev.map((s) => + s.id === student.id + ? { ...s, paid: s.paid + amountNum } + : s + ) + ); + + // Record transaction + const txn: Transaction = { + id: Date.now(), + date: paymentForm.date, + account: "Tuition Fees", + description: `Fee payment by ${student.name}`, + amount: amountNum, + type: "Income", + studentId: student.id, + }; + setTransactions((prev) => [...prev, txn]); + setReceipt(txn); + setPaymentForm({ studentId: "", amount: "", date: "" }); + + // Send to backend + try { + await fetch(BACKEND_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(txn), + }); + } catch (err) { + alert("Failed to save transaction to backend."); + } + }; + + // Handle Expense Voucher + const handleVoucher = (e: React.FormEvent) => { + e.preventDefault(); + const amountNum = Number(voucherForm.amount); + const txn: Transaction = { + id: Date.now(), + date: voucherForm.date, + account: voucherForm.account, + description: voucherForm.description, + amount: amountNum, + type: "Expense", + }; + setTransactions((prev) => [...prev, txn]); + setVoucher(txn); + setVoucherForm({ account: "", description: "", amount: "", date: "" }); + }; + + return ( +
+

Accountant Dashboard

+ + {/* Fee Payment Form */} +
+

Record Fee Payment

+
+ + setPaymentForm(f => ({ ...f, amount: e.target.value }))} + required + min={1} + className="p-2 border rounded" + /> + setPaymentForm(f => ({ ...f, date: e.target.value }))} + required + className="p-2 border rounded" + /> + +
+ {receipt && ( +
+
+

Receipt

+
Date: {receipt.date}
+
Student: {students.find(s => s.id === receipt.studentId)?.name}
+
Amount Paid: ${receipt.amount}
+
Description: {receipt.description}
+
Receipt No: {receipt.id}
+
+ ( + + )} + content={() => receiptRef.current} + /> +
+ )} +
+ + {/* Expense Voucher Form */} +
+

Record Expense / Payment Voucher

+
+ + setVoucherForm(f => ({ ...f, description: e.target.value }))} + required + className="p-2 border rounded" + /> + setVoucherForm(f => ({ ...f, amount: e.target.value }))} + required + min={1} + className="p-2 border rounded" + /> + setVoucherForm(f => ({ ...f, date: e.target.value }))} + required + className="p-2 border rounded" + /> + +
+ {voucher && ( +
+

Payment Voucher

+
Date: {voucher.date}
+
Account: {voucher.account}
+
Amount: ${voucher.amount}
+
Description: {voucher.description}
+
Voucher No: {voucher.id}
+
+ )} +
+ + {/* Students Bill Table */} +
+

Students Outstanding Bills

+ + + + + + + + + + + {students.map(s => ( + + + + + + + ))} + +
StudentTotal BillPaidOutstanding
{s.name}${s.totalBill}${s.paid}${s.totalBill - s.paid}
+
+ + {/* All Transactions Table */} +

All Transactions

+
+ + + + + + + + + + + + {transactions.length === 0 ? ( + + + + ) : ( + transactions.map((txn) => ( + + + + + + + + )) + )} + +
DateAccountDescriptionTypeAmount
+ No transactions recorded. +
{txn.date}{txn.account}{txn.description} + {txn.type} + + {txn.type === "Expense" ? "-" : "+"}${txn.amount.toFixed(2)} +
+
+
+ ); +} + diff --git a/src/app/bills/page.tsx b/src/app/bills/page.tsx new file mode 100644 index 00000000..84884628 --- /dev/null +++ b/src/app/bills/page.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { useState } from "react"; + +type Student = { + id: string; + name: string; +}; + +// Dummy students list (replace with real data or fetch from API) +const students: Student[] = [ + { id: "1", name: "John Doe" }, + { id: "2", name: "Jane Smith" }, + { id: "3", name: "Alice Johnson" }, +]; + +export default function GenerateBillPage() { + const [studentId, setStudentId] = useState(""); + const [amount, setAmount] = useState(""); + const [description, setDescription] = useState(""); + const [success, setSuccess] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // TODO: Send bill data to your backend here + setSuccess(true); + setStudentId(""); + setAmount(""); + setDescription(""); + }; + + return ( +
+

Generate Student Bill

+
+ + + + + {success && ( +
+ Bill generated successfully! +
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6fd77da6..fe330e57 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -18,7 +18,7 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + {children} diff --git a/src/app/teacher/dashboard/page.tsx b/src/app/teacher/dashboard/page.tsx new file mode 100644 index 00000000..32ba6192 --- /dev/null +++ b/src/app/teacher/dashboard/page.tsx @@ -0,0 +1,134 @@ +"use client"; + +import { useState } from "react"; + +const subjects = [ + "Mathematics", + "English", + "Science", + "Social Studies", + "ICT", +]; + +const students = [ + { id: "1", name: "John Doe" }, + { id: "2", name: "Jane Smith" }, + { id: "3", name: "Alice Johnson" }, +]; + +const assessmentFields = [ + { key: "classwork", label: "Classwork", max: 10 }, + { key: "homework", label: "Homework", max: 10 }, + { key: "test1", label: "Test 1", max: 20 }, + { key: "test2", label: "Test 2", max: 20 }, + { key: "projectwork", label: "Project Work", max: 20 }, + { key: "groupwork", label: "Group Work", max: 20 }, +]; + +type Marks = { + [studentId: string]: { + [field: string]: number | ""; + }; +}; + +export default function TeacherDashboard() { + const [activeSubject, setActiveSubject] = useState(subjects[0]); + const [marks, setMarks] = useState({}); + + const handleInput = ( + studentId: string, + field: string, + value: string, + max: number + ) => { + let num = value === "" ? "" : Math.max(0, Math.min(Number(value), max)); + setMarks((prev) => ({ + ...prev, + [studentId]: { + ...(prev[studentId] ?? {}), + [field]: num as number | "", + } as { [field: string]: number | "" }, + })); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // TODO: Send marks[studentId] for activeSubject to backend + alert("Marks saved for " + activeSubject); + }; + + return ( +
+

Teacher Dashboard

+ {/* Subject Tabs */} +
+ {subjects.map((subject) => ( + + ))} +
+ + {/* SBA Input Table */} +
+ + + + + {assessmentFields.map((field) => ( + + ))} + + + + {students.map((student) => ( + + + {assessmentFields.map((field) => ( + + ))} + + ))} + +
Student + {field.label} (/{field.max}) +
{student.name} + + handleInput( + student.id, + field.key, + e.target.value, + field.max + ) + } + className="w-16 p-1 border rounded" + required + /> +
+ +
+
+ ); +} \ No newline at end of file diff --git a/src/middleware.ts b/src/middleware.ts index f4b9a89a..2ff78558 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,6 +2,9 @@ import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; import { routeAccessMap } from "./lib/settings"; import { NextResponse } from "next/server"; +// filepath: c:\Users\I EXPRESS\Desktop\SchMeg\full-stack-school\src\middleware.ts +console.log("CLERK_PUBLISHABLE_KEY:", process.env.CLERK_PUBLISHABLE_KEY); + const matchers = Object.keys(routeAccessMap).map((route) => ({ matcher: createRouteMatcher([route]), allowedRoles: routeAccessMap[route], diff --git a/tsconfig.json b/tsconfig.json index 7b285893..f48e7ee6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -18,9 +22,19 @@ } ], "paths": { - "@/*": ["./src/*"] - } + "@/*": [ + "./src/*" + ] + }, + "target": "ES2017" }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } From 550c8d04744f42c5869b691f464ac370ff4cd48e Mon Sep 17 00:00:00 2001 From: nii-ev Date: Mon, 2 Jun 2025 09:09:06 +0100 Subject: [PATCH 02/26] new files --- src/app/(dashboard)/parent/page.tsx | 128 +++++++++++++++++++++++++++ src/components/CanteenWallet.tsx | 17 ++++ src/components/ReportDownloader.tsx | 26 ++++++ src/components/StudentBilling.tsx | 17 ++++ src/components/StudentPass.tsx | 17 ++++ src/components/StudentWallet.tsx | 48 ++++++++++ src/components/TermlyReportGraph.tsx | 17 ++++ src/components/TimeLogger.tsx | 17 ++++ src/components/ui/Card.tsx | 30 +++++++ src/components/ui/tabs.tsx | 30 +++++++ 10 files changed, 347 insertions(+) create mode 100644 src/components/CanteenWallet.tsx create mode 100644 src/components/ReportDownloader.tsx create mode 100644 src/components/StudentBilling.tsx create mode 100644 src/components/StudentPass.tsx create mode 100644 src/components/StudentWallet.tsx create mode 100644 src/components/TermlyReportGraph.tsx create mode 100644 src/components/TimeLogger.tsx create mode 100644 src/components/ui/Card.tsx create mode 100644 src/components/ui/tabs.tsx diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx index ff919725..35195be4 100644 --- a/src/app/(dashboard)/parent/page.tsx +++ b/src/app/(dashboard)/parent/page.tsx @@ -38,3 +38,131 @@ const ParentPage = async () => { }; export default ParentPage; + + + + +import { useState } from "react"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +// Update the import path below to the correct location of your Card components. +// For example, if the file is at 'src/components/ui/Card.tsx', use: +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card"; +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import StudentBilling from "@/components/StudentBilling"; +import StudentWallet from "@/components/StudentWallet"; +import TermlyReportGraph from "@/components/TermlyReportGraph"; +import ReportDownloader from "@/components/ReportDownloader"; +import CanteenWallet from "@/components/CanteenWallet"; +import StudentPass from "@/components/StudentPass"; +import TimeLogger from "@/components/TimeLogger"; + +// Mock data - replace with actual API calls +const mockStudents = [ + { + id: 1, + name: "John", + surname: "Doe", + classId: "class-1", + parentId: "parent-1" + }, + { + id: 2, + name: "Jane", + surname: "Doe", + classId: "class-2", + parentId: "parent-1" + } +]; + +const ParentPage = () => { + const [selectedStudent, setSelectedStudent] = useState(mockStudents[0]); + + return ( +
+ {/* Student Selector */} + + + Select Student + + +
+ {mockStudents.map((student) => ( + + ))} +
+
+
+ + {/* Main Dashboard */} + + + Schedule + Billing + Wallet + Reports + Canteen + Pass + Time Log + News + + + + + + + Schedule ({selectedStudent.name} {selectedStudent.surname}) + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + + + + + + + + + + + + +
+
+ ); +}; + +export default ParentPage; diff --git a/src/components/CanteenWallet.tsx b/src/components/CanteenWallet.tsx new file mode 100644 index 00000000..70d58d13 --- /dev/null +++ b/src/components/CanteenWallet.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const CanteenWallet: React.FC = ({ studentId }) => { + return ( +
+

Canteen Wallet

+

Show canteen wallet balance and transactions for student ID: {studentId}

+ {/* Add wallet balance and transaction list here */} +
+ ); +}; + +export default CanteenWallet; \ No newline at end of file diff --git a/src/components/ReportDownloader.tsx b/src/components/ReportDownloader.tsx new file mode 100644 index 00000000..5fea4d99 --- /dev/null +++ b/src/components/ReportDownloader.tsx @@ -0,0 +1,26 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const ReportDownloader: React.FC = ({ studentId }) => { + const handleDownload = () => { + // Implement download logic here + alert(`Download report for student ID: ${studentId}`); + }; + + return ( +
+

Report Downloader

+ +
+ ); +}; + +export default ReportDownloader; \ No newline at end of file diff --git a/src/components/StudentBilling.tsx b/src/components/StudentBilling.tsx new file mode 100644 index 00000000..586222da --- /dev/null +++ b/src/components/StudentBilling.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const StudentBilling: React.FC = ({ studentId }) => { + return ( +
+

Student Billing

+

Show billing details for student ID: {studentId}

+ {/* Add billing table or summary here */} +
+ ); +}; + +export default StudentBilling; \ No newline at end of file diff --git a/src/components/StudentPass.tsx b/src/components/StudentPass.tsx new file mode 100644 index 00000000..04dd2e42 --- /dev/null +++ b/src/components/StudentPass.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const StudentPass: React.FC = ({ studentId }) => { + return ( +
+

Student Pass

+

Show student pass info for student ID: {studentId}

+ {/* Add pass details or QR code here */} +
+ ); +}; + +export default StudentPass; \ No newline at end of file diff --git a/src/components/StudentWallet.tsx b/src/components/StudentWallet.tsx new file mode 100644 index 00000000..5225d129 --- /dev/null +++ b/src/components/StudentWallet.tsx @@ -0,0 +1,48 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const StudentWallet: React.FC = ({ studentId }) => { + // Replace with real data fetching logic + const walletBalance = 150.0; + const transactions = [ + { id: 1, date: "2024-06-01", type: "Deposit", amount: 100 }, + { id: 2, date: "2024-06-05", type: "Purchase", amount: -20 }, + { id: 3, date: "2024-06-10", type: "Deposit", amount: 70 }, + ]; + + return ( +
+

Student Wallet

+
+ Balance: ${walletBalance.toFixed(2)} +
+

Recent Transactions

+ + + + + + + + + + {transactions.map((txn) => ( + + + + + + ))} + +
DateTypeAmount
{txn.date}{txn.type} + {txn.amount > 0 ? "+" : ""} + {txn.amount} +
+
+ ); +}; + +export default StudentWallet; \ No newline at end of file diff --git a/src/components/TermlyReportGraph.tsx b/src/components/TermlyReportGraph.tsx new file mode 100644 index 00000000..06315516 --- /dev/null +++ b/src/components/TermlyReportGraph.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const TermlyReportGraph: React.FC = ({ studentId }) => { + return ( +
+

Termly Report Graph

+

Display performance graph for student ID: {studentId}

+ {/* Add chart/graph here */} +
+ ); +}; + +export default TermlyReportGraph; \ No newline at end of file diff --git a/src/components/TimeLogger.tsx b/src/components/TimeLogger.tsx new file mode 100644 index 00000000..24fa184e --- /dev/null +++ b/src/components/TimeLogger.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +type Props = { + studentId: number | string; +}; + +const TimeLogger: React.FC = ({ studentId }) => { + return ( +
+

Time Logger

+

Display time logs for student ID: {studentId}

+ {/* Add time log table or chart here */} +
+ ); +}; + +export default TimeLogger; \ No newline at end of file diff --git a/src/components/ui/Card.tsx b/src/components/ui/Card.tsx new file mode 100644 index 00000000..8643b488 --- /dev/null +++ b/src/components/ui/Card.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +export type CardProps = React.HTMLAttributes; + +export const Card: React.FC = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardHeader: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardTitle: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardContent: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); \ No newline at end of file diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 00000000..8643b488 --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +export type CardProps = React.HTMLAttributes; + +export const Card: React.FC = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardHeader: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardTitle: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); + +export const CardContent: React.FC> = ({ children, className = "", ...props }) => ( +
+ {children} +
+); \ No newline at end of file From ed966d3acb5c3b16760fb27c77089f1f0e3d3027 Mon Sep 17 00:00:00 2001 From: nii-ev Date: Mon, 2 Jun 2025 09:18:57 +0100 Subject: [PATCH 03/26] edit --- src/app/(dashboard)/parent/page.tsx | 44 ------------------ src/components/ui/tabs.tsx | 71 ++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx index 35195be4..d1b5b8a0 100644 --- a/src/app/(dashboard)/parent/page.tsx +++ b/src/app/(dashboard)/parent/page.tsx @@ -1,47 +1,3 @@ -import Announcements from "@/components/Announcements"; -import BigCalendarContainer from "@/components/BigCalendarContainer"; -import prisma from "@/lib/prisma"; -import { auth } from "@clerk/nextjs/server"; - - -const ParentPage = async () => { - const { userId } = auth(); - const currentUserId = userId; - - const students = await prisma.student.findMany({ - where: { - parentId: currentUserId!, - }, - }); - - return ( -
- {/* LEFT */} -
- {students.map((student) => ( -
-
-

- Schedule ({student.name + " " + student.surname}) -

- -
-
- ))} -
- {/* RIGHT */} -
- -
-
- ); -}; - -export default ParentPage; - - - - import { useState } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; // Update the import path below to the correct location of your Card components. diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx index 8643b488..76a7c92e 100644 --- a/src/components/ui/tabs.tsx +++ b/src/components/ui/tabs.tsx @@ -27,4 +27,73 @@ export const CardContent: React.FC> = ({ ch
{children}
-); \ No newline at end of file +); + +import { createContext, useContext, useState, ReactNode } from "react"; + +// Context to share active tab value +type TabsContextType = { + value: string; + setValue: (value: string) => void; +}; +const TabsContext = createContext(undefined); + +// Tabs root component +type TabsProps = { + defaultValue: string; + children: ReactNode; + className?: string; +}; +export const Tabs: React.FC = ({ defaultValue, children, className }) => { + const [value, setValue] = useState(defaultValue); + return ( + +
{children}
+
+ ); +}; + +// TabsList component +type TabsListProps = { + children: ReactNode; + className?: string; +}; +export const TabsList: React.FC = ({ children, className }) => ( +
{children}
+); + +// TabsTrigger component +type TabsTriggerProps = { + value: string; + children: ReactNode; + className?: string; +}; +export const TabsTrigger: React.FC = ({ value, children, className }) => { + const ctx = useContext(TabsContext); + if (!ctx) throw new Error("TabsTrigger must be used within Tabs"); + const isActive = ctx.value === value; + return ( + + ); +}; + +// TabsContent component +type TabsContentProps = { + value: string; + children: ReactNode; + className?: string; +}; +export const TabsContent: React.FC = ({ value, children, className }) => { + const ctx = useContext(TabsContext); + if (!ctx) throw new Error("TabsContent must be used within Tabs"); + if (ctx.value !== value) return null; + return
{children}
; +}; \ No newline at end of file From 14c4ffabb384cb8824e92c04255b1b69674833a0 Mon Sep 17 00:00:00 2001 From: nii-ev Date: Mon, 2 Jun 2025 10:41:57 +0100 Subject: [PATCH 04/26] new file --- src/app/(dashboard)/superadmin/page.tsx | 89 +++ src/components/StaffRoleManager.tsx | 0 src/components/StudentManager.tsx | 0 src/components/StudentReports.tsx | 224 +++++++ src/components/SystemOverview.tsx | 0 src/components/ui/accordion.tsx | 56 ++ src/components/ui/alert-dialog.tsx | 139 +++++ src/components/ui/alert.tsx | 59 ++ src/components/ui/aspect-ratio.tsx | 5 + src/components/ui/avatar.tsx | 48 ++ src/components/ui/badge.tsx | 37 ++ src/components/ui/breadcrumb.tsx | 115 ++++ src/components/ui/button.tsx | 56 ++ src/components/ui/calendar.tsx | 64 ++ src/components/ui/card copy.tsx | 79 +++ src/components/ui/carousel.tsx | 260 ++++++++ src/components/ui/chart.tsx | 363 +++++++++++ src/components/ui/checkbox.tsx | 28 + src/components/ui/collapsible.tsx | 9 + src/components/ui/command.tsx | 153 +++++ src/components/ui/context-menu.tsx | 198 ++++++ src/components/ui/dialog.tsx | 120 ++++ src/components/ui/drawer.tsx | 116 ++++ src/components/ui/dropdown-menu.tsx | 198 ++++++ src/components/ui/form.tsx | 176 ++++++ src/components/ui/hover-card.tsx | 27 + src/components/ui/input-otp.tsx | 69 +++ src/components/ui/input.tsx | 26 + src/components/ui/label.tsx | 24 + src/components/ui/menubar.tsx | 234 ++++++++ src/components/ui/navigation-menu.tsx | 128 ++++ src/components/ui/pagination.tsx | 117 ++++ src/components/ui/popover.tsx | 29 + src/components/ui/progress.tsx | 26 + src/components/ui/radio-group.tsx | 42 ++ src/components/ui/resizable.tsx | 43 ++ src/components/ui/scroll-area.tsx | 46 ++ src/components/ui/select.tsx | 158 +++++ src/components/ui/separator.tsx | 29 + src/components/ui/sheet.tsx | 131 ++++ src/components/ui/sidebar.tsx | 761 ++++++++++++++++++++++++ src/components/ui/skeleton.tsx | 15 + src/components/ui/slider.tsx | 26 + src/components/ui/sonner.tsx | 29 + src/components/ui/switch.tsx | 27 + src/components/ui/table.tsx | 117 ++++ src/components/ui/tabs copy.tsx | 53 ++ src/components/ui/textarea.tsx | 24 + src/components/ui/toast.tsx | 127 ++++ src/components/ui/toaster.tsx | 33 + src/components/ui/toggle-group.tsx | 59 ++ src/components/ui/toggle.tsx | 43 ++ src/components/ui/tooltip.tsx | 28 + src/components/ui/use-toast.ts | 3 + 54 files changed, 5066 insertions(+) create mode 100644 src/app/(dashboard)/superadmin/page.tsx create mode 100644 src/components/StaffRoleManager.tsx create mode 100644 src/components/StudentManager.tsx create mode 100644 src/components/StudentReports.tsx create mode 100644 src/components/SystemOverview.tsx create mode 100644 src/components/ui/accordion.tsx create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/alert.tsx create mode 100644 src/components/ui/aspect-ratio.tsx create mode 100644 src/components/ui/avatar.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/breadcrumb.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/calendar.tsx create mode 100644 src/components/ui/card copy.tsx create mode 100644 src/components/ui/carousel.tsx create mode 100644 src/components/ui/chart.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/collapsible.tsx create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/context-menu.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/drawer.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/form.tsx create mode 100644 src/components/ui/hover-card.tsx create mode 100644 src/components/ui/input-otp.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/menubar.tsx create mode 100644 src/components/ui/navigation-menu.tsx create mode 100644 src/components/ui/pagination.tsx create mode 100644 src/components/ui/popover.tsx create mode 100644 src/components/ui/progress.tsx create mode 100644 src/components/ui/radio-group.tsx create mode 100644 src/components/ui/resizable.tsx create mode 100644 src/components/ui/scroll-area.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/components/ui/sheet.tsx create mode 100644 src/components/ui/sidebar.tsx create mode 100644 src/components/ui/skeleton.tsx create mode 100644 src/components/ui/slider.tsx create mode 100644 src/components/ui/sonner.tsx create mode 100644 src/components/ui/switch.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/components/ui/tabs copy.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/ui/toast.tsx create mode 100644 src/components/ui/toaster.tsx create mode 100644 src/components/ui/toggle-group.tsx create mode 100644 src/components/ui/toggle.tsx create mode 100644 src/components/ui/tooltip.tsx create mode 100644 src/components/ui/use-toast.ts diff --git a/src/app/(dashboard)/superadmin/page.tsx b/src/app/(dashboard)/superadmin/page.tsx new file mode 100644 index 00000000..3b082185 --- /dev/null +++ b/src/app/(dashboard)/superadmin/page.tsx @@ -0,0 +1,89 @@ + +import { useState } from "react"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import StaffRoleManager from "@/components/StaffRoleManager"; +import UserCard from "@/components/UserCard"; +import FinanceChart from "@/components/FinanceChart"; +import Announcements from "@/components/Announcements"; +import SystemOverview from "@/components/SystemOverview"; +import StudentManager from "@/components/StudentManager"; +import StudentBilling from "@/components/StudentBilling"; +import StudentReports from "@/components/StudentReports"; + +const SuperAdminPage = ({ + searchParams, +}: { + searchParams: { [keys: string]: string | undefined }; +}) => { + return ( +
+ {/* HEADER */} +
+

Super Admin Dashboard

+
+ + + + Overview + Staff Management + Student Management + Student Reports + Student Billing + Analytics + System + Announcements + + + +
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + System Settings + + +

System configuration and settings will be displayed here.

+
+
+
+ + + + +
+
+ ); +}; + +export default SuperAdminPage; diff --git a/src/components/StaffRoleManager.tsx b/src/components/StaffRoleManager.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/components/StudentManager.tsx b/src/components/StudentManager.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/components/StudentReports.tsx b/src/components/StudentReports.tsx new file mode 100644 index 00000000..4df73d7d --- /dev/null +++ b/src/components/StudentReports.tsx @@ -0,0 +1,224 @@ + +import { useState } from "react"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { MessageSquare, Eye, Download, Plus } from "lucide-react"; + +const StudentReports = () => { + const [selectedStudent, setSelectedStudent] = useState(""); + const [comments, setComments] = useState<{[key: number]: string}>({}); + const [newComment, setNewComment] = useState(""); + + const students = [ + { id: 1, name: "John Smith", class: "Grade 10A" }, + { id: 2, name: "Jane Doe", class: "Grade 9B" }, + { id: 3, name: "Mike Johnson", class: "Grade 11A" } + ]; + + const reports = [ + { + id: 1, + studentId: 1, + studentName: "John Smith", + subject: "Mathematics", + term: "Term 1", + grade: "A-", + percentage: 88, + date: "2024-01-30", + status: "Completed", + hasComments: true + }, + { + id: 2, + studentId: 1, + studentName: "John Smith", + subject: "English", + term: "Term 1", + grade: "B+", + percentage: 82, + date: "2024-01-30", + status: "Completed", + hasComments: false + }, + { + id: 3, + studentId: 2, + studentName: "Jane Doe", + subject: "Science", + term: "Term 1", + grade: "A", + percentage: 95, + date: "2024-01-30", + status: "Completed", + hasComments: false + } + ]; + + const handleAddComment = (reportId: number) => { + if (newComment.trim()) { + setComments({ + ...comments, + [reportId]: newComment + }); + setNewComment(""); + } + }; + + const getGradeBadge = (grade: string) => { + const gradeColors: {[key: string]: string} = { + 'A': 'bg-green-500', + 'A-': 'bg-green-400', + 'B+': 'bg-blue-500', + 'B': 'bg-blue-400', + 'C+': 'bg-yellow-500', + 'C': 'bg-yellow-400', + 'D': 'bg-red-400', + 'F': 'bg-red-500' + }; + + const colorClass = gradeColors[grade] || 'bg-gray-500'; + return {grade}; + }; + + const filteredReports = selectedStudent + ? reports.filter(report => report.studentId === parseInt(selectedStudent)) + : reports; + + return ( +
+ {/* Filter Section */} + + + Student Reports Management + + +
+
+ + +
+
+
+
+ + {/* Reports Table */} + + + Academic Reports + + + + + + Student + Subject + Term + Grade + Percentage + Date + Comments + Actions + + + + {filteredReports.map((report) => ( + + {report.studentName} + {report.subject} + {report.term} + {getGradeBadge(report.grade)} + {report.percentage}% + {report.date} + + {report.hasComments || comments[report.id] ? ( + + + Has Comments + + ) : ( + No Comments + )} + + +
+ + + + + + + + + Add Comment - {report.studentName} + +
+
+ +
+

Subject: {report.subject}

+

Term: {report.term}

+

Grade: {report.grade} ({report.percentage}%)

+
+
+ {comments[report.id] && ( +
+ +
+

{comments[report.id]}

+
+
+ )} +
+ +