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;
diff --git a/package-lock.json b/package-lock.json
index cf999766d..81aac9c79 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,14 @@
"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-dom": "^18"
+ "react-big-calendar": "^1.17.1",
+ "react-calendar": "^5.1.0",
+ "react-dom": "^18",
+ "recharts": "^2.15.0"
},
"devDependencies": {
"@types/node": "^20",
@@ -36,6 +41,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",
@@ -443,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",
@@ -466,6 +502,65 @@
"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/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",
@@ -487,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==",
- "dev": 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,
"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",
@@ -511,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",
@@ -652,6 +760,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",
@@ -1150,6 +1266,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 +1343,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",
@@ -1283,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",
@@ -1301,6 +1544,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",
@@ -1377,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",
@@ -1417,6 +1673,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 +2346,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 +2358,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",
@@ -2346,6 +2624,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",
@@ -2408,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",
@@ -2647,6 +2941,22 @@
"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/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",
@@ -3265,6 +3575,16 @@
"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-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",
@@ -3291,6 +3611,45 @@
"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",
+ "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/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",
@@ -3315,6 +3674,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",
@@ -3348,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",
@@ -3484,7 +3870,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"
@@ -3654,6 +4039,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",
@@ -3989,7 +4382,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",
@@ -4040,6 +4432,65 @@
"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",
+ "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",
@@ -4057,9 +4508,61 @@
"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-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",
+ "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 +4586,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 +4643,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 +5338,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",
@@ -4980,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",
@@ -5004,6 +5566,35 @@
"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/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 dd3389bbf..3880fe2d0 100644
--- a/package.json
+++ b/package.json
@@ -9,18 +9,26 @@
"lint": "next lint"
},
"dependencies": {
+ "@hookform/resolvers": "^3.9.1",
+ "@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",
- "next": "14.2.5"
+ "react-hook-form": "^7.54.2",
+ "recharts": "^2.15.0",
+ "zod": "^3.24.1"
},
"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"
}
}
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
diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx
new file mode 100644
index 000000000..9bd207793
--- /dev/null
+++ b/src/app/(dashboard)/admin/page.tsx
@@ -0,0 +1,46 @@
+import Announcements from '@/components/Announcements'
+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'
+
+const AdminPage = () => {
+ return (
+
+ {/* Left side */}
+
+ {/* User Cards */}
+
+
+
+
+
+
+ {/* Middle Chart */}
+
+ {/* Count Chart */}
+
+
+
+ {/* Attendance Chart */}
+
+
+ {/* Bottom Chart */}
+
+
+
+
+ {/* Right side */}
+
+
+ )
+}
+
+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..bfff1d952
--- /dev/null
+++ b/src/app/(dashboard)/layout.tsx
@@ -0,0 +1,26 @@
+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<{
+ children: React.ReactNode;
+}>) {
+ return
+ {/** Sidebar */}
+
+
+
+ Gifted
+
+
+
+ {/** Content */}
+
+
+ {children}
+
+
+}
diff --git a/src/app/(dashboard)/list/announcements/page.tsx b/src/app/(dashboard)/list/announcements/page.tsx
new file mode 100644
index 000000000..e7510d8af
--- /dev/null
+++ b/src/app/(dashboard)/list/announcements/page.tsx
@@ -0,0 +1,74 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.title}
+
+ {item.class}
+ {item.date}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Announcements
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default AnnouncementListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/assignments/page.tsx b/src/app/(dashboard)/list/assignments/page.tsx
new file mode 100644
index 000000000..3c32bcdd3
--- /dev/null
+++ b/src/app/(dashboard)/list/assignments/page.tsx
@@ -0,0 +1,77 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.subject}
+
+ {item.class}
+ {item.teacher}
+ {item.dueDate}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Assignments
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default AssignmentListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/classes/page.tsx b/src/app/(dashboard)/list/classes/page.tsx
new file mode 100644
index 000000000..1dbb82533
--- /dev/null
+++ b/src/app/(dashboard)/list/classes/page.tsx
@@ -0,0 +1,83 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.name}
+
+ {item.capacity}
+ {item.grade}
+ {item.supervisor}
+
+
+ {role === "admin" && (
+ <>
+
+ {/* {
+
+ } */}
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Classes
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+ //
+ //
+ //
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default ClassListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/events/page.tsx b/src/app/(dashboard)/list/events/page.tsx
new file mode 100644
index 000000000..4dcb8f650
--- /dev/null
+++ b/src/app/(dashboard)/list/events/page.tsx
@@ -0,0 +1,80 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.title}
+
+ {item.class}
+ {item.date}
+ {item.startTime}
+ {item.endTime}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Events
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default EventListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/exams/page.tsx b/src/app/(dashboard)/list/exams/page.tsx
new file mode 100644
index 000000000..bc685c615
--- /dev/null
+++ b/src/app/(dashboard)/list/exams/page.tsx
@@ -0,0 +1,77 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.subject}
+
+ {item.class}
+ {item.teacher}
+ {item.date}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Exams
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default ExamListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/lessons/page.tsx b/src/app/(dashboard)/list/lessons/page.tsx
new file mode 100644
index 000000000..00d537a72
--- /dev/null
+++ b/src/app/(dashboard)/list/lessons/page.tsx
@@ -0,0 +1,77 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.subject}
+
+ {item.class}
+ {item.teacher}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Lessons
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+ //
+ //
+ //
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default LessonListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/parents/page.tsx b/src/app/(dashboard)/list/parents/page.tsx
new file mode 100644
index 000000000..8880b3984
--- /dev/null
+++ b/src/app/(dashboard)/list/parents/page.tsx
@@ -0,0 +1,87 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+
+
{item.name}
+
{item?.email}
+
+
+ {item.students.join(',')}
+ {item.phone}
+ {item.address}
+
+
+ {role === "admin" && (
+ <>
+
+ {/* {
+
+ } */}
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Parents
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+ //
+ //
+ //
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default ParentListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/results/page.tsx b/src/app/(dashboard)/list/results/page.tsx
new file mode 100644
index 000000000..78c046a9c
--- /dev/null
+++ b/src/app/(dashboard)/list/results/page.tsx
@@ -0,0 +1,84 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.subject}
+
+ {item.student}
+ {item.score}
+ {item.teacher}
+ {item.class}
+ {item.date}
+
+
+ {role === "admin" && (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Results
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default ResultListPage
\ No newline at end of file
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 */}
+
+ {/* Card */}
+
+ {/* Card */}
+
+
+
+ {/* 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
diff --git a/src/app/(dashboard)/list/students/page.tsx b/src/app/(dashboard)/list/students/page.tsx
new file mode 100644
index 000000000..4b278bfdf
--- /dev/null
+++ b/src/app/(dashboard)/list/students/page.tsx
@@ -0,0 +1,95 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+
+
+
{item.name}
+
{item.class}
+
+
+ {item.studentId}
+ {item.grade}
+ {item.phone}
+ {item.address}
+
+
+
+
+
+
+
+ {role === "admin" && (
+ //
+ //
+ //
+
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Students
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+ //
+ //
+ //
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default StudentListPage
\ No newline at end of file
diff --git a/src/app/(dashboard)/list/subjects/page.tsx b/src/app/(dashboard)/list/subjects/page.tsx
new file mode 100644
index 000000000..75cfee749
--- /dev/null
+++ b/src/app/(dashboard)/list/subjects/page.tsx
@@ -0,0 +1,77 @@
+import FormModal from '@/components/FormModal'
+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) => (
+
+
+ {item.name}
+
+ {item.teachers.join(',')}
+
+
+ {role === "admin" && (
+ <>
+
+ {/* {
+
+ } */}
+
+ >
+ )}
+
+
+
+ )
+
+ return (
+
+ {/* Top */}
+
+
All Subjects
+
+
+
+
+
+
+
+
+
+ {role === "admin" &&
+ //
+ //
+ //
+
+ }
+
+
+
+ {/* List */}
+
+ {/* Pagination */}
+
+
+ )
+}
+
+export default SubjectListPage
\ No newline at end of file
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..af90fbf52
--- /dev/null
+++ b/src/app/(dashboard)/list/teachers/[id]/page.tsx
@@ -0,0 +1,121 @@
+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'
+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 */}
+
+ {/* Card */}
+
+ {/* Card */}
+
+
+
+ {/* 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
diff --git a/src/app/(dashboard)/list/teachers/page.tsx b/src/app/(dashboard)/list/teachers/page.tsx
new file mode 100644
index 000000000..d8d5cc721
--- /dev/null
+++ b/src/app/(dashboard)/list/teachers/page.tsx
@@ -0,0 +1,97 @@
+import FormModal from '@/components/FormModal'
+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.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
diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx
new file mode 100644
index 000000000..d2b2527c8
--- /dev/null
+++ b/src/app/(dashboard)/parent/page.tsx
@@ -0,0 +1,23 @@
+import Announcements from '@/components/Announcements'
+import BigCalendar from '@/components/BigCalendar'
+import React from 'react'
+
+const ParentPage = () => {
+ return (
+
+ {/* Left side */}
+
+
+
Schedule (John Doe)
+
+
+
+ {/* Right side */}
+
+
+ )
+}
+
+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..5e8b6f6f2
--- /dev/null
+++ b/src/app/(dashboard)/student/page.tsx
@@ -0,0 +1,25 @@
+import Announcements from '@/components/Announcements'
+import BigCalendar from '@/components/BigCalendar'
+import EventCalendar from '@/components/EventCalendar'
+import React from 'react'
+
+const StudentPage = () => {
+ return (
+
+ {/* Left side */}
+
+ {/* Right side */}
+
+
+ )
+}
+
+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..cabcfff48
--- /dev/null
+++ b/src/app/(dashboard)/teacher/page.tsx
@@ -0,0 +1,23 @@
+import Announcements from '@/components/Announcements'
+import BigCalendar from '@/components/BigCalendar'
+import React from 'react'
+
+const TeacherPage = () => {
+ return (
+
+ {/* Left side */}
+
+ {/* Right side */}
+
+
+ )
+}
+
+export default TeacherPage
\ No newline at end of file
diff --git a/src/app/globals.css b/src/app/globals.css
index bd6213e1d..412588354 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,3 +1,112 @@
@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;
+}
+
+.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
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/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
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
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
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
+
Girls (45%)
+
+
+
+ )
+}
+
+export default CountChart
\ No newline at end of file
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
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
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 ? (
+
+ ) : 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 (
+ <>
+ setOpen(true)}>
+
+
+ {open && (
+
+
+
+
setOpen(false)}>
+
+
+
+
+ )}
+ >
+ )
+}
+
+export default FormModal
\ No newline at end of file
diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx
index de074fa04..bac91ee16 100644
--- a/src/components/Menu.tsx
+++ b/src/components/Menu.tsx
@@ -111,4 +111,34 @@ const menuItems = [
},
],
},
-];
\ No newline at end of file
+];
+
+import { role } from '@/lib/data';
+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) => {
+ if (item.visible.includes(role)) {
+ return (
+
+
+ {item.label}
+
+ )
+
+ }
+ })}
+
+ ))}
+
+ )
+}
+
+export default Menu
\ No newline at end of file
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
new file mode 100644
index 000000000..dbb5f3cc3
--- /dev/null
+++ b/src/components/Navbar.tsx
@@ -0,0 +1,31 @@
+import Image from 'next/image'
+import React from 'react'
+
+const Navbar = () => {
+ return (
+
+ {/** Search */}
+
+
+
+
+ {/** Icons and User */}
+
+
+
+
+
+
+ John Doe
+ Admin
+
+
+
+
+ )
+}
+
+export default Navbar
\ No newline at end of file
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 (
+
+
Prev
+
+ 1
+ 2
+ 3
+ ...
+ 10
+
+
Next
+
+ )
+}
+
+export default Pagination
\ No newline at end of file
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
+
+
+
+
+
+
+
+
+
1st Semester - 2nd Semester
+
+ )
+}
+
+export default Performance
\ No newline at end of file
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 => (
+ {col.header}
+ ))}
+
+
+
+ {data.map((item) => renderRow(item))}
+
+
+ )
+}
+
+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 (
+
+
+
+
+ )
+}
+
+export default TableSearch
\ No newline at end of file
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
+
+
+
1,234
+
{type + "s"}
+
+ )
+}
+
+export default UserCard
\ No newline at end of file
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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+export default AttendanceForm
\ No newline at end of file
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 (
+
+ )
+}
+
+export default ClassForm
\ 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 (
+
+ )
+}
+
+export default EventForm
\ 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 (
+
+ )
+}
+
+export default ExamForm
\ No newline at end of file
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 (
+
+
{label}
+
+ {error?.message &&
{error.message.toString()}
}
+
+ )
+}
+
+export default InputField
\ 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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+export default SubjectForm
\ No newline at end of file
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 (
+
+ )
+}
+
+export default TeacherForm
\ No newline at end of file
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",
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: [],