From f990619e05cfb4d73337401f3bb7fb09c5742376 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Fri, 27 Sep 2024 11:06:54 -0600 Subject: [PATCH] more centralization --- nextjs/package-lock.json | 129 ++++++++++-------- nextjs/package.json | 2 +- .../modules/[moduleName]/pages/route.ts | 4 +- .../modules/[moduleName]/quizzes/route.ts | 4 +- .../[courseName]/modules/ExpandableModule.tsx | 16 +-- nextjs/src/hooks/hookHydration.ts | 52 ++----- .../src/hooks/localCourse/assignmentHooks.ts | 4 +- .../src/hooks/localCourse/localCourseKeys.ts | 8 +- .../localCourse/localCourseModuleHooks.ts | 66 ++------- nextjs/src/hooks/localCourse/pageHooks.ts | 69 +++++----- nextjs/src/hooks/localCourse/quizHooks.ts | 34 ++--- .../courseItemFileStorageService.ts | 39 ++++++ .../fileStorage/fileStorageService.ts | 3 +- 13 files changed, 205 insertions(+), 225 deletions(-) diff --git a/nextjs/package-lock.json b/nextjs/package-lock.json index 0cba1c3..54488c7 100644 --- a/nextjs/package-lock.json +++ b/nextjs/package-lock.json @@ -8,21 +8,13 @@ "name": "canvas-mangement", "version": "0.1.0", "dependencies": { - "@monaco-editor/react": "^4.6.0", - "@tanstack/react-query": "^5.54.1", - "axios": "^1.7.5", - "isomorphic-dompurify": "^2.15.0", - "katex": "^0.16.11", - "marked": "^14.1.2", - "marked-katex-extension": "^5.1.2", "next": "^14.2.7", "react": "^18", - "react-dom": "^18", - "react-error-boundary": "^4.0.13", - "react-hot-toast": "^2.4.1", - "yaml": "^2.5.0" + "react-dom": "^18" }, "devDependencies": { + "@monaco-editor/react": "^4.6.0", + "@tanstack/react-query": "^5.54.1", "@tanstack/react-query-devtools": "^5.54.1", "@testing-library/dom": "^10.4.0", "@testing-library/react": "^16.0.0", @@ -30,12 +22,18 @@ "@types/react": "^18", "@types/react-dom": "^18", "@vitejs/plugin-react": "^4.3.1", + "axios": "^1.7.5", "eslint-config-next": "^14.2.7", + "isomorphic-dompurify": "^2.15.0", "jsdom": "^25.0.0", + "marked": "^14.1.2", "postcss": "^8", + "react-error-boundary": "^4.0.13", + "react-hot-toast": "^2.4.1", "tailwindcss": "^3.4.1", "typescript": "^5", - "vitest": "^2.0.5" + "vitest": "^2.0.5", + "yaml": "^2.5.0" } }, "node_modules/@alloc/quick-lru": { @@ -400,6 +398,7 @@ "version": "7.25.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1087,6 +1086,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", + "dev": true, "license": "MIT", "dependencies": { "state-local": "^1.0.6" @@ -1099,6 +1099,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "dev": true, "license": "MIT", "dependencies": { "@monaco-editor/loader": "^1.4.0" @@ -1579,6 +1580,7 @@ "version": "5.54.1", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.54.1.tgz", "integrity": "sha512-hKS+WRpT5zBFip21pB6Jx1C0hranWQrbv5EJ7qPoiV5MYI3C8rTCqWC9DdBseiPT1JgQWh8Y55YthuYZNiw3Xw==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -1600,6 +1602,7 @@ "version": "5.54.1", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.54.1.tgz", "integrity": "sha512-SuMi4JBYv49UtmiRyqjxY7XAnE1qwLht9nlkC8sioxFXz5Uzj30lepiKf2mYXuXfC7fHYjTrAPkNx+427pRHXA==", + "dev": true, "license": "MIT", "dependencies": { "@tanstack/query-core": "5.54.1" @@ -1734,6 +1737,7 @@ "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": "*" @@ -1753,12 +1757,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/katex": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", - "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "22.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.2.tgz", @@ -1801,6 +1799,7 @@ "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/parser": { @@ -2094,6 +2093,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.4" @@ -2381,6 +2381,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, "license": "MIT" }, "node_modules/available-typed-arrays": { @@ -2413,6 +2414,7 @@ "version": "1.7.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -2710,6 +2712,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -2774,6 +2777,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, "license": "MIT", "dependencies": { "rrweb-cssom": "^0.6.0" @@ -2786,12 +2790,14 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, "license": "MIT" }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -2805,6 +2811,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, "license": "MIT", "dependencies": { "whatwg-mimetype": "^4.0.0", @@ -2872,6 +2879,7 @@ "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -2889,6 +2897,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, "license": "MIT" }, "node_modules/deep-eql": { @@ -2982,6 +2991,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -3049,6 +3059,7 @@ "version": "3.1.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", + "dev": true, "license": "(MPL-2.0 OR Apache-2.0)" }, "node_modules/eastasianwidth": { @@ -3090,6 +3101,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -3977,6 +3989,7 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, "funding": [ { "type": "individual", @@ -4024,6 +4037,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -4294,6 +4308,7 @@ "version": "2.1.14", "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz", "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==", + "dev": true, "license": "MIT", "peerDependencies": { "csstype": "^3.0.10" @@ -4418,6 +4433,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, "license": "MIT", "dependencies": { "whatwg-encoding": "^3.1.1" @@ -4430,6 +4446,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -4443,6 +4460,7 @@ "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.0.2", @@ -4466,6 +4484,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -4855,6 +4874,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, "license": "MIT" }, "node_modules/is-regex": { @@ -5025,6 +5045,7 @@ "version": "2.15.0", "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-2.15.0.tgz", "integrity": "sha512-RDHlyeVmwEDAPZuX1VaaBzSn9RrsfvswxH7faEQK9cTHC1dXeNuK6ElUeSr7locFyeLguut8ASfhQWxHB4Ttug==", + "dev": true, "license": "MIT", "dependencies": { "@types/dompurify": "^3.0.5", @@ -5102,6 +5123,7 @@ "version": "25.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dev": true, "license": "MIT", "dependencies": { "cssstyle": "^4.0.1", @@ -5204,31 +5226,6 @@ "node": ">=4.0" } }, - "node_modules/katex": { - "version": "0.16.11", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", - "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5373,6 +5370,7 @@ "version": "14.1.2", "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.2.tgz", "integrity": "sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ==", + "dev": true, "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -5381,19 +5379,6 @@ "node": ">= 18" } }, - "node_modules/marked-katex-extension": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/marked-katex-extension/-/marked-katex-extension-5.1.2.tgz", - "integrity": "sha512-jRtacvDAPULKBWArDno0IGpzzpUw12yb8OaEsv3dTlvcIr21+mF9kD+Bxo2m/ErX/2ZIml6zFVMnpxCpqx3stw==", - "license": "MIT", - "dependencies": { - "@types/katex": "^0.16.7" - }, - "peerDependencies": { - "katex": ">=0.16 <0.17", - "marked": ">=4 <15" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5429,6 +5414,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -5438,6 +5424,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==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -5496,6 +5483,7 @@ "version": "0.50.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz", "integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==", + "dev": true, "license": "MIT", "peer": true }, @@ -5503,6 +5491,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -5671,6 +5660,7 @@ "version": "2.2.12", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true, "license": "MIT" }, "node_modules/object-assign": { @@ -5917,6 +5907,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, "license": "MIT", "dependencies": { "entities": "^4.4.0" @@ -6289,18 +6280,21 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, "license": "MIT" }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6310,6 +6304,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, "license": "MIT" }, "node_modules/queue-microtask": { @@ -6362,6 +6357,7 @@ "version": "4.0.13", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" @@ -6374,6 +6370,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "dev": true, "license": "MIT", "dependencies": { "goober": "^2.1.10" @@ -6452,6 +6449,7 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, "license": "MIT" }, "node_modules/regexp.prototype.flags": { @@ -6477,6 +6475,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, "license": "MIT" }, "node_modules/resolve": { @@ -6610,6 +6609,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, "license": "MIT" }, "node_modules/run-parallel": { @@ -6677,12 +6677,14 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" @@ -6861,6 +6863,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "dev": true, "license": "MIT" }, "node_modules/std-env": { @@ -7202,6 +7205,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, "license": "MIT" }, "node_modules/tailwindcss": { @@ -7377,6 +7381,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", @@ -7392,6 +7397,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -7598,6 +7604,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4.0.0" @@ -7649,6 +7656,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, "license": "MIT", "dependencies": { "querystringify": "^2.1.1", @@ -7814,6 +7822,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, "license": "MIT", "dependencies": { "xml-name-validator": "^5.0.0" @@ -7826,6 +7835,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -7835,6 +7845,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -7847,6 +7858,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7856,6 +7868,7 @@ "version": "14.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, "license": "MIT", "dependencies": { "tr46": "^5.0.0", @@ -8105,6 +8118,7 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -8126,6 +8140,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -8135,6 +8150,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, "license": "MIT" }, "node_modules/yallist": { @@ -8148,6 +8164,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/nextjs/package.json b/nextjs/package.json index f5ce20c..ea5945c 100644 --- a/nextjs/package.json +++ b/nextjs/package.json @@ -6,7 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint", + "lint": "tsc && next lint", "test": "vitest" }, "dependencies": { diff --git a/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/pages/route.ts b/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/pages/route.ts index f41fa24..a1bfbd5 100644 --- a/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/pages/route.ts +++ b/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/pages/route.ts @@ -8,9 +8,9 @@ export const GET = async ( }: { params: { courseName: string; moduleName: string } } ) => await withErrorHandling(async () => { - const settings = await fileStorageService.pages.getPageNames( + const pages = await fileStorageService.pages.getPages( courseName, moduleName ); - return Response.json(settings); + return Response.json(pages); }); diff --git a/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/quizzes/route.ts b/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/quizzes/route.ts index 6e0d39e..ca0092d 100644 --- a/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/quizzes/route.ts +++ b/nextjs/src/app/api/courses/[courseName]/modules/[moduleName]/quizzes/route.ts @@ -8,9 +8,9 @@ export const GET = async ( }: { params: { courseName: string; moduleName: string } } ) => await withErrorHandling(async () => { - const settings = await fileStorageService.quizzes.getQuizNames( + const quizzes = await fileStorageService.quizzes.getQuizzes( courseName, moduleName ); - return Response.json(settings); + return Response.json(quizzes); }); diff --git a/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx b/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx index 147892a..4fa636c 100644 --- a/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx +++ b/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx @@ -1,13 +1,9 @@ "use client"; +import { useAssignmentsQueries } from "@/hooks/localCourse/assignmentHooks"; import { - useAssignmentsQueries, -} from "@/hooks/localCourse/assignmentHooks"; -import { - usePageNamesQuery, usePagesQueries, } from "@/hooks/localCourse/pageHooks"; import { - useQuizNamesQuery, useQuizzesQueries, } from "@/hooks/localCourse/quizHooks"; import { IModuleItem } from "@/models/local/IModuleItem"; @@ -33,15 +29,11 @@ export default function ExpandableModule({ }: { moduleName: string; }) { - const { data: quizNames } = useQuizNamesQuery(moduleName); - const { data: pageNames } = usePageNamesQuery(moduleName); const { itemDropOnModule } = useDraggingContext(); - const { data: assignments } = useAssignmentsQueries( - moduleName, - ); - const { data: quizzes } = useQuizzesQueries(moduleName, quizNames); - const { data: pages } = usePagesQueries(moduleName, pageNames); + const { data: assignments } = useAssignmentsQueries(moduleName); + const { data: quizzes } = useQuizzesQueries(moduleName); + const { data: pages } = usePagesQueries(moduleName); const [expanded, setExpanded] = useState(false); diff --git a/nextjs/src/hooks/hookHydration.ts b/nextjs/src/hooks/hookHydration.ts index af505aa..1efd60d 100644 --- a/nextjs/src/hooks/hookHydration.ts +++ b/nextjs/src/hooks/hookHydration.ts @@ -73,16 +73,16 @@ export const hydrateCanvasCourse = async ( }; const loadAllModuleData = async (courseName: string, moduleName: string) => { - const [assignmentNames, pageNames, quizNames] = await Promise.all([ + const [assignmentNames, pages, quizzes] = await Promise.all([ await fileStorageService.assignments.getAssignmentNames( courseName, moduleName ), - await fileStorageService.pages.getPageNames(courseName, moduleName), - await fileStorageService.quizzes.getQuizNames(courseName, moduleName), + await fileStorageService.pages.getPages(courseName, moduleName), + await fileStorageService.quizzes.getQuizzes(courseName, moduleName), ]); - const [assignments, quizzes, pages] = await Promise.all([ + const [assignments] = await Promise.all([ await Promise.all( assignmentNames.map(async (assignmentName) => { try { @@ -97,33 +97,11 @@ const loadAllModuleData = async (courseName: string, moduleName: string) => { } }) ), - await Promise.all( - quizNames.map( - async (quizName) => - await fileStorageService.quizzes.getQuiz( - courseName, - moduleName, - quizName - ) - ) - ), - await Promise.all( - pageNames.map( - async (pageName) => - await fileStorageService.pages.getPage( - courseName, - moduleName, - pageName - ) - ) - ), ]); - const assignmentsLoaded = assignments.filter(a => a !== null); + const assignmentsLoaded = assignments.filter((a) => a !== null); return { moduleName, - pageNames, - quizNames, assignments: assignmentsLoaded, quizzes, pages, @@ -133,15 +111,11 @@ const loadAllModuleData = async (courseName: string, moduleName: string) => { const hydrateModuleData = async ( { moduleName, - pageNames, - quizNames, assignments, quizzes, pages, }: { moduleName: string; - pageNames: string[]; - quizNames: string[]; assignments: LocalAssignment[]; quizzes: LocalQuiz[]; pages: LocalCoursePage[]; @@ -153,6 +127,14 @@ const hydrateModuleData = async ( queryKey: localCourseKeys.allAssignments(courseName, moduleName), queryFn: () => assignments, }); + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), + queryFn: () => quizzes, + }); + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.allPages(courseName, moduleName), + queryFn: () => pages, + }); await Promise.all( assignments.map( async (assignment) => @@ -166,10 +148,6 @@ const hydrateModuleData = async ( }) ) ); - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), - queryFn: () => quizNames, - }); await Promise.all( quizzes.map( async (quiz) => @@ -179,10 +157,6 @@ const hydrateModuleData = async ( }) ) ); - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), - queryFn: () => pageNames, - }); await Promise.all( pages.map( async (page) => diff --git a/nextjs/src/hooks/localCourse/assignmentHooks.ts b/nextjs/src/hooks/localCourse/assignmentHooks.ts index f8a47b8..4f2cbfc 100644 --- a/nextjs/src/hooks/localCourse/assignmentHooks.ts +++ b/nextjs/src/hooks/localCourse/assignmentHooks.ts @@ -28,7 +28,7 @@ export const getAllAssignmentsQueryConfig = ( }, }); -export const useAllAssignmentNamesQuery = (moduleName: string) => { +const useAllAssignmentsQuery = (moduleName: string) => { const { courseName } = useCourseContext(); return useSuspenseQuery(getAllAssignmentsQueryConfig(courseName, moduleName)); }; @@ -70,7 +70,7 @@ export const useAssignmentQuery = ( }; export const useAssignmentsQueries = (moduleName: string) => { - const { data: allAssignments } = useAllAssignmentNamesQuery(moduleName); + const { data: allAssignments } = useAllAssignmentsQuery(moduleName); const { courseName } = useCourseContext(); return useSuspenseQueries({ queries: allAssignments.map((assignment) => diff --git a/nextjs/src/hooks/localCourse/localCourseKeys.ts b/nextjs/src/hooks/localCourse/localCourseKeys.ts index 30d7587..1d1412c 100644 --- a/nextjs/src/hooks/localCourse/localCourseKeys.ts +++ b/nextjs/src/hooks/localCourse/localCourseKeys.ts @@ -19,23 +19,23 @@ export const localCourseKeys = { "assignments", { type: "all assignments" }, ] as const, - quizNames: (courseName: string, moduleName: string) => + allQuizzes: (courseName: string, moduleName: string) => [ "course details", courseName, "modules", moduleName, "quizzes", - { type: "names" }, + { type: "all quizzes" }, ] as const, - pageNames: (courseName: string, moduleName: string) => + allPages: (courseName: string, moduleName: string) => [ "course details", courseName, "modules", moduleName, "pages", - { type: "names" }, + { type: "all pages" }, ] as const, assignment: ( courseName: string, diff --git a/nextjs/src/hooks/localCourse/localCourseModuleHooks.ts b/nextjs/src/hooks/localCourse/localCourseModuleHooks.ts index 81d5d30..51b1aba 100644 --- a/nextjs/src/hooks/localCourse/localCourseModuleHooks.ts +++ b/nextjs/src/hooks/localCourse/localCourseModuleHooks.ts @@ -11,8 +11,8 @@ import { getAllAssignmentsQueryConfig, getAssignmentQueryConfig, } from "./assignmentHooks"; -import { getPageNamesQueryConfig, getPageQueryConfig } from "./pageHooks"; -import { getQuizNamesQueryConfig, getQuizQueryConfig } from "./quizHooks"; +import { getAllPagesQueryConfig, getPageQueryConfig } from "./pageHooks"; +import { getAllQuizzesQueryConfig, getQuizQueryConfig } from "./quizHooks"; export const useModuleNamesQuery = () => { const { courseName } = useCourseContext(); @@ -92,57 +92,15 @@ export const useAllCourseDataQuery = () => { }), }); - // const { data: assignmentsAndModules } = useSuspenseQueries({ - // queries: assignmentsAndModules.map( - // ({ moduleName, assignment }, i) => - // getAssignmentQueryConfig(courseName, moduleName, assignment) - // ), - // combine: (results) => ({ - // data: results.flatMap((r, i) => ({ - // moduleName: assignmentsAndModules[i].moduleName, - // assignment: r.data, - // })), - // pending: results.some((r) => r.isPending), - // }), - // }); - - const { data: quizNamesAndModules } = useSuspenseQueries({ - queries: moduleNames.map((moduleName) => - getQuizNamesQueryConfig(courseName, moduleName) - ), - combine: (results) => ({ - data: results.flatMap((r, i) => - r.data.map((quizName) => ({ - moduleName: moduleNames[i], - quizName: quizName, - })) - ), - pending: results.some((r) => r.isPending), - }), - }); - const { data: quizzesAndModules } = useSuspenseQueries({ - queries: quizNamesAndModules.map(({ moduleName, quizName }, i) => - getQuizQueryConfig(courseName, moduleName, quizName) - ), - combine: (results) => ({ - data: results.flatMap((r, i) => ({ - moduleName: quizNamesAndModules[i].moduleName, - quiz: r.data, - })), - pending: results.some((r) => r.isPending), - }), - }); - - const { data: pageNamesAndModules } = useSuspenseQueries({ queries: moduleNames.map((moduleName) => - getPageNamesQueryConfig(courseName, moduleName) + getAllQuizzesQueryConfig(courseName, moduleName) ), combine: (results) => ({ data: results.flatMap((r, i) => - r.data.map((pageName) => ({ + r.data.map((quiz) => ({ moduleName: moduleNames[i], - pageName, + quiz, })) ), pending: results.some((r) => r.isPending), @@ -150,14 +108,16 @@ export const useAllCourseDataQuery = () => { }); const { data: pagesAndModules } = useSuspenseQueries({ - queries: pageNamesAndModules.map(({ moduleName, pageName }, i) => - getPageQueryConfig(courseName, moduleName, pageName) + queries: moduleNames.map((moduleName) => + getAllPagesQueryConfig(courseName, moduleName) ), combine: (results) => ({ - data: results.flatMap((r, i) => ({ - moduleName: pageNamesAndModules[i].moduleName, - page: r.data, - })), + data: results.flatMap((r, i) => + r.data.map((page) => ({ + moduleName: moduleNames[i], + page, + })) + ), pending: results.some((r) => r.isPending), }), }); diff --git a/nextjs/src/hooks/localCourse/pageHooks.ts b/nextjs/src/hooks/localCourse/pageHooks.ts index 6327dac..dbbe302 100644 --- a/nextjs/src/hooks/localCourse/pageHooks.ts +++ b/nextjs/src/hooks/localCourse/pageHooks.ts @@ -10,13 +10,10 @@ import { localCourseKeys } from "./localCourseKeys"; import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; import { axiosClient } from "@/services/axiosUtils"; -export function getPageNamesQueryConfig( - courseName: string, - moduleName: string -) { +export function getAllPagesQueryConfig(courseName: string, moduleName: string) { return { - queryKey: localCourseKeys.pageNames(courseName, moduleName), - queryFn: async (): Promise => { + queryKey: localCourseKeys.allPages(courseName, moduleName), + queryFn: async (): Promise => { const url = "/api/courses/" + encodeURIComponent(courseName) + @@ -29,29 +26,6 @@ export function getPageNamesQueryConfig( }; } -export const usePageNamesQuery = (moduleName: string) => { - const { courseName } = useCourseContext(); - return useSuspenseQuery(getPageNamesQueryConfig(courseName, moduleName)); -}; - -export const usePageQuery = (moduleName: string, pageName: string) => { - const { courseName } = useCourseContext(); - return useSuspenseQuery(getPageQueryConfig(courseName, moduleName, pageName)); -}; - -export const usePagesQueries = (moduleName: string, pageNames: string[]) => { - const { courseName } = useCourseContext(); - return useSuspenseQueries({ - queries: pageNames.map((name) => - getPageQueryConfig(courseName, moduleName, name) - ), - combine: (results) => ({ - data: results.map((r) => r.data), - pending: results.some((r) => r.isPending), - }), - }); -}; - export function getPageQueryConfig( courseName: string, moduleName: string, @@ -72,13 +46,37 @@ export function getPageQueryConfig( return response.data; } catch (e) { console.log("error getting page", e, url); - debugger; throw e; } }, }; } +export const usePageQuery = (moduleName: string, pageName: string) => { + const { courseName } = useCourseContext(); + return useSuspenseQuery(getPageQueryConfig(courseName, moduleName, pageName)); +}; + +const useAllPagesQuery = (moduleName: string) => { + const { courseName } = useCourseContext(); + return useSuspenseQuery(getAllPagesQueryConfig(courseName, moduleName)); +}; + +export const usePagesQueries = (moduleName: string) => { + const { courseName } = useCourseContext(); + const { data: allPages } = useAllPagesQuery(moduleName); + return useSuspenseQueries({ + queries: allPages.map((page) => ({ + ...getPageQueryConfig(courseName, moduleName, page.name), + queryFn: () => page, + })), + combine: (results) => ({ + data: results.map((r) => r.data), + pending: results.some((r) => r.isPending), + }), + }); +}; + export const useUpdatePageMutation = () => { const { courseName } = useCourseContext(); const queryClient = useQueryClient(); @@ -109,7 +107,7 @@ export const useUpdatePageMutation = () => { ), }); queryClient.removeQueries({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryKey: localCourseKeys.allPages(courseName, moduleName), }); } queryClient.setQueryData( @@ -131,7 +129,7 @@ export const useUpdatePageMutation = () => { }, onSuccess: async (_, { moduleName, pageName }) => { await queryClient.invalidateQueries({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryKey: localCourseKeys.allPages(courseName, moduleName), }); await queryClient.invalidateQueries({ queryKey: localCourseKeys.page(courseName, moduleName, pageName), @@ -171,7 +169,7 @@ export const useCreatePageMutation = () => { queryKey: localCourseKeys.page(courseName, moduleName, pageName), }); queryClient.invalidateQueries({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryKey: localCourseKeys.allPages(courseName, moduleName), }); }, }); @@ -192,7 +190,7 @@ export const useDeletePageMutation = () => { queryKey: localCourseKeys.page(courseName, moduleName, pageName), }); queryClient.removeQueries({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryKey: localCourseKeys.allPages(courseName, moduleName), }); const url = "/api/courses/" + @@ -202,11 +200,10 @@ export const useDeletePageMutation = () => { "/pages/" + encodeURIComponent(pageName); await axiosClient.delete(url); - }, onSuccess: async (_, { moduleName, pageName }) => { await queryClient.invalidateQueries({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryKey: localCourseKeys.allPages(courseName, moduleName), }); await queryClient.invalidateQueries({ queryKey: localCourseKeys.page(courseName, moduleName, pageName), diff --git a/nextjs/src/hooks/localCourse/quizHooks.ts b/nextjs/src/hooks/localCourse/quizHooks.ts index 60ed308..0352037 100644 --- a/nextjs/src/hooks/localCourse/quizHooks.ts +++ b/nextjs/src/hooks/localCourse/quizHooks.ts @@ -10,13 +10,13 @@ import { localCourseKeys } from "./localCourseKeys"; import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; import { axiosClient } from "@/services/axiosUtils"; -export function getQuizNamesQueryConfig( +export function getAllQuizzesQueryConfig( courseName: string, moduleName: string ) { return { - queryKey: localCourseKeys.quizNames(courseName, moduleName), - queryFn: async (): Promise => { + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), + queryFn: async (): Promise => { const url = "/api/courses/" + encodeURIComponent(courseName) + @@ -28,22 +28,24 @@ export function getQuizNamesQueryConfig( }, }; } -export const useQuizNamesQuery = (moduleName: string) => { - const { courseName } = useCourseContext(); - return useSuspenseQuery(getQuizNamesQueryConfig(courseName, moduleName)); -}; export const useQuizQuery = (moduleName: string, quizName: string) => { const { courseName } = useCourseContext(); return useSuspenseQuery(getQuizQueryConfig(courseName, moduleName, quizName)); }; -export const useQuizzesQueries = (moduleName: string, quizNames: string[]) => { +const useAllQuizzesQuery = (moduleName: string) => { const { courseName } = useCourseContext(); + return useSuspenseQuery(getAllQuizzesQueryConfig(courseName, moduleName)); +}; +export const useQuizzesQueries = (moduleName: string) => { + const { courseName } = useCourseContext(); + const { data: allQuizzes } = useAllQuizzesQuery(moduleName); return useSuspenseQueries({ - queries: quizNames.map((name) => - getQuizQueryConfig(courseName, moduleName, name) - ), + queries: allQuizzes.map((quiz) => ({ + ...getQuizQueryConfig(courseName, moduleName, quiz.name), + queryFn: () => quiz, + })), combine: (results) => ({ data: results.map((r) => r.data), pending: results.some((r) => r.isPending), @@ -102,7 +104,7 @@ export const useUpdateQuizMutation = () => { ), }); queryClient.removeQueries({ - queryKey: localCourseKeys.quizNames(courseName, previousModuleName), + queryKey: localCourseKeys.allQuizzes(courseName, previousModuleName), }); } queryClient.setQueryData( @@ -128,7 +130,7 @@ export const useUpdateQuizMutation = () => { }, onSuccess: async (_, { moduleName, quizName }) => { await queryClient.invalidateQueries({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), }); await queryClient.invalidateQueries({ queryKey: localCourseKeys.quiz(courseName, moduleName, quizName), @@ -165,7 +167,7 @@ export const useCreateQuizMutation = () => { }, onSuccess: async (_, { moduleName, quizName }) => { await queryClient.invalidateQueries({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), }); await queryClient.invalidateQueries({ queryKey: localCourseKeys.quiz(courseName, moduleName, quizName), @@ -194,12 +196,12 @@ export const useDeleteQuizMutation = () => { encodeURIComponent(quizName); await axiosClient.delete(url); queryClient.removeQueries({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), }); }, onSuccess: async (_, { moduleName, quizName }) => { await queryClient.invalidateQueries({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), + queryKey: localCourseKeys.allQuizzes(courseName, moduleName), }); await queryClient.invalidateQueries({ queryKey: localCourseKeys.quiz(courseName, moduleName, quizName), diff --git a/nextjs/src/services/fileStorage/courseItemFileStorageService.ts b/nextjs/src/services/fileStorage/courseItemFileStorageService.ts index ad2363d..04a423e 100644 --- a/nextjs/src/services/fileStorage/courseItemFileStorageService.ts +++ b/nextjs/src/services/fileStorage/courseItemFileStorageService.ts @@ -13,6 +13,8 @@ import { LocalCoursePage, localPageMarkdownUtils, } from "@/models/local/page/localCoursePage"; +import { assignmentMarkdownSerializer } from "@/models/local/assignment/utils/assignmentMarkdownSerializer"; +import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils"; const typeToFolder = { Assignment: "assignments", @@ -99,4 +101,41 @@ export const courseItemFileStorageService = { ).filter((a) => a !== null); return items; }, + async updateOrCreateAssignment({ + courseName, + moduleName, + name, + item, + type, + }: { + courseName: string; + moduleName: string; + name: string; + item: LocalAssignment | LocalQuiz | LocalCoursePage; + type: CourseItemType; + }) { + const typeFolder = typeToFolder[type]; + const folder = path.join(basePath, courseName, moduleName, typeFolder); + await fs.mkdir(folder, { recursive: true }); + + const filePath = path.join( + basePath, + courseName, + moduleName, + typeFolder, + name + ".md" + ); + + const markdownDictionary: { + [key in CourseItemType]: () => string; + } = { + Assignment: () => assignmentMarkdownSerializer.toMarkdown(item as LocalAssignment), + Quiz: () => quizMarkdownUtils.toMarkdown(item as LocalQuiz), + Page: () => localPageMarkdownUtils.toMarkdown(item as LocalCoursePage), + }; + const itemMarkdown = markdownDictionary[type](); + + console.log(`Saving ${type} ${filePath}`); + await fs.writeFile(filePath, itemMarkdown); + }, }; diff --git a/nextjs/src/services/fileStorage/fileStorageService.ts b/nextjs/src/services/fileStorage/fileStorageService.ts index 2e8dce4..e0d48dd 100644 --- a/nextjs/src/services/fileStorage/fileStorageService.ts +++ b/nextjs/src/services/fileStorage/fileStorageService.ts @@ -13,7 +13,6 @@ export const fileStorageService = { assignments: assignmentsFileStorageService, quizzes: quizFileStorageService, pages: pageFileStorageService, - async getEmptyDirectories(): Promise { if (!(await directoryOrFileExists(basePath))) { @@ -48,7 +47,7 @@ export const fileStorageService = { await fs.mkdir(courseDirectory, { recursive: true }); }, async createModuleFolderForTesting(courseName: string, moduleName: string) { - const courseDirectory = path.join(basePath, courseName); + const courseDirectory = path.join(basePath, courseName, moduleName); await fs.mkdir(courseDirectory, { recursive: true }); },