diff --git a/package-lock.json b/package-lock.json index 97c2a09..67b3c09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ }, "devDependencies": { "@eslint/js": "^9.25.0", + "@types/node": "^25.9.1", "@types/react": "^19.1.2", "@types/react-dom": "^19.1.2", "@typescript-eslint/eslint-plugin": "^8.54.0", @@ -1072,9 +1073,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", - "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", "cpu": [ "arm" ], @@ -1085,9 +1086,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", - "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", "cpu": [ "arm64" ], @@ -1098,9 +1099,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", - "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", "cpu": [ "arm64" ], @@ -1111,9 +1112,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", - "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", "cpu": [ "x64" ], @@ -1124,9 +1125,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", - "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", "cpu": [ "arm64" ], @@ -1137,9 +1138,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", - "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", "cpu": [ "x64" ], @@ -1150,9 +1151,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", - "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", "cpu": [ "arm" ], @@ -1163,9 +1164,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", - "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", "cpu": [ "arm" ], @@ -1176,9 +1177,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", - "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", "cpu": [ "arm64" ], @@ -1189,9 +1190,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", - "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", "cpu": [ "arm64" ], @@ -1201,10 +1202,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", - "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", "cpu": [ "loong64" ], @@ -1214,10 +1215,36 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", - "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", "cpu": [ "ppc64" ], @@ -1228,9 +1255,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", - "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", "cpu": [ "riscv64" ], @@ -1241,9 +1268,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", - "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", "cpu": [ "riscv64" ], @@ -1254,9 +1281,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", - "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", "cpu": [ "s390x" ], @@ -1267,9 +1294,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz", - "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", "cpu": [ "x64" ], @@ -1280,9 +1307,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz", - "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", "cpu": [ "x64" ], @@ -1292,10 +1319,36 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", - "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", "cpu": [ "arm64" ], @@ -1306,9 +1359,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", - "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", "cpu": [ "ia32" ], @@ -1318,10 +1371,23 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", - "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", "cpu": [ "x64" ], @@ -2122,6 +2188,16 @@ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "license": "MIT" }, + "node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, "node_modules/@types/react": { "version": "19.1.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", @@ -2328,21 +2404,23 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2447,10 +2525,22 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2489,16 +2579,19 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" } }, "node_modules/balanced-match": { @@ -2509,9 +2602,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -2556,6 +2649,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -2653,6 +2747,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -2675,12 +2770,16 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/crelt": { @@ -2825,7 +2924,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "dependencies": { "ms": "^2.1.3" }, @@ -2854,6 +2952,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -2871,6 +2970,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -2916,6 +3016,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2924,14 +3025,16 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -2943,6 +3046,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -3288,16 +3392,16 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -3315,9 +3419,10 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -3353,6 +3458,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3371,6 +3477,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -3394,6 +3501,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -3432,6 +3540,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3459,6 +3568,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3470,6 +3580,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -3481,9 +3592,10 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -3500,6 +3612,19 @@ "react-is": "^16.7.0" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3911,9 +4036,19 @@ } }, "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" @@ -3982,14 +4117,24 @@ } }, "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", - "linkify-it": "^5.0.0", + "linkify-it": "^5.0.1", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" @@ -4002,6 +4147,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -4015,6 +4161,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4023,6 +4170,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -4031,9 +4179,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -4053,9 +4201,9 @@ } }, "node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "license": "MIT", "dependencies": { "minipass": "^7.1.2" @@ -4064,32 +4212,16 @@ "node": ">= 18" } }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -4223,9 +4355,10 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -4234,9 +4367,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -4253,7 +4386,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -4478,10 +4611,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/punycode": { "version": "2.3.1", @@ -4613,9 +4749,9 @@ } }, "node_modules/react-router": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.2.tgz", - "integrity": "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==", + "version": "7.15.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.1.tgz", + "integrity": "sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -4635,12 +4771,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.2.tgz", - "integrity": "sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==", + "version": "7.15.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.1.tgz", + "integrity": "sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==", "license": "MIT", "dependencies": { - "react-router": "7.6.2" + "react-router": "7.15.1" }, "engines": { "node": ">=20.0.0" @@ -4708,9 +4844,9 @@ } }, "node_modules/rollup": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz", - "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -4723,26 +4859,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.44.1", - "@rollup/rollup-android-arm64": "4.44.1", - "@rollup/rollup-darwin-arm64": "4.44.1", - "@rollup/rollup-darwin-x64": "4.44.1", - "@rollup/rollup-freebsd-arm64": "4.44.1", - "@rollup/rollup-freebsd-x64": "4.44.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.44.1", - "@rollup/rollup-linux-arm-musleabihf": "4.44.1", - "@rollup/rollup-linux-arm64-gnu": "4.44.1", - "@rollup/rollup-linux-arm64-musl": "4.44.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.44.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1", - "@rollup/rollup-linux-riscv64-gnu": "4.44.1", - "@rollup/rollup-linux-riscv64-musl": "4.44.1", - "@rollup/rollup-linux-s390x-gnu": "4.44.1", - "@rollup/rollup-linux-x64-gnu": "4.44.1", - "@rollup/rollup-linux-x64-musl": "4.44.1", - "@rollup/rollup-win32-arm64-msvc": "4.44.1", - "@rollup/rollup-win32-ia32-msvc": "4.44.1", - "@rollup/rollup-win32-x64-msvc": "4.44.1", + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", "fsevents": "~2.3.2" } }, @@ -4772,9 +4913,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/shebang-command": { @@ -4851,16 +4992,15 @@ } }, "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "license": "ISC", + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", + "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "engines": { @@ -4969,7 +5109,15 @@ "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "devOptional": true, + "license": "MIT" }, "node_modules/update-browserslist-db": { "version": "1.1.3", @@ -5043,9 +5191,10 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/package.json b/package.json index e021f37..1bd76d5 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ }, "devDependencies": { "@eslint/js": "^9.25.0", + "@types/node": "^25.9.1", "@types/react": "^19.1.2", "@types/react-dom": "^19.1.2", "@typescript-eslint/eslint-plugin": "^8.54.0", diff --git a/src/App.tsx b/src/App.tsx index eaef918..765a019 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -28,6 +28,16 @@ import Dashboard from "./Pages/Dashboard"; import EditFaq from "./Pages/EditFAQ"; import EditFeedback from "./Pages/EditFeedback"; import EditLowongan from "./Pages/EditLowongan"; +import HomeInternPage from "./Pages/internify/intern/HomeInternPage"; +import {InternLayout, MentorLayout} from "./Pages/internify/layout"; +import ProjectsPage from "./Pages/internify/intern/ProjectsPage"; +import SertificatePage from "./Pages/internify/intern/SertificatePage"; +import ProjectDetailPage from "./Pages/internify/intern/ProjectDetailPage"; +import HomeMentorPage from "./Pages/internify/mentor/HomeMentorPage"; +import MentorProjectsPage from "./Pages/internify/mentor/MentorProjectsPage"; +import MentorCertificatePage from "./Pages/internify/mentor/MentorCertificatePage"; +import MentorInternPage from "./Pages/internify/mentor/MentorInternPage"; +import MentorDetailProject from "./Pages/internify/mentor/MentorDetailProject"; function App() { return ( @@ -42,9 +52,9 @@ function App() { } /> } /> } /> - {/* Endpoint khusus admin login langsung di inject ajah */} - }> + {/* Endpoint khusus admin login langsung di inject ajah */} + }> } /> } /> } /> @@ -52,10 +62,7 @@ function App() { } /> } /> } /> - } - /> + }/> } /> } /> } /> @@ -64,10 +71,27 @@ function App() { } /> } /> } /> - }> - }> - }> + }> + }> + }> + + + {/* // Endpoints for intern-specific pages */} + }> + } /> + } /> + } /> + }/> + + + }> + }/> + } /> + } /> + } /> + }/> + ); diff --git a/src/Pages/internify/Header.tsx b/src/Pages/internify/Header.tsx new file mode 100644 index 0000000..c9190bf --- /dev/null +++ b/src/Pages/internify/Header.tsx @@ -0,0 +1,25 @@ +import { Bell } from "lucide-react" +import humiclogo from "../../assets/logo.png"; + +const Header = () => { + return ( +
+
+ Humic Logo +
+ +
+ +
+ +
+
+
+ ) +} + +export default Header diff --git a/src/Pages/internify/intern/HomeInternPage.tsx b/src/Pages/internify/intern/HomeInternPage.tsx new file mode 100644 index 0000000..8c93a95 --- /dev/null +++ b/src/Pages/internify/intern/HomeInternPage.tsx @@ -0,0 +1,26 @@ +import HomeHeader from "./components/HomeHeader"; +import HomeProjectList from "./components/HomeProjectList"; +import HomeCalendar from "./components/HomeCalendar"; +import TaskTimeline from "./components/TaskTImeline"; + +// PR: tambahin breadcrumb +export default function HomeInternPage() { + return ( +
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/Pages/internify/intern/ProjectDetailPage.tsx b/src/Pages/internify/intern/ProjectDetailPage.tsx new file mode 100644 index 0000000..961b10e --- /dev/null +++ b/src/Pages/internify/intern/ProjectDetailPage.tsx @@ -0,0 +1,71 @@ +import { useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { mockProjects } from '../../../lib/mockData'; +import ForumTab from './ProjectForum'; +import ParticipantsTab from './ProjectParticipants'; +import { ChevronLeft } from 'lucide-react'; + +// ─── ProjectDetailPage ───────────────────────────────────────────────────────── +export default function ProjectDetailPage() { + const { id } = useParams<{ id: string }>(); + const navigate = useNavigate(); + const [activeTab, setActiveTab] = useState<'forum' | 'participants'>('forum'); + + const handleBack = () => { + if (window.history.length > 1) { + navigate(-1); + } else { + navigate('/intern/projects'); + } + }; + + const project = mockProjects.find((p) => p.id === Number(id)); + + if (!project) { + return ( +
+ Project tidak ditemukan. +
+ ); + } + + const tabClass = (tab: string) => + `pr-0 py-2.5 mr-7 text-sm bg-transparent border-0 cursor-pointer transition-colors duration-150 border-b-2 ${activeTab === tab + ? 'font-bold text-[#C0392B] border-[#C0392B]' + : 'font-medium text-[#666] border-transparent' + }`; + + return ( +
+
+ + {/* Back Button */} + + + {/* Tabs */} +
+ + +
+ + {/* Tab content */} + {activeTab === 'forum' + ? + : + } +
+
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/ProjectForum.tsx b/src/Pages/internify/intern/ProjectForum.tsx new file mode 100644 index 0000000..67cd5cb --- /dev/null +++ b/src/Pages/internify/intern/ProjectForum.tsx @@ -0,0 +1,26 @@ +import type { Project } from '../../../lib/mockData'; +import ProjectTimeline from './components/ProjectTimeline'; +import TaskCard from './components/ProjectTaskCard'; +import HeroProject from './components/Hero-project'; + +export default function ForumTab({ project }: { project: Project }) { + return ( +
+ {/* Hero banner */} + + + {/* Timeline + Task list */} +
+
+ +
+ +
+ {project.tasks.map((task, idx) => ( + + ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/ProjectParticipants.tsx b/src/Pages/internify/intern/ProjectParticipants.tsx new file mode 100644 index 0000000..5e71a80 --- /dev/null +++ b/src/Pages/internify/intern/ProjectParticipants.tsx @@ -0,0 +1,45 @@ +import type { Project, Intern } from '../../../lib/mockData'; + +export default function ParticipantsTab({ project }: { project: Project }) { + return ( +
+ {/* Mentor */} +
+

+ Mentor +

+
+
+ + {project.mentor} + +
+
+
+ + {/* Members */} +
+

+ Members +

+ {project.interns.map((intern: Intern, idx: number) => ( +
+
+ + {intern.email} + +
+ + {intern.role} + +
+ ))} +
+
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/ProjectsPage.tsx b/src/Pages/internify/intern/ProjectsPage.tsx new file mode 100644 index 0000000..496d7ec --- /dev/null +++ b/src/Pages/internify/intern/ProjectsPage.tsx @@ -0,0 +1,20 @@ +import ProjectCard from './components/ProjectsCard' +import { mockProjects } from '../../../lib/mockData' + +export default function ProjectsPage() { + return ( +
+
+ List Projects +

View assigned projects and track their progress.

+
+ + {/* Grid card */} +
+ {mockProjects.map(project => ( + + ))} +
+
+ ) +} \ No newline at end of file diff --git a/src/Pages/internify/intern/SertificatePage.tsx b/src/Pages/internify/intern/SertificatePage.tsx new file mode 100644 index 0000000..d2c1ad9 --- /dev/null +++ b/src/Pages/internify/intern/SertificatePage.tsx @@ -0,0 +1,18 @@ +const SertificatePage = () => { + return ( +
+
+

Certificates

+

View and download internship certificates

+
+
+
+ +
+ +
+
+ ) +} + +export default SertificatePage diff --git a/src/Pages/internify/intern/components/FooterIntern.tsx b/src/Pages/internify/intern/components/FooterIntern.tsx new file mode 100644 index 0000000..2c40392 --- /dev/null +++ b/src/Pages/internify/intern/components/FooterIntern.tsx @@ -0,0 +1,79 @@ +import { Briefcase, Globe, Users } from 'lucide-react'; +import { useNavigate } from 'react-router-dom'; + +const footerLinks = { + Internship: [ + { label: "Beranda", path: "/" }, + { label: "Tentang", path: "/tentang" }, + { label: "Life At Humic", path: "/life" }, + ], + "Internify Logo": [ + { label: "Humic Website", path: "/humic" }, + { label: "Our Activity", path: "/activity" }, + { label: "Life At Humic", path: "/life-humic" }, + { label: "Our Developer", path: "/developer" }, + ], +}; + +const socials = [ + { label: "Website", icon: Globe, href: "https://placeholder.com" }, + { label: "Team", icon: Users, href: "https://placeholder.com" }, + { label: "Work", icon: Briefcase, href: "https://placeholder.com" }, +]; + + +export function FooterIntern() { + const navigate = useNavigate(); + + return ( +
+ {/* Brand info */} +
+

Internify Logo

+
+ Gedung Kultubai Selatan, Blok F
+ Jl. Telekomunikasi, Terusan Buah Batu Bandung
+ Jawa Barat, Indonesia. 40257 +
+
+ {socials.map(({ label, icon: Icon, href }) => ( + + + + ))} +
+
+ + {/* Link columns */} +
+ {Object.entries(footerLinks).map(([title, links]) => ( +
+

{title}

+
    + {links.map(({ label, path }) => ( +
  • + +
  • + ))} +
+
+ ))} +
+
+ ); +} + + +export default FooterIntern diff --git a/src/Pages/internify/intern/components/Hero-project.tsx b/src/Pages/internify/intern/components/Hero-project.tsx new file mode 100644 index 0000000..c1f6946 --- /dev/null +++ b/src/Pages/internify/intern/components/Hero-project.tsx @@ -0,0 +1,26 @@ +interface HeroProps { + title: string, + description: string +} + +export default function HeroProject({ title, description }: HeroProps) { + return ( +
+ {/* Decorative circles */} +
+
+ +

+ {title.toUpperCase()} +

+ {description.split('\n\n').map((para, i) => ( +

+ {para} +

+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/components/HomeCalendar.tsx b/src/Pages/internify/intern/components/HomeCalendar.tsx new file mode 100644 index 0000000..af11681 --- /dev/null +++ b/src/Pages/internify/intern/components/HomeCalendar.tsx @@ -0,0 +1,181 @@ +import { useState } from 'react' +import { ChevronLeft, ChevronRight } from 'lucide-react' + +interface Deadline { + date: number + month: number + year: number + label: string +} + +const DEADLINES: Deadline[] = [ + { date: 4, month: 4, year: 2025, label: 'Laporan Progress 1 Internify– 4 May' }, + { date: 5, month: 4, year: 2025, label: 'Laporan Progress 1 Internify– 4 May' }, +] + +const DAY_LABELS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] +const MONTH_NAMES = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December', +] + +function getDaysInMonth(year: number, month: number) { + return new Date(year, month + 1, 0).getDate() +} + +function getFirstDayOfMonth(year: number, month: number) { + return new Date(year, month, 1).getDay() +} + +const HomeCalendar = () => { + const today = new Date() + const [currentYear, setCurrentYear] = useState(2025) + const [currentMonth, setCurrentMonth] = useState(4) // May = 4 (0-indexed) + + const daysInMonth = getDaysInMonth(currentYear, currentMonth) + const firstDay = getFirstDayOfMonth(currentYear, currentMonth) + + const prevMonth = () => { + if (currentMonth === 0) { + setCurrentMonth(11) + setCurrentYear(y => y - 1) + } else { + setCurrentMonth(m => m - 1) + } + } + + const nextMonth = () => { + if (currentMonth === 11) { + setCurrentMonth(0) + setCurrentYear(y => y + 1) + } else { + setCurrentMonth(m => m + 1) + } + } + + const isToday = (day: number) => + day === today.getDate() && + currentMonth === today.getMonth() && + currentYear === today.getFullYear() + + const hasDeadline = (day: number) => + DEADLINES.some(d => d.date === day && d.month === currentMonth && d.year === currentYear) + + const upcomingDeadlines = DEADLINES.filter( + d => d.month === currentMonth && d.year === currentYear + ) + + // Previous month trailing days + const prevMonthDays = getDaysInMonth(currentYear, currentMonth - 1 < 0 ? 11 : currentMonth - 1) + const trailingDays = Array.from({ length: firstDay }, (_, i) => prevMonthDays - firstDay + 1 + i) + + // Current month days + const currentDays = Array.from({ length: daysInMonth }, (_, i) => i + 1) + + // Next month leading days + const totalCells = Math.ceil((firstDay + daysInMonth) / 7) * 7 + const leadingDays = Array.from({ length: totalCells - firstDay - daysInMonth }, (_, i) => i + 1) + + // Bold dates (weekends or special) + const isBold = (day: number) => { + const d = new Date(currentYear, currentMonth, day).getDay() + return d === 0 || d === 6 // Sun or Sat + } + + return ( +
+ {/* Header */} +
+

+ {MONTH_NAMES[currentMonth]} {currentYear} +

+
+ + +
+
+ + {/* Day labels */} +
+ {DAY_LABELS.map(day => ( +
+ {day} +
+ ))} +
+ + {/* Calendar grid */} +
+ {/* Trailing days from prev month */} + {trailingDays.map(day => ( +
+ {day} +
+ ))} + + {/* Current month days */} + {currentDays.map(day => ( +
+ {isToday(day) ? ( + + {day} + + ) : ( + + {day} + + )} +
+ ))} + + {/* Leading days from next month */} + {leadingDays.map(day => ( +
+ {day} +
+ ))} +
+ + {/* Divider */} +
+ + {/* Upcoming Deadlines */} +
+

+ Upcoming Deadlines +

+ {upcomingDeadlines.length > 0 ? ( +
    + {upcomingDeadlines.map((d, i) => ( +
  • + + {d.label} +
  • + ))} +
+ ) : ( +

No upcoming deadlines this month.

+ )} +
+
+ ) +} + +export default HomeCalendar \ No newline at end of file diff --git a/src/Pages/internify/intern/components/HomeHeader.tsx b/src/Pages/internify/intern/components/HomeHeader.tsx new file mode 100644 index 0000000..6545db4 --- /dev/null +++ b/src/Pages/internify/intern/components/HomeHeader.tsx @@ -0,0 +1,12 @@ +const HomeHeader = () => { + const name = "Karina"; + return ( +
+
+

Hi, {name}!

+
+
+ ) +} + +export default HomeHeader diff --git a/src/Pages/internify/intern/components/HomeProjectList.tsx b/src/Pages/internify/intern/components/HomeProjectList.tsx new file mode 100644 index 0000000..167a9e1 --- /dev/null +++ b/src/Pages/internify/intern/components/HomeProjectList.tsx @@ -0,0 +1,40 @@ +import { Code2, ChessKing, Beef } from 'lucide-react' +import { useNavigate } from 'react-router-dom' +import { mockProjects } from '../../../../lib/mockData' + +interface Project { + name: string + role: string + logo: React.ElementType + iconBg: string + iconColor: string +} + +const HomeProjectList = () => { + const navigate = useNavigate(); + return ( +
+

Projects

+
+ {mockProjects.map((project, index) => { + return ( +
navigate(`/intern/projects/${project.id}`)} + className="flex items-center gap-4 border border-gray-200 rounded-lg px-4 py-3 hover:bg-gray-50 cursor-pointer transition-colors duration-150" + > +
+
+
+

{project.name}

+ {/*

{project.role}

*/} +
+
+ ) + })} +
+
+ ) +} + +export default HomeProjectList \ No newline at end of file diff --git a/src/Pages/internify/intern/components/ProjectTaskCard.tsx b/src/Pages/internify/intern/components/ProjectTaskCard.tsx new file mode 100644 index 0000000..c0d005f --- /dev/null +++ b/src/Pages/internify/intern/components/ProjectTaskCard.tsx @@ -0,0 +1,34 @@ +import type { Task } from "../../../../lib/mockData"; + +const formatDate = (date: Date) => + new Date(date).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); + +export default function TaskCard({ task }: { task: Task }) { + return ( +
+
+
+ Deadline : {formatDate(task.deadline.date)} at {task.deadline.time} +
+
+ {task.title} +
+
+ {task.description} +
+
+ +
+ {task.isSubmitted ? ( + + DONE + + ) : ( + + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/components/ProjectTimeline.tsx b/src/Pages/internify/intern/components/ProjectTimeline.tsx new file mode 100644 index 0000000..3430820 --- /dev/null +++ b/src/Pages/internify/intern/components/ProjectTimeline.tsx @@ -0,0 +1,48 @@ +import type { Task } from "../../../../lib/mockData"; + +const formatDate = (date: Date) => + new Date(date).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); + +export default function ProjectTimeline({ tasks }: { tasks: Task[] }) { + const today = new Date(); + today.setHours(0, 0, 0, 0); + + return ( +
+
+ + Timeline + +
+ +
    + {tasks.map((task, idx) => { + const d = new Date(task.deadline.date); + d.setHours(0, 0, 0, 0); + const isToday = d.getTime() === today.getTime(); + const isPast = d < today; + const active = isToday || isPast; + + return ( +
  • + {/* Dot */} +
    +
    + {isToday ? 'Hari ini' : formatDate(task.deadline.date)} +
    +
    + {task.title} +
    +
  • + ); + })} +
+
+ ); +} \ No newline at end of file diff --git a/src/Pages/internify/intern/components/ProjectsCard.tsx b/src/Pages/internify/intern/components/ProjectsCard.tsx new file mode 100644 index 0000000..56af5f0 --- /dev/null +++ b/src/Pages/internify/intern/components/ProjectsCard.tsx @@ -0,0 +1,76 @@ +import { useNavigate } from 'react-router-dom' + +interface ProjectCardProps { + id: number | string + name: string + mentor: string + avatarUrl?: string + thumbnailUrl?: string + progress: number + tasksDone: number + tasksTotal: number +} + +const ProjectCard = ({ + id, + name, + mentor, + avatarUrl, + thumbnailUrl, + progress, + tasksDone, + tasksTotal, +}: ProjectCardProps) => { + const navigate = useNavigate() + + return ( +
+ {/* Thumbnail */} +
+ {thumbnailUrl && ( + {name} + )} +
+ + {/* Content */} +
+

{name}

+ + {/* Mentor */} +
+
+ {avatarUrl ? ( + {mentor} + ) : ( +
+ )} +
+ {mentor} +
+ + {/* Progress bar */} +
+
+
+
+ + {tasksDone}/{tasksTotal} + +
+ + {/* Button */} + +
+
+ ) +} + +export default ProjectCard \ No newline at end of file diff --git a/src/Pages/internify/intern/components/SidebarIntern.tsx b/src/Pages/internify/intern/components/SidebarIntern.tsx new file mode 100644 index 0000000..5bcaca2 --- /dev/null +++ b/src/Pages/internify/intern/components/SidebarIntern.tsx @@ -0,0 +1,97 @@ +import { useNavigate } from 'react-router-dom'; +import { Home, FolderKanban, Award, Settings, HelpCircle, LogOut, ChevronRight } from 'lucide-react'; +import { useState } from 'react'; + +const navItems = [ + { label: "Home", icon: Home, path: "/intern" }, + { label: "List Projects", icon: FolderKanban, path: "/intern/projects" }, + { label: "Certificates", icon: Award, path: "/intern/certificates" }, +]; + +const prefItems = [ + { label: "Settings", icon: Settings, path: "/intern/settings" }, + { label: "FAQ", icon: HelpCircle, path: "/intern/faq" }, + { label: "Logout", icon: LogOut, path: "/intern/logout", danger: true }, +]; + +function SidebarIntern() { + const navigate = useNavigate(); + const [active, setActive] = useState("/intern"); + + const handleNav = (path: string) => { + setActive(path); + navigate(path); + }; + + return ( + + ); +} + + +export default SidebarIntern diff --git a/src/Pages/internify/intern/components/TaskTimeline.tsx b/src/Pages/internify/intern/components/TaskTimeline.tsx new file mode 100644 index 0000000..b10a66d --- /dev/null +++ b/src/Pages/internify/intern/components/TaskTimeline.tsx @@ -0,0 +1,79 @@ +interface Task { + tanggal: string + title: string + description: string +} + +interface TaskTimelineProps { + tasks?: Task[] +} + +const defaultTasks: Task[] = [ + { + tanggal: 'MAY 14, 2026 AT 23:59 PM', + title: 'Laporan tugas 1', + description: 'Berisi design uiux, dan user flow dari aplikasi internify', + }, + { + tanggal: 'MAY 15, 2026 AT 23:59 PM', + title: 'Laporan tugas 1', + description: 'Berisi design uiux, dan user flow dari aplikasi internify', + }, + { + tanggal: 'MAY 16, 2026 AT 23:59 PM', + title: 'Laporan tugas 1', + description: 'Berisi design uiux, dan user flow dari aplikasi internify', + }, +] + +const TaskTimeline = ({ tasks = defaultTasks }: TaskTimelineProps) => { + const today = new Date() + + const isOverdue = (tanggal: string) => { + const deadline = new Date(tanggal) + return deadline < today + } + + return ( +
+

Task Timeline

+ +
+ {/* Vertical line */} +
+ +
    + {tasks.map((task, index) => { + const overdue = isOverdue(task.tanggal) + + return ( +
  • + {/* Dot */} +
    + +
    + + {/* Content */} +
    +

    + {task.tanggal} +

    +

    {task.title}

    +

    {task.description}

    +
    +
  • + ) + })} +
+
+
+ ) +} + +export default TaskTimeline \ No newline at end of file diff --git a/src/Pages/internify/layout.tsx b/src/Pages/internify/layout.tsx new file mode 100644 index 0000000..122cf7c --- /dev/null +++ b/src/Pages/internify/layout.tsx @@ -0,0 +1,36 @@ +import { Outlet } from "react-router-dom"; +import Header from './Header'; +import SidebarIntern from './intern/components/SidebarIntern'; +import SidebarAdmin from '../../Layout/SidebarAdmin'; +import FooterIntern from './intern/components/FooterIntern'; + +export const InternLayout = () => { + return ( +
+
+
+ +
+ +
+
+ +
+ ); +}; + +export const MentorLayout = () => { + return ( +
+
+
+ +
+ +
+
+ +
+ ) +} + diff --git a/src/Pages/internify/mentor/HomeMentorPage.tsx b/src/Pages/internify/mentor/HomeMentorPage.tsx new file mode 100644 index 0000000..87fcabb --- /dev/null +++ b/src/Pages/internify/mentor/HomeMentorPage.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const HomeMentorPage = () => { + return ( +
+ +
+ ) +} + +export default HomeMentorPage diff --git a/src/Pages/internify/mentor/MentorCertificatePage.tsx b/src/Pages/internify/mentor/MentorCertificatePage.tsx new file mode 100644 index 0000000..39e7621 --- /dev/null +++ b/src/Pages/internify/mentor/MentorCertificatePage.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const MentorCertificatePage = () => { + return ( +
+ +
+ ) +} + +export default MentorCertificatePage diff --git a/src/Pages/internify/mentor/MentorDetailProject.tsx b/src/Pages/internify/mentor/MentorDetailProject.tsx new file mode 100644 index 0000000..d19c1d0 --- /dev/null +++ b/src/Pages/internify/mentor/MentorDetailProject.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const MentorDetailProject = () => { + return ( +
+ +
+ ) +} + +export default MentorDetailProject diff --git a/src/Pages/internify/mentor/MentorInternPage.tsx b/src/Pages/internify/mentor/MentorInternPage.tsx new file mode 100644 index 0000000..e01ae40 --- /dev/null +++ b/src/Pages/internify/mentor/MentorInternPage.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const MentorInternPage = () => { + return ( +
+ +
+ ) +} + +export default MentorInternPage diff --git a/src/Pages/internify/mentor/MentorProjectsPage.tsx b/src/Pages/internify/mentor/MentorProjectsPage.tsx new file mode 100644 index 0000000..f8f040d --- /dev/null +++ b/src/Pages/internify/mentor/MentorProjectsPage.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const MentorProjectsPage = () => { + return ( +
+ +
+ ) +} + +export default MentorProjectsPage diff --git a/src/Pages/internify/mentor/SidebarMentor.tsx b/src/Pages/internify/mentor/SidebarMentor.tsx new file mode 100644 index 0000000..bf0fb08 --- /dev/null +++ b/src/Pages/internify/mentor/SidebarMentor.tsx @@ -0,0 +1,99 @@ +import { useNavigate } from 'react-router-dom'; +import { Home, FolderKanban, Award, Settings, HelpCircle, LogOut, ChevronRight } from 'lucide-react'; +import { useState } from 'react'; + +const navItems = [ + // belum kutambahin + { label: "Home", icon: Home, path: "" }, + { label: "List Projects", icon: FolderKanban, path: "" }, + { label: "Interns", icon: FolderKanban, path: "" }, + { label: "Certificates", icon: Award, path: "" }, +]; + +const prefItems = [ + { label: "Settings", icon: Settings, path: "/home-intern/settings" }, + { label: "FAQ", icon: HelpCircle, path: "/home-intern/faq" }, + { label: "Logout", icon: LogOut, path: "/home-intern/logout", danger: true }, +]; + +function SidebarIntern() { + const navigate = useNavigate(); + const [active, setActive] = useState("/home-intern"); + + const handleNav = (path: string) => { + setActive(path); + navigate(path); + }; + + return ( + + ); +} + + +export default SidebarIntern diff --git a/src/Pages/utils/InternRoute.tsx b/src/Pages/utils/InternRoute.tsx new file mode 100644 index 0000000..bde4c6d --- /dev/null +++ b/src/Pages/utils/InternRoute.tsx @@ -0,0 +1,18 @@ +// App.tsx / router.tsx +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import HomeInternPage from "../internify/intern/HomeInternPage"; +import InternLayout from "../internify/layout"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + children: [ + { path: "home", element: }, + ], + }, +]); + +export default function App() { + return ; +} \ No newline at end of file diff --git a/src/lib/mockData.ts b/src/lib/mockData.ts new file mode 100644 index 0000000..5f9eb7c --- /dev/null +++ b/src/lib/mockData.ts @@ -0,0 +1,219 @@ +export interface Deadline { + date: Date; + label: string; + time: string; +} + +export const DEADLINES: Deadline[] = [ + { + date: new Date(2025, 4, 4), // May 4, 2025 + label: "Laporan Progress 1 Internify – 4 Juni", + time: "23:59 PM", + }, + { + date: new Date(2026, 5, 5), + label: "Laporan Progress 2 Internify - 5 May", + time: "23:59 PM", + }, +]; + +export const deadlineDates: Date[] = DEADLINES.map((d) => d.date); + +export interface Task { + title: string; + description: string; + deadline: Deadline; + isSubmitted: boolean; +} + +export interface Intern { + name: string; + role: string; + email: string; +} + +export interface Project { + id: number; + name: string; + description: string; + tasks: Task[]; + interns: Intern[]; + mentor: string; + avatarUrl?: string; + thumbnailUrl?: string; + progress: number; + tasksDone: number; + tasksTotal: number; +} + +export const mockProjects: Project[] = [ + { + id: 1, + name: "Internify Project", + description: + "Internify merupakan website Human Capital (HUMC) yang dirancang sebagai platform pendaftaran dan pengelolaan program magang secara digital. Sistem ini dibuat untuk membantu proses rekrutmen peserta magang mulai dari pendaftaran, seleksi, hingga monitoring aktivitas peserta selama program berlangsung.\n\nFokus utama dari pengembangan Internify adalah pembuatan Learning Management System (LMS) yang digunakan untuk mendukung kegiatan pembelajaran dan pengelolaan peserta magang. LMS pada Internify menyediakan fitur seperti akses materi pembelajaran, pengumpulan tugas, monitoring progress peserta, absensi, sertifikat, hingga komunikasi antara mentor dan peserta magang.", + tasks: [ + { + title: "Laporan tugas", + description: "Berisi design ulux, dan user flow dari aplikasi internify", + deadline: { date: new Date(2026, 4, 1), label: "Laporan tugas – 1 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Laporan tugas 1", + description: "Berisi design ulux, dan user flow dari aplikasi internify", + deadline: { date: new Date(2026, 4, 14), label: "Laporan tugas 1 – 14 Mei", time: "23:59 PM" }, + isSubmitted: false, + }, + { + title: "Laporan tugas 2", + description: "Berisi design ulux, dan user flow dari aplikasi internify", + deadline: { date: new Date(2026, 4, 28), label: "Laporan tugas 2 – 28 Mei", time: "23:59 PM" }, + isSubmitted: false, + }, + { + title: "Laporan tugas 3", + description: "Berisi wireframe halaman dashboard aplikasi internify", + deadline: { date: new Date(2026, 5, 5), label: "Laporan tugas 3 – 5 Jun", time: "23:59 PM" }, + isSubmitted: false, + }, + ], + interns: [ + { name: "Jonathan Kristina", role: "Backend", email: "jonathankristina@gmail.com" }, + { name: "Anisa Rahmawati", role: "Backend", email: "jonathankristina@gmail.com" }, + { name: "Budi Santoso", role: "Frontend", email: "jonathankristina@gmail.com" }, + { name: "Cindy Permata", role: "Frontend", email: "jonathankristina@gmail.com" }, + { name: "Dewa Aditya", role: "UI/UX", email: "jonathankristina@gmail.com" }, + { name: "Eka Pratiwi", role: "UI/UX", email: "jonathankristina@gmail.com" }, + ], + mentor: "jonathankristina@gmail.com", + progress: 12, + tasksDone: 1, + tasksTotal: 8, + }, + { + id: 2, + name: "Rekrutmen Digital Platform", + description: + "Platform digital yang memudahkan proses rekrutmen karyawan baru secara end-to-end. Mulai dari posting lowongan, screening CV otomatis, penjadwalan wawancara, hingga onboarding karyawan baru.\n\nSistem ini mengintegrasikan berbagai modul HR seperti manajemen data kandidat, penilaian kompetensi berbasis AI, dan dashboard analytics untuk tim HR dalam mengambil keputusan rekrutmen yang lebih efektif dan efisien.", + tasks: [ + { + title: "Analisis Kebutuhan Sistem", + description: "Dokumentasi kebutuhan fungsional dan non-fungsional platform rekrutmen", + deadline: { date: new Date(2026, 4, 5), label: "Analisis Kebutuhan – 5 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Desain Database Schema", + description: "Rancangan struktur database untuk kandidat, lowongan, dan proses seleksi", + deadline: { date: new Date(2026, 4, 10), label: "Desain Database – 10 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Implementasi Auth Module", + description: "Pengembangan sistem autentikasi dan otorisasi multi-role", + deadline: { date: new Date(2026, 4, 18), label: "Auth Module – 18 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Modul Posting Lowongan", + description: "Fitur buat, edit, dan publish lowongan pekerjaan", + deadline: { date: new Date(2026, 4, 25), label: "Posting Lowongan – 25 Mei", time: "23:59 PM" }, + isSubmitted: false, + }, + ], + interns: [ + { name: "Fajar Nugroho", role: "Backend", email: "fajarnugroho@gmail.com" }, + { name: "Gita Melinda", role: "Backend", email: "gitamelinda@gmail.com" }, + { name: "Hendra Wijaya", role: "Frontend", email: "hendrawijaya@gmail.com" }, + { name: "Indira Sari", role: "Frontend", email: "indirasari@gmail.com" }, + { name: "Joko Purnomo", role: "UI/UX", email: "jokopurnomo@gmail.com" }, + { name: "Kartika Dewi", role: "QA", email: "kartikadewi@gmail.com" }, + { name: "Lukman Hakim", role: "QA", email: "lukmanhakim@gmail.com" }, + ], + mentor: "seniormHR@company.com", + progress: 37, + tasksDone: 3, + tasksTotal: 8, + }, + { + id: 3, + name: "E-Commerce Analytics Dashboard", + description: + "Dashboard analitik komprehensif untuk platform e-commerce yang menyajikan insight real-time tentang performa penjualan, perilaku pelanggan, dan efektivitas kampanye marketing.\n\nProyek ini mencakup pengembangan pipeline data dari berbagai sumber transaksi, visualisasi interaktif menggunakan chart library modern, serta fitur export laporan dalam berbagai format untuk kebutuhan manajemen bisnis.", + tasks: [ + { + title: "Setup Pipeline Data", + description: "Konfigurasi ETL pipeline dari database transaksi ke data warehouse", + deadline: { date: new Date(2026, 4, 3), label: "Setup Pipeline – 3 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Desain Komponen Chart", + description: "Pembuatan reusable chart component untuk berbagai tipe visualisasi data", + deadline: { date: new Date(2026, 4, 12), label: "Komponen Chart – 12 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Dashboard Overview Page", + description: "Halaman utama dengan ringkasan KPI dan metric utama bisnis", + deadline: { date: new Date(2026, 4, 20), label: "Overview Page – 20 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + { + title: "Laporan Penjualan", + description: "Modul analitik penjualan dengan filter periode dan kategori produk", + deadline: { date: new Date(2026, 4, 28), label: "Laporan Penjualan – 28 Mei", time: "23:59 PM" }, + isSubmitted: true, + }, + ], + interns: [ + { name: "Maya Anggraeni", role: "Backend", email: "mayaanggraeni@gmail.com" }, + { name: "Nando Pratama", role: "Backend", email: "nandopratama@gmail.com" }, + { name: "Olivia Susanto", role: "Frontend", email: "oliviasusanto@gmail.com" }, + { name: "Pandu Kusuma", role: "Frontend", email: "pandukukusuma@gmail.com" }, + { name: "Qori Ramadhan", role: "Data Analyst", email: "qoriramadhan@gmail.com" }, + { name: "Rini Handayani", role: "UI/UX", email: "rinihandayani@gmail.com" }, + ], + mentor: "leadanalyst@company.com", + progress: 50, + tasksDone: 4, + tasksTotal: 8, + }, +]; + +export const certificateData = { + isReceived: true, // ubah ke false untuk tampilan "belum tersedia" + projectProgress: 65, + remainingTasks: 3, + certificate: { + id: "INF-2024-88392", + issuedDate: "24 Oct 2024", + recipientName: "JonathanKristina", + programName: "Internify Project", + duration: "8 Minggu", + finalScore: 94, + grade: "A", + status: "VERIFIED", + }, + history: [ + { + id: 1, + month: "Juni 2023", + title: "Web Development Fundamentals", + grade: "A+", + }, + { + id: 2, + month: "Maret 2023", + title: "UI/UX Design Essentials", + grade: "A", + }, + { + id: 3, + month: "Januari 2023", + title: "Data Analytics Bootcamp", + grade: "B+", + }, + ], +};