diff --git a/package-lock.json b/package-lock.json index 8dd4151..12efe8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,9 @@ "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "dompurify": "^3.1.7", + "framer-motion": "^11.11.9", + "lottie-react": "^2.4.0", "lucide-react": "^0.400.0", "next": "^14.2.5", "radix-ui": "^1.0.1", @@ -29,6 +32,8 @@ "zod": "^3.23.8" }, "devDependencies": { + "@types/dompurify": "^3.0.5", + "@types/js-cookie": "^3.0.6", "@types/node": "^20.14.9", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", @@ -2810,12 +2815,29 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.17.7", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", @@ -2863,6 +2885,13 @@ "@types/react": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.15.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", @@ -3570,6 +3599,12 @@ "node": ">=6.0.0" } }, + "node_modules/dompurify": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", + "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==", + "license": "(MPL-2.0 OR Apache-2.0)" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4095,6 +4130,31 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.11.9", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.9.tgz", + "integrity": "sha512-XpdZseuCrZehdHGuW22zZt3SF5g6AHJHJi7JwQIigOznW4Jg1n0oGPMJQheMaKLC+0rp5gxUKMRYI6ytd3q4RQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4543,6 +4603,25 @@ "loose-envify": "cli.js" } }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "license": "MIT", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", diff --git a/package.json b/package.json index 66da343..4eeea91 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "dompurify": "^3.1.7", + "framer-motion": "^11.11.9", + "lottie-react": "^2.4.0", "lucide-react": "^0.400.0", "next": "^14.2.5", "radix-ui": "^1.0.1", @@ -31,6 +34,8 @@ "zod": "^3.23.8" }, "devDependencies": { + "@types/dompurify": "^3.0.5", + "@types/js-cookie": "^3.0.6", "@types/node": "^20.14.9", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/public/assets/todo_pending_animation.json b/public/assets/todo_pending_animation.json new file mode 100644 index 0000000..2bca429 --- /dev/null +++ b/public/assets/todo_pending_animation.json @@ -0,0 +1 @@ +{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":"#eaedf1"},"fr":60,"ip":0,"op":240,"w":600,"h":600,"nm":"Scanning","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle Copy 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[274,400.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[128,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle Copy 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[368.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[41,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle Copy 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[348.5,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[81,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle Copy 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rectangle Copy 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[121,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Rectangle 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,234.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[90,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Rectangle 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[299.89,304.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[245.78,319.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":19,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.48627450980392156,0.3686274509803922,0.9803921568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle Copy 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[274,400.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[128,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle Copy 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[368.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[41,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle Copy 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[348.5,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[81,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle Copy 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rectangle Copy","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[121,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,234.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[90,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[299.89,304.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[245.78,319.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":19,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.48627450980392156,0.3686274509803922,0.9803921568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.376,"y":1},"o":{"x":0.275,"y":0},"t":0,"s":[300,485.50000000000006,0],"to":[0,-60,0],"ti":[0,0,0]},{"i":{"x":0.725,"y":1},"o":{"x":0.632,"y":0},"t":110,"s":[300,125.49999999999999,0],"to":[0,0,0],"ti":[0,-60,0]},{"t":220,"s":[300,485.50000000000006,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,9],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"bottom-grad","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[40]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[40]},{"t":218,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.374,"y":1},"o":{"x":0.274,"y":0},"t":1,"s":[300,463.5,0],"to":[0,-52.833,0],"ti":[0,-7.167,0]},{"i":{"x":0.726,"y":1},"o":{"x":0.621,"y":0},"t":111,"s":[300,146.5,0],"to":[0,7.167,0],"ti":[0,-60,0]},{"t":221,"s":[300,506.50000000000006,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,-100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,45],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.094,0.439,0.843,0.5,0.094,0.439,0.843,1,0.094,0.439,0.843,0,0,0.252,0.2,0.505,0.4,0.752,0.7,1,1],"ix":9}},"s":{"a":0,"k":[0,-22.5],"ix":5},"e":{"a":0,"k":[0,22.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"top-grad","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[40]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":89,"s":[40]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"t":221,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.376,"y":1},"o":{"x":0.271,"y":0},"t":1,"s":[300,463.5,0],"to":[0,-60,0],"ti":[0,0,0]},{"i":{"x":0.725,"y":1},"o":{"x":0.632,"y":0},"t":111,"s":[300,103.49999999999999,0],"to":[0,0,0],"ti":[0,-60,0]},{"t":221,"s":[300,463.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,45],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.094,0.439,0.843,0.5,0.094,0.439,0.843,1,0.094,0.439,0.843,0,0,0.252,0.2,0.505,0.4,0.752,0.7,1,1],"ix":9}},"s":{"a":0,"k":[0,-22.5],"ix":5},"e":{"a":0,"k":[0,22.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"full","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2},"a":{"a":0,"k":[300,300,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"i","pt":{"a":1,"k":[{"i":{"x":0.364,"y":1},"o":{"x":0.272,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,479.957],[448.801,479.957]],"c":true}]},{"i":{"x":0.73,"y":1},"o":{"x":0.631,"y":0},"t":110,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,129.957],[448.801,129.957]],"c":true}]},{"t":220,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,479.957],[448.801,479.957]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"w":600,"h":600,"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"trans","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2},"a":{"a":0,"k":[300,300,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":600,"h":600,"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 0921ece..fe4c165 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,21 +1,49 @@ import './App.css'; -import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { useState, useEffect } from 'react'; import Mentors from './pages/root/mentor'; import Login from './pages/auth/Login'; -import Singup from './pages/auth/Singup'; +import Signup from './pages/auth/Singup'; import ForgotPassword from './pages/auth/ForgotPassword'; import Student from './pages/student'; +import Dashboard from './pages/root/dashboard/page'; +import Loader from './pages/root/Loader'; function App() { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const token = localStorage.getItem('token'); + setIsAuthenticated(!!token); + + + setIsLoading(false); + }, []); + + if (isLoading) { + return ; + } + return ( - } /> - } /> - } /> - } /> - } /> - } /> + + : } + /> + : } + /> + } /> + } /> + } /> + : } + /> ); diff --git a/src/actions/planner_actions.ts b/src/actions/planner_actions.ts new file mode 100644 index 0000000..a66ee00 --- /dev/null +++ b/src/actions/planner_actions.ts @@ -0,0 +1,122 @@ +"use server"; + +import { getCookie } from "./cookie_actions"; +import { revalidateTag } from "next/cache"; + +export const getPlanner = async () => { + const token = await getCookie("token"); + + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_STUDENT_API_BASE_URL}/api/planner/get`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Cookie: `token=${token}`, + }, + credentials: "include", + // cache: "force-cache", + next: { + tags: ["plannerData"], + }, + } + ); + + const responseData = await res.json(); + + return responseData; + } catch (error: unknown) { + if (error instanceof Error) { + throw new Error(`Error fetching planner data: ${error.message}`); + } else { + throw new Error("An unknown error occurred while fetching planner data!"); + } + } +}; + +export const createPlanner = async () => { + const token = await getCookie("token"); + + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_STUDENT_API_BASE_URL}/api/planner/create`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Cookie: `token=${token}`, + }, + credentials: "include", + } + ); + + const responseData = await res.json(); + + return responseData; + } catch (error: unknown) { + if (error instanceof Error) { + throw new Error(`Error creating planner: ${error.message}`); + } else { + throw new Error("An unknown error occurred while creating planner!"); + } + } +}; + +export const updatePlanner = async () => { + const token = await getCookie("token"); + + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_STUDENT_API_BASE_URL}/api/planner/update`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Cookie: `token=${token}`, + }, + credentials: "include", + } + ); + + const responseData = await res.json(); + revalidateTag("plannerData"); + + return responseData; + } catch (error: unknown) { + if (error instanceof Error) { + throw new Error(`Error creating planner: ${error.message}`); + } else { + throw new Error("An unknown error occurred while creating planner!"); + } + } +}; + +export const allocateBackTopics = async () => { + const token = await getCookie("token"); + + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_STUDENT_API_BASE_URL}/api/planner/allocateTopics`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Cookie: `token=${token}`, + }, + credentials: "include", + } + ); + + const responseData = await res.json(); + revalidateTag("plannerData"); + + return responseData; + } catch (error: unknown) { + if (error instanceof Error) { + throw new Error(`Error creating planner: ${error.message}`); + } else { + throw new Error("An unknown error occurred while creating planner!"); + } + } +}; diff --git a/src/apiClient/apiClient.ts b/src/apiClient/apiClient.ts index 3abc716..690c9a8 100644 --- a/src/apiClient/apiClient.ts +++ b/src/apiClient/apiClient.ts @@ -6,6 +6,7 @@ const apiClient = axios.create({ headers: { 'Content-Type': 'application/json', }, + }); apiClient.interceptors.request.use( diff --git a/src/assets/todo_pending_animation.json b/src/assets/todo_pending_animation.json new file mode 100644 index 0000000..2bca429 --- /dev/null +++ b/src/assets/todo_pending_animation.json @@ -0,0 +1 @@ +{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":"#eaedf1"},"fr":60,"ip":0,"op":240,"w":600,"h":600,"nm":"Scanning","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle Copy 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[274,400.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[128,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle Copy 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[368.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[41,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle Copy 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[348.5,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[81,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle Copy 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rectangle Copy 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[121,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Rectangle 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,234.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[90,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Rectangle 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[299.89,304.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[245.78,319.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":19,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.48627450980392156,0.3686274509803922,0.9803921568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle Copy 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[274,400.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[128,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle Copy 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[368.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[41,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle Copy 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[348.5,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[81,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle Copy 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249,351.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rectangle Copy","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270.5,302.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[121,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle Copy","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,234.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[90,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[299.89,304.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[245.78,319.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":19,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.48627450980392156,0.3686274509803922,0.9803921568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.376,"y":1},"o":{"x":0.275,"y":0},"t":0,"s":[300,485.50000000000006,0],"to":[0,-60,0],"ti":[0,0,0]},{"i":{"x":0.725,"y":1},"o":{"x":0.632,"y":0},"t":110,"s":[300,125.49999999999999,0],"to":[0,0,0],"ti":[0,-60,0]},{"t":220,"s":[300,485.50000000000006,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,9],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4.5,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.2,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"bottom-grad","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[40]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[40]},{"t":218,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.374,"y":1},"o":{"x":0.274,"y":0},"t":1,"s":[300,463.5,0],"to":[0,-52.833,0],"ti":[0,-7.167,0]},{"i":{"x":0.726,"y":1},"o":{"x":0.621,"y":0},"t":111,"s":[300,146.5,0],"to":[0,7.167,0],"ti":[0,-60,0]},{"t":221,"s":[300,506.50000000000006,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,-100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,45],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.094,0.439,0.843,0.5,0.094,0.439,0.843,1,0.094,0.439,0.843,0,0,0.252,0.2,0.505,0.4,0.752,0.7,1,1],"ix":9}},"s":{"a":0,"k":[0,-22.5],"ix":5},"e":{"a":0,"k":[0,22.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"top-grad","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[40]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":89,"s":[40]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"t":221,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.376,"y":1},"o":{"x":0.271,"y":0},"t":1,"s":[300,463.5,0],"to":[0,-60,0],"ti":[0,0,0]},{"i":{"x":0.725,"y":1},"o":{"x":0.632,"y":0},"t":111,"s":[300,103.49999999999999,0],"to":[0,0,0],"ti":[0,-60,0]},{"t":221,"s":[300,463.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[300,45],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.094,0.439,0.843,0.5,0.094,0.439,0.843,1,0.094,0.439,0.843,0,0,0.252,0.2,0.505,0.4,0.752,0.7,1,1],"ix":9}},"s":{"a":0,"k":[0,-22.5],"ix":5},"e":{"a":0,"k":[0,22.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"full","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2},"a":{"a":0,"k":[300,300,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"i","pt":{"a":1,"k":[{"i":{"x":0.364,"y":1},"o":{"x":0.272,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,479.957],[448.801,479.957]],"c":true}]},{"i":{"x":0.73,"y":1},"o":{"x":0.631,"y":0},"t":110,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,129.957],[448.801,129.957]],"c":true}]},{"t":220,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[448.801,109],[153,109],[153,479.957],[448.801,479.957]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"w":600,"h":600,"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"trans","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2},"a":{"a":0,"k":[300,300,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":600,"h":600,"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/components/icons/AttachIcon.tsx b/src/components/icons/AttachIcon.tsx new file mode 100644 index 0000000..8dddad2 --- /dev/null +++ b/src/components/icons/AttachIcon.tsx @@ -0,0 +1,23 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const AttachIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default AttachIcon; diff --git a/src/components/icons/CallIcon.tsx b/src/components/icons/CallIcon.tsx new file mode 100644 index 0000000..6c6db30 --- /dev/null +++ b/src/components/icons/CallIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const CallIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default CallIcon; diff --git a/src/components/icons/ChatIcon.tsx b/src/components/icons/ChatIcon.tsx new file mode 100644 index 0000000..8e4ae8e --- /dev/null +++ b/src/components/icons/ChatIcon.tsx @@ -0,0 +1,25 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const ChatIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + ); +}; + +export default ChatIcon; diff --git a/src/components/icons/ChatIcon3.tsx b/src/components/icons/ChatIcon3.tsx new file mode 100644 index 0000000..9ff3006 --- /dev/null +++ b/src/components/icons/ChatIcon3.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const ChatIcon3 = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default ChatIcon3; diff --git a/src/components/icons/ClockIcon.tsx b/src/components/icons/ClockIcon.tsx new file mode 100644 index 0000000..7809cd0 --- /dev/null +++ b/src/components/icons/ClockIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const ClockIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default ClockIcon; diff --git a/src/components/icons/ConferenceMeetingIcon.tsx b/src/components/icons/ConferenceMeetingIcon.tsx new file mode 100644 index 0000000..670be82 --- /dev/null +++ b/src/components/icons/ConferenceMeetingIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const ConferenceMeetingIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default ConferenceMeetingIcon; diff --git a/src/components/icons/DashboardIcon.tsx b/src/components/icons/DashboardIcon.tsx new file mode 100644 index 0000000..e8570ec --- /dev/null +++ b/src/components/icons/DashboardIcon.tsx @@ -0,0 +1,19 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const DashboardIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + + + ); +}; + +export default DashboardIcon; diff --git a/src/components/icons/DateIcon.tsx b/src/components/icons/DateIcon.tsx new file mode 100644 index 0000000..2ac1507 --- /dev/null +++ b/src/components/icons/DateIcon.tsx @@ -0,0 +1,24 @@ +import { cn } from '../../lib/utils'; + +const DateIcon = ({ className }: { className?: string }) => { + return ( + + + + ); +}; + +export default DateIcon; diff --git a/src/components/icons/DownArrowIcon.tsx b/src/components/icons/DownArrowIcon.tsx new file mode 100644 index 0000000..d000c48 --- /dev/null +++ b/src/components/icons/DownArrowIcon.tsx @@ -0,0 +1,16 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const DownArrowIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default DownArrowIcon; diff --git a/src/components/icons/EfficiencyIcon.tsx b/src/components/icons/EfficiencyIcon.tsx new file mode 100644 index 0000000..b09f43f --- /dev/null +++ b/src/components/icons/EfficiencyIcon.tsx @@ -0,0 +1,33 @@ +import { cn } from "../../lib/utils"; + + +const EfficiencyIcon = ({ className }: { className?: string }) => { + return ( + + + + + + ); +}; +export default EfficiencyIcon \ No newline at end of file diff --git a/src/components/icons/ErrorBookIcon.tsx b/src/components/icons/ErrorBookIcon.tsx new file mode 100644 index 0000000..9a654a5 --- /dev/null +++ b/src/components/icons/ErrorBookIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const ErrorBookIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default ErrorBookIcon; diff --git a/src/components/icons/GrowthMeterIcon.tsx b/src/components/icons/GrowthMeterIcon.tsx new file mode 100644 index 0000000..8e3c24a --- /dev/null +++ b/src/components/icons/GrowthMeterIcon.tsx @@ -0,0 +1,16 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const GrowthMeterIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default GrowthMeterIcon; diff --git a/src/components/icons/LeftArrowIcon.tsx b/src/components/icons/LeftArrowIcon.tsx new file mode 100644 index 0000000..4fd594d --- /dev/null +++ b/src/components/icons/LeftArrowIcon.tsx @@ -0,0 +1,16 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const LeftArrowIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default LeftArrowIcon; diff --git a/src/components/icons/LibertyIcon.tsx b/src/components/icons/LibertyIcon.tsx new file mode 100644 index 0000000..75d26a2 --- /dev/null +++ b/src/components/icons/LibertyIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const LibertyIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default LibertyIcon; diff --git a/src/components/icons/MenuIcon.tsx b/src/components/icons/MenuIcon.tsx new file mode 100644 index 0000000..6a49868 --- /dev/null +++ b/src/components/icons/MenuIcon.tsx @@ -0,0 +1,30 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const MenuIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + + ); +}; + +export default MenuIcon; diff --git a/src/components/icons/MicIcon.tsx b/src/components/icons/MicIcon.tsx new file mode 100644 index 0000000..69d9017 --- /dev/null +++ b/src/components/icons/MicIcon.tsx @@ -0,0 +1,34 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const MicIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + + ); +}; + +export default MicIcon; diff --git a/src/components/icons/NotificationIcon.tsx b/src/components/icons/NotificationIcon.tsx new file mode 100644 index 0000000..d64b56e --- /dev/null +++ b/src/components/icons/NotificationIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const NotificationIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default NotificationIcon; diff --git a/src/components/icons/OneOnOneMeetingIcon.tsx b/src/components/icons/OneOnOneMeetingIcon.tsx new file mode 100644 index 0000000..a112310 --- /dev/null +++ b/src/components/icons/OneOnOneMeetingIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const OneOnOneMeetingIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default OneOnOneMeetingIcon; diff --git a/src/components/icons/PlannerIcon.tsx b/src/components/icons/PlannerIcon.tsx new file mode 100644 index 0000000..d6f2b2b --- /dev/null +++ b/src/components/icons/PlannerIcon.tsx @@ -0,0 +1,25 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const PlannerIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + + ); +}; + +export default PlannerIcon; diff --git a/src/components/icons/Questionicon.tsx b/src/components/icons/Questionicon.tsx new file mode 100644 index 0000000..6e22c7c --- /dev/null +++ b/src/components/icons/Questionicon.tsx @@ -0,0 +1,24 @@ +import { cn } from '../../lib/utils'; + +const QuestionIcon = ({ className }: { className?: string }) => { + return ( + + + + ); +}; + +export default QuestionIcon; diff --git a/src/components/icons/QuizIcon.tsx b/src/components/icons/QuizIcon.tsx new file mode 100644 index 0000000..71263a6 --- /dev/null +++ b/src/components/icons/QuizIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const QuizIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default QuizIcon; diff --git a/src/components/icons/RequestMeetingIcon.tsx b/src/components/icons/RequestMeetingIcon.tsx new file mode 100644 index 0000000..bec1311 --- /dev/null +++ b/src/components/icons/RequestMeetingIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const RequestMeetingIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default RequestMeetingIcon; diff --git a/src/components/icons/RightArrowIcon.tsx b/src/components/icons/RightArrowIcon.tsx new file mode 100644 index 0000000..46a7b93 --- /dev/null +++ b/src/components/icons/RightArrowIcon.tsx @@ -0,0 +1,28 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const RightArrowIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + ); +}; + +export default RightArrowIcon; diff --git a/src/components/icons/SendIcon.tsx b/src/components/icons/SendIcon.tsx new file mode 100644 index 0000000..e785446 --- /dev/null +++ b/src/components/icons/SendIcon.tsx @@ -0,0 +1,24 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const SendIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + ); +}; + +export default SendIcon; diff --git a/src/components/icons/StudyRoomIcon.tsx b/src/components/icons/StudyRoomIcon.tsx new file mode 100644 index 0000000..178d280 --- /dev/null +++ b/src/components/icons/StudyRoomIcon.tsx @@ -0,0 +1,17 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const StudyRoomIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + + ); +}; + +export default StudyRoomIcon; diff --git a/src/components/icons/TimeIcon.tsx b/src/components/icons/TimeIcon.tsx new file mode 100644 index 0000000..a1786ce --- /dev/null +++ b/src/components/icons/TimeIcon.tsx @@ -0,0 +1,21 @@ +import { cn } from "../../lib/utils"; + +const TimeIcon = ({ className }: { className?: string }) => { + return ( + + + + ); +}; + +export default TimeIcon; diff --git a/src/components/icons/TrackerIcon.tsx b/src/components/icons/TrackerIcon.tsx new file mode 100644 index 0000000..c40106d --- /dev/null +++ b/src/components/icons/TrackerIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const TrackerIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default TrackerIcon; diff --git a/src/components/icons/TrophyIcon.tsx b/src/components/icons/TrophyIcon.tsx new file mode 100644 index 0000000..df709ea --- /dev/null +++ b/src/components/icons/TrophyIcon.tsx @@ -0,0 +1,28 @@ +import { cn } from '../../lib/utils'; + +const TrophyIcon = ({ className }: { className?: string }) => { + return ( + + + + + ); +}; +export default TrophyIcon; diff --git a/src/components/icons/UpArrowIcon.tsx b/src/components/icons/UpArrowIcon.tsx new file mode 100644 index 0000000..e0a5fab --- /dev/null +++ b/src/components/icons/UpArrowIcon.tsx @@ -0,0 +1,16 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const UpArrowIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default UpArrowIcon; diff --git a/src/components/icons/VideoChatIcon.tsx b/src/components/icons/VideoChatIcon.tsx new file mode 100644 index 0000000..ffaa2ea --- /dev/null +++ b/src/components/icons/VideoChatIcon.tsx @@ -0,0 +1,16 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const VideoChatIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default VideoChatIcon; diff --git a/src/components/icons/WorkshopIcon.tsx b/src/components/icons/WorkshopIcon.tsx new file mode 100644 index 0000000..42ab8d7 --- /dev/null +++ b/src/components/icons/WorkshopIcon.tsx @@ -0,0 +1,20 @@ +import { IIconProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const WorkshopIcon = ({ className, ...props }: IIconProps) => { + return ( + + + + ); +}; + +export default WorkshopIcon; diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 0000000..06dba63 --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,71 @@ +import Container from "./shared/Container"; +import Logo from "./shared/Logo"; +import Header from "./shared/Header"; +import SidebarDesktop from "./shared/SidebarDesktop"; +import Sidebar from "./shared/Sidebar"; +import TabNavItem from "./shared/TabNavItem"; +import TabContent from "./shared/TabContent"; +import MobileNavBar from "./shared/MobileNavBar"; +import MobileMenu from "./shared/MobileMenu"; +import Input from "./shared/Input"; + +// import SemiRadialChart from "./charts/SemiRadialChart"; +// import RadialBarChart from "./charts/RadialBarChart"; +// import BarChart from "./charts/BarChart"; +// import MonthlyReportChart from "./charts/MonthlyReportChart"; +// import OverallReportChart from "./charts/OverallReportChart"; +// import DonutChart from "./charts/DonutChart"; + +import RightArrowIcon from "./icons/RightArrowIcon"; +import LeftArrowIcon from "./icons/LeftArrowIcon"; +import NotificationIcon from "./icons/NotificationIcon"; +import ChatIcon from "./icons/ChatIcon"; +import VideoChatIcon from "./icons/VideoChatIcon"; +import RequestMeetingIcon from "./icons/RequestMeetingIcon"; +import UpArrowIcon from "./icons/UpArrowIcon"; +import DownArrowIcon from "./icons/DownArrowIcon"; +import AttachIcon from "./icons/AttachIcon"; +import CallIcon from "./icons/CallIcon"; +import ChatIcon3 from "./icons/ChatIcon3"; +import MenuIcon from "./icons/MenuIcon"; +import MicIcon from "./icons/MicIcon"; +import SendIcon from "./icons/SendIcon"; +import OneOnOneMeetingIcon from "./icons/OneOnOneMeetingIcon"; +import ConferenceMeetingIcon from "./icons/ConferenceMeetingIcon"; +import ClockIcon from "./icons/ClockIcon"; + +export { + Container, + Logo, + Header, + SidebarDesktop, + Sidebar, + TabNavItem, + TabContent, + MobileNavBar, + MobileMenu, + Input, + // SemiRadialChart, + // RadialBarChart, + // BarChart, + // MonthlyReportChart, + // OverallReportChart, + // DonutChart, + RightArrowIcon, + LeftArrowIcon, + NotificationIcon, + ChatIcon, + VideoChatIcon, + RequestMeetingIcon, + UpArrowIcon, + DownArrowIcon, + AttachIcon, + CallIcon, + ChatIcon3, + MenuIcon, + MicIcon, + SendIcon, + OneOnOneMeetingIcon, + ConferenceMeetingIcon, + ClockIcon, +}; diff --git a/src/components/shared/ComingSoon.tsx b/src/components/shared/ComingSoon.tsx new file mode 100644 index 0000000..f1f6893 --- /dev/null +++ b/src/components/shared/ComingSoon.tsx @@ -0,0 +1,18 @@ +import Header from "./Header"; + +const ComingSoon = ({ pageTitle }: { pageTitle: string }) => { + return ( +
+

+ {pageTitle} +

+
+
+ ); +}; + +export default ComingSoon; diff --git a/src/components/shared/Container.tsx b/src/components/shared/Container.tsx new file mode 100644 index 0000000..a9b5b4f --- /dev/null +++ b/src/components/shared/Container.tsx @@ -0,0 +1,10 @@ +import { TContainerProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const Container = ({ children, className }: TContainerProps) => { + return ( +
{children}
+ ); +}; + +export default Container; diff --git a/src/components/shared/Header.tsx b/src/components/shared/Header.tsx new file mode 100644 index 0000000..05619dc --- /dev/null +++ b/src/components/shared/Header.tsx @@ -0,0 +1,22 @@ +import { THeaderProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const Header = ({ + title, + className, + icon: Icon, + titleClassName, +}: THeaderProps) => { + return ( +
+

{title}

+ {Icon &&
{Icon}
} +
+ ); +}; + +export default Header; diff --git a/src/components/shared/Input.tsx b/src/components/shared/Input.tsx new file mode 100644 index 0000000..23d7b84 --- /dev/null +++ b/src/components/shared/Input.tsx @@ -0,0 +1,51 @@ +import { cn } from "../../lib/utils"; + +import React, { + ForwardRefRenderFunction, + InputHTMLAttributes, + forwardRef, + useId, +} from "react"; + +interface InputProps extends InputHTMLAttributes { + label?: string; + icon1?: React.ReactNode; + icon2?: React.ReactNode; +} + +const Input: ForwardRefRenderFunction = ( + { + label, + className = "", + type = "text", + placeholder = "", + icon1, + icon2, + ...props + }, + ref +) => { + const id = useId(); + + return ( +
+ {label && } +
+ {icon1 && icon1} + + + + {icon2 && icon2} +
+
+ ); +}; + +export default forwardRef(Input); diff --git a/src/components/shared/Loader.tsx b/src/components/shared/Loader.tsx new file mode 100644 index 0000000..9b42651 --- /dev/null +++ b/src/components/shared/Loader.tsx @@ -0,0 +1,11 @@ +import { Loader2 } from "lucide-react"; + +const Loader = () => { + return ( +
+ +
+ ); +}; + +export default Loader; diff --git a/src/components/shared/Logo.tsx b/src/components/shared/Logo.tsx new file mode 100644 index 0000000..cab5282 --- /dev/null +++ b/src/components/shared/Logo.tsx @@ -0,0 +1,34 @@ +import Image from "next/image"; + +import { TLogoProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const Logo = ({ + fullLogoWidth, + fullLogoHeight, + fullLogoClassName, + smallLogoWidth, + smallLogoHeight, + smallLogoClassName, +}: TLogoProps) => { + return ( + <> + Leadlly_logo + Leadlly_logo + + ); +}; + +export default Logo; diff --git a/src/components/shared/LogoutButton.tsx b/src/components/shared/LogoutButton.tsx new file mode 100644 index 0000000..1ae6777 --- /dev/null +++ b/src/components/shared/LogoutButton.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { useRouter } from "next/navigation"; + +import { LogOut } from "lucide-react"; + +import { toast } from "sonner"; + +import { Button } from "../ui/button"; + +// import { useAppDispatch } from "@/redux/hooks"; +// import { userData } from "@/redux/slices/userSlice"; + +const LogoutButton = () => { + const router = useRouter(); + + // const dispatch = useAppDispatch(); + + const logoutHandler = async () => { + try { + const response = await fetch("/api/auth/logout", { + method: "Get", + headers: { + "Content-Type": "application/json", + }, + }); + + const responseData = await response.json(); + toast.success(responseData.message); + router.push("/login"); + // dispatch(userData(null)); + } catch (error: any) { + toast.error("Logout Failed!", { + description: error?.message, + }); + } + }; + return ( + + ); +}; + +export default LogoutButton; diff --git a/src/components/shared/MobileMenu.tsx b/src/components/shared/MobileMenu.tsx new file mode 100644 index 0000000..6fa834e --- /dev/null +++ b/src/components/shared/MobileMenu.tsx @@ -0,0 +1,125 @@ +"use client"; + +import React, { useEffect, useRef, useState } from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +import { motion } from "framer-motion"; + +import { userSidebarLinks } from "../../helpers/constants"; +import { cn } from "../../lib/utils"; + +const MobileMenu = ({ meetingsLength }: { meetingsLength: number }) => { + const [navScrollPosition, setNavScrollPosition] = useState(0); + const navbarRef = useRef(null); + + const pathname = usePathname(); + + useEffect(() => { + const handleScroll = () => { + if (navbarRef.current) { + setNavScrollPosition(navbarRef.current.scrollLeft); + } + }; + + if (navbarRef.current) { + navbarRef.current.addEventListener("scroll", handleScroll); + } + + return () => { + if (navbarRef.current) { + navbarRef.current.removeEventListener("scroll", handleScroll); + } + }; + }, []); + + const handleMenuItemClick = (e: React.MouseEvent) => { + const clickedItem = e.currentTarget; + const navbarWidth = navbarRef.current?.offsetWidth || 0; + const clickedItemRect = clickedItem.getBoundingClientRect(); + const isLastVisibleItem = + clickedItemRect.right >= navbarWidth + navScrollPosition; + const isFirstVisibleItem = clickedItemRect.left <= navScrollPosition; + + if (navbarRef.current) { + if (isLastVisibleItem) { + const newScrollPosition = clickedItemRect.left - navbarWidth / 5; + navbarRef.current.scrollTo({ + left: newScrollPosition, + behavior: "smooth", + }); + } else if (isFirstVisibleItem) { + const newScrollPosition = clickedItemRect.right - navbarWidth / 5; + navbarRef.current.scrollTo({ + left: newScrollPosition, + behavior: "smooth", + }); + } + } + }; + + return ( + + ); +}; + +export default MobileMenu; diff --git a/src/components/shared/MobileNavBar.tsx b/src/components/shared/MobileNavBar.tsx new file mode 100644 index 0000000..815455b --- /dev/null +++ b/src/components/shared/MobileNavBar.tsx @@ -0,0 +1,49 @@ +import Image from "next/image"; +import Link from "next/link"; + +// import { Logo, NotificationIcon } from "@/components"; + +const MobileNavBar = () => { + return ( + + ); +}; + +export default MobileNavBar; diff --git a/src/components/shared/Modal.tsx b/src/components/shared/Modal.tsx new file mode 100644 index 0000000..250bf8f --- /dev/null +++ b/src/components/shared/Modal.tsx @@ -0,0 +1,27 @@ +"use client"; + +import React from "react"; +import { Dialog, DialogContent, DialogOverlay } from "../ui/dialog"; + +const Modal = ({ + children, + setOpenDialogBox, +}: { + children: React.ReactNode; + setOpenDialogBox: (openDialogBox: boolean) => void; +}) => { + const handleOpenChange = () => { + setOpenDialogBox(false); + }; + return ( + + + + {children} + + + + ); +}; + +export default Modal; diff --git a/src/components/shared/MotionDiv.tsx b/src/components/shared/MotionDiv.tsx new file mode 100644 index 0000000..1c32996 --- /dev/null +++ b/src/components/shared/MotionDiv.tsx @@ -0,0 +1,5 @@ +"use client"; + +import { motion } from "framer-motion"; + +export const MotionDiv = motion.div; diff --git a/src/components/shared/OtpInput.tsx b/src/components/shared/OtpInput.tsx new file mode 100644 index 0000000..b19d701 --- /dev/null +++ b/src/components/shared/OtpInput.tsx @@ -0,0 +1,31 @@ +// OtpInput.tsx + +import React from 'react'; + +const OtpInput = () => { + // Handle key press events to move focus + const handleKeyUp = (e: React.KeyboardEvent, index: number) => { + if (e.currentTarget.value.length === 1) { + const nextInput = document.querySelectorAll('input')[index + 1]; + if (nextInput) nextInput.focus(); + } + }; + + return ( +
+ {Array.from({ length: 4 }).map((_, index) => ( + handleKeyUp(e, index)} + /> + ))} +
+ ); +}; + +export default OtpInput; diff --git a/src/components/shared/Sidebar.tsx b/src/components/shared/Sidebar.tsx new file mode 100644 index 0000000..630cac8 --- /dev/null +++ b/src/components/shared/Sidebar.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import SidebarDesktop from "./SidebarDesktop"; // Ensure this path is correct +import { userSidebarLinks } from "../../helpers/constants"; // Adjust path if necessary + +type SidebarProps = { + meetingsLength: number; // TypeScript prop definition +}; + +const Sidebar: React.FC = ({ meetingsLength }) => { + return ( + + ); +}; + +export default Sidebar; diff --git a/src/components/shared/SidebarDesktop.tsx b/src/components/shared/SidebarDesktop.tsx new file mode 100644 index 0000000..d636958 --- /dev/null +++ b/src/components/shared/SidebarDesktop.tsx @@ -0,0 +1,93 @@ +"use client"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { motion } from "framer-motion"; + +import { Logo } from "../../components"; +import { TSidebarLink } from "../../helpers/types"; +import { cn } from "../../lib/utils"; +// import { Button } from "../ui/button"; +// import { LogOut } from "lucide-react"; +// import LogoutButton from "./LogoutButton"; + +type SidebarDesktopProps = { + sidebar: TSidebarLink[]; + meetingsLength: number; +}; +const SidebarDesktop: React.FC = ({ sidebar, meetingsLength }) => { + const pathname = usePathname(); + return ( + + ); +}; + +export default SidebarDesktop; diff --git a/src/components/shared/TabContent.tsx b/src/components/shared/TabContent.tsx new file mode 100644 index 0000000..635cdb0 --- /dev/null +++ b/src/components/shared/TabContent.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { AnimatePresence, motion, Variants } from "framer-motion"; + +import { TTabContentProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const tabContentVariants: Variants = { + initial: { + x: 0, + opacity: 1, + }, + enter: { + x: 0, + opacity: 1, + }, + exit: { + x: -100, + opacity: 0, + }, +}; + +const TabContent = ({ + id, + activeTab, + children, + className, +}: TTabContentProps) => { + return activeTab === id ? ( + + + {children} + + + ) : null; +}; + +export default TabContent; diff --git a/src/components/shared/TabNavItem.tsx b/src/components/shared/TabNavItem.tsx new file mode 100644 index 0000000..3215c72 --- /dev/null +++ b/src/components/shared/TabNavItem.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { motion } from "framer-motion"; +import { TTabNavItemProps } from "../../helpers/types"; +import { cn } from "../../lib/utils"; + +const TabNavItem = ({ + id, + title, + activeTab, + setActiveTab, + className, + activeTabClassName, + titleClassName, + layoutIdPrefix, +}: TTabNavItemProps) => { + const handleClick = () => { + setActiveTab(id); + }; + + const layoutId = `${layoutIdPrefix}_active__tab`; + + return ( +
  • + {activeTab === id && ( + + )} + {title} +
  • + ); +}; + +export default TabNavItem; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 0ba4277..4106711 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -2,7 +2,7 @@ import * as React from "react" import { Slot } from "@radix-ui/react-slot" import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "@/lib/utils" +import { cn } from "../../lib/utils" const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", diff --git a/src/helpers/constants/efficiency.ts b/src/helpers/constants/efficiency.ts new file mode 100644 index 0000000..3b81ee0 --- /dev/null +++ b/src/helpers/constants/efficiency.ts @@ -0,0 +1,73 @@ +import { EfficiencyOption } from "."; +export const efficiencyOptions: EfficiencyOption[] = [ + { + max: 30, + label: '0-30%', + progressBarColor: 'bg-red-500', + textColor: 'text-red-500', + }, + { + min: 30, + max: 50, + label: '30-50%', + progressBarColor: 'bg-orange-500', + textColor: 'text-orange-500', + }, + { + min: 50, + max: 70, + label: '50-70%', + progressBarColor: 'bg-yellow-500', + textColor: 'text-yellow-500', + }, + { + min: 70, + max: 90, + label: '70-90%', + progressBarColor: 'bg-orange-300', + textColor: 'text-orange-300', + }, + { + min: 90, + label: '90-100%', + progressBarColor: 'bg-green-400', + textColor: 'text-green-400', + }, +]; + + +function findEfficiencyOption( + efficiency: number +): EfficiencyOption | undefined { + if (isNaN(efficiency)) { + throw new Error("Efficiency must be a number."); + } + + return efficiencyOptions.find((opt) => { + if (opt.min !== undefined && opt.max !== undefined) { + return efficiency >= opt.min && efficiency < opt.max; + } else if (opt.min !== undefined) { + return efficiency >= opt.min; + } else if (opt.max !== undefined) { + return efficiency < opt.max; + } + return false; + }); +} + +export function getProgressBarColor(efficiency: number): string { + const option = findEfficiencyOption(efficiency); + if (!option) { + return 'bg-[#ffffff]'; + } + + return option.progressBarColor; +} +export function getTextColor(efficiency: number): string { + const option = findEfficiencyOption(efficiency); + if (!option) { + return 'text-red-500' + } + + return option.textColor; +} diff --git a/src/helpers/constants/index.ts b/src/helpers/constants/index.ts new file mode 100644 index 0000000..1684bbb --- /dev/null +++ b/src/helpers/constants/index.ts @@ -0,0 +1,188 @@ +import { TSidebarLink } from "../types"; + +import DashboardIcon from "../../components/icons/DashboardIcon"; +import PlannerIcon from "../../components/icons/PlannerIcon"; +import TrackerIcon from "../../components/icons/TrackerIcon"; +import ErrorBookIcon from "../../components/icons/ErrorBookIcon"; +import GrowthMeterIcon from "../../components/icons/GrowthMeterIcon"; +import WorkshopIcon from "../../components/icons/WorkshopIcon"; +import LibertyIcon from "../../components/icons/LibertyIcon"; +import QuizIcon from "../../components/icons/QuizIcon"; +import StudyRoomIcon from "../../components/icons/StudyRoomIcon"; +import ChatIcon3 from "../../components/icons/ChatIcon3"; + +export const userSidebarLinks: TSidebarLink[] = [ + { + label: "dashboard", + icon: DashboardIcon, + href: "/", + }, + { + label: "planner", + icon: PlannerIcon, + href: "/planner", + }, + { + label: "tracker", + icon: TrackerIcon, + href: "/tracker", + }, + { + label: "chat", + icon: ChatIcon3, + href: "/chat", + }, + { + label: "quizzes", + icon: QuizIcon, + href: "/quizzes", + }, + { + label: "errorbook", + icon: ErrorBookIcon, + href: "/error-book", + }, + { + label: "growth meter", + icon: GrowthMeterIcon, + href: "/growth-meter", + }, + { + label: "workshops", + icon: WorkshopIcon, + href: "/workshops", + }, + { + label: "library", + icon: LibertyIcon, + href: "/library", + }, + { + label: "study room", + icon: StudyRoomIcon, + href: "/study-room", + }, +]; + +export const moodEmojis = [ + { + moodImg: "/assets/icons/sad_emoji.png", + mood_id: "sad-emoji", + mood: "sad", + }, + { + moodImg: "/assets/icons/unhappy_emoji.png", + mood_id: "unhappy-emoji", + mood: "unhappy", + }, + { + moodImg: "/assets/icons/neutral_emoji.png", + mood_id: "neutral-emoji", + mood: "neutral", + }, + { + moodImg: "/assets/icons/smiling_emoji.png", + mood: "smiling", + mood_id: "smiling-emoji", + }, + { + moodImg: "/assets/icons/laughing_emoji.png", + mood_id: "laughing-emoji", + mood: "laughing", + }, +]; + +export const manageAccountTabs = [ + { + id: "personal-info", + label: "Personal Info", + }, + { + id: "study-progress", + label: "Study Progress", + }, + // { + // id: "subject-overview", + // label: "Subject Overview", + // }, + // { + // id: "your-mentor", + // label: "Your Mentor", + // }, +]; + +export const subscriptionPlanningBenefits = [ + { + label: "goal setting & tracking", + }, + { + label: "schedule builder", + }, + { + label: "to-do list & reminders", + }, + { + label: "subject, chapter & topic tracking", + }, +]; + +export const subscriptionExpertBenefits = [ + { + label: "connect with a mentor", + }, + { + label: "live & on-demand workshops", + }, +]; +export const subscriptionLearningBenefits = [ + { + label: "growth meter", + }, + { + label: "points & levels", + }, + { + label: "know your mistakes", + }, +]; +export interface EfficiencyOption { + min?: number; + max?: number; + label: string; + progressBarColor: string; + textColor: string; +} +export const SUBJECT_COLORS = { + Maths: "bg-[#107FFC30]", + Chemistry: "bg-[#72EFDD4A]", + Physics: "bg-[#A36AF53D]", +}; + +export const chatPageTabs = [ + // { + // title: "chat", + // id: "chat", + // desktopView: true, + // }, + { + title: "meetings", + id: "meetings", + desktopView: true, + }, + { + title: "request meeting", + id: "requestMeeting", + desktopView: false, + }, +]; + +export const meetingTabs = [ + { + id: "upcoming", + label: "upcoming", + }, + { + id: "done", + label: "done", + }, +]; diff --git a/src/helpers/types/index.ts b/src/helpers/types/index.ts index 620caf5..fd7965c 100644 --- a/src/helpers/types/index.ts +++ b/src/helpers/types/index.ts @@ -1,5 +1,5 @@ import React, { SVGProps } from "react"; - +import { SUBJECT_COLORS } from "../constants"; export type TContainerProps = { children: React.ReactNode; className?: string; @@ -349,3 +349,13 @@ export type PlannerDataProps = { export type DataProps = { data: PlannerDataProps; }; + +export type Subject = keyof typeof SUBJECT_COLORS; + +export type TMeetingsProps = { + rescheduled: { + isRescheduled: boolean; + date: Date; + time: string; + }; +} \ No newline at end of file diff --git a/src/helpers/utils/index.ts b/src/helpers/utils/index.ts new file mode 100644 index 0000000..6c91001 --- /dev/null +++ b/src/helpers/utils/index.ts @@ -0,0 +1,181 @@ +import DOMPurify from "dompurify"; +import { SUBJECT_COLORS } from "../constants"; +import { Subject } from "../types"; + +const daysOfWeek = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +]; +const monthsOfYear = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +]; + +export function getTodaysDay() { + const today = new Date(); + const dayOfWeek = daysOfWeek[today.getDay()]; + + return `${dayOfWeek}`; +} + +export function getMonthDate(date: Date): string { + const dayOfMonth: string = String(date.getDate()).padStart(2, "0"); + const month: string = monthsOfYear[date.getMonth()]; + + return `${month} ${dayOfMonth}`; +} + +export function getMonthDateForProd(date: Date): string { + // Get the time in milliseconds since the epoch (UTC) + const utcTime = date.getTime(); + + // Define the IST offset in milliseconds (5 hours and 30 minutes) + const istOffset = 5.5 * 60 * 60 * 1000; + + // Calculate the IST time in milliseconds + const istTime = utcTime + istOffset; + + // Create a new Date object for IST time + const istDate = new Date(istTime); + + // Extract the day of the month and the month name in IST + const dayOfMonth: string = String(istDate.getUTCDate()).padStart(2, "0"); + const month: string = monthsOfYear[istDate.getUTCMonth()]; + + return `${month} ${dayOfMonth}`; +} + +export function getTodaysFormattedDate() { + const today = new Date(); + const dayOfMonth = String(today.getDate()).padStart(2, "0"); + const month = monthsOfYear[today.getMonth()]; + const year = today.getFullYear(); + + return `${dayOfMonth} ${month} ${year}`; +} + +export function getFormattedDate(date: Date): string { + const dayOfMonth: string = String(date.getDate()).padStart(2, "0"); + const month: string = monthsOfYear[date.getMonth()]; + const year: number = date.getFullYear(); + + return `${dayOfMonth} ${month} ${year}`; +} + +export function getFormattedDateForProd(date: Date): string { + const istOffset = 5 * 60 * 60 * 1000 + 30 * 60 * 1000; // IST is UTC +5:30 + const istDate = new Date(date.getTime() + istOffset); + + const dayOfMonth: string = String(istDate.getDate()).padStart(2, "0"); + const month: string = monthsOfYear[istDate.getMonth()]; + const year: number = istDate.getFullYear(); + + return `${dayOfMonth} ${month} ${year}`; +} + +export function convertDateString(inputDate: Date): string { + const utcDate = new Date(inputDate); + + // Convert to IST by adding 5 hours and 30 minutes + const istDate = new Date(utcDate.getTime() + 5.5 * 60 * 60 * 1000); + + // Format the date + const day = istDate.getDate().toString().padStart(2, "0"); + const month = (istDate.getMonth() + 1).toString().padStart(2, "0"); // Months are 0-indexed + const year = istDate.getFullYear(); + + // Format the date as DD-MM-YYYY + return `${day}-${month}-${year}`; +} + +export function formatDate(dateString: Date): string { + const date = new Date(dateString); + const day = date.getDate(); + const month = date.toLocaleString("default", { month: "short" }); + return `${day} ${month}`; +} + +export function calculateDaysLeft(meetingDate: Date): number { + // Get the current date + const currentDate = new Date(); + + // Calculate the difference in milliseconds + const differenceInMs = meetingDate.getTime() - currentDate.getTime(); + + // Convert milliseconds to days + const daysLeft = Math.ceil(differenceInMs / (1000 * 60 * 60 * 24)); + + return daysLeft; +} + +export function capitalizeFirstLetter( + sentence: string | undefined +): string | undefined { + if (!sentence) { + return sentence; + } + + return sentence.charAt(0).toUpperCase() + sentence.slice(1); +} + +export const formatTime = (seconds: number) => { + const days = Math.floor(seconds / (24 * 60 * 60)) + .toString() + .padStart(2, "0"); + const hours = Math.floor((seconds % (24 * 60 * 60)) / (60 * 60)) + .toString() + .padStart(2, "0"); + const minutes = Math.floor((seconds % (60 * 60)) / 60) + .toString() + .padStart(2, "0"); + const secs = (seconds % 60).toString().padStart(2, "0"); + + return `${days}d : ${hours}h : ${minutes}m : ${secs}s`; +}; + +export const sanitizedHtml = (htmlString: string) => { + DOMPurify.sanitize(htmlString); + return htmlString; +}; + +export const getColorBySubject = (subject: Subject): string => { + return SUBJECT_COLORS[subject] || "bg-[#B0BEC5]"; +}; + +export function isMoodButtonDisabled(lastMoodDate: String) { + if (!lastMoodDate) return false; + + const today = new Date(); + const formattedToday = today.toISOString().split("T")[0]; + + return lastMoodDate === formattedToday; +} + +export const loadRazorpayScript = () => { + return new Promise((resolve) => { + const script = document.createElement("script"); + script.src = "https://checkout.razorpay.com/v1/checkout.js"; + script.onload = () => { + resolve(true); + }; + script.onerror = () => { + resolve(false); + }; + document.body.appendChild(script); + }); +}; diff --git a/src/pages/auth/Login.tsx b/src/pages/auth/Login.tsx index 22b1f5e..b6bdefe 100644 --- a/src/pages/auth/Login.tsx +++ b/src/pages/auth/Login.tsx @@ -23,8 +23,6 @@ const Login = () => { const handleSubmit = async (e: any) => { e.preventDefault(); setIsLoggingIn(true); - setIsLoading(true) - setLoginSuccess(true) try { const response = await apiClient.post(`/api/auth/admin/login`, { @@ -33,17 +31,23 @@ const Login = () => { }); if (response.status === 200) { - navigate('/mentors'); - + const { token } = response.data; + if (token) { + localStorage.setItem("token", token); + console.log('Token saved:', token); + navigate('/'); + } else { + throw new Error('Token not provided in the response'); + } } - } catch (error: any) { - setError(error); - + } catch (error: any) { + setError(error.response?.data?.message || error.message); } finally { setIsLoggingIn(false); setIsLoading(false) } }; + return ( <> {isLoading ? ( diff --git a/src/pages/root/dashboard/_components/ContinuousRevision.tsx b/src/pages/root/dashboard/_components/ContinuousRevision.tsx new file mode 100644 index 0000000..d707bbc --- /dev/null +++ b/src/pages/root/dashboard/_components/ContinuousRevision.tsx @@ -0,0 +1,65 @@ +"use client"; + +// import { ChatIcon, VideoChatIcon, RequestMeetingIcon } from "@/components"; +// import Link from "next/link"; +import Image from "next/image"; +// import { useAppSelector } from "@/redux/hooks"; +import { Button } from "../../../../components/ui/button"; +// import { useState } from "react"; +// import ContinuousRevisionForm from "./ContinuousRevisionForm"; +// import { ISubject } from "@/helpers/types"; + +const ContinuousRevision = () => { + // const [activeSubject, setActiveSubject] = useState(null); + + // const userSubjects = useAppSelector( + // (state) => state.user.user?.academic.subjects + // ); + + // const userStandard = useAppSelector( + // (state) => state.user.user?.academic.standard + // ); + + return ( +
    + {/* {!activeSubject ? ( */} + <> +

    + What did you Learnt New Today? +

    + +
    + Leadlly student studying +
    + +
    + {/* {userSubjects?.map((subject) => ( */} + + {/* ))} */} +
    + + {/* ) : ( + + )} */} +
    + ); +}; + +export default ContinuousRevision; diff --git a/src/pages/root/dashboard/_components/ContinuousRevisionForm.tsx b/src/pages/root/dashboard/_components/ContinuousRevisionForm.tsx new file mode 100644 index 0000000..5313a55 --- /dev/null +++ b/src/pages/root/dashboard/_components/ContinuousRevisionForm.tsx @@ -0,0 +1,271 @@ +"use client"; + +// import { NewTopicLearntSchema } from "@/schemas/newTopicLearntSchema"; +// import { zodResolver } from "@hookform/resolvers/zod"; +// import * as z from "zod"; +// import { useForm } from "react-hook-form"; +import { + // Form, + FormControl, + FormField, + FormItem, + FormMessage, +} from "../../../../components/ui/form"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "../../../../components/ui/popover"; +import { Button } from "../../../../components/ui/button"; +import { cn } from "../../../../lib/utils"; +import { Check, ChevronDown, Loader2 } from "lucide-react"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "../../../../components/ui/command"; +import { MultiSelect } from "../../../../components/ui/multi-select"; +import { LeftArrowIcon } from "../../../../components"; +// import { +// getChapterTopics, +// getSubjectChapters, +// } from "@/actions/question_actions"; +// import { toast } from "sonner"; +import { useState } from "react"; +import { subjectChaptersProps } from "../../../../helpers/types"; +// import { saveStudyData } from "@/actions/studyData_actions"; +// import { updatePlanner } from "@/actions/planner_actions"; + +const ContinuousRevisionForm = ({ + // activeSubject, + // userStandard, + setActiveSubject, + // userSubjects, +}: { + activeSubject: string; + setActiveSubject: (activeSubject: string | null) => void; + userStandard: number; + // userSubjects: ISubject[]; +}) => { + const [activeTabChapters, setActiveTabChapters] = useState< + subjectChaptersProps[] + >([]); + const [topics, setTopics] = useState([]); + const [isSubmitting, setIsSubmitting] = useState(false); + const [chapterPopoverOpen, setChapterPopoverOpen] = useState(false); + + // const form = useForm>({ + // resolver: zodResolver(NewTopicLearntSchema), + // }); + + // const selectedChapter = form.watch("chapterName"); + + // const onSubmit = async (data: z.infer) => { + // setIsSubmitting(true); + + // const formattedData = { + // tag: "continuous_revision", + // topics: data.topicNames.map((topic) => ({ name: topic })), + // chapter: { + // name: data.chapterName, + // }, + // subject: activeSubject, + // standard: userStandard, + // }; + + // try { + // const responseData = await saveStudyData(formattedData); + + // await updatePlanner(); + // toast.success(responseData.message); + + // form.reset({ + // chapterName: "", + // topicNames: [], + // }); + // } catch (error: any) { + // toast.error(error?.message); + // } finally { + // setIsSubmitting(false); + // } + // }; + + // useEffect(() => { + // const chapters = async () => { + // try { + // const data = await getSubjectChapters(activeSubject, userStandard); + + // setActiveTabChapters(data.chapters); + // } catch (error: any) { + // toast.error("Unable to fetch chapters!", { + // description: error.message, + // }); + // } + // }; + + // chapters(); + // }, [activeSubject, userStandard]); + + // useEffect(() => { + // const topics = async () => { + // try { + // const data = await getChapterTopics( + // activeSubject, + // selectedChapter, + // userStandard + // ); + // setTopics(data.topics); + // } catch (error: any) { + // toast.error("Unable to fetch topics!", { + // description: error.message, + // }); + // } + // }; + + // topics(); + // }, [activeSubject, selectedChapter, userStandard]); + + return ( +
    +
    + {/* {userSubjects.map((subject) => ( */} + + {/* ))} */} +
    + {/*
    */} + + ( + + + + + + + + + + + + No chapter found. + + {activeTabChapters?.map((chapter) => ( + { + // form.setValue("chapterName", chapter.name); + setChapterPopoverOpen(false); + }} + className="cursor-pointer" + > + + {chapter.name} + + ))} + + + + + + + + )} + /> + + ( + + + + + + + + )} + /> + +
    + + + +
    + + {/* */} +
    + ); +}; + +export default ContinuousRevisionForm; diff --git a/src/pages/root/dashboard/_components/DailyReport.tsx b/src/pages/root/dashboard/_components/DailyReport.tsx new file mode 100644 index 0000000..387923c --- /dev/null +++ b/src/pages/root/dashboard/_components/DailyReport.tsx @@ -0,0 +1,49 @@ +"use client"; + +// import { RadialBarChart } from "../../../../components"; +// import { formatDate } from "../../../../helpers/utils"; +// import { useAppSelector } from "@/redux/hooks"; + +const DailyReport = () => { + // const userDetails = useAppSelector((state) => state.user.user?.details); + return ( +
    +

    Daily Report

    +
    + {/* */} + +
    +
    + + Sessions +
    +
    + + Quizzes +
    +
    +
    +
    + ); +}; + +export default DailyReport; diff --git a/src/pages/root/dashboard/_components/DailyStreakDialogBox.tsx b/src/pages/root/dashboard/_components/DailyStreakDialogBox.tsx new file mode 100644 index 0000000..7e3e9b8 --- /dev/null +++ b/src/pages/root/dashboard/_components/DailyStreakDialogBox.tsx @@ -0,0 +1,173 @@ +"use client"; + +import { Button } from "../../../../components/ui/button"; +import { cn } from "../../../../lib/utils"; +import { ArrowLeft } from "lucide-react"; +// import { useState } from "react"; +import Modal from "../../../../components/shared/Modal"; +import { Questions } from "../../../../helpers/types/index"; +// import { sanitizedHtml } from "../../../../helpers/utils/index"; +// import { useAppSelector } from "@/redux/hooks"; + +const DailyStreakDialogBox = ({ + setOpenQuestionDialogBox, + // questions, +}: { + openQuestionDialogBox: boolean; + setOpenQuestionDialogBox: (openQuestionDialogBox: boolean) => void; + questions: Questions; +}) => { + // const [activeQuestion, setActiveQuestion] = useState(0); + // const [attemptedQuestion, setAttemptedQuestion] = useState([]); + // const [selectedAnswer, setSelectedAnswer] = useState(""); + // const [selectedAnswerIndex, setSelectedAnswerIndex] = useState( + // null + // ); + + // const userSubjects = useAppSelector( + // (state) => state.user.user?.academic.subjects + // ); + // const [activeTab, setActiveTab] = useState(userSubjects?.[0]?.name); + + // const questionData = questions[activeTab?.toLowerCase()!]; + + // if (!questionData) return null; + + // const { question, options } = questionData; + + // const allOptions = options.map((option: Option) => option.name); + // const correctOptions = options + // .filter((option: Option) => option.tag === "Correct") + // .map((option: Option) => option.name); + + // const onAnswerSelect = (answer: string, index: number) => { + // setSelectedAnswerIndex(index); + + // setSelectedAnswer(answer); + + // if (!attemptedQuestion.includes(activeQuestion) && !selectedAnswer) { + // setAttemptedQuestion((prev) => [...prev, activeQuestion]); + // } + // }; + + // const handleNextQuestion = () => { + // setSelectedAnswerIndex(null); + // setSelectedAnswer(""); + + // const currentIndex = userSubjects?.findIndex( + // (subject) => subject.name === activeTab + // ); + // const nextIndex = (currentIndex! + 1) % userSubjects?.length!; + // setActiveTab(userSubjects?.[nextIndex].name); + // }; + + return ( + +
    +
    +
    setOpenQuestionDialogBox(false)} + > + +
    + + +
    + +
    +
    + {/* {userSubjects?.map((tab) => ( */} + + {/* ))} */} +
    + +
    +
    +

    + Q. + {/* */} +

    + +
      + {/* {allOptions.map((option: string, index: number) => ( */} +
    • onAnswerSelect(option, index)} + > +
      + {/* {selectedAnswerIndex === index && + correctOptions.includes(option) && ( + + )} + + {selectedAnswerIndex === index && + !correctOptions.includes(option) && ( + + )} */} +
      + {/* */} +
    • + {/* ))} */} +
    +
    +
    + +
    +
    +
    +
    +
    + ); +}; + +export default DailyStreakDialogBox; diff --git a/src/pages/root/dashboard/_components/DailyStreakQuestions.tsx b/src/pages/root/dashboard/_components/DailyStreakQuestions.tsx new file mode 100644 index 0000000..552a365 --- /dev/null +++ b/src/pages/root/dashboard/_components/DailyStreakQuestions.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { Button } from "../../../../components/ui/button"; +import Image from "next/image"; +import React, { useState } from "react"; +import DailyStreakDialogBox from "./DailyStreakDialogBox"; +import { Questions } from "../../../../helpers/types/index"; +// import { getDailyStreakQuestions } from "@/actions/daily_quiz_actions"; +// import { toast } from "sonner"; +import { Loader2 } from "lucide-react"; + +const DailyStreakQuestions: React.FC = () => { + const [openQuestionDialogBox, setOpenQuestionDialogBox] = useState(false); + const [questions, setQuestions] = useState({}); + const [isQuestionLoading, setIsQuestionLoading] = useState(false); + + // const handleBoxClick = async () => { + // setIsQuestionLoading(true); + // try { + // const response = await getDailyStreakQuestions(); + + // if (response.success) { + // setQuestions(response.questions); + // setOpenQuestionDialogBox(true); + // } else { + // toast.error("Failed to fetch questions:", { + // description: response.message, + // }); + // } + // } catch (error: any) { + // toast.error("Error fetching questions:", { + // description: error.message, + // }); + // } finally { + // setIsQuestionLoading(false); + // } + // }; + + return ( + <> +
    +
    +

    + Daily Streak Questions +

    +

    + Daily prompts sustain commitment, motivation. +

    + +
    + +
    + young man working remotely +
    +
    + + {openQuestionDialogBox && ( + + )} + + ); +}; + +export default DailyStreakQuestions; diff --git a/src/pages/root/dashboard/_components/DesktopUI.tsx b/src/pages/root/dashboard/_components/DesktopUI.tsx new file mode 100644 index 0000000..465570a --- /dev/null +++ b/src/pages/root/dashboard/_components/DesktopUI.tsx @@ -0,0 +1,86 @@ +"use client"; +import { Header } from "../../../../components"; + +import TodaysPlan from "./TodaysPlan"; +// import ContinuousRevision from "./ContinuousRevision"; +// import SubjectProgress from "./SubjectProgress"; +// import DailyReport from "./DailyReport"; +// import ProgressAnalytics from "./ProgressAnalytics"; +import ProfileBox from "./ProfileBox"; +import PointsBox from "./PointsBox"; +// import TodaysVibe from "./TodaysVibe"; +// import DailyStreakQuestions from "./DailyStreakQuestions"; +// import UpcomingWorkshops from "./UpcomingWorkshops"; +// import { useAppSelector } from "@/redux/hooks"; +// import UpgradeSubscriptionButton from "./UpgradeSubscriptionButton"; +import { Suspense } from "react"; +import Loader from "../../Loader"; +import { TDayProps } from "../../../.././helpers/types"; +// import InitialTodoBox from "./InitailTodoBox"; + +const DesktopUI = ({ quizTopics}: { quizTopics: TDayProps }) => { + // const user = useAppSelector((state) => state.user.user); + return ( +
    +
    +
    +
    +
    +
    + {/*
    } + /> */} + {/* */} +
    +
    + +
    +
    +
    +
    + }> + { } + +
    + + {/*
    + +
    */} +
    + + {/*
    +
    + +
    + +
    + +
    +
    + +
    + +
    */} +
    + +
    +
    + + + +{/* + + + + + */} +
    +
    +
    +
    + ); +}; + +export default DesktopUI; diff --git a/src/pages/root/dashboard/_components/InitailTodoBox.tsx b/src/pages/root/dashboard/_components/InitailTodoBox.tsx new file mode 100644 index 0000000..e8396bb --- /dev/null +++ b/src/pages/root/dashboard/_components/InitailTodoBox.tsx @@ -0,0 +1,34 @@ +"use client"; + +import React from "react"; +import Link from "next/link"; +import { Button } from "@/components/ui/button"; + +const InitialTodoBox = () => { + return ( +
    +
    +

    + Help us create your plan +

    + +

    + Please provide an update on the topics you’ve completed in class so + far. This will help us tailor the sessions to your needs. +

    +
    + +
    + + + +
    +
    + ); +}; + +export default InitialTodoBox; diff --git a/src/pages/root/dashboard/_components/LevelPoints.tsx b/src/pages/root/dashboard/_components/LevelPoints.tsx new file mode 100644 index 0000000..abb2ce1 --- /dev/null +++ b/src/pages/root/dashboard/_components/LevelPoints.tsx @@ -0,0 +1,85 @@ +import { UpArrowIcon } from "@/components"; +import { Progress } from "@/components/ui/progress"; +import { TLevelPointProps } from "@/helpers/types"; +import { cn } from "@/lib/utils"; + +import { ChevronRight } from "lucide-react"; +import Image from "next/image"; +import React from "react"; + +const LevelPoints = ({ + cardBgColor, + iconImageSrc, + iconAltText, + iconShadowColor, + chevronBgColor, + pointsColor, + points, + pointsText, + progressValue, + pointsProgressText, + pointsProgressTextColor, + progressIndicatorBg, + progressIconStroke, +}: TLevelPointProps) => { + return ( +
    +
    + {iconAltText} + + +
    + +
    +

    + {points} +

    +

    {pointsText}

    + + + + {/* {pointsText !== "Streak" && ( +
    + + + +
    + )} */} + + {pointsText === "Streak" && ( + <> +
    + Jan12 + Feb12 +
    + + )} +
    +
    + ); +}; + +export default LevelPoints; diff --git a/src/pages/root/dashboard/_components/MobileUI.tsx b/src/pages/root/dashboard/_components/MobileUI.tsx new file mode 100644 index 0000000..c5749c1 --- /dev/null +++ b/src/pages/root/dashboard/_components/MobileUI.tsx @@ -0,0 +1,55 @@ +"use client"; +import { Header } from "@/components"; +import TodaysPlan from "./TodaysPlan"; +import ContinuousRevision from "./ContinuousRevision"; +import DailyReport from "./DailyReport"; +import SubjectProgress from "./SubjectProgress"; +import ProgressAnalytics from "./ProgressAnalytics"; +import UserProfileSheet from "./UserProfileSheet"; +import UpgradeSubscriptionButton from "./UpgradeSubscriptionButton"; +import { Suspense } from "react"; +import Loader from "@/components/shared/Loader"; +import { TDayProps } from "@/helpers/types"; +import InitialTodoBox from "./InitailTodoBox"; +import { useAppSelector } from "@/redux/hooks"; + +const MobileUI = ({ quizTopics }: { quizTopics: TDayProps }) => { + const user = useAppSelector((state) => state.user.user); + return ( +
    +
    +
    +
    + + +
    +
    + +
    + }> + {/* */} + {user && user.planner === false ? : } + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    +
    + ); +}; + +export default MobileUI; diff --git a/src/pages/root/dashboard/_components/MoodEmojiSelector.tsx b/src/pages/root/dashboard/_components/MoodEmojiSelector.tsx new file mode 100644 index 0000000..80d5eb2 --- /dev/null +++ b/src/pages/root/dashboard/_components/MoodEmojiSelector.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { useState } from "react"; +import Image from "next/image"; + +import { cn } from "../../../../lib/utils"; +// import { toast } from "sonner"; +import { moodEmojis } from "../../../../helpers/constants"; +// import { getUser, setTodaysVibe } from "@/actions/user_actions"; +// import { useAppDispatch, useAppSelector } from "@/redux/hooks"; +// import { userData } from "@/redux/slices/userSlice"; +import { Loader2 } from "lucide-react"; +// import { isMoodButtonDisabled } from "../../../../helpers/utils"; + +const MoodEmojiSelector = () => { + // const user = useAppSelector((state) => state.user.user); + + // const userCurrentMood = user?.details?.mood; + const today = new Date().toISOString().split("T")[0]; + + // const currentDateMoodIndex = userCurrentMood?.findIndex( + // (mood) => mood.day === today + // ); + + // const [currentMood, setCurrentMood] = useState( + // userCurrentMood && + // userCurrentMood.length && + // userCurrentMood?.[currentDateMoodIndex!]?.emoji + // ? userCurrentMood?.[currentDateMoodIndex!]?.emoji + // : "neutral" + // ); + + const [isCurrentMood, setIsCurrentMood] = useState(false); + + // const dispatch = useAppDispatch(); + + // const handleChangeMood = async (mood: string) => { + // setIsCurrentMood(true); + // try { + // setCurrentMood(mood); + + // const response = await setTodaysVibe({ + // todaysVibe: mood, + // }); + + // dispatch( + // userData({ + // ...user, + // details: { + // ...user?.details, + // mood: [...(user?.details?.mood || []), { day: today, emoji: mood }], + // }, + // }) + // ); + // toast.success(response.message); + // // setIsTodaysMoodSet(true); + // } catch (error: any) { + // setCurrentMood(currentMood); + // toast.error("Saving your current mood failed!", { + // description: error.message, + // }); + // } finally { + // setIsCurrentMood(false); + // } + // }; + + // const isDisabled = isMoodButtonDisabled( + // userCurrentMood?.[currentDateMoodIndex!]?.day! + // ); + + return ( +
    +
    + + {moodEmojis.map((emoji) => ( + {emoji.mood} handleChangeMood(emoji.mood)} + className={cn( + "cursor-pointer transition-all ease-in duration-200", + // currentMood === emoji.mood ? "grayscale-0" : "grayscale", + // isCurrentMood && "pointer-events-none opacity-90", + // isDisabled && "pointer-events-none opacity-90" + )} + /> + ))} + + +
    +
    + {isCurrentMood && ( + + )} +
    + ); +}; + +export default MoodEmojiSelector; diff --git a/src/pages/root/dashboard/_components/PointsBox.tsx b/src/pages/root/dashboard/_components/PointsBox.tsx new file mode 100644 index 0000000..63d3d90 --- /dev/null +++ b/src/pages/root/dashboard/_components/PointsBox.tsx @@ -0,0 +1,78 @@ +"use client"; + +// import { useAppSelector } from "@/redux/hooks"; +import LevelPoints from "./LevelPoints"; + +const PointsBox = () => { + // const userDetails = useAppSelector((state) => state.user.user?.details); + + return ( +
    + + + +
    + ); +}; + +export default PointsBox; diff --git a/src/pages/root/dashboard/_components/ProfileBox.tsx b/src/pages/root/dashboard/_components/ProfileBox.tsx new file mode 100644 index 0000000..2cf58c3 --- /dev/null +++ b/src/pages/root/dashboard/_components/ProfileBox.tsx @@ -0,0 +1,67 @@ +"use client"; + +import { Avatar, AvatarFallback, AvatarImage } from "../../../../components/ui/avatar"; +import { Button } from "../../../../components/ui/button"; + +// import { useAppSelector } from "@/redux/hooks"; + +import Link from "next/link"; + +const ProfileBox = () => { + // const user = useAppSelector((state) => state.user?.user); + + return ( +
    +
    + + + + {/* {user?.firstname?.[0]} */} + + {/* {user?.lastname ? user.lastname?.[0] : ""} */} + + + +
    +

    + {/* Hello, {user?.firstname}{" "} + {user?.lastname} */} +

    + +
    + + + +
    +
    +
    +
    +

    + Embrace the course as a catalyst for personal growth and empowerment, + propelling you towards success with unwavering determination. +

    + +
    + + + +
    +
    +
    + ); +}; + +export default ProfileBox; diff --git a/src/pages/root/dashboard/_components/ProgressAnalytics.tsx b/src/pages/root/dashboard/_components/ProgressAnalytics.tsx new file mode 100644 index 0000000..bce75b6 --- /dev/null +++ b/src/pages/root/dashboard/_components/ProgressAnalytics.tsx @@ -0,0 +1,79 @@ +"use client"; + +import { useState } from "react"; +import { + // MonthlyReportChart, + // BarChart, + // OverallReportChart, + TabContent, + TabNavItem, +} from "../../../../components"; +// import { useAppSelector } from "@/redux/hooks"; + +const progressAnalyticsMenus = [ + { + id: "weekly", + title: "Weekly", + }, + { + id: "monthly", + title: "Monthly", + }, + { + id: "overall", + title: "Overall", + }, +]; + +const ProgressAnalytics = () => { + const [activeTab, setActiveTab] = useState("weekly"); + + // const weeklyReportData = useAppSelector((state) => state.weeklyReport.report); + // const monthlyReportData = useAppSelector( + // (state) => state.monthlyReport.report + // ); + // const overallReportData = useAppSelector( + // (state) => state.overallReport.report + // ); + + return ( +
    +
    +

    Progress Analytics

    +
      + {progressAnalyticsMenus.map((tab) => ( + + ))} +
    +
    + +
    + +
    + {/* */} +
    +
    + +
    + {/* */} +
    +
    + +
    + {/* */} +
    +
    +
    +
    + ); +}; + +export default ProgressAnalytics; diff --git a/src/pages/root/dashboard/_components/QuestionDialogBox.tsx b/src/pages/root/dashboard/_components/QuestionDialogBox.tsx new file mode 100644 index 0000000..b2ff608 --- /dev/null +++ b/src/pages/root/dashboard/_components/QuestionDialogBox.tsx @@ -0,0 +1,294 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Progress } from "@/components/ui/progress"; + +import { cn } from "@/lib/utils"; + +import { TQuizAnswerProps, TQuizQuestionProps } from "@/helpers/types"; + +import { ArrowLeft, Check, Loader2, X } from "lucide-react"; +import React, { useState } from "react"; +import { MotionDiv } from "@/components/shared/MotionDiv"; +import Modal from "@/components/shared/Modal"; + +import { sanitizedHtml } from "@/helpers/utils"; +import { toast } from "sonner"; +import { saveDailyQuiz } from "@/actions/daily_quiz_actions"; +import { getUser } from "@/actions/user_actions"; +import { useAppDispatch } from "@/redux/hooks"; +import { userData } from "@/redux/slices/userSlice"; +import { + getMonthlyReport, + getOverallReport, + getWeeklyReport, +} from "@/actions/student_report_actions"; +import { weeklyData } from "@/redux/slices/weeklyReportSlice"; +import { monthlyData } from "@/redux/slices/monthlyReportSlice"; +import { overallData } from "@/redux/slices/overallReportSlice"; + +const QuestionDialogBox = ({ + setOpenQuestionDialogBox, + questions, + topic, +}: { + openQuestionDialogBox: boolean; + setOpenQuestionDialogBox: (openQuestionDialogBox: boolean) => void; + questions: TQuizQuestionProps[]; + topic: { name: string; _id: string } | null; +}) => { + const [activeQuestion, setActiveQuestion] = useState(0); + const [attemptedQuestionIndex, setAttemptedQuestionIndex] = useState< + number[] + >([]); + const [attemptedQuestion, setAttemptedQuestion] = useState< + TQuizAnswerProps[] + >([]); + const [selectedAnswer, setSelectedAnswer] = useState(""); + const [selectedAnswerIndex, setSelectedAnswerIndex] = useState( + null + ); + const [optionSelected, setOptionSelected] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + + const dispatch = useAppDispatch(); + + const onAnswerSelect = (answer: string, optionTag: string, index: number) => { + setSelectedAnswerIndex(index); + + setSelectedAnswer(answer); + setOptionSelected(true); + + if (!attemptedQuestionIndex.includes(activeQuestion) && !selectedAnswer) { + setAttemptedQuestionIndex((prev) => [...prev, activeQuestion]); + } + + const formattedData: TQuizAnswerProps = { + question: questions[activeQuestion], + studentAnswer: answer, + isCorrect: optionTag === "Correct", + tag: "daily_quiz", + }; + + if (!attemptedQuestion.includes(formattedData)) { + setAttemptedQuestion((prev) => [...prev, formattedData]); + } + }; + + const handleNextQuestion = () => { + setSelectedAnswerIndex(null); + setSelectedAnswer(""); + setOptionSelected(false); + + if (activeQuestion !== questions.length - 1) { + setActiveQuestion((prev) => prev + 1); + } + }; + + const onHandleSubmit = async () => { + setIsSubmitting(true); + + try { + const res = await saveDailyQuiz({ + topic: { name: topic?.name! }, + questions: attemptedQuestion, + }); + + if (res.success) { + const userInfo = getUser(); + const weeklyReportInfo = getWeeklyReport(); + const monthlyReportInfo = getMonthlyReport(); + const overallReportInfo = getOverallReport(); + + const [user, weeklyReport, monthlyReport, overallReport] = + await Promise.all([ + userInfo, + weeklyReportInfo, + monthlyReportInfo, + overallReportInfo, + ]); + + dispatch(userData(user.user)); + dispatch(weeklyData(weeklyReport.weeklyReport)); + dispatch(monthlyData(monthlyReport.monthlyReport)); + dispatch(overallData(overallReport.overallReport)); + toast.success(res.message); + + setOpenQuestionDialogBox(false); + } else { + toast.error(res.message); + } + } catch (error: any) { + toast.error(error.message); + } finally { + setIsSubmitting(false); + } + }; + + return ( + + {questions && questions.length > 0 && questions[activeQuestion] ? ( + <> +
    +
    setOpenQuestionDialogBox(false)} + > + +
    + +
    + +

    + {attemptedQuestionIndex.length}/{questions.length} +

    +
    + + +
    + +
    +
    +

    + Quiz on {topic?.name} +

    + +
    +
      + {questions.map((ques, index) => ( +
    • { + setSelectedAnswerIndex(null); + setSelectedAnswer(""); + setOptionSelected(false); + setActiveQuestion(index); + }} + > + Q{index + 1} + {activeQuestion === index && ( + + )} +
    • + ))} +
    +
    + +
    +

    + {activeQuestion + 1}. + +

    + +
      + {questions[activeQuestion].options.map((option, index) => ( +
    • + onAnswerSelect(option.name, option.tag, index) + } + > +
      + {optionSelected && option.tag === "Correct" && ( + + )} + + {selectedAnswerIndex === index && + option.tag === "Incorrect" && ( + + )} +
      + +
    • + ))} +
    +
    +
    + +
    +
    +
    + + ) : ( +
    +

    + No questions yet! +

    + +
    + )} +
    + ); +}; + +export default QuestionDialogBox; diff --git a/src/pages/root/dashboard/_components/SubjectProgress.tsx b/src/pages/root/dashboard/_components/SubjectProgress.tsx new file mode 100644 index 0000000..5942b08 --- /dev/null +++ b/src/pages/root/dashboard/_components/SubjectProgress.tsx @@ -0,0 +1,101 @@ +"use client"; + +import { useState } from "react"; +import { TabContent, TabNavItem } from "../../../../components"; +// import { useAppSelector } from "@/redux/hooks"; + +const SubjectProgress = () => { + // const userSubjects = useAppSelector( + // (state) => state.user.user?.academic?.subjects + // ); + // const [activeTab, setActiveTab] = useState(userSubjects?.[0]?.name); + + // const subject = userSubjects?.filter( + // (subject) => subject.name === activeTab + // )[0]; + + return ( +
    +
    +

    Subject Progress

    +
      + {/* {userSubjects?.map((tab, i) => ( */} + {/* */} + {/* ))} */} +
    +
    +
    + {/* */} +
    +
    + {/* */} +
    + +
    + {/* */} +
    +
    + {/*
    */} + + {/* +
    +
    + +
    + +
    + +
    +
    +
    + + +
    +
    + +
    + +
    + +
    +
    +
    */} +
    +
    + ); +}; + +export default SubjectProgress; diff --git a/src/pages/root/dashboard/_components/TabletUI.tsx b/src/pages/root/dashboard/_components/TabletUI.tsx new file mode 100644 index 0000000..7d3a7e2 --- /dev/null +++ b/src/pages/root/dashboard/_components/TabletUI.tsx @@ -0,0 +1,73 @@ +"use client"; +import { Header } from "@/components"; +import TodaysPlan from "./TodaysPlan"; +import ContinuousRevision from "./ContinuousRevision"; +import SubjectProgress from "./SubjectProgress"; +import ProfileBox from "./ProfileBox"; +import PointsBox from "./PointsBox"; +import DailyStreakQuestions from "./DailyStreakQuestions"; +import TodaysVibe from "./TodaysVibe"; +import UpcomingWorkshops from "./UpcomingWorkshops"; +import DailyReport from "./DailyReport"; +import ProgressAnalytics from "./ProgressAnalytics"; +import UpgradeSubscriptionButton from "./UpgradeSubscriptionButton"; +import { Suspense } from "react"; +import Loader from "@/components/shared/Loader"; +import { TDayProps } from "@/helpers/types"; +import { useAppSelector } from "@/redux/hooks"; +import InitialTodoBox from "./InitailTodoBox"; + +const TabletUI = ({ quizTopics }: { quizTopics: TDayProps }) => { + const user = useAppSelector((state) => state.user.user); + return ( +
    +
    +
    + + +
    + +
    +
    +
    +
    + }> + {/* */} + {user && user.planner === false ? : } + + +
    +
    + +
    +
    + +
    +
    + +
    + + + + + + + + + + +
    + +
    +
    +
    + +
    + +
    +
    +
    + ); +}; + +export default TabletUI; diff --git a/src/pages/root/dashboard/_components/ToDoListButton.tsx b/src/pages/root/dashboard/_components/ToDoListButton.tsx new file mode 100644 index 0000000..72fb20a --- /dev/null +++ b/src/pages/root/dashboard/_components/ToDoListButton.tsx @@ -0,0 +1,86 @@ +import { TRevisionProps } from "@/helpers/types"; +import { cn } from "@/lib/utils"; +import { Check } from "lucide-react"; + +const ToDoListButton = ({ + topic, + setTopic, + setOpenQuestionDialogBox, + completedTopics, + incompleteTopics, +}: { + topic: TRevisionProps; + completedTopics: any[]; + incompleteTopics: any[]; + setOpenQuestionDialogBox: (openQuestionDialogBox: boolean) => void; + setTopic: (topic: { name: string; _id: string } | null) => void; +}) => { + const handleCheckboxClick = (topic: string, topicId: string) => { + setTopic({ name: topic, _id: topicId }); + setOpenQuestionDialogBox(true); + }; + return ( +
    +
  • handleCheckboxClick(topic.topic.name, topic._id)} + > + 0 && + completedTopics.includes(topic.topic.name) && + "bg-[#0FD679]/80 border-none", + incompleteTopics && + incompleteTopics.length > 0 && + incompleteTopics.includes(topic.topic.name) && + "bg-[#ff2e2e]/80 border-none" + )} + > + {completedTopics && + completedTopics.length > 0 && + completedTopics.includes(topic.topic.name) && ( + + )} + + {incompleteTopics && + incompleteTopics.length > 0 && + incompleteTopics.includes(topic.topic.name) && ( + ! + )} + + +
    +

    {topic.topic.name}

    +
    +
  • + {completedTopics && + completedTopics.length > 0 && + completedTopics.includes(topic.topic.name) && ( +
    +

    completed

    +
    + )} + {incompleteTopics && + incompleteTopics.length > 0 && + incompleteTopics.includes(topic.topic.name) && ( +
    +

    incomplete

    +
    + )} +
    + ); +}; + +export default ToDoListButton; diff --git a/src/pages/root/dashboard/_components/TodaysPlan.tsx b/src/pages/root/dashboard/_components/TodaysPlan.tsx new file mode 100644 index 0000000..b454ddb --- /dev/null +++ b/src/pages/root/dashboard/_components/TodaysPlan.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { getTodaysDay, getTodaysFormattedDate } from "../../../../helpers/utils"; +import { TDayProps } from "../../../../helpers/types"; +// import QuestionDialogBox from "./QuestionDialogBox"; +// import Loader from "../../../../components/shared/Loader"; +// import ToDoListButton from "./ToDoListButton"; +import Player from "lottie-react"; +import loginAnimation from "../../../../assets/todo_pending_animation.json"; + +const TodaysPlan = ({ quizData }: { quizData: TDayProps | undefined }) => { + // const [openQuestionDialogBox, setOpenQuestionDialogBox] = useState(false); + // const [topic, setTopic] = useState<{ name: string; _id: string } | null>(null); + const [hasTopics, setHasTopics] = useState(false); + useEffect(() => { + if (quizData) { + const hasTopicsData = + quizData.backRevisionTopics.length > 0 + // quizData.continuousRevisionTopics.length > 0; + setHasTopics(hasTopicsData); + } + console.log('quizData:', quizData); + console.log('hasTopics:', hasTopics); + }, [quizData, hasTopics]); + + if (!quizData) { + return ( +
    +
    +

    + Please hold on... +

    +

    + While your plan is being generated, your itinerary will be ready shortly. +

    +
    + +
    + +
    + +
    + ); + } + + // const hasTopics = + // quizData.backRevisionTopics.length > 0 || + // quizData.continuousRevisionTopics.length > 0; + + return ( + <> + {/* {hasTopics ? ( */} + <> +
    +
    +

    Todo list

    +

    + {getTodaysDay()} {getTodaysFormattedDate()} +

    +
    +
    + +
    +
      + {/* {quizData.backRevisionTopics.map((topicItem) => ( + + ))} + {/* {quizData.continuousRevisionTopics.map((topicItem) => ( */} + {/* + // ))} */} +
    +
    + + {/* ) : ( */} + //
    +
    + +

    + Please hold on... +

    +

    + While your plan is being generated, your itinerary will be ready shortly. +

    +
    + +
    +
    + //
    + {/* )} */} + + {/* {openQuestionDialogBox && topic && ( + }> + + + )} */} + + ); +}; + +export default TodaysPlan; diff --git a/src/pages/root/dashboard/_components/TodaysVibe.tsx b/src/pages/root/dashboard/_components/TodaysVibe.tsx new file mode 100644 index 0000000..7d1a7df --- /dev/null +++ b/src/pages/root/dashboard/_components/TodaysVibe.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import MoodEmojiSelector from "./MoodEmojiSelector"; + +const TodaysVibe = () => { + return ( +
    +

    Today's Vibes

    +

    + Sessions and quizzes were insightful and engaging ? +

    + + +
    + ); +}; + +export default TodaysVibe; diff --git a/src/pages/root/dashboard/_components/TrialPeriodTimer.tsx b/src/pages/root/dashboard/_components/TrialPeriodTimer.tsx new file mode 100644 index 0000000..4adfbc7 --- /dev/null +++ b/src/pages/root/dashboard/_components/TrialPeriodTimer.tsx @@ -0,0 +1,62 @@ +"use client"; + +import { formatTime } from "../../../../helpers/utils"; +// import { useAppSelector } from "@/redux/hooks"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +const TrialPeriodTimer = () => { + const [timeLeft, setTimeLeft] = useState(null); + + const router = useRouter(); + + // const subscriptionStatus = useAppSelector( + // (state) => state.user.user?.subscription?.status + // ); + // const freeTrialStatus = useAppSelector( + // (state) => state.user.user?.freeTrial.active + // ); + // const freeTrialDeactivationDate = useAppSelector( + // (state) => state.user.user?.freeTrial?.dateOfDeactivation + // ); + + // useEffect(() => { + // const checkTrialStatus = () => { + // const trialEndDate = new Date(freeTrialDeactivationDate!); + // const now = new Date(); + + // // If the subscription is active, do nothing (user is subscribed) + // if (subscriptionStatus === "active") { + // return; + // } + + // // If no active free trial or the free trial has expired, redirect to subscription plans + // if (!freeTrialStatus || now >= trialEndDate) { + // router.replace("/subscription-plans"); + // } else { + // // Calculate remaining time for the active free trial + // const remainingTime = Math.max( + // 0, + // Math.floor((trialEndDate.getTime() - now.getTime()) / 1000) + // ); + // setTimeLeft(remainingTime); + // } + // }; + + // checkTrialStatus(); + + // const timerInterval = setInterval(() => { + // checkTrialStatus(); + // }, 1000); + + // return () => clearInterval(timerInterval); + // }, [freeTrialDeactivationDate, freeTrialStatus, router, subscriptionStatus]); + + return ( +

    + {timeLeft !== null ? formatTime(timeLeft) : "Loading..."} +

    + ); +}; + +export default TrialPeriodTimer; diff --git a/src/pages/root/dashboard/_components/UpcomingWorkshops.tsx b/src/pages/root/dashboard/_components/UpcomingWorkshops.tsx new file mode 100644 index 0000000..6af9add --- /dev/null +++ b/src/pages/root/dashboard/_components/UpcomingWorkshops.tsx @@ -0,0 +1,64 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Ellipsis } from "lucide-react"; +import Image from "next/image"; +import React from "react"; + +const UpcomingWorkshops = () => { + return ( +
    +

    Upcoming Workshops

    + +
    +
    +
    + + Live +
    + +
    + +
    +
    + +
    +
    +

    + Study On Ocular Potential +

    +

    + It tells about Visual function +

    +

    + Meeting at 10AM, 27Feb 2024 +

    +
    +
    + + - By Doris Wilson + + {/*
    + Mentor Image +
    */} + + + + LA + + +
    +
    +
    +
    + ); +}; + +export default UpcomingWorkshops; diff --git a/src/pages/root/dashboard/_components/UserProfileSheet.tsx b/src/pages/root/dashboard/_components/UserProfileSheet.tsx new file mode 100644 index 0000000..2c5b57b --- /dev/null +++ b/src/pages/root/dashboard/_components/UserProfileSheet.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { + Sheet, + SheetContent, + SheetHeader, + SheetTrigger, +} from "@/components/ui/sheet"; +import { ArrowLeft } from "lucide-react"; +import ProfileBox from "./ProfileBox"; +import PointsBox from "./PointsBox"; +import TodaysVibe from "./TodaysVibe"; +import DailyStreakQuestions from "./DailyStreakQuestions"; +import UpcomingWorkshops from "./UpcomingWorkshops"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; + +import { useAppSelector } from "@/redux/hooks"; + +const UserProfileSheet = () => { + const user = useAppSelector((state) => state.user.user); + return ( + + + + + + {user?.firstname?.[0]} + + {user?.lastname ? user.lastname?.[0] : ""} + + + + + } + sheetCloseClassName="left-4" + > + + Profile + + + + + + + + + ); +}; + +export default UserProfileSheet; diff --git a/src/pages/root/dashboard/_components/_skeletons/ToDoSkeleton.tsx b/src/pages/root/dashboard/_components/_skeletons/ToDoSkeleton.tsx new file mode 100644 index 0000000..8eb1e6c --- /dev/null +++ b/src/pages/root/dashboard/_components/_skeletons/ToDoSkeleton.tsx @@ -0,0 +1,23 @@ +import { Skeleton } from "@/components/ui/skeleton"; +import React from "react"; + +const ToDoSkeleton = () => { + return ( +
    +
    + + +
    +
    + {Array.from({ length: 5 }).map((_, i) => ( +
    + + +
    + ))} +
    +
    + ); +}; + +export default ToDoSkeleton; diff --git a/src/pages/root/dashboard/page.tsx b/src/pages/root/dashboard/page.tsx new file mode 100644 index 0000000..509b116 --- /dev/null +++ b/src/pages/root/dashboard/page.tsx @@ -0,0 +1,29 @@ +"use client"; +import { getPlanner } from "../../../actions/planner_actions"; +import DesktopUI from "./_components/DesktopUI"; +// import MobileUI from "./_components/MobileUI"; +// import TabletUI from "./_components/TabletUI"; +import { DataProps } from "../../../helpers/types"; +import { getFormattedDate, getFormattedDateForProd } from "../../../helpers/utils"; + +const Dashboard = async () => { + const { data }: DataProps = await getPlanner(); + + return ( +
    + + process.env.NODE_ENV === "development" + ? getFormattedDate(new Date(item.date)) === + getFormattedDate(new Date(Date.now())) + : getFormattedDateForProd(new Date(item.date)) === + getFormattedDateForProd(new Date(Date.now())) + )[0] + } + /> +
    + ); +}; + +export default Dashboard; diff --git a/src/pages/root/layout.tsx b/src/pages/root/layout.tsx new file mode 100644 index 0000000..c7288f8 --- /dev/null +++ b/src/pages/root/layout.tsx @@ -0,0 +1,34 @@ +"use client"; +import type { Metadata } from "next"; +import Sidebar from "../../components/shared/Sidebar"; +import MobileMenu from "../../components/shared/MobileMenu"; + +export const metadata: Metadata = { + title: "Leadlly", + description: + "Say goodbye to one-size-fits-all! We tailor study plans and resources to your individual learning style and goals.", +}; + +export default function MainLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + const meetingsLength = 0; // Set a default value for meetingsLength + + return ( + <> +
    +
    + {/* Pass the default value */} +
    +
    + {children} +
    +
    +
    + {/* Pass the default value */} +
    + + ); +} diff --git a/vite.config.ts b/vite.config.ts index d36c010..a36e829 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,4 +9,7 @@ export default defineConfig({ "@": path.resolve(__dirname, "./src"), }, }, + define: { + 'process.env': {}, + }, }) \ No newline at end of file