From 23c1205abac6d1c05ae540328a88bb1bca4a2ecd Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sat, 28 Dec 2024 23:48:26 +0100 Subject: [PATCH 01/57] feat(dashboard): add dashboard layout and role-specific pages - Created `dashboard` folder with `layout.tsx` for shared layout. - Added subfolders for `teacher`, `student`, `parent`, and `admin` roles. - Included `page.tsx` files with boilerplate components for each role. --- src/app/(dashboard)/admin/page.tsx | 9 +++++++++ src/app/(dashboard)/layout.tsx | 16 ++++++++++++++++ src/app/(dashboard)/parent/page.tsx | 9 +++++++++ src/app/(dashboard)/student/page.tsx | 9 +++++++++ src/app/(dashboard)/teacher/page.tsx | 9 +++++++++ src/app/layout.tsx | 2 +- src/app/sign-in/page.tsx | 9 +++++++++ src/components/Navbar.tsx | 9 +++++++++ 8 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/app/(dashboard)/admin/page.tsx create mode 100644 src/app/(dashboard)/layout.tsx create mode 100644 src/app/(dashboard)/parent/page.tsx create mode 100644 src/app/(dashboard)/student/page.tsx create mode 100644 src/app/(dashboard)/teacher/page.tsx create mode 100644 src/app/sign-in/page.tsx create mode 100644 src/components/Navbar.tsx diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx new file mode 100644 index 000000000..766d8282f --- /dev/null +++ b/src/app/(dashboard)/admin/page.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const AdminPage = () => { + return ( +
AdminPage
+ ) +} + +export default AdminPage \ No newline at end of file diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx new file mode 100644 index 000000000..714ed26fa --- /dev/null +++ b/src/app/(dashboard)/layout.tsx @@ -0,0 +1,16 @@ +export default function DashboardLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return
+ {/** Sidebar */} +
+ Sidebar +
+ {/** Content */} +
+ {children} +
+
+} diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx new file mode 100644 index 000000000..b8dd199bf --- /dev/null +++ b/src/app/(dashboard)/parent/page.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const ParentPage = () => { + return ( +
ParentPage
+ ) +} + +export default ParentPage \ No newline at end of file diff --git a/src/app/(dashboard)/student/page.tsx b/src/app/(dashboard)/student/page.tsx new file mode 100644 index 000000000..3f6015563 --- /dev/null +++ b/src/app/(dashboard)/student/page.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const StudentPage = () => { + return ( +
StudentPage
+ ) +} + +export default StudentPage \ No newline at end of file diff --git a/src/app/(dashboard)/teacher/page.tsx b/src/app/(dashboard)/teacher/page.tsx new file mode 100644 index 000000000..301776963 --- /dev/null +++ b/src/app/(dashboard)/teacher/page.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const TeacherPage = () => { + return ( +
TeacherPage
+ ) +} + +export default TeacherPage \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 44c71f8db..4b0612eb8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,7 +5,7 @@ import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Lama Dev School Management Dashboard", + title: "School Management Dashboard", description: "Next.js School Management System", }; diff --git a/src/app/sign-in/page.tsx b/src/app/sign-in/page.tsx new file mode 100644 index 000000000..9bb4d3611 --- /dev/null +++ b/src/app/sign-in/page.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const LoginPage = () => { + return ( +
LoginPage
+ ) +} + +export default LoginPage \ No newline at end of file diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 000000000..afa1f4d6e --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const Navbar = () => { + return ( +
Navbar
+ ) +} + +export default Navbar \ No newline at end of file From fbe183cfca2f849875001b83c24297969bd7895d Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 08:58:49 +0100 Subject: [PATCH 02/57] Add sidebar and navbar to dashboard layout --- src/app/(dashboard)/layout.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index 714ed26fa..219748f08 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -1,3 +1,8 @@ +import Menu from "@/components/Menu"; +import Navbar from "@/components/Navbar"; +import Image from "next/image"; +import Link from "next/link"; + export default function DashboardLayout({ children, }: Readonly<{ @@ -5,11 +10,16 @@ export default function DashboardLayout({ }>) { return
{/** Sidebar */} -
- Sidebar +
+ + Logo + Gifted + +
{/** Content */} -
+
+ {children}
From fe136e9776209f240ded0cfac56c0467d0642299 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 09:07:13 +0100 Subject: [PATCH 03/57] Add sidebar menu --- src/components/Menu.tsx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx index de074fa04..3a8302fe2 100644 --- a/src/components/Menu.tsx +++ b/src/components/Menu.tsx @@ -111,4 +111,28 @@ const menuItems = [ }, ], }, -]; \ No newline at end of file +]; + +import Image from 'next/image'; +import Link from 'next/link'; +import React from 'react' + +const Menu = () => { + return ( +
+ {menuItems.map((menu, index) => ( +
+ {menu.title} + {menu.items.map((item, index) => ( + + {item.label} + {item.label} + + ))} +
+ ))} +
+ ) +} + +export default Menu \ No newline at end of file From 9522259e92b76771331ae563a9ebff0609c8bd82 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 09:07:34 +0100 Subject: [PATCH 04/57] Add navbar --- src/components/Navbar.tsx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index afa1f4d6e..dbb5f3cc3 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,8 +1,30 @@ +import Image from 'next/image' import React from 'react' const Navbar = () => { return ( -
Navbar
+
+ {/** Search */} +
+ Search + +
+ {/** Icons and User */} +
+
+ Message +
+
+ Message +
1
+
+
+ John Doe + Admin +
+ +
+
) } From 7898f6c4fe4ecd3bb7751a6d0c5969fb21220395 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:49:26 +0100 Subject: [PATCH 05/57] Install recharts --- package-lock.json | 325 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 9 +- 2 files changed, 325 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf999766d..9ccde5b36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "14.2.5", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "recharts": "^2.15.0" }, "devDependencies": { "@types/node": "^20", @@ -36,6 +37,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.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", @@ -466,6 +478,60 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1150,6 +1216,14 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1219,9 +1293,118 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -1301,6 +1484,11 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -1417,6 +1605,15 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2081,6 +2278,11 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2088,6 +2290,14 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2647,6 +2857,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -3265,6 +3483,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3484,7 +3707,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3989,7 +4211,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -4057,9 +4278,37 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -4083,6 +4332,41 @@ "node": ">=8.10.0" } }, + "node_modules/recharts": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.0.tgz", + "integrity": "sha512-cIvMxDfpAmqAmVgc4yb7pgm/O1tmmkl/CjrvXuW+62/+7jj/iF9Ykm+hb/UJt42TREHMyd3gb+pkgoa2MxgDIw==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -4105,6 +4389,11 @@ "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==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -4795,6 +5084,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5004,6 +5298,27 @@ "dev": true, "license": "MIT" }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index dd3389bbf..08418a0ac 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,19 @@ "lint": "next lint" }, "dependencies": { + "next": "14.2.5", "react": "^18", "react-dom": "^18", - "next": "14.2.5" + "recharts": "^2.15.0" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.2.5", "postcss": "^8", "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "14.2.5" + "typescript": "^5" } } From c665e1fb78d8f31cf77b2a54e94c492165c6e5d6 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:49:54 +0100 Subject: [PATCH 06/57] feat(tailwind): add custom color palette --- tailwind.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tailwind.config.ts b/tailwind.config.ts index e9a0944e7..0f2c2f811 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -13,6 +13,14 @@ const config: Config = { "gradient-conic": "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", }, + colors: { + mySky: "#C3EBFA", + mySkyLight: "#EDF9FD", + myPurple: "#CFCEFF", + myPurpleLight: "#F1F0FF", + myYellow: "#FAE27C", + myYellowLight: "#FEFCE8", + } }, }, plugins: [], From 80ca7af0ae76f1d28243c986b3393c1e9098f563 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:50:12 +0100 Subject: [PATCH 07/57] feat(admin): enhance admin page layout with user cards and charts --- src/app/(dashboard)/admin/page.tsx | 36 +++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx index 766d8282f..1732cde10 100644 --- a/src/app/(dashboard)/admin/page.tsx +++ b/src/app/(dashboard)/admin/page.tsx @@ -1,8 +1,42 @@ +import AttendanceChart from '@/components/AttendanceChart' +import CountChart from '@/components/CountChart' +import UserCard from '@/components/UserCard' import React from 'react' const AdminPage = () => { return ( -
AdminPage
+
+ {/* Left side */} +
+ {/* User Cards */} +
+ + + + +
+ {/* Middle Chart */} +
+ {/* Count Chart */} +
+ +
+ {/* Attendance Chart */} +
+ +
+
+ {/* Bottom Chart */} +
+
+ {/* Right side */} +
+
+

Admin Sidebar

+

This is the admin sidebar

+
+
+
) } From bd5e6514f7398869dfdabd4f31eeb04d35110c08 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:50:34 +0100 Subject: [PATCH 08/57] feat(user): add UserCard component for displaying user information --- src/components/UserCard.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/components/UserCard.tsx diff --git a/src/components/UserCard.tsx b/src/components/UserCard.tsx new file mode 100644 index 000000000..2d191a2d8 --- /dev/null +++ b/src/components/UserCard.tsx @@ -0,0 +1,17 @@ +import Image from 'next/image' +import React from 'react' + +const UserCard = ({type}:{type:string}) => { + return ( +
+
+ 2024/25 + user +
+

1,234

+

{type + "s"}

+
+ ) +} + +export default UserCard \ No newline at end of file From bdc798a439aaff103d862eb3a3187a8e9dc21bed Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:51:13 +0100 Subject: [PATCH 09/57] feat(chart): add AttendanceChart component for visualizing attendance data --- src/components/AttendanceChart.tsx | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/components/AttendanceChart.tsx diff --git a/src/components/AttendanceChart.tsx b/src/components/AttendanceChart.tsx new file mode 100644 index 000000000..5cc1f206f --- /dev/null +++ b/src/components/AttendanceChart.tsx @@ -0,0 +1,63 @@ +"use client" + +import { BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; + +const data = [ + { + name: 'Mon', + present: 60, + absent: 40, + }, + { + name: 'Tue', + present: 70, + absent: 60, + }, + { + name: 'Wed', + present: 90, + absent: 75, + }, + { + name: 'Thu', + present: 90, + absent: 75, + }, + { + name: 'Fri', + present: 65, + absent: 55, + }, +]; + +import React from 'react' +import Image from 'next/image'; + +const AttendanceChart = () => { + return ( +
+
+

Attendance

+ +
+ + + + + + + + } legendType='circle' radius={[10,10,0,0]}/> + } legendType='circle' radius={[10,10,0,0]}/> + + +
+ ) +} + +export default AttendanceChart \ No newline at end of file From 45a23d75b59b52c1430d2db53493ed26305ae659 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 29 Dec 2024 23:51:36 +0100 Subject: [PATCH 10/57] feat(chart): add CountChart component for visualizing student gender distribution --- src/components/CountChart.tsx | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/components/CountChart.tsx diff --git a/src/components/CountChart.tsx b/src/components/CountChart.tsx new file mode 100644 index 000000000..954d06e90 --- /dev/null +++ b/src/components/CountChart.tsx @@ -0,0 +1,61 @@ +"use client"; +import Image from 'next/image'; +import React from 'react' +import { RadialBarChart, RadialBar, Legend, ResponsiveContainer } from 'recharts'; + +const data = [ + { + name: 'Total', + count: 106, + fill: 'white', + }, + { + name: 'Girls', + count: 53, + fill: '#FAE27C', + }, + { + name: 'Boys', + count: 53, + fill: '#C3E8FA', + }, +]; + +const CountChart = () => { + return ( +
+ {/* Title */} +
+

Students

+ +
+ {/* Chart */} +
+ + + + + + +
+ {/* Bottom */} +
+
+
+

1,234

+

Boys (55%)

+
+
+
+

1,234

+

Girls (45%)

+
+
+
+ ) +} + +export default CountChart \ No newline at end of file From 0f1c944c60a11dff87aa6df06ec1dc3414627165 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Mon, 30 Dec 2024 23:23:00 +0100 Subject: [PATCH 11/57] feat(admin): add EventCalendar and FinanceChart components to admin page --- src/app/(dashboard)/admin/page.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx index 1732cde10..5eaab397c 100644 --- a/src/app/(dashboard)/admin/page.tsx +++ b/src/app/(dashboard)/admin/page.tsx @@ -1,5 +1,7 @@ import AttendanceChart from '@/components/AttendanceChart' import CountChart from '@/components/CountChart' +import EventCalendar from '@/components/EventCalendar' +import FinanceChart from '@/components/FinanceChart' import UserCard from '@/components/UserCard' import React from 'react' @@ -27,14 +29,13 @@ const AdminPage = () => {
{/* Bottom Chart */} -
+
+ +
{/* Right side */} -
-
-

Admin Sidebar

-

This is the admin sidebar

-
+
+
) From e4eb0c5d3f415705c63f2e38798c99ff100d3f47 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Mon, 30 Dec 2024 23:23:22 +0100 Subject: [PATCH 12/57] feat(chart): add FinanceChart component for visualizing financial data --- src/components/FinanceChart.tsx | 104 ++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/components/FinanceChart.tsx diff --git a/src/components/FinanceChart.tsx b/src/components/FinanceChart.tsx new file mode 100644 index 000000000..f0e462e01 --- /dev/null +++ b/src/components/FinanceChart.tsx @@ -0,0 +1,104 @@ +"use client" +import Image from 'next/image' +import React from 'react' + +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; + +const data = [ + { + name: 'Jan', + income: 4000, + expence: 2400, + }, + { + name: 'Feb', + income: 3000, + expence: 1398, + }, + { + name: 'Mar', + income: 2000, + expence: 9800, + }, + { + name: 'Apr', + income: 2780, + expence: 3908, + }, + { + name: 'May', + income: 1890, + expence: 4800, + }, + { + name: 'Jun', + income: 2390, + expence: 3800, + }, + { + name: 'Jul', + income: 3490, + expence: 4300, + }, + { + name: 'Aug', + income: 3490, + expence: 4300, + }, + { + name: 'Sep', + income: 3490, + expence: 4300, + }, + { + name: 'Oct', + income: 3490, + expence: 4300, + }, + { + name: 'Nov', + income: 3490, + expence: 4300, + }, + { + name: 'Dec', + income: 3490, + expence: 4300, + }, +]; + +const FinanceChart = () => { + return ( +
+ {/* Title */} +
+

Finance

+ +
+ {/* Chart */} + + + + + + + + + + + +
+ ) +} + +export default FinanceChart \ No newline at end of file From 411a9fe50c940983b09431031ab0fbff37632a9f Mon Sep 17 00:00:00 2001 From: lucidcity Date: Mon, 30 Dec 2024 23:24:11 +0100 Subject: [PATCH 13/57] install "react-calendar" --- package-lock.json | 98 ++++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ccde5b36..71c715a6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "next": "14.2.5", "react": "^18", + "react-calendar": "^5.1.0", "react-dom": "^18", "recharts": "^2.15.0" }, @@ -553,14 +554,14 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -718,6 +719,14 @@ "dev": true, "license": "ISC" }, + "node_modules/@wojtekmaj/date-utils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.5.1.tgz", + "integrity": "sha512-+i7+JmNiE/3c9FKxzWFi2IjRJ+KzZl1QPu6QNrsgaa2MuBgXvUy4gA1TVzf/JMdIIloB76xSKikTWuyYAIVLww==", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -2556,6 +2565,17 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-user-locale": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-2.3.2.tgz", + "integrity": "sha512-O2GWvQkhnbDoWFUJfaBlDIKUEdND8ATpBXD6KXcbhxlfktyD/d8w6mkzM/IlQEqGZAMz/PW6j6Hv53BiigKLUQ==", + "dependencies": { + "mem": "^8.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, "node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -3514,6 +3534,32 @@ "dev": true, "license": "ISC" }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3538,6 +3584,14 @@ "node": ">=8.6" } }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3876,6 +3930,14 @@ "node": ">= 0.8.0" } }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4261,6 +4323,30 @@ "node": ">=0.10.0" } }, + "node_modules/react-calendar": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-5.1.0.tgz", + "integrity": "sha512-09o/rQHPZGEi658IXAJtWfra1N69D1eFnuJ3FQm9qUVzlzNnos1+GWgGiUeSs22QOpNm32aoVFOimq0p3Ug9Eg==", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^2.0.0", + "get-user-locale": "^2.2.1", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -5319,6 +5405,14 @@ "d3-timer": "^3.0.1" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 08418a0ac..1768747c7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "next": "14.2.5", "react": "^18", + "react-calendar": "^5.1.0", "react-dom": "^18", "recharts": "^2.15.0" }, From bfa0b5351906d61f35de0eb67a1ffcb7ad192415 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:38:58 +0100 Subject: [PATCH 14/57] feat(calendar): add EventCalendar component for displaying events --- src/components/EventCalendar.tsx | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/components/EventCalendar.tsx diff --git a/src/components/EventCalendar.tsx b/src/components/EventCalendar.tsx new file mode 100644 index 000000000..a83aefa35 --- /dev/null +++ b/src/components/EventCalendar.tsx @@ -0,0 +1,58 @@ +"use client"; +import Image from 'next/image'; +import React, { useState } from 'react' +import Calendar from 'react-calendar'; +import 'react-calendar/dist/Calendar.css'; + +type ValuePiece = Date | null; + +type Value = ValuePiece | [ValuePiece, ValuePiece]; + +// TEMPORARY +const events = [ + { + id: 1, + title: "Lorem ipsum dolor", + time: "12:00 PM - 2:00 PM", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + }, + { + id: 2, + title: "Lorem ipsum dolor", + time: "12:00 PM - 2:00 PM", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + }, + { + id: 3, + title: "Lorem ipsum dolor", + time: "12:00 PM - 2:00 PM", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + }, + ]; + +const EventCalendar = () => { + const [value, onChange] = useState(new Date()); + + return ( +
+ +
+

Events

+ +
+
+ {events.map(event => ( +
+
+

{event.title}

+ {event.time} +
+

{event.description}

+
+ ))} +
+
+ ) +} + +export default EventCalendar \ No newline at end of file From f0a65d5d84594d7ccfba68b4be5b4b0a744b4fb4 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:39:14 +0100 Subject: [PATCH 15/57] feat(announcements): add Announcements component for displaying notifications --- src/components/Announcements.tsx | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/components/Announcements.tsx diff --git a/src/components/Announcements.tsx b/src/components/Announcements.tsx new file mode 100644 index 000000000..b37a398e1 --- /dev/null +++ b/src/components/Announcements.tsx @@ -0,0 +1,43 @@ +import React from 'react' + +const Announcements = () => { + return ( +
+
+

Announcements

+ View All +
+
+
+
+

Lorem ipsum dolor sit

+ 2025-01-01 +
+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatum, + expedita. Rerum quidem, quas, voluptates. +

+
+
+
+

Lorem ipsum dolor sit

+ 2025-01-01 +
+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatum, + expedita. Rerum quidem, quas, voluptates. +

+
+
+
+

Lorem ipsum dolor sit

+ 2025-01-01 +
+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatum, + expedita. Rerum quidem, quas, voluptates. +

+
+
+
+ ) +} + +export default Announcements \ No newline at end of file From 511bbf800c0498c4d529e638b741ab0a50fde851 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:39:30 +0100 Subject: [PATCH 16/57] feat(styles): enhance react-calendar styles for improved UI --- src/app/globals.css | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app/globals.css b/src/app/globals.css index bd6213e1d..d2186976d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,3 +1,18 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +.react-calendar{ + width: 100% !important; + border: none !important; + font-family: "inter", sans-serif !important; +} + +.react-calendar__navigation__label__labelText{ + font-weight: 600 !important; +} + +.react-calendar__tile--active{ + background-color: #C3E8FA !important; + color: #000 !important; +} \ No newline at end of file From a5a4e947e954f8f943e6bc6169bf6ad85c3a5fab Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:39:49 +0100 Subject: [PATCH 17/57] feat(layout): update sidebar styles for improved visibility --- src/app/(dashboard)/layout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index 219748f08..2740bc4a1 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -10,10 +10,10 @@ export default function DashboardLayout({ }>) { return
{/** Sidebar */} -
+
Logo - Gifted + Gifted
From e7132839c537171229651b2c3f7a58aa5d574b53 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:40:33 +0100 Subject: [PATCH 18/57] feat(admin): add Announcements component to AdminPage --- src/app/(dashboard)/admin/page.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx index 5eaab397c..9bd207793 100644 --- a/src/app/(dashboard)/admin/page.tsx +++ b/src/app/(dashboard)/admin/page.tsx @@ -1,3 +1,4 @@ +import Announcements from '@/components/Announcements' import AttendanceChart from '@/components/AttendanceChart' import CountChart from '@/components/CountChart' import EventCalendar from '@/components/EventCalendar' @@ -36,6 +37,7 @@ const AdminPage = () => { {/* Right side */}
+
) From f599c45ddce77b0835215484648b98f495bae5fe Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 31 Dec 2024 09:40:52 +0100 Subject: [PATCH 19/57] feat(menu): filter menu items based on user role visibility --- src/components/Menu.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx index 3a8302fe2..bac91ee16 100644 --- a/src/components/Menu.tsx +++ b/src/components/Menu.tsx @@ -113,6 +113,7 @@ const menuItems = [ }, ]; +import { role } from '@/lib/data'; import Image from 'next/image'; import Link from 'next/link'; import React from 'react' @@ -123,12 +124,17 @@ const Menu = () => { {menuItems.map((menu, index) => (
{menu.title} - {menu.items.map((item, index) => ( - - {item.label} - {item.label} - - ))} + {menu.items.map((item, index) => { + if (item.visible.includes(role)) { + return ( + + {item.label} + {item.label} + + ) + + } + })}
))}
From 78b7558f7a68b11a4b67816132587a7851a89008 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Thu, 2 Jan 2025 08:50:52 +0100 Subject: [PATCH 20/57] Install "react-big-calendar" --- package-lock.json | 186 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 + 2 files changed, 187 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71c715a6b..81aac9c79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "lama-dev-next-dashboard", "version": "0.1.0", "dependencies": { + "@types/react-big-calendar": "^1.16.0", + "moment": "^2.30.1", "next": "14.2.5", "react": "^18", + "react-big-calendar": "^1.17.1", "react-calendar": "^5.1.0", "react-dom": "^18", "recharts": "^2.15.0" @@ -456,6 +459,26 @@ "node": ">=14" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", @@ -533,6 +556,11 @@ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, + "node_modules/@types/date-arithmetic": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/date-arithmetic/-/date-arithmetic-4.1.4.tgz", + "integrity": "sha512-p9eZ2X9B80iKiTW4ukVj8B4K6q9/+xFtQ5MGYA5HWToY9nL4EkhV9+6ftT2VHpVMEZb5Tv00Iel516bVdO+yRw==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -554,20 +582,28 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-big-calendar": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-1.16.0.tgz", + "integrity": "sha512-1w2GXAJWlGmaPZOd9J9cyWA/XBNOGRZ4MmRNypEQhwEMIIL9cfd1UdcvzSrQsnBm0qYF/scqmsISNbUzPBE1vg==", + "dependencies": { + "@types/date-arithmetic": "*", + "@types/prop-types": "*", + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", @@ -578,6 +614,11 @@ "@types/react": "*" } }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" + }, "node_modules/@typescript-eslint/parser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", @@ -1475,6 +1516,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-arithmetic": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", + "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -1574,6 +1625,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2638,6 +2697,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/globalize": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/globalize/-/globalize-0.1.1.tgz", + "integrity": "sha512-5e01v8eLGfuQSOvx2MsDMOWS0GFtCx1wPzQSmcHw4hkxFzrQDBO3Xwg/m8Hr/7qXMrHeOIE29qWVzyv06u1TZA==" + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -2885,6 +2949,14 @@ "node": ">=12" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -3508,6 +3580,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3534,6 +3611,14 @@ "dev": true, "license": "ISC" }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -3560,6 +3645,11 @@ "url": "https://github.com/sindresorhus/mem?sponsor=1" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3625,6 +3715,25 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.46", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.46.tgz", + "integrity": "sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4323,6 +4432,41 @@ "node": ">=0.10.0" } }, + "node_modules/react-big-calendar": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.17.1.tgz", + "integrity": "sha512-LltUAMSGODWQBKx4013bRe6R0jaINV9hrs970+F860KedpozwRGGMT66esV9mA3mAhfSKoazF/QH1WCyLkXYZA==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "clsx": "^1.2.1", + "date-arithmetic": "^4.1.0", + "dayjs": "^1.11.7", + "dom-helpers": "^5.2.1", + "globalize": "^0.1.1", + "invariant": "^2.2.4", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "luxon": "^3.2.1", + "memoize-one": "^6.0.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.40", + "prop-types": "^15.8.1", + "react-overlays": "^5.2.1", + "uncontrollable": "^7.2.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17 || ^18", + "react-dom": "^16.14.0 || ^17 || ^18" + } + }, + "node_modules/react-big-calendar/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/react-calendar": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-5.1.0.tgz", @@ -4366,6 +4510,30 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-overlays": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz", + "integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==", + "dependencies": { + "@babel/runtime": "^7.13.8", + "@popperjs/core": "^2.11.6", + "@restart/hooks": "^0.4.7", + "@types/warning": "^3.0.0", + "dom-helpers": "^5.2.0", + "prop-types": "^15.7.2", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/react-smooth": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", @@ -5360,6 +5528,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/package.json b/package.json index 1768747c7..1e70901e8 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,11 @@ "lint": "next lint" }, "dependencies": { + "@types/react-big-calendar": "^1.16.0", + "moment": "^2.30.1", "next": "14.2.5", "react": "^18", + "react-big-calendar": "^1.17.1", "react-calendar": "^5.1.0", "react-dom": "^18", "recharts": "^2.15.0" From a93b5a7c9d50aea48362cb4d9cd9ca24f9519d6f Mon Sep 17 00:00:00 2001 From: lucidcity Date: Thu, 2 Jan 2025 09:42:48 +0100 Subject: [PATCH 21/57] feat(parent): integrate Announcements and BigCalendar components into ParentPage layout --- src/app/(dashboard)/parent/page.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx index b8dd199bf..d2b2527c8 100644 --- a/src/app/(dashboard)/parent/page.tsx +++ b/src/app/(dashboard)/parent/page.tsx @@ -1,8 +1,22 @@ +import Announcements from '@/components/Announcements' +import BigCalendar from '@/components/BigCalendar' import React from 'react' const ParentPage = () => { return ( -
ParentPage
+
+ {/* Left side */} +
+
+

Schedule (John Doe)

+ +
+
+ {/* Right side */} +
+ +
+
) } From 1fc8de61130a0e9ae181d58536341329876a8969 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Thu, 2 Jan 2025 09:43:18 +0100 Subject: [PATCH 22/57] feat(dashboard): integrate Announcements and BigCalendar components into Student and Teacher pages --- src/app/(dashboard)/student/page.tsx | 18 +++++++++++++++++- src/app/(dashboard)/teacher/page.tsx | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/app/(dashboard)/student/page.tsx b/src/app/(dashboard)/student/page.tsx index 3f6015563..5e8b6f6f2 100644 --- a/src/app/(dashboard)/student/page.tsx +++ b/src/app/(dashboard)/student/page.tsx @@ -1,8 +1,24 @@ +import Announcements from '@/components/Announcements' +import BigCalendar from '@/components/BigCalendar' +import EventCalendar from '@/components/EventCalendar' import React from 'react' const StudentPage = () => { return ( -
StudentPage
+
+ {/* Left side */} +
+
+

Schedule (4A)

+ +
+
+ {/* Right side */} +
+ + +
+
) } diff --git a/src/app/(dashboard)/teacher/page.tsx b/src/app/(dashboard)/teacher/page.tsx index 301776963..cabcfff48 100644 --- a/src/app/(dashboard)/teacher/page.tsx +++ b/src/app/(dashboard)/teacher/page.tsx @@ -1,8 +1,22 @@ +import Announcements from '@/components/Announcements' +import BigCalendar from '@/components/BigCalendar' import React from 'react' const TeacherPage = () => { return ( -
TeacherPage
+
+ {/* Left side */} +
+
+

Schedule

+ +
+
+ {/* Right side */} +
+ +
+
) } From bd105f0e3795775f5ed92495886f3cac5c1eeb22 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Thu, 2 Jan 2025 09:43:30 +0100 Subject: [PATCH 23/57] feat(styles): enhance calendar component styles for better visibility and layout --- src/app/globals.css | 96 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/src/app/globals.css b/src/app/globals.css index d2186976d..412588354 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -15,4 +15,98 @@ .react-calendar__tile--active{ background-color: #C3E8FA !important; color: #000 !important; -} \ No newline at end of file +} + +.rbc-btn-group:first-child{ + display: none !important; +} + +.rbc-toolbar-label{ + text-align: right !important; + padding: 0px 20px !important; +} + +.rbc-btn-group:last-child{ + font-size: 13px !important; +} + +.rbc-btn-group:last-child button{ + border: none !important; + background-color: #f1f0ff !important; + margin-left: 2px !important; +} + +.rbc-toolbar button.rbc-active{ + background-color: #dbdafe !important; + box-shadow: none !important; +} + +.rbc-time-view{ + border-color: #eee !important; +} + +.rbc-time-header{ + display: none !important; +} + +.rbc-time-content{ + border: none !important; +} + +.rbc-time-gutter.rbc-time-column{ + font-size: 12px !important; +} + +.rbc-time-gutter.rbc-time-column.rbc-timeslot-group{ + padding: 0px 20px !important; +} + +.rbc-timeslot-group{ + background-color: #f7fdff !important; +} + +.rbc-day-slot{ + font-size: 14px !important; +} + +.rbc-event{ + border: none !important; + color: #000 !important; + padding: 10px !important; + margin: 10px !important; + width: 99% !important; +} + +.rbc-event:nth-child(1){ + background-color: #e2f8ff !important; +} + +.rbc-event:nth-child(2) { + background-color: #fefce8 !important; + } + .rbc-event:nth-child(3) { + background-color: #f2f1ff !important; + } + .rbc-event:nth-child(4) { + background-color: #fdf2fb !important; + } + .rbc-event:nth-child(5) { + background-color: #e2f8ff !important; + } + .rbc-event:nth-child(6) { + background-color: #fefce8 !important; + } + .rbc-event:nth-child(7) { + background-color: #f2f1ff !important; + } + .rbc-event:nth-child(8) { + background-color: #fdf2fb !important; + } + .rbc-event:nth-child(9) { + background-color: #e2f8ff !important; + } + + .rbc-event-label{ + color: gray !important; + margin-bottom: 5px; + } \ No newline at end of file From 59231165b57a985dd94deed8f3489d0198775b80 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Thu, 2 Jan 2025 09:43:48 +0100 Subject: [PATCH 24/57] feat(calendar): add BigCalendar component with customizable views and event handling --- src/components/BigCalendar.tsx | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/components/BigCalendar.tsx diff --git a/src/components/BigCalendar.tsx b/src/components/BigCalendar.tsx new file mode 100644 index 000000000..f5e3d068f --- /dev/null +++ b/src/components/BigCalendar.tsx @@ -0,0 +1,31 @@ +"use client"; +import { Calendar, momentLocalizer, View, Views } from 'react-big-calendar' +import moment from 'moment' +import { calendarEvents } from '@/lib/data'; +import 'react-big-calendar/lib/css/react-big-calendar.css' +import { useState } from 'react'; + +const localizer = momentLocalizer(moment) + +const BigCalendar = () => { + const [view, setView] = useState(Views.WORK_WEEK); + + const handleOnChangeView = (selectedView: View) => { + setView(selectedView); + } + return ( + + ) +} +export default BigCalendar; \ No newline at end of file From 01d103c37dc919c2f7e9a3ea58e262a61a38528c Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:27:23 +0100 Subject: [PATCH 25/57] feat(config): add remote image pattern for Pexels in Next.js configuration --- next.config.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/next.config.mjs b/next.config.mjs index 4678774e6..642331f50 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,8 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + images:{ + remotePatterns: [{ hostname: 'images.pexels.com'}] + } +}; export default nextConfig; From 7a05449b1b06069317f8f6d2c365b9a5c2746e2d Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:28:27 +0100 Subject: [PATCH 26/57] Add "flex col" class --- src/app/(dashboard)/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index 2740bc4a1..bfff1d952 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -18,7 +18,7 @@ export default function DashboardLayout({
{/** Content */} -
+
{children}
From d3f0ddb18392b7c4a1c1583537412003b5aecdff Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:29:20 +0100 Subject: [PATCH 27/57] feat(table): add Table and TableSearch components for data display and search functionality --- src/components/Table.tsx | 20 ++++++++++++++++++++ src/components/TableSearch.tsx | 13 +++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/components/Table.tsx create mode 100644 src/components/TableSearch.tsx diff --git a/src/components/Table.tsx b/src/components/Table.tsx new file mode 100644 index 000000000..f7f4515a2 --- /dev/null +++ b/src/components/Table.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const Table = ({columns, renderRow, data}:{columns:{header:string; accessor:string; className?:string}[]; renderRow:(item:any) => React.ReactNode; data: any[]}) => { + return ( + + + + {columns.map(col => ( + + ))} + + + + {data.map((item) => renderRow(item))} + +
{col.header}
+ ) +} + +export default Table \ No newline at end of file diff --git a/src/components/TableSearch.tsx b/src/components/TableSearch.tsx new file mode 100644 index 000000000..8793746fc --- /dev/null +++ b/src/components/TableSearch.tsx @@ -0,0 +1,13 @@ +import Image from 'next/image' +import React from 'react' + +const TableSearch = () => { + return ( +
+ Search + +
+ ) +} + +export default TableSearch \ No newline at end of file From 9c8bab7f7e453278493991e9cfbb4591b43e526c Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:29:30 +0100 Subject: [PATCH 28/57] feat(pagination): add Pagination component for navigation between pages --- src/components/Pagination.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/components/Pagination.tsx diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx new file mode 100644 index 000000000..2b07f1d71 --- /dev/null +++ b/src/components/Pagination.tsx @@ -0,0 +1,19 @@ +import React from 'react' + +const Pagination = () => { + return ( +
+ +
+ + + + ... + +
+ +
+ ) +} + +export default Pagination \ No newline at end of file From 645d9649735c82a1e2893306c0296f40abd27ffc Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:30:15 +0100 Subject: [PATCH 29/57] feat(teachers): add TeacherListPage component with table and pagination --- src/app/(dashboard)/list/teachers/page.tsx | 91 ++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/app/(dashboard)/list/teachers/page.tsx diff --git a/src/app/(dashboard)/list/teachers/page.tsx b/src/app/(dashboard)/list/teachers/page.tsx new file mode 100644 index 000000000..947259472 --- /dev/null +++ b/src/app/(dashboard)/list/teachers/page.tsx @@ -0,0 +1,91 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { role, teachersData } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Teacher = { + id: number; + teacherId: string; + name: string; + email?: string; + photo: string; + subjects: string[]; + classes: string[]; + phone: string; + address: string; +} + +const columns = [ + { header: 'info', accessor: 'info' }, + { header: 'Teacher ID', accessor: 'teacherId', className: 'hidden md:table-cell' }, + { header: 'Subjects', accessor: 'subjects', className: 'hidden md:table-cell' }, + { header: 'Classes', accessor: 'classes', className: 'hidden md:table-cell' }, + { header: 'Phone', accessor: 'phone', className: 'hidden lg:table-cell' }, + { header: 'Address', accessor: 'address', className: 'hidden lg:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const TeacherListPage = () => { + + const renderRow = (item: Teacher) => ( + + + {item.name} +
+

{item.name}

+

{item.email}

+
+ + {item.teacherId} + {item.subjects.join(', ')} + {item.classes.join(', ')} + {item.phone} + {item.address} + +
+ + + + {role === "admin" && ( + )} +
+ + + ) + + return ( +
+ {/* Top */} +
+

All Teachers

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} + + {/* Pagination */} + + + ) +} + +export default TeacherListPage \ No newline at end of file From cac4d8bb8f498226830eb53a289f1899910cdd86 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:30:54 +0100 Subject: [PATCH 30/57] feat(subject): add SubjectListPage component with table and pagination --- src/app/(dashboard)/list/subjects/page.tsx | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/app/(dashboard)/list/subjects/page.tsx diff --git a/src/app/(dashboard)/list/subjects/page.tsx b/src/app/(dashboard)/list/subjects/page.tsx new file mode 100644 index 000000000..5b02bf5c1 --- /dev/null +++ b/src/app/(dashboard)/list/subjects/page.tsx @@ -0,0 +1,73 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { role, subjectsData } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Subject = { + id: number; + name: string; + teachers: string[]; +} + +const columns = [ + { header: 'Subject Name', accessor: 'name' }, + { header: 'Teachers', accessor: 'teachers', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const SubjectListPage = () => { + + const renderRow = (item: Subject) => ( + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Subjects

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.name} + {item.teachers.join(',')} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default SubjectListPage \ No newline at end of file From 88a5bf19ae3a5d2104a12c9f5be865efea69ce9e Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:31:29 +0100 Subject: [PATCH 31/57] feat(student): add StudentListPage component with table and pagination --- src/app/(dashboard)/list/students/page.tsx | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/app/(dashboard)/list/students/page.tsx diff --git a/src/app/(dashboard)/list/students/page.tsx b/src/app/(dashboard)/list/students/page.tsx new file mode 100644 index 000000000..752270e0d --- /dev/null +++ b/src/app/(dashboard)/list/students/page.tsx @@ -0,0 +1,89 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { role, studentsData } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Student = { + id: number; + studentId: string; + name: string; + email?: string; + photo: string; + class: string; + grade: number; + phone?: string; + address: string; +} + +const columns = [ + { header: 'info', accessor: 'info' }, + { header: 'Student ID', accessor: 'studentId', className: 'hidden md:table-cell' }, + { header: 'Grade', accessor: 'grade', className: 'hidden md:table-cell' }, + { header: 'Phone', accessor: 'phone', className: 'hidden lg:table-cell' }, + { header: 'Address', accessor: 'address', className: 'hidden lg:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const StudentListPage = () => { + + const renderRow = (item: Student) => ( + + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Students

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.name} +
+

{item.name}

+

{item.class}

+
+
{item.studentId}{item.grade}{item.phone}{item.address} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default StudentListPage \ No newline at end of file From 022f680bbbcb62312ffa6530b142c410b7530561 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:32:07 +0100 Subject: [PATCH 32/57] feat(results): add ResultListPage component with table and pagination --- src/app/(dashboard)/list/results/page.tsx | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/app/(dashboard)/list/results/page.tsx diff --git a/src/app/(dashboard)/list/results/page.tsx b/src/app/(dashboard)/list/results/page.tsx new file mode 100644 index 000000000..3aef47b41 --- /dev/null +++ b/src/app/(dashboard)/list/results/page.tsx @@ -0,0 +1,86 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { resultsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Result = { + id: number; + subject: string; + class: string; + teacher: string; + student: string; + type: "exam" | "assignment"; + date: string; + score: number; +} + +const columns = [ + { header: 'Subject Name', accessor: 'name' }, + { header: 'Student', accessor: 'student' }, + { header: 'Score', accessor: 'score', className: 'hidden md:table-cell' }, + { header: 'Teacher', accessor: 'teacher', className: 'hidden md:table-cell' }, + { header: 'Class', accessor: 'class', className: 'hidden md:table-cell' }, + { header: 'Date', accessor: 'date', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const ResultListPage = () => { + + const renderRow = (item: Result) => ( + + + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Results

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.subject} + {item.student}{item.score}{item.teacher}{item.class}{item.date} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default ResultListPage \ No newline at end of file From b0b776359aef73ac8300a0c010815c67168220e9 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:32:40 +0100 Subject: [PATCH 33/57] feat(parents): add ParentListPage component with table and pagination --- src/app/(dashboard)/list/parents/page.tsx | 83 +++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/app/(dashboard)/list/parents/page.tsx diff --git a/src/app/(dashboard)/list/parents/page.tsx b/src/app/(dashboard)/list/parents/page.tsx new file mode 100644 index 000000000..edbb52806 --- /dev/null +++ b/src/app/(dashboard)/list/parents/page.tsx @@ -0,0 +1,83 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { parentsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Parent = { + id: number; + name: string; + email?: string; + students: string[]; + phone: string; + address: string; +} + +const columns = [ + { header: 'info', accessor: 'info' }, + { header: 'Student Names', accessor: 'students', className: 'hidden md:table-cell' }, + { header: 'Phone', accessor: 'phone', className: 'hidden lg:table-cell' }, + { header: 'Address', accessor: 'address', className: 'hidden lg:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const ParentListPage = () => { + + const renderRow = (item: Parent) => ( + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Parents

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+
+

{item.name}

+

{item?.email}

+
+
{item.students.join(',')}{item.phone}{item.address} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default ParentListPage \ No newline at end of file From c5943cb1b37ca1d5ffe588e336b01f778d1435f4 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:33:12 +0100 Subject: [PATCH 34/57] feat(lessons): add LessonListPage component with table and pagination --- src/app/(dashboard)/list/lessons/page.tsx | 76 +++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/app/(dashboard)/list/lessons/page.tsx diff --git a/src/app/(dashboard)/list/lessons/page.tsx b/src/app/(dashboard)/list/lessons/page.tsx new file mode 100644 index 000000000..6fcd1b3b3 --- /dev/null +++ b/src/app/(dashboard)/list/lessons/page.tsx @@ -0,0 +1,76 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { lessonsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Lesson = { + id: number; + subject: string; + class: string; + teacher: string; +} + +const columns = [ + { header: 'Subject Name', accessor: 'name' }, + { header: 'Class', accessor: 'class' }, + { header: 'Teacher', accessor: 'teacher', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const LessonListPage = () => { + + const renderRow = (item: Lesson) => ( + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Lessons

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.subject} + {item.class}{item.teacher} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default LessonListPage \ No newline at end of file From d36212a7f3a4b32a6189ede45fd33682fd163521 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:33:39 +0100 Subject: [PATCH 35/57] feat(exams): add ExamListPage component with table and pagination --- src/app/(dashboard)/list/exams/page.tsx | 79 +++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/app/(dashboard)/list/exams/page.tsx diff --git a/src/app/(dashboard)/list/exams/page.tsx b/src/app/(dashboard)/list/exams/page.tsx new file mode 100644 index 000000000..d3cb112f7 --- /dev/null +++ b/src/app/(dashboard)/list/exams/page.tsx @@ -0,0 +1,79 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { examsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Exam = { + id: number; + subject: string; + class: string; + teacher: string; + date: string; +} + +const columns = [ + { header: 'Subject Name', accessor: 'name' }, + { header: 'Class', accessor: 'class' }, + { header: 'Teacher', accessor: 'teacher', className: 'hidden md:table-cell' }, + { header: 'Date', accessor: 'date', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const ExamListPage = () => { + + const renderRow = (item: Exam) => ( + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Exams

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.subject} + {item.class}{item.teacher}{item.date} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default ExamListPage \ No newline at end of file From 0b9456d6ef5915cd67f4ffd3633046d1ef632c98 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:34:00 +0100 Subject: [PATCH 36/57] feat(events): add EventListPage component with table and pagination --- src/app/(dashboard)/list/events/page.tsx | 82 ++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/app/(dashboard)/list/events/page.tsx diff --git a/src/app/(dashboard)/list/events/page.tsx b/src/app/(dashboard)/list/events/page.tsx new file mode 100644 index 000000000..b0cf9029f --- /dev/null +++ b/src/app/(dashboard)/list/events/page.tsx @@ -0,0 +1,82 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { eventsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Event = { + id: number; + title: string; + class: string; + date: string; + startTime: string; + endTime: number; +} + +const columns = [ + { header: 'Title', accessor: 'title' }, + { header: 'Class', accessor: 'class'}, + { header: 'Date', accessor: 'date', className: 'hidden md:table-cell' }, + { header: 'Start Time', accessor: 'startTime', className: 'hidden md:table-cell' }, + { header: 'End Time', accessor: 'endTime', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const EventListPage = () => { + + const renderRow = (item: Event) => ( + + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Events

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.title} + {item.class}{item.date}{item.startTime}{item.endTime} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default EventListPage \ No newline at end of file From b72a1ebf921e6082725d5f57fa1102c8177c44c6 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:34:30 +0100 Subject: [PATCH 37/57] feat(classes): add ClassListPage component with table and pagination --- src/app/(dashboard)/list/classes/page.tsx | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/app/(dashboard)/list/classes/page.tsx diff --git a/src/app/(dashboard)/list/classes/page.tsx b/src/app/(dashboard)/list/classes/page.tsx new file mode 100644 index 000000000..937e6cc23 --- /dev/null +++ b/src/app/(dashboard)/list/classes/page.tsx @@ -0,0 +1,79 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { classesData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Class = { + id: number; + name: string; + capacity: number; + grade: number; + supervisor: string; +} + +const columns = [ + { header: 'Class Name', accessor: 'name' }, + { header: 'Capacity', accessor: 'capacity', className: 'hidden md:table-cell' }, + { header: 'Grade', accessor: 'grade', className: 'hidden md:table-cell' }, + { header: 'Spervisor', accessor: 'supervisor', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const ClassListPage = () => { + + const renderRow = (item: Class) => ( + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Classes

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.name} + {item.capacity}{item.grade}{item.supervisor} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default ClassListPage \ No newline at end of file From a72cd79935d8a69d0076555f7403f1542ad0f714 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:35:22 +0100 Subject: [PATCH 38/57] feat(assignments): add AssignmentListPage component with table and pagination --- src/app/(dashboard)/list/assignments/page.tsx | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/app/(dashboard)/list/assignments/page.tsx diff --git a/src/app/(dashboard)/list/assignments/page.tsx b/src/app/(dashboard)/list/assignments/page.tsx new file mode 100644 index 000000000..ea75e377c --- /dev/null +++ b/src/app/(dashboard)/list/assignments/page.tsx @@ -0,0 +1,79 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { assignmentsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Assignment = { + id: number; + subject: string; + class: string; + teacher: string; + dueDate: string; +} + +const columns = [ + { header: 'Subject Name', accessor: 'name' }, + { header: 'Class', accessor: 'class' }, + { header: 'Teacher', accessor: 'teacher', className: 'hidden md:table-cell' }, + { header: 'Due Date', accessor: 'dueDate', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const AssignmentListPage = () => { + + const renderRow = (item: Assignment) => ( + + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Assignments

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.subject} + {item.class}{item.teacher}{item.dueDate} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default AssignmentListPage \ No newline at end of file From 0dce55acf3de379b74ca3e0cff3ad72d02b675b0 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:35:34 +0100 Subject: [PATCH 39/57] feat(announcements): add AnnouncementListPage component with table and pagination --- .../(dashboard)/list/announcements/page.tsx | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/app/(dashboard)/list/announcements/page.tsx diff --git a/src/app/(dashboard)/list/announcements/page.tsx b/src/app/(dashboard)/list/announcements/page.tsx new file mode 100644 index 000000000..3444d662f --- /dev/null +++ b/src/app/(dashboard)/list/announcements/page.tsx @@ -0,0 +1,76 @@ +import Pagination from '@/components/Pagination' +import Table from '@/components/Table' +import TableSearch from '@/components/TableSearch' +import { announcementsData, role } from '@/lib/data' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +type Announcement = { + id: number; + title: string; + class: string; + date: string; +} + +const columns = [ + { header: 'Title', accessor: 'title' }, + { header: 'Class', accessor: 'class'}, + { header: 'Date', accessor: 'date', className: 'hidden md:table-cell' }, + { header: 'Actions', accessor: 'actions' }, +] + +const AnnouncementListPage = () => { + + const renderRow = (item: Announcement) => ( + + + + + + + ) + + return ( +
+ {/* Top */} +
+

All Announcements

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* List */} +
+ {item.title} + {item.class}{item.date} +
+ + + + {role === "admin" && ( + )} +
+
+ {/* Pagination */} + + + ) +} + +export default AnnouncementListPage \ No newline at end of file From 1cd308a32827820b36b0f5dad4d7d96b3d8d8bcd Mon Sep 17 00:00:00 2001 From: lucidcity Date: Fri, 3 Jan 2025 12:36:49 +0100 Subject: [PATCH 40/57] Update calendarEvents with most recent date to test event display --- src/lib/data.ts | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/lib/data.ts b/src/lib/data.ts index 5fcd9281e..43b856020 100644 --- a/src/lib/data.ts +++ b/src/lib/data.ts @@ -921,94 +921,94 @@ export const calendarEvents = [ { title: "Math", allDay: false, - start: new Date(2024, 7, 12, 8, 0), - end: new Date(2024, 7, 12, 8, 45), + start: new Date(2025, 0, 2, 8, 0), // January is month 0 + end: new Date(2025, 0, 2, 8, 45), }, { title: "English", allDay: false, - start: new Date(2024, 7, 12, 9, 0), - end: new Date(2024, 7, 12, 9, 45), + start: new Date(2025, 0, 2, 9, 0), + end: new Date(2025, 0, 2, 9, 45), }, { title: "Biology", allDay: false, - start: new Date(2024, 7, 12, 10, 0), - end: new Date(2024, 7, 12, 10, 45), + start: new Date(2025, 0, 2, 10, 0), + end: new Date(2025, 0, 2, 10, 45), }, { title: "Physics", allDay: false, - start: new Date(2024, 7, 12, 11, 0), - end: new Date(2024, 7, 12, 11, 45), + start: new Date(2025, 0, 2, 11, 0), + end: new Date(2025, 0, 2, 11, 45), }, { title: "Chemistry", allDay: false, - start: new Date(2024, 7, 12, 13, 0), - end: new Date(2024, 7, 12, 13, 45), + start: new Date(2025, 0, 2, 12, 0), + end: new Date(2025, 0, 2, 12, 45), }, { title: "History", allDay: false, - start: new Date(2024, 7, 12, 14, 0), - end: new Date(2024, 7, 12, 14, 45), + start: new Date(2025, 0, 2, 13, 0), + end: new Date(2025, 0, 2, 13, 45), }, { title: "English", allDay: false, - start: new Date(2024, 7, 13, 9, 0), - end: new Date(2024, 7, 13, 9, 45), + start: new Date(2025, 0, 2, 14, 0), + end: new Date(2025, 0, 2, 14, 45), }, { title: "Biology", allDay: false, - start: new Date(2024, 7, 13, 10, 0), - end: new Date(2024, 7, 13, 10, 45), + start: new Date(2025, 0, 2, 15, 0), + end: new Date(2025, 0, 2, 15, 45), }, { title: "Physics", allDay: false, - start: new Date(2024, 7, 13, 11, 0), - end: new Date(2024, 7, 13, 11, 45), + start: new Date(2025, 0, 2, 16, 0), + end: new Date(2025, 0, 2, 16, 45), }, { title: "History", allDay: false, - start: new Date(2024, 7, 13, 14, 0), - end: new Date(2024, 7, 13, 14, 45), + start: new Date(2025, 0, 3, 16, 0), + end: new Date(2025, 0, 3, 16, 45), }, { title: "Math", allDay: false, - start: new Date(2024, 7, 14, 8, 0), - end: new Date(2024, 7, 14, 8, 45), + start: new Date(2025, 0, 3, 9, 0), + end: new Date(2025, 0, 3, 9, 45), }, { title: "Biology", allDay: false, - start: new Date(2024, 7, 14, 10, 0), - end: new Date(2024, 7, 14, 10, 45), + start: new Date(2025, 7, 14, 10, 0), + end: new Date(2025, 7, 14, 10, 45), }, { title: "Chemistry", allDay: false, - start: new Date(2024, 7, 14, 13, 0), - end: new Date(2024, 7, 14, 13, 45), + start: new Date(2025, 7, 14, 13, 0), + end: new Date(2025, 7, 14, 13, 45), }, { title: "History", allDay: false, - start: new Date(2024, 7, 14, 14, 0), - end: new Date(2024, 7, 13, 14, 45), + start: new Date(2025, 7, 14, 14, 0), + end: new Date(2025, 7, 13, 14, 45), }, { title: "English", allDay: false, - start: new Date(2024, 7, 15, 9, 0), - end: new Date(2024, 7, 15, 9, 45), + start: new Date(2025, 7, 15, 9, 0), + end: new Date(2025, 7, 15, 9, 45), }, { title: "Biology", From 3367d0ea95426f24fa93170f31dff1bb73ced748 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 5 Jan 2025 23:54:06 +0100 Subject: [PATCH 41/57] feat(performance): add Performance component with pie chart visualization --- src/components/Performance.tsx | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/components/Performance.tsx diff --git a/src/components/Performance.tsx b/src/components/Performance.tsx new file mode 100644 index 000000000..b4df3ce24 --- /dev/null +++ b/src/components/Performance.tsx @@ -0,0 +1,41 @@ +"use client"; +import Image from 'next/image'; +import React from 'react' +import { PieChart, Pie, Sector, Cell, ResponsiveContainer } from 'recharts'; + +const data = [ + { name: 'Group A', value: 92, fill: '#C3EBFA' }, + { name: 'Group B', value: 8, fill: '#FAE27C' }, +]; + +const Performance = () => { + return ( +
+
+

Performance

+ +
+ + + + + +
+

9.2

+

of 10 ITS

+
+

1st Semester - 2nd Semester

+
+ ) +} + +export default Performance \ No newline at end of file From 255e3fb7b3d41a77a6316ff7a76168faa6205782 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Sun, 5 Jan 2025 23:54:17 +0100 Subject: [PATCH 42/57] feat(teachers): add SingleTeacherPage component with profile, schedule, and shortcuts --- .../(dashboard)/list/teachers/[id]/page.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/app/(dashboard)/list/teachers/[id]/page.tsx diff --git a/src/app/(dashboard)/list/teachers/[id]/page.tsx b/src/app/(dashboard)/list/teachers/[id]/page.tsx new file mode 100644 index 000000000..69a36c2aa --- /dev/null +++ b/src/app/(dashboard)/list/teachers/[id]/page.tsx @@ -0,0 +1,104 @@ +import Announcements from '@/components/Announcements' +import BigCalendar from '@/components/BigCalendar' +import Performance from '@/components/Performance' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +const SingleTeacherPage = () => { + return ( +
+ {/* Left side */} +
+ {/* Top */} +
+ {/* User Info Card */} +
+
+ +
+
+

John Doe

+

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Saepe ducimus magni fuga, alias earum asperiores rerum.

+
+
+ + AB+ +
+
+ + January +
+
+ + user@gmail.com+ +
+
+ + 1 234 567 +
+
+
+
+ {/* Small Cards */} +
+ {/* Card */} +
+ +
+

90%

+ Attendance +
+
+ {/* Card */} +
+ +
+

2

+ Branches +
+
+ {/* Card */} +
+ +
+

6

+ Lessons +
+
+ {/* Card */} +
+ +
+

6

+ classes +
+
+
+
+ {/* Bottom */} +
+

Teacher's schedule

+ +
+
+ {/* Right side */} +
+
+

Shortcuts

+
+ Teacher's Classes + Teacher's Students + Teacher's Lessons + Teacher's Exams + Teacher's Assignments +
+
+ + +
+
+ ) +} + +export default SingleTeacherPage \ No newline at end of file From 75e780ef47636c5b13007797b8228ff468e662bf Mon Sep 17 00:00:00 2001 From: lucidcity Date: Mon, 6 Jan 2025 10:47:34 +0100 Subject: [PATCH 43/57] Change image names: 'plus' is now 'create' and 'edit' is now 'update' --- public/{plus.png => create.png} | Bin public/{edit.png => update.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename public/{plus.png => create.png} (100%) rename public/{edit.png => update.png} (100%) diff --git a/public/plus.png b/public/create.png similarity index 100% rename from public/plus.png rename to public/create.png diff --git a/public/edit.png b/public/update.png similarity index 100% rename from public/edit.png rename to public/update.png From d98ac4eb035eb9259a092ea6073b15572c704227 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:39:20 +0100 Subject: [PATCH 44/57] install "@hookform/resolvers", "react-hook-form" and "zod" for form validation. --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e70901e8..3880fe2d0 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@hookform/resolvers": "^3.9.1", "@types/react-big-calendar": "^1.16.0", "moment": "^2.30.1", "next": "14.2.5", @@ -16,7 +17,9 @@ "react-big-calendar": "^1.17.1", "react-calendar": "^5.1.0", "react-dom": "^18", - "recharts": "^2.15.0" + "react-hook-form": "^7.54.2", + "recharts": "^2.15.0", + "zod": "^3.24.1" }, "devDependencies": { "@types/node": "^20", From 2a04642ef9bc3bc0938b67cdb826e082e19cd8ef Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:40:20 +0100 Subject: [PATCH 45/57] feat(students): add SingleStudentPage component with profile, schedule, and shortcuts --- .../(dashboard)/list/students/[id]/page.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/app/(dashboard)/list/students/[id]/page.tsx diff --git a/src/app/(dashboard)/list/students/[id]/page.tsx b/src/app/(dashboard)/list/students/[id]/page.tsx new file mode 100644 index 000000000..73d2806c8 --- /dev/null +++ b/src/app/(dashboard)/list/students/[id]/page.tsx @@ -0,0 +1,104 @@ +import Announcements from '@/components/Announcements' +import BigCalendar from '@/components/BigCalendar' +import Performance from '@/components/Performance' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' + +const SingleStudentPage = () => { + return ( +
+ {/* Left side */} +
+ {/* Top */} +
+ {/* User Info Card */} +
+
+ +
+
+

Jane Doe

+

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Saepe ducimus magni fuga, alias earum asperiores rerum.

+
+
+ + AB+ +
+
+ + January +
+
+ + user@gmail.com+ +
+
+ + 1 234 567 +
+
+
+
+ {/* Small Cards */} +
+ {/* Card */} +
+ +
+

90%

+ Attendance +
+
+ {/* Card */} +
+ +
+

6th

+ Grade +
+
+ {/* Card */} +
+ +
+

18

+ Lessons +
+
+ {/* Card */} +
+ +
+

6A

+ class +
+
+
+
+ {/* Bottom */} +
+

Student's schedule

+ +
+
+ {/* Right side */} +
+
+

Shortcuts

+
+ Student's Lessons + Student's Teachers + Student's Exams + Student's Assignments + Student's Results +
+
+ + +
+
+ ) +} + +export default SingleStudentPage \ No newline at end of file From b31c7ec356588f4d502997d0a136f13c84e3f789 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:40:38 +0100 Subject: [PATCH 46/57] feat(forms): add FormModal component for dynamic form handling --- src/components/FormModal.tsx | 113 +++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/components/FormModal.tsx diff --git a/src/components/FormModal.tsx b/src/components/FormModal.tsx new file mode 100644 index 000000000..2d63d628a --- /dev/null +++ b/src/components/FormModal.tsx @@ -0,0 +1,113 @@ +"use client"; +import dynamic from 'next/dynamic'; +import Image from 'next/image'; +import React, { useState } from 'react' + +const TeacherForm = dynamic(() => import('./forms/TeacherForm'), { + loading: () =>

Loading...

, + // ssr: false +}); +const StudentForm = dynamic(() => import('./forms/StudentForm'), { + loading: () =>

Loading...

, +}); +const ParentForm = dynamic(() => import('./forms/ParentForm'), { + loading: () =>

Loading...

, +}); +const EventForm = dynamic(() => import('./forms/EventForm'), { + loading: () =>

Loading...

, +}); +const LessonForm = dynamic(() => import('./forms/LessonForm'), { + loading: () =>

Loading...

, +}); +const ExamForm = dynamic(() => import('./forms/ExamForm'), { + loading: () =>

Loading...

, +}); +const ClassForm = dynamic(() => import('./forms/ClassForm'), { + loading: () =>

Loading...

, +}); +const AssignmentForm = dynamic(() => import('./forms/AssignmentForm'), { + loading: () =>

Loading...

, +}); +const SubjectForm = dynamic(() => import('./forms/SubjectForm'), { + loading: () =>

Loading...

, +}); +const AttendanceForm = dynamic(() => import('./forms/AttendanceForm'), { + loading: () =>

Loading...

, +}); +const AnnouncementForm = dynamic(() => import('./forms/AnnouncementForm'), { + loading: () =>

Loading...

, +}); +const ResultForm = dynamic(() => import('./forms/ResultForm'), { + loading: () =>

Loading...

, +}); + +const forms:{[key:string]:(type:'create' | 'update', data?:any) => JSX.Element;} = { + teacher: (type,data) => , + student: (type,data) => , + parent: (type,data) => , + event: (type,data) => , + lesson: (type,data) => , + exam: (type,data) => , + class: (type,data) => , + assignment: (type,data) => , + subject: (type,data) => , + attendance: (type,data) => , + announcement: (type,data) => , + result: (type,data) => , +} + +const FormModal = ({ + table,type,data,id}:{ + table: + | "teacher" + | "student" + | "parent" + | "subject" + | "class" + | "lesson" + | "exam" + | "assignment" + | "result" + | "attendance" + | "event" + | "announcement"; + type:"create"|"update" | "delete"; + data?:any; + id?:number; + }) => { + + const [open, setOpen] = useState(false); + + const Form = () => { + return type === "delete" && id ? ( +
+ All data will be lost. Are you sure you want to delete this {table}? + + + ) : type === 'create' || type === 'update' ? ( + forms[table](type,data) + ) : 'Form not found'; + } + + const size = type === "create" ? "w-8 h-8" : "w-7 h-7"; + const bgColor = type === "create" ? "bg-myYellow" : type === "update" ? "bg-mySky" : "bg-myPurple"; + return ( + <> + + {open && ( +
+
+
+
setOpen(false)}> + +
+
+
+ )} + + ) +} + +export default FormModal \ No newline at end of file From 128661f34c2243bbca5189b21d6db66dce053c1b Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:40:52 +0100 Subject: [PATCH 47/57] feat(announcements): integrate FormModal for create, update, and delete actions --- .../(dashboard)/list/announcements/page.tsx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/(dashboard)/list/announcements/page.tsx b/src/app/(dashboard)/list/announcements/page.tsx index 3444d662f..e7510d8af 100644 --- a/src/app/(dashboard)/list/announcements/page.tsx +++ b/src/app/(dashboard)/list/announcements/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -31,14 +32,11 @@ const AnnouncementListPage = () => {
@@ -59,9 +57,9 @@ const AnnouncementListPage = () => { - {role === "admin" && } + {role === "admin" && + + } From afffa527aa1bfcd1f41a9b929472a1415a909d9e Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:41:04 +0100 Subject: [PATCH 48/57] feat(assignments): integrate FormModal for create, update, and delete actions in AssignmentListPage --- src/app/(dashboard)/list/assignments/page.tsx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/(dashboard)/list/assignments/page.tsx b/src/app/(dashboard)/list/assignments/page.tsx index ea75e377c..3c32bcdd3 100644 --- a/src/app/(dashboard)/list/assignments/page.tsx +++ b/src/app/(dashboard)/list/assignments/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -34,14 +35,11 @@ const AssignmentListPage = () => { @@ -62,9 +60,9 @@ const AssignmentListPage = () => { - {role === "admin" && } + {role === "admin" && + + } From 705c10ada6177652e2f3729c2c395d0b9abe82bb Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:41:15 +0100 Subject: [PATCH 49/57] feat(classes): integrate FormModal for create, update, and delete actions in ClassListPage --- src/app/(dashboard)/list/classes/page.tsx | 26 +++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/app/(dashboard)/list/classes/page.tsx b/src/app/(dashboard)/list/classes/page.tsx index 937e6cc23..1dbb82533 100644 --- a/src/app/(dashboard)/list/classes/page.tsx +++ b/src/app/(dashboard)/list/classes/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -34,14 +35,14 @@ const ClassListPage = () => { @@ -62,9 +63,12 @@ const ClassListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } From fdf142e19fc4bc89a49eb374aedf23eca5ac1639 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:41:39 +0100 Subject: [PATCH 50/57] feat(events): integrate FormModal for create, update, and delete actions in EventListPage --- src/app/(dashboard)/list/events/page.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/(dashboard)/list/events/page.tsx b/src/app/(dashboard)/list/events/page.tsx index b0cf9029f..4dcb8f650 100644 --- a/src/app/(dashboard)/list/events/page.tsx +++ b/src/app/(dashboard)/list/events/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -37,14 +38,11 @@ const EventListPage = () => { @@ -65,9 +63,9 @@ const EventListPage = () => { - {role === "admin" && } + {role === "admin" && + + } From 4e3f80776dd6febd8fba3268e4dd35245c7a51e8 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:41:52 +0100 Subject: [PATCH 51/57] feat(exams): integrate FormModal for create, update, and delete actions in ExamListPage --- src/app/(dashboard)/list/exams/page.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/(dashboard)/list/exams/page.tsx b/src/app/(dashboard)/list/exams/page.tsx index d3cb112f7..bc685c615 100644 --- a/src/app/(dashboard)/list/exams/page.tsx +++ b/src/app/(dashboard)/list/exams/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -34,14 +35,11 @@ const ExamListPage = () => { @@ -62,9 +60,9 @@ const ExamListPage = () => { - {role === "admin" && } + {role === "admin" && + + } From 74c71773fe77c81ac364778342b534ad7043a649 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:43:20 +0100 Subject: [PATCH 52/57] feat(lessons, parents, results, students, subjects, teachers): integrate FormModal for create, update, and delete actions in respective list pages --- src/app/(dashboard)/list/lessons/page.tsx | 23 ++++++++++--------- src/app/(dashboard)/list/parents/page.tsx | 26 +++++++++++++--------- src/app/(dashboard)/list/results/page.tsx | 20 ++++++++--------- src/app/(dashboard)/list/students/page.tsx | 18 ++++++++++----- src/app/(dashboard)/list/subjects/page.tsx | 26 +++++++++++++--------- src/app/(dashboard)/list/teachers/page.tsx | 18 ++++++++++----- 6 files changed, 75 insertions(+), 56 deletions(-) diff --git a/src/app/(dashboard)/list/lessons/page.tsx b/src/app/(dashboard)/list/lessons/page.tsx index 6fcd1b3b3..00d537a72 100644 --- a/src/app/(dashboard)/list/lessons/page.tsx +++ b/src/app/(dashboard)/list/lessons/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -31,14 +32,11 @@ const LessonListPage = () => { @@ -59,9 +57,12 @@ const LessonListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } diff --git a/src/app/(dashboard)/list/parents/page.tsx b/src/app/(dashboard)/list/parents/page.tsx index edbb52806..8880b3984 100644 --- a/src/app/(dashboard)/list/parents/page.tsx +++ b/src/app/(dashboard)/list/parents/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -38,14 +39,14 @@ const ParentListPage = () => { @@ -66,9 +67,12 @@ const ParentListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } diff --git a/src/app/(dashboard)/list/results/page.tsx b/src/app/(dashboard)/list/results/page.tsx index 3aef47b41..78c046a9c 100644 --- a/src/app/(dashboard)/list/results/page.tsx +++ b/src/app/(dashboard)/list/results/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -41,14 +42,11 @@ const ResultListPage = () => { @@ -69,9 +67,9 @@ const ResultListPage = () => { - {role === "admin" && } + {role === "admin" && + + } diff --git a/src/app/(dashboard)/list/students/page.tsx b/src/app/(dashboard)/list/students/page.tsx index 752270e0d..4b278bfdf 100644 --- a/src/app/(dashboard)/list/students/page.tsx +++ b/src/app/(dashboard)/list/students/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -49,9 +50,11 @@ const StudentListPage = () => { - {role === "admin" && ( + {role === "admin" && ( + // + )} @@ -72,9 +75,12 @@ const StudentListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } diff --git a/src/app/(dashboard)/list/subjects/page.tsx b/src/app/(dashboard)/list/subjects/page.tsx index 5b02bf5c1..75cfee749 100644 --- a/src/app/(dashboard)/list/subjects/page.tsx +++ b/src/app/(dashboard)/list/subjects/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -28,14 +29,14 @@ const SubjectListPage = () => { @@ -56,9 +57,12 @@ const SubjectListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } diff --git a/src/app/(dashboard)/list/teachers/page.tsx b/src/app/(dashboard)/list/teachers/page.tsx index 947259472..d8d5cc721 100644 --- a/src/app/(dashboard)/list/teachers/page.tsx +++ b/src/app/(dashboard)/list/teachers/page.tsx @@ -1,3 +1,4 @@ +import FormModal from '@/components/FormModal' import Pagination from '@/components/Pagination' import Table from '@/components/Table' import TableSearch from '@/components/TableSearch' @@ -51,9 +52,11 @@ const TeacherListPage = () => { - {role === "admin" && ( + {role === "admin" && ( + // + )} @@ -74,9 +77,12 @@ const TeacherListPage = () => { - {role === "admin" && } + {role === "admin" && + // + + } From 32044ad3d067681c0a4eea3d777a1a94aec0999e Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:43:29 +0100 Subject: [PATCH 53/57] feat(teachers): integrate FormModal for updating teacher details on SingleTeacherPage --- .../(dashboard)/list/teachers/[id]/page.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/app/(dashboard)/list/teachers/[id]/page.tsx b/src/app/(dashboard)/list/teachers/[id]/page.tsx index 69a36c2aa..af90fbf52 100644 --- a/src/app/(dashboard)/list/teachers/[id]/page.tsx +++ b/src/app/(dashboard)/list/teachers/[id]/page.tsx @@ -1,5 +1,6 @@ import Announcements from '@/components/Announcements' import BigCalendar from '@/components/BigCalendar' +import FormModal from '@/components/FormModal' import Performance from '@/components/Performance' import Image from 'next/image' import Link from 'next/link' @@ -18,7 +19,23 @@ const SingleTeacherPage = () => {
-

John Doe

+
+

John Doe

+ +

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Saepe ducimus magni fuga, alias earum asperiores rerum.

From 2635a0a7d966f55422ed51781fa2bb26a573b916 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:43:41 +0100 Subject: [PATCH 54/57] feat(teachers): add TeacherForm component for creating and updating teacher details --- src/components/forms/TeacherForm.tsx | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/components/forms/TeacherForm.tsx diff --git a/src/components/forms/TeacherForm.tsx b/src/components/forms/TeacherForm.tsx new file mode 100644 index 000000000..3e7f29512 --- /dev/null +++ b/src/components/forms/TeacherForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const TeacherForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( + +

Create a new teacher

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default TeacherForm \ No newline at end of file From 5699ecee46addf95c050aa53efe6a2a5112dc17f Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:45:02 +0100 Subject: [PATCH 55/57] feat(exams, classes): add ExamForm and ClassForm components for creating and updating exam and class details --- src/components/forms/ClassForm.tsx | 77 ++++++++++++++++++++++++++++++ src/components/forms/ExamForm.tsx | 77 ++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/components/forms/ClassForm.tsx create mode 100644 src/components/forms/ExamForm.tsx diff --git a/src/components/forms/ClassForm.tsx b/src/components/forms/ClassForm.tsx new file mode 100644 index 000000000..dcf782ac2 --- /dev/null +++ b/src/components/forms/ClassForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const ClassForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Class

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default ClassForm \ No newline at end of file diff --git a/src/components/forms/ExamForm.tsx b/src/components/forms/ExamForm.tsx new file mode 100644 index 000000000..a6bc609bc --- /dev/null +++ b/src/components/forms/ExamForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const ExamForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default ExamForm \ No newline at end of file From 716140717a5646b5a178734bef684dd9d92f62ac Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:47:41 +0100 Subject: [PATCH 56/57] feat(events, lessons, assignments, announcements, lessons, parents, results, students, subjects, events, attendance): add respective form components for creating and updating forms --- src/components/forms/AnnouncementForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/AssignmentForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/AttendanceForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/EventForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/LessonForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/ParentForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/ResultForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/StudentForm.tsx | 77 +++++++++++++++++++++++ src/components/forms/SubjectForm.tsx | 77 +++++++++++++++++++++++ 9 files changed, 693 insertions(+) create mode 100644 src/components/forms/AnnouncementForm.tsx create mode 100644 src/components/forms/AssignmentForm.tsx create mode 100644 src/components/forms/AttendanceForm.tsx create mode 100644 src/components/forms/EventForm.tsx create mode 100644 src/components/forms/LessonForm.tsx create mode 100644 src/components/forms/ParentForm.tsx create mode 100644 src/components/forms/ResultForm.tsx create mode 100644 src/components/forms/StudentForm.tsx create mode 100644 src/components/forms/SubjectForm.tsx diff --git a/src/components/forms/AnnouncementForm.tsx b/src/components/forms/AnnouncementForm.tsx new file mode 100644 index 000000000..fecf95568 --- /dev/null +++ b/src/components/forms/AnnouncementForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const AnnouncementForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Announcement

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default AnnouncementForm \ No newline at end of file diff --git a/src/components/forms/AssignmentForm.tsx b/src/components/forms/AssignmentForm.tsx new file mode 100644 index 000000000..4f04ab0c9 --- /dev/null +++ b/src/components/forms/AssignmentForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const AssignmentForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default AssignmentForm \ No newline at end of file diff --git a/src/components/forms/AttendanceForm.tsx b/src/components/forms/AttendanceForm.tsx new file mode 100644 index 000000000..d7f2dcd97 --- /dev/null +++ b/src/components/forms/AttendanceForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const AttendanceForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default AttendanceForm \ No newline at end of file diff --git a/src/components/forms/EventForm.tsx b/src/components/forms/EventForm.tsx new file mode 100644 index 000000000..b5a98485b --- /dev/null +++ b/src/components/forms/EventForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const EventForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default EventForm \ No newline at end of file diff --git a/src/components/forms/LessonForm.tsx b/src/components/forms/LessonForm.tsx new file mode 100644 index 000000000..6f2b87685 --- /dev/null +++ b/src/components/forms/LessonForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const LessonForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default LessonForm \ No newline at end of file diff --git a/src/components/forms/ParentForm.tsx b/src/components/forms/ParentForm.tsx new file mode 100644 index 000000000..baae295bc --- /dev/null +++ b/src/components/forms/ParentForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const ParentForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default ParentForm \ No newline at end of file diff --git a/src/components/forms/ResultForm.tsx b/src/components/forms/ResultForm.tsx new file mode 100644 index 000000000..b9e21873a --- /dev/null +++ b/src/components/forms/ResultForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const ResultForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default ResultForm \ No newline at end of file diff --git a/src/components/forms/StudentForm.tsx b/src/components/forms/StudentForm.tsx new file mode 100644 index 000000000..7b22b4423 --- /dev/null +++ b/src/components/forms/StudentForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const StudentForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default StudentForm \ No newline at end of file diff --git a/src/components/forms/SubjectForm.tsx b/src/components/forms/SubjectForm.tsx new file mode 100644 index 000000000..44e7419aa --- /dev/null +++ b/src/components/forms/SubjectForm.tsx @@ -0,0 +1,77 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react' +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import InputField from './InputField'; +import Image from 'next/image'; + +const schema = z.object({ + username: z.string().min(3, { message: 'username must be at least 3 characters long!' }).max(3, { message: 'username must be at most 20 characters long!' }), + email: z.string().email({message: 'Invalid email address!'}), + password: z.string().min(8, {message: 'password must be at least 8 characters long!'}), + firstName: z.string().min(1, { message: 'first name is required!' }), + lastName: z.string().min(1, { message: 'last name is required!' }), + phone: z.number().min(1, { message: 'phone number is required!' }), + address: z.string().min(1, { message: 'address is required!' }), + bloodType: z.string().min(1, { message: 'Blood type is required!' }), + birthday: z.date( { message: 'birthday is required!' }), + sex: z.enum(['male','female'], { message:'sex is required!'}), + img: z.instanceof(File, { message: 'image is required!' }), + }); + + type Inputs = z.infer; + +const SubjectForm = ({type,data}:{type:'create' | 'update'; data?:any}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = handleSubmit(data=>{ + console.log(data) + }) + + return ( +
+

Create a new Student

+ Authentication Information +
+ + + +
+ Personal Information +
+ + + + + + +
+ + + {errors.sex?.message &&

{errors.sex.message.toString()}

} +
+
+ + + {errors?.img?.message &&

{errors.img.message.toString()}

} +
+
+ + + ) +} + +export default SubjectForm \ No newline at end of file From 0b49081b81ace18b2b3eacee482b9ffcb37b7089 Mon Sep 17 00:00:00 2001 From: lucidcity Date: Tue, 7 Jan 2025 08:47:51 +0100 Subject: [PATCH 57/57] feat(forms): add InputField component for form input handling --- src/components/forms/InputField.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/components/forms/InputField.tsx diff --git a/src/components/forms/InputField.tsx b/src/components/forms/InputField.tsx new file mode 100644 index 000000000..9c1f50871 --- /dev/null +++ b/src/components/forms/InputField.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { FieldError } from 'react-hook-form'; + +type InputFieldProps = { + label: string; + type?: string; + register: any; + name: string; + defaultValue?: string; + error?: FieldError; + inputProps?: React.InputHTMLAttributes +} + +const InputField = ({ + label, type = 'text', register, error, name, defaultValue, inputProps +}: InputFieldProps) => { + return ( +
+ + + {error?.message &&

{error.message.toString()}

} +
+ ) +} + +export default InputField \ No newline at end of file
{item.date}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.dueDate}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.supervisor}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + {/* { } */} + + )}
{item.endTime}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.date}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.teacher}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.address}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + {/* { } */} + + )}
{item.date}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + + )}
{item.teachers.join(',')}
- - - - {role === "admin" && ( + {role === "admin" && ( + <> + + {/* { } */} + + )}