From 2179f39814801a8be21b6f48323c5a7516e22b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Alexander=20Str=C3=B8mseng?= Date: Sat, 27 Apr 2024 17:16:09 +0200 Subject: [PATCH] Refactoring zustand (#367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip refactor * quick dev fix, needs more work * wip refactor * fix warning * more refactoring and fixes * finally working fixes * more fixes and refactoring * fix add button * remove type def causing build error * add comment * fix build warning and errors * create nominal types and fix bugs * more type annotations and converting to satNumToEntry * install knip to find unused files, and add dependency not listed * remove unused files * remove unused type export * remove last uses of name to entry * remove unused store functions * fix bugs caused by removing state * rename ouiImage to placeholder image * 89 docs testing (#358) * docs(docs): :memo: write docs for testing Co-authored-by: Jakob , Co-authored-by: Lucas * chore(ide): add docs scope to conventional commits * docs(docs): :memo: Co-authored-by: Jakob , Co-authored-by: Lucas * docs(docs): :memo: add test file location to documentation * docs(docs): :memo: Update docs for component testing * test(docs): :memo: update docs for testing * docs(docs): :memo: Update docs for frontend, backend, general usage and root * docs(docs): :memo: update readmes and remove yarn from command lines since we only use npm * fix: :bug: prettier * docs(docs): :memo: add prettier info * docs(docs): :memo: write ESLint docs --------- Co-authored-by: Mats Nyfløt Co-authored-by: Jakob , Co-authored-by: Lucas Co-authored-by: Jakob Grøtan Gregusson Co-authored-by: Mads Hermansen * 319 strapi docs (#364) * Strapi docs * Strapi backend docs * docs(backend): :memo: Update docs --------- Co-authored-by: Lucas Tran Co-authored-by: Mads Hermansen * feat(frontend): :art: add text to select satellite button (#297) * feat(frontend): :art: add text to select satellite button * style(frontend): :art: Update SatDropdown component to display selected satellite and add icon * Update SatDropdown component to display selected satellite and add icon --------- Co-authored-by: Mads Hermansen * Update autoredeploy.yml checkout version to v4 * fix build error * rename env variables, add new strapi url variable for https fix --------- Co-authored-by: luctra02 <64017398+luctra02@users.noreply.github.com> Co-authored-by: Mats Nyfløt Co-authored-by: Jakob , Co-authored-by: Lucas Co-authored-by: Jakob Grøtan Gregusson Co-authored-by: Mads Hermansen Co-authored-by: EliasKnudsen <38568225+EliasKnudsen@users.noreply.github.com> Co-authored-by: Lucas Tran --- .github/workflows/autoredeploy.yml | 60 +-- backend/.env.example | 14 +- backend/config/env/production/server.js | 11 + backend/config/server.js | 9 +- frontend/.env.development | 4 +- frontend/.env.production | 4 +- frontend/knip.ts | 8 + frontend/package-lock.json | 455 +++++++++++++++++- frontend/package.json | 9 +- frontend/src/app/blog/[articleSlug]/page.tsx | 12 +- frontend/src/app/layout.tsx | 15 +- .../src/app/projects/[projectSlug]/page.tsx | 2 +- frontend/src/app/projects/page.tsx | 6 +- .../app/satellites/[satelliteSlug]/page.tsx | 9 +- frontend/src/components/2dmap/Map2d.tsx | 18 +- frontend/src/components/ExternalLink.tsx | 13 - frontend/src/components/HeroWrapper.tsx | 2 +- .../RelatedProjectsAndSatellites.tsx | 6 +- .../components/SatelliteResponsiveTable.tsx | 3 + frontend/src/components/fullBlogCard.tsx | 4 +- .../components/homeComponents/SatDropdown.tsx | 74 +-- .../homeComponents/SatelliteSelector.tsx | 12 +- .../components/homeComponents/homeGlobe.tsx | 148 +++--- .../satelliteData/SatelliteDataHome.tsx | 9 +- .../satelliteData/SatelliteDataIndividual.tsx | 85 ---- .../satelliteData/SatelliteInitialFetch.tsx | 16 +- .../satelliteData/SatelliteStatsTable.tsx | 103 ---- .../satelliteData/SatelliteStatsTableRow.tsx | 20 +- .../{exampleSatData.js => _exampleSatData.js} | 0 frontend/src/components/ui/satelliteCard.tsx | 67 --- .../src/components/wrappers/ApolloWrapper.tsx | 2 +- frontend/src/lib/ApolloClient.js | 2 +- frontend/src/lib/convertSatrec.ts | 3 +- frontend/src/lib/data/fetchArticleInfo.tsx | 2 +- frontend/src/lib/data/fetchFeaturedImage.tsx | 6 +- frontend/src/lib/data/fetchSatelliteInfo.ts | 11 +- .../src/lib/data/fetchSatelliteNamesAndId.ts | 23 +- frontend/src/lib/getSatelliteData.ts | 41 +- frontend/src/lib/helpers.ts | 27 +- frontend/src/lib/mapHelpers.ts | 42 -- frontend/src/lib/store.ts | 102 ++-- .../SolarActivity/SolarData.tsx | 0 .../scrollLinkedDiv.tsx | 0 .../separator.tsx | 0 44 files changed, 847 insertions(+), 612 deletions(-) create mode 100644 backend/config/env/production/server.js create mode 100644 frontend/knip.ts delete mode 100644 frontend/src/components/ExternalLink.tsx delete mode 100644 frontend/src/components/satelliteData/SatelliteDataIndividual.tsx delete mode 100644 frontend/src/components/satelliteData/SatelliteStatsTable.tsx rename frontend/src/components/satelliteData/{exampleSatData.js => _exampleSatData.js} (100%) delete mode 100644 frontend/src/components/ui/satelliteCard.tsx delete mode 100644 frontend/src/lib/mapHelpers.ts rename frontend/src/{components => unused_work_for_later_improvements}/SolarActivity/SolarData.tsx (100%) rename frontend/src/{components/ui => unused_work_for_later_improvements}/scrollLinkedDiv.tsx (100%) rename frontend/src/{components/ui => unused_work_for_later_improvements}/separator.tsx (100%) diff --git a/.github/workflows/autoredeploy.yml b/.github/workflows/autoredeploy.yml index 114348e..3986ca0 100644 --- a/.github/workflows/autoredeploy.yml +++ b/.github/workflows/autoredeploy.yml @@ -1,33 +1,35 @@ name: Server auto deploy on: - push: - branches: ["main"] + push: + branches: ["main"] jobs: - docker-build: - strategy: - matrix: - node-version: [20.x] - runs-on: self-hosted - steps: - - uses: actions/checkout@v4 - - name: Stop and remove containers and images, using docker compose down - run: docker-compose down --rmi "all" - - name: Create .env files - run: | - # Create .env with all variables except HOST_URL Backend - echo "HOST=${{ vars.HOST }}" >> .env - echo "PORT=${{ vars.PORT }}" >> .env - echo "DATABASE_CLIENT=${{ vars.DATABASE_CLIENT }}" >> .env - echo "DATABASE_FILENAME=${{ vars.DATABASE_FILENAME }}" >> .env - echo "ADMIN_JWT_SECRET=${{ secrets.ADMIN_JWT_SECRET }}" >> .env - echo "API_TOKEN_SALT=${{ secrets.API_TOKEN_SALT }}" >> .env - echo "APP_KEYS=${{ secrets.APP_KEYS }}" >> .env - echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env - echo "TRANSFER_TOKEN_SALT=${{ secrets.TRANSFER_TOKEN_SALT }}" >> .env - # Create .env.production with HOST_URL Frontend - echo "STRAPI_URL=${{ vars.STRAPI_URL }}" >> .env.production - - name: Docker build - run: docker-compose build - - name: Docker up - run: docker-compose up -d + docker-build: + strategy: + matrix: + node-version: [20.x] + runs-on: self-hosted + steps: + - uses: actions/checkout@v4 + - name: Stop and remove containers and images, using docker compose down + run: docker-compose down --rmi "all" + - name: Create .env files + run: | + # Create .env with all variables except HOST_URL Backend + echo "HOST=${{ vars.HOST }}" >> .env + echo "PORT=${{ vars.PORT }}" >> .env + echo "DATABASE_CLIENT=${{ vars.DATABASE_CLIENT }}" >> .env + echo "DATABASE_FILENAME=${{ vars.DATABASE_FILENAME }}" >> .env + echo "STRAPI_URL=${{ vars.STRAPI_URL }}" >> .env + echo "ADMIN_JWT_SECRET=${{ secrets.ADMIN_JWT_SECRET }}" >> .env + echo "API_TOKEN_SALT=${{ secrets.API_TOKEN_SALT }}" >> .env + echo "APP_KEYS=${{ secrets.APP_KEYS }}" >> .env + echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env + echo "TRANSFER_TOKEN_SALT=${{ secrets.TRANSFER_TOKEN_SALT }}" >> .env + + # Create .env.production with HOST_URL Frontend + echo "BACKEND_INTERNAL_URL=${{ vars.BACKEND_INTERNAL_URL }}" >> .env.production + - name: Docker build + run: docker-compose build + - name: Docker up + run: docker-compose up -d diff --git a/backend/.env.example b/backend/.env.example index 0ba278a..680ee45 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,10 +1,14 @@ +# All these should be set in the GitHub Repository actions and secrets at https://github.com/NTNU-SmallSat-Lab/outreach-website/settings/variables/actions +# Any changes done here will not be reflected in the production environment +# All variables named toBeGenerated should be generated with the command `openssl rand -base64 32` HOST=0.0.0.0 PORT=1337 -APP_KEYS="toBeModified1,toBeModified2" -API_TOKEN_SALT=tobemodified -ADMIN_JWT_SECRET=tobemodified -TRANSFER_TOKEN_SALT=tobemodified -JWT_SECRET=tobemodified +STRAPI_URL="https://hypso.space/strapi/" +APP_KEYS="toBeGenerated1,toBeGenerated2" +API_TOKEN_SALT=toBeGenerated +ADMIN_JWT_SECRET=toBeGenerated +TRANSFER_TOKEN_SALT=toBeGenerated +JWT_SECRET=toBeGenerated DATABASE_CLIENT=sqlite DATABASE_FILENAME=dbLocation.sqlite # in dev, will use backend root dir, in prod, will be from server os root dir so should be /var/data/strapi.db or similar diff --git a/backend/config/env/production/server.js b/backend/config/env/production/server.js new file mode 100644 index 0000000..cc66640 --- /dev/null +++ b/backend/config/env/production/server.js @@ -0,0 +1,11 @@ +module.exports = ({ env }) => ({ + host: env("HOST", "127.0.0.1"), + port: env.int("PORT", 1337), + app: { + keys: env.array("APP_KEYS"), + }, + webhooks: { + populateRelations: env.bool("WEBHOOKS_POPULATE_RELATIONS", false), + }, + url: env("STRAPI_URL", "http://localhost:1337"), +}); diff --git a/backend/config/server.js b/backend/config/server.js index 08cc4ef..fe927ab 100644 --- a/backend/config/server.js +++ b/backend/config/server.js @@ -1,11 +1,10 @@ module.exports = ({ env }) => ({ - host: env('HOST', '127.0.0.1'), - port: env.int('PORT', 1337), + host: env("HOST", "127.0.0.1"), + port: env.int("PORT", 1337), app: { - keys: env.array('APP_KEYS'), + keys: env.array("APP_KEYS"), }, webhooks: { - populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false), + populateRelations: env.bool("WEBHOOKS_POPULATE_RELATIONS", false), }, - url: "https://hypso.space/strapi/" }); diff --git a/frontend/.env.development b/frontend/.env.development index 6daed48..a67a9b9 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -1,2 +1,2 @@ -# Database url for outside requests -STRAPI_URL=http://localhost:1337 +# Strapi url which ApolloClient will use +BACKEND_INTERNAL_URL=http://localhost:1337 diff --git a/frontend/.env.production b/frontend/.env.production index 4b3d365..cd67490 100644 --- a/frontend/.env.production +++ b/frontend/.env.production @@ -1,3 +1,3 @@ -# Database url for outside requests, set in github repo variables -STRAPI_URL=http://web.hypso.ies.ntnu.no:1337 +# Strapi url which ApolloClient will use, set in github repo variables, at https://github.com/NTNU-SmallSat-Lab/outreach-website/settings/variables/actions +BACKEND_INTERNAL_URL=http://web.hypso.ies.ntnu.no:1337 diff --git a/frontend/knip.ts b/frontend/knip.ts new file mode 100644 index 0000000..f39da6b --- /dev/null +++ b/frontend/knip.ts @@ -0,0 +1,8 @@ +module.exports = { + ignore: [ + "src/__generated__/*", // ignore generated files + "src/components/shadcn/*", // ignore shadcn + "src/unused_work_for_later_improvements/**", // ignore unused work + "src/**/_*.*", // ignore files starting with underscore + ], +}; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8ff0716..e3e4476 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,6 +27,7 @@ "@visx/geo": "^3.5.0", "@visx/scale": "^3.5.0", "@visx/shape": "^3.5.0", + "@visx/vendor": "^3.5.0", "add": "^2.0.6", "chart.js": "^4.4.1", "chartjs-adapter-luxon": "^1.3.1", @@ -75,7 +76,7 @@ "@tailwindcss/typography": "^0.5.10", "@types/chart.js": "^2.9.41", "@types/luxon": "^3.4.2", - "@types/node": "^20", + "@types/node": "^20.12.7", "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.2.4", "@types/react": "^18", "@types/react-dom": "^18", @@ -85,11 +86,12 @@ "eslint": "^8", "eslint-config-next": "14.1.0", "eslint-config-prettier": "^9.1.0", + "knip": "^5.10.0", "postcss": "^8", "prettier": "^3.2.4", "prettier-plugin-tailwindcss": "^0.5.12", "tailwindcss": "^3.3.0", - "typescript": "^5.3.3" + "typescript": "^5.4.5" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1688,6 +1690,45 @@ "node": ">=16" } }, + "node_modules/@ericcornelissen/bash-parser": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@ericcornelissen/bash-parser/-/bash-parser-0.5.2.tgz", + "integrity": "sha512-4pIMTa1nEFfMXitv7oaNEWOdM+zpOZavesa5GaiWTgda6Zk32CFGxjUp/iIaN0PwgUW1yTq/fztSjbpE8SLGZQ==", + "dev": true, + "dependencies": { + "array-last": "^1.1.1", + "babylon": "^6.9.1", + "compose-function": "^3.0.3", + "deep-freeze": "0.0.1", + "filter-iterator": "0.0.1", + "filter-obj": "^1.1.0", + "has-own-property": "^0.1.0", + "identity-function": "^1.0.0", + "is-iterable": "^1.1.0", + "iterable-lookahead": "^1.0.0", + "lodash.curry": "^4.1.1", + "magic-string": "^0.16.0", + "map-obj": "^2.0.0", + "object-pairs": "^0.1.0", + "object-values": "^1.0.0", + "reverse-arguments": "^1.0.0", + "shell-quote-word": "^1.0.1", + "to-pascal-case": "^1.0.0", + "unescape-js": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@ericcornelissen/bash-parser/node_modules/magic-string": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.16.0.tgz", + "integrity": "sha512-c4BEos3y6G2qO0B9X7K0FVLOPT9uGrjYwYRLFmDqyl5YMboUviyecnXWp94fJTSMwPw2/sf+CEYt5AGpmklkkQ==", + "dev": true, + "dependencies": { + "vlq": "^0.2.1" + } + }, "node_modules/@esbuild-plugins/node-globals-polyfill": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", @@ -4902,6 +4943,23 @@ "dev": true, "peer": true }, + "node_modules/@snyk/github-codeowners": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz", + "integrity": "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==", + "dev": true, + "dependencies": { + "commander": "^4.1.1", + "ignore": "^5.1.8", + "p-map": "^4.0.0" + }, + "bin": { + "github-codeowners": "dist/cli.js" + }, + "engines": { + "node": ">=8.10" + } + }, "node_modules/@strapi/blocks-react-renderer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@strapi/blocks-react-renderer/-/blocks-react-renderer-1.0.0.tgz", @@ -6821,9 +6879,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", - "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "devOptional": true, "dependencies": { "undici-types": "~5.26.4" @@ -8725,6 +8783,12 @@ "dequal": "^2.0.3" } }, + "node_modules/arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ==", + "dev": true + }, "node_modules/array-bounds": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-bounds/-/array-bounds-1.0.1.tgz", @@ -8772,6 +8836,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-normalize": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array-normalize/-/array-normalize-1.1.4.tgz", @@ -9105,6 +9190,15 @@ "@babel/core": "^7.0.0" } }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -10206,6 +10300,15 @@ "node": ">=4.0.0" } }, + "node_modules/compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha512-xzhzTJ5eC+gmIzvZq+C3kCJHsp9os6tJkrigDRZclyGtOKINbZtE8n1Tzmeh32jW+BUDPbvZpibwvJHBLGMVwg==", + "dev": true, + "dependencies": { + "arity-n": "^1.0.4" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -10880,6 +10983,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg==", + "dev": true + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -11192,6 +11301,18 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, "node_modules/edge-runtime": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.5.7.tgz", @@ -12673,6 +12794,21 @@ "node": ">=8" } }, + "node_modules/filter-iterator": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/filter-iterator/-/filter-iterator-0.0.1.tgz", + "integrity": "sha512-v4lhL7Qa8XpbW3LN46CEnmhGk3eHZwxfNl5at20aEkreesht4YKb/Ba3BUIbnPhAC/r3dmu7ABaGk6MAvh2alA==", + "dev": true + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -13775,6 +13911,12 @@ "is-browser": "^2.0.1" } }, + "node_modules/has-own-property": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-own-property/-/has-own-property-0.1.0.tgz", + "integrity": "sha512-14qdBKoonU99XDhWcFKZTShK+QV47qU97u8zzoVo9cL5TZ3BmBHXogItSt9qJjR0KUMFRhcCW8uGIGl8nkl7Aw==", + "dev": true + }, "node_modules/has-passive-events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-passive-events/-/has-passive-events-1.0.0.tgz", @@ -14027,6 +14169,12 @@ "node": ">=0.10.0" } }, + "node_modules/identity-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/identity-function/-/identity-function-1.0.0.tgz", + "integrity": "sha512-kNrgUK0qI+9qLTBidsH85HjDLpZfrrS0ElquKKe/fJFdB3D7VeKdXXEvOPDUHSHOzdZKCAAaQIWWyp0l2yq6pw==", + "dev": true + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -14504,6 +14652,15 @@ "node": ">=8" } }, + "node_modules/is-iterable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-iterable/-/is-iterable-1.1.1.tgz", + "integrity": "sha512-EdOZCr0NsGE00Pot+x1ZFx9MJK3C6wy91geZpXwvwexDLJvA4nzYyZf7r+EIwSeVsOLDdBz7ATg9NqKTzuNYuQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/is-lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", @@ -14816,6 +14973,15 @@ "ws": "*" } }, + "node_modules/iterable-lookahead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iterable-lookahead/-/iterable-lookahead-1.0.0.tgz", + "integrity": "sha512-hJnEP2Xk4+44DDwJqUQGdXal5VbyeWLaPyDl2AQc242Zr7iqz4DgpQOrEzglWVMGHMDCkguLHEKxd1+rOsmgSQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/iterator.prototype": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", @@ -15079,6 +15245,164 @@ "node": ">=6" } }, + "node_modules/knip": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.10.0.tgz", + "integrity": "sha512-cC8wbMoJ1DJEI39tSTA0ToinTHr7rYpoSec+lpQ+CIuvplsRoQdnMd8Uqi62ycqJFoVfrKldLtGo+LlYITitow==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/webpro" + } + ], + "dependencies": { + "@ericcornelissen/bash-parser": "0.5.2", + "@nodelib/fs.walk": "2.0.0", + "@snyk/github-codeowners": "1.1.0", + "easy-table": "1.2.0", + "fast-glob": "3.3.2", + "file-entry-cache": "8.0.0", + "jiti": "1.21.0", + "js-yaml": "4.1.0", + "minimist": "1.2.8", + "picocolors": "1.0.0", + "picomatch": "^4.0.1", + "pretty-ms": "9.0.0", + "resolve": "1.22.8", + "smol-toml": "1.1.4", + "strip-json-comments": "5.0.1", + "summary": "2.1.0", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "bin": { + "knip": "bin/knip.js", + "knip-bun": "bin/knip-bun.js" + }, + "engines": { + "node": ">=18.6.0" + }, + "peerDependencies": { + "@types/node": ">=18", + "typescript": ">=5.0.4" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.scandir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-3.0.0.tgz", + "integrity": "sha512-ktI9+PxfHYtKjF3cLTUAh2N+b8MijCRPNwKJNqTVdL0gB0QxLU2rIRaZ1t71oEa3YBDE6bukH1sR0+CDnpp/Mg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "3.0.0", + "run-parallel": "^1.2.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.stat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-3.0.0.tgz", + "integrity": "sha512-2tQOI38s19P9i7X/Drt0v8iMA+KMsgdhB/dyPER+e+2Y8L1Z7QvnuRdW/uLuf5YRFUYmnj4bMA6qCuZHFI1GDQ==", + "dev": true, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-2.0.0.tgz", + "integrity": "sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "3.0.0", + "fastq": "^1.15.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/knip/node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/knip/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/knip/node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/knip/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/knip/node_modules/pretty-ms": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.0.0.tgz", + "integrity": "sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==", + "dev": true, + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/knip/node_modules/strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -15228,6 +15552,12 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "node_modules/lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==", + "dev": true + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -15479,6 +15809,15 @@ "wrappy": "1" } }, + "node_modules/map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha512-TzQSV2DiMYgoF5RycneKVUzIa9bQsj/B3tTgsE3dOGqlzHnGIDaC7XBE7grnA+8kZPnfqSGFe95VHc2oc0VFUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/mapbox-gl": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.3.tgz", @@ -16753,6 +17092,21 @@ "node": ">= 0.4" } }, + "node_modules/object-pairs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-pairs/-/object-pairs-0.1.0.tgz", + "integrity": "sha512-3ECr6K831I4xX/Mduxr9UC+HPOz/d6WKKYj9p4cmC8Lg8p7g8gitzsxNX5IWlSIgFWN/a4JgrJaoAMKn20oKwA==", + "dev": true + }, + "node_modules/object-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object-values/-/object-values-1.0.0.tgz", + "integrity": "sha512-+8hwcz/JnQ9EpLIXzN0Rs7DLsBpJNT/xYehtB/jU93tHYr5BFEO8E+JGQNOSqE7opVzz5cGksKFHt7uUJVLSjQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object.assign": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", @@ -18618,6 +18972,12 @@ "node": ">=0.10.0" } }, + "node_modules/reverse-arguments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/reverse-arguments/-/reverse-arguments-1.0.0.tgz", + "integrity": "sha512-/x8uIPdTafBqakK0TmPNJzgkLP+3H+yxpUJhCQHsLBg1rYEVNR2D8BRYNWQhVBjyOd7oo1dZRVzIkwMY2oqfYQ==", + "dev": true + }, "node_modules/rfdc": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", @@ -19505,6 +19865,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shell-quote-word": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/shell-quote-word/-/shell-quote-word-1.0.1.tgz", + "integrity": "sha512-lT297f1WLAdq0A4O+AknIFRP6kkiI3s8C913eJ0XqBxJbZPGWUNkRQk2u8zk4bEAjUJ5i+fSLwB6z1HzeT+DEg==", + "dev": true + }, "node_modules/shellac": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/shellac/-/shellac-0.8.0.tgz", @@ -19588,6 +19954,16 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.1.4.tgz", + "integrity": "sha512-Y0OT8HezWsTNeEOSVxDnKOW/AyNXHQ4BwJNbAXlLTF5wWsBvrcHhIkE5Rf8kQMLmgf7nDX3PVOlgC6/Aiggu3Q==", + "dev": true, + "engines": { + "node": ">= 18", + "pnpm": ">= 8" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -19948,6 +20324,12 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/string.fromcodepoint": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz", + "integrity": "sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg==", + "dev": true + }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", @@ -20136,6 +20518,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/summary": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz", + "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==", + "dev": true + }, "node_modules/supercluster": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", @@ -20607,6 +20995,21 @@ "integrity": "sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==", "peer": true }, + "node_modules/to-no-case": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", + "integrity": "sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==", + "dev": true + }, + "node_modules/to-pascal-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-pascal-case/-/to-pascal-case-1.0.0.tgz", + "integrity": "sha512-QGMWHqM6xPrcQW57S23c5/3BbYb0Tbe9p+ur98ckRnGDwD4wbbtDiYI38CfmMKNB5Iv0REjs5SNDntTwvDxzZA==", + "dev": true, + "dependencies": { + "to-space-case": "^1.0.0" + } + }, "node_modules/to-px": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-px/-/to-px-1.0.1.tgz", @@ -20627,6 +21030,15 @@ "node": ">=8.0" } }, + "node_modules/to-space-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", + "integrity": "sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==", + "dev": true, + "dependencies": { + "to-no-case": "^1.0.0" + } + }, "node_modules/toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -20942,9 +21354,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -21026,6 +21438,15 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "devOptional": true }, + "node_modules/unescape-js": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/unescape-js/-/unescape-js-1.1.4.tgz", + "integrity": "sha512-42SD8NOQEhdYntEiUQdYq/1V/YHwr1HLwlHuTJB5InVVdOSbgI6xu8jK5q65yIzuFCfczzyDF/7hbGzVbyCw0g==", + "dev": true, + "dependencies": { + "string.fromcodepoint": "^0.2.1" + } + }, "node_modules/unified": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", @@ -21905,6 +22326,12 @@ "@esbuild/win32-x64": "0.20.2" } }, + "node_modules/vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, "node_modules/vt-pbf": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", @@ -22613,6 +23040,18 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-validation-error": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.2.0.tgz", + "integrity": "sha512-cYlPR6zuyrgmu2wRTdumEAJGuwI7eHVHGT+VyneAQxmRAKtGRL1/7pjz4wfLhz4J05f5qoSZc3rGacswgyTjjw==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } + }, "node_modules/zstddec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 77aed42..51ea83d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,8 @@ "test": "npx playwright test", "testui": "npx playwright test --ui", "codegen": "npx playwright codegen", - "test-ct": "playwright test -c playwright-ct.config.ts" + "test-ct": "playwright test -c playwright-ct.config.ts", + "find-unused-files": "knip" }, "dependencies": { "@apollo/client": "^3.9.0-alpha.5", @@ -36,6 +37,7 @@ "@visx/geo": "^3.5.0", "@visx/scale": "^3.5.0", "@visx/shape": "^3.5.0", + "@visx/vendor": "^3.5.0", "add": "^2.0.6", "chart.js": "^4.4.1", "chartjs-adapter-luxon": "^1.3.1", @@ -84,7 +86,7 @@ "@tailwindcss/typography": "^0.5.10", "@types/chart.js": "^2.9.41", "@types/luxon": "^3.4.2", - "@types/node": "^20", + "@types/node": "^20.12.7", "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.2.4", "@types/react": "^18", "@types/react-dom": "^18", @@ -94,10 +96,11 @@ "eslint": "^8", "eslint-config-next": "14.1.0", "eslint-config-prettier": "^9.1.0", + "knip": "^5.10.0", "postcss": "^8", "prettier": "^3.2.4", "prettier-plugin-tailwindcss": "^0.5.12", "tailwindcss": "^3.3.0", - "typescript": "^5.3.3" + "typescript": "^5.4.5" } } diff --git a/frontend/src/app/blog/[articleSlug]/page.tsx b/frontend/src/app/blog/[articleSlug]/page.tsx index 22ec4ba..9357121 100644 --- a/frontend/src/app/blog/[articleSlug]/page.tsx +++ b/frontend/src/app/blog/[articleSlug]/page.tsx @@ -6,8 +6,9 @@ import { gql } from "@/__generated__/gql"; import { getClient } from "@/lib/ApolloClient"; import ShareButtons from "@/components/ShareButtons"; import NextImage from "next/image"; +import fullNameToInitials from "@/lib/helpers"; -const STRAPI_URL = process.env.STRAPI_URL; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; const GET_ARTICLE_BY_SLUG = gql( `query ArticleWithSlug($articlesFilters: ArticleFiltersInput) { @@ -100,11 +101,10 @@ export default async function Page({ )} {!avatarURL && ( - {// Get initials from author name - authorName - ?.split(" ") - .map((name: any) => name[0]) - .join("")} + { + // Get initials from author name + fullNameToInitials(authorName) + } )} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 8ee1d01..8f1a48f 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -6,7 +6,7 @@ import Navbar from "@/components/Navbar"; import Footer from "@/components/Footer"; import React from "react"; import { ApolloWrapper } from "@/components/wrappers/ApolloWrapper"; -import SatelliteInitialFetch from "@/components/satelliteData/SatelliteInitialFetch"; +import SatelliteInitialClientFetch from "@/components/satelliteData/SatelliteInitialFetch"; // imports to get satellites from strapi and fetch the data serverside import fetchSatelliteNamesAndId from "@/lib/data/fetchSatelliteNamesAndId"; @@ -21,6 +21,7 @@ export const metadata: Metadata = { import ErrorBoundaryNavigation from "@/components/ErrorBoundaryNavigation"; import Starfield from "@/components/starBackground/Starfield"; +import { SatelliteEntry } from "@/lib/store"; export default async function RootLayout({ children, @@ -29,18 +30,18 @@ export default async function RootLayout({ }>) { // fetch satellite names and id to be set in the store in the navbar const satellites = await fetchSatelliteNamesAndId(); - let satData: any[] = []; + let satData: SatelliteEntry[] = []; if (satellites) { for (const sat of satellites) { - if (sat.id) { + if (sat.num) { try { - const data = await satLoaderById(sat.id); - satData.push({ name: sat.name, id: sat.id, data }); + const entry = await satLoaderById(sat.num); + satData.push(entry); } catch (e) { console.error( "Either CelesTrak has IP banned the server, or the satellite data is not available for the provided NORAD ID: " + - sat.id + + sat.num + ", or CelesTrak is down.", ); } @@ -52,7 +53,7 @@ export default async function RootLayout({ - +
diff --git a/frontend/src/app/projects/[projectSlug]/page.tsx b/frontend/src/app/projects/[projectSlug]/page.tsx index 98db280..6004f0e 100644 --- a/frontend/src/app/projects/[projectSlug]/page.tsx +++ b/frontend/src/app/projects/[projectSlug]/page.tsx @@ -4,7 +4,7 @@ import { getClient } from "@/lib/ApolloClient"; import { BlocksContent } from "@strapi/blocks-react-renderer"; import RelatedProjectsAndSatellites from "@/components/RelatedProjectsAndSatellites"; import { ProjectOrSatellite } from "@/app/satellites/[satelliteSlug]/page"; -const STRAPI_URL = process.env.STRAPI_URL; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; const GET_PROJECT_BY_SLUG = gql(` query Projects($projectFilters: ProjectFiltersInput) { diff --git a/frontend/src/app/projects/page.tsx b/frontend/src/app/projects/page.tsx index dc63dd3..7941333 100644 --- a/frontend/src/app/projects/page.tsx +++ b/frontend/src/app/projects/page.tsx @@ -14,8 +14,8 @@ import { PageHeaderAndSubtitle, PageSubtitle, } from "@/components/PageHeader"; -import { OuiImage } from "@/components/fullBlogCard"; -const STRAPI_URL = process.env.STRAPI_URL; +import { PlaceholderImage } from "@/components/fullBlogCard"; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; const GET_PROJECTS = gql(` query GET_PROJECTS { @@ -102,7 +102,7 @@ export default async function ProjectsPage() { /> ) : (
- +
)} diff --git a/frontend/src/app/satellites/[satelliteSlug]/page.tsx b/frontend/src/app/satellites/[satelliteSlug]/page.tsx index 344cf8b..a4b83a1 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/page.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/page.tsx @@ -12,13 +12,14 @@ import { PageHeaderAndSubtitle, } from "@/components/PageHeader"; import Image from "next/image"; +import { SatelliteName, SatelliteNumber } from "@/lib/store"; export interface SatelliteInfo { launchDate: string | undefined; - name: string; + name: SatelliteName; content: BlocksContent; relatedProjects?: ProjectOrSatellite[]; - noradId: string | undefined; + noradId: SatelliteNumber | undefined; missionStatus: string | undefined; massKg: number | undefined; satelliteImage: string | undefined; @@ -32,7 +33,7 @@ export interface ProjectOrSatellite { isProject: boolean; } -const STRAPI_URL = process.env.STRAPI_URL; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; export default async function SatelliteInfoPage({ params, @@ -113,7 +114,7 @@ export default async function SatelliteInfoPage({ {/* Container for map */} {satelliteInfo.noradId ? (
- +
) : null} diff --git a/frontend/src/components/2dmap/Map2d.tsx b/frontend/src/components/2dmap/Map2d.tsx index aba8cf8..9c63051 100644 --- a/frontend/src/components/2dmap/Map2d.tsx +++ b/frontend/src/components/2dmap/Map2d.tsx @@ -1,6 +1,6 @@ "use client"; import Map2dNaturalProjection from "./2dMapProjection"; -import { useSatelliteStore } from "@/lib/store"; +import { SatelliteNumber, useSatelliteStore } from "@/lib/store"; import React, { useState, useEffect, useRef, useLayoutEffect } from "react"; import { SatelliteInfo, @@ -10,8 +10,8 @@ import { const updateInterval = 100; -export default function Map2d({ satName }: { satName: string }) { - const { satelliteData } = useSatelliteStore(); +export default function Map2d({ satNum }: { satNum: SatelliteNumber }) { + const { satNumToEntry } = useSatelliteStore(); const [satelliteInfo, setSatelliteInfo] = useState( null, ); @@ -27,8 +27,8 @@ export default function Map2d({ satName }: { satName: string }) { useEffect(() => { const intervalId = setInterval(() => { // Access satellite data by name - const satData = satelliteData[satName]; - if (satData) { + const satData = satNumToEntry[satNum]; + if (satData && satData.satrec) { const updatedInfo = convertSatrec(satData.satrec, satData.name); setSatelliteInfo(updatedInfo); } @@ -36,7 +36,7 @@ export default function Map2d({ satName }: { satName: string }) { // Clear interval on component unmount return () => clearInterval(intervalId); - }, [satelliteData, satName]); + }, [satNumToEntry, satNum]); // Calculate and update size based on the container's width useLayoutEffect(() => { @@ -63,10 +63,10 @@ export default function Map2d({ satName }: { satName: string }) { // Get future satellite positions on component mount useEffect(() => { - if (!satelliteData[satName] || !satelliteData[satName].satrec) return; + if (!satNumToEntry[satNum] || !satNumToEntry[satNum].satrec) return; const predictions = predictFuturePositions( - satelliteData[satName].satrec, + satNumToEntry[satNum]?.satrec, projectionAmount, ); const futurePosTuples: [number, number][] = predictions.map( @@ -77,7 +77,7 @@ export default function Map2d({ satName }: { satName: string }) { ) as [number, number][]; setFuturePositions(futurePosTuples); - }, [satelliteData, satName, projectionAmount]); + }, [satNum, projectionAmount, satNumToEntry]); // Function to handle projection amount change const handleSliderChange = (event: { target: { value: any } }) => { diff --git a/frontend/src/components/ExternalLink.tsx b/frontend/src/components/ExternalLink.tsx deleted file mode 100644 index 1f47274..0000000 --- a/frontend/src/components/ExternalLink.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ReactNode } from "react"; -type ExternalLinkProps = { - href: string; - children: ReactNode; -}; - -export function ExternalLink({ href, children }: ExternalLinkProps) { - return ( - -

{children}

-
- ); -} diff --git a/frontend/src/components/HeroWrapper.tsx b/frontend/src/components/HeroWrapper.tsx index 7e6bfba..ae63851 100644 --- a/frontend/src/components/HeroWrapper.tsx +++ b/frontend/src/components/HeroWrapper.tsx @@ -2,7 +2,7 @@ import { gql } from "@/__generated__/gql"; import { getClient } from "@/lib/ApolloClient"; import Hero from "@components/ui/hero"; -const STRAPI_URL = process.env.STRAPI_URL; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; const GET_HERO_DATA = gql(` query Query($publicationState: PublicationState) { diff --git a/frontend/src/components/RelatedProjectsAndSatellites.tsx b/frontend/src/components/RelatedProjectsAndSatellites.tsx index 4b48518..c46e281 100644 --- a/frontend/src/components/RelatedProjectsAndSatellites.tsx +++ b/frontend/src/components/RelatedProjectsAndSatellites.tsx @@ -1,14 +1,14 @@ import { ProjectOrSatellite } from "@/app/satellites/[satelliteSlug]/page"; import Link from "next/link"; import Image from "next/image"; -const STRAPI_URL = process.env.STRAPI_URL; +const STRAPI_URL = process.env.BACKEND_INTERNAL_URL; import { Card, CardContent, CardHeader, CardTitle, } from "@/components/shadcn/card"; -import { OuiImage } from "@/components/fullBlogCard"; +import { PlaceholderImage } from "@/components/fullBlogCard"; export default function RelatedProjectsAndSatellites({ project, @@ -45,7 +45,7 @@ export default function RelatedProjectsAndSatellites({ /> ) : (
- +
)} diff --git a/frontend/src/components/SatelliteResponsiveTable.tsx b/frontend/src/components/SatelliteResponsiveTable.tsx index 2b598a9..cf674d7 100644 --- a/frontend/src/components/SatelliteResponsiveTable.tsx +++ b/frontend/src/components/SatelliteResponsiveTable.tsx @@ -72,6 +72,9 @@ export default function SatelliteResponsiveTable({ handleRowClick(satellite.attributes.slug) } diff --git a/frontend/src/components/fullBlogCard.tsx b/frontend/src/components/fullBlogCard.tsx index 973f040..41c0b3d 100644 --- a/frontend/src/components/fullBlogCard.tsx +++ b/frontend/src/components/fullBlogCard.tsx @@ -12,7 +12,7 @@ import Image from "next/image"; import { cn } from "@/lib/utils"; import { SVGProps } from "react"; -export function OuiImage(props: SVGProps) { +export function PlaceholderImage(props: SVGProps) { return ( ) : (
- +
)}
diff --git a/frontend/src/components/homeComponents/SatDropdown.tsx b/frontend/src/components/homeComponents/SatDropdown.tsx index d778233..c4a1ff9 100644 --- a/frontend/src/components/homeComponents/SatDropdown.tsx +++ b/frontend/src/components/homeComponents/SatDropdown.tsx @@ -3,24 +3,30 @@ import React, { useState } from "react"; import { motion } from "framer-motion"; import { cn } from "@/lib/utils"; import { satLoaderById } from "@/lib/getSatelliteData"; +import { + SatelliteActions, + SatelliteName, + SatelliteNumber, + SatelliteState, +} from "@/lib/store"; type DropdownProps = { - satelliteNames: string[]; - selectedSatellite: string; - // eslint-disable-next-line no-unused-vars - setSelectedSatellite: (satellite: string) => void; - // eslint-disable-next-line no-unused-vars - setSatellites: (satellites: any) => void; + selectedSatellite: SatelliteState["selectedSatellite"]; + setSelectedSatellite: SatelliteActions["setSelectedSatellite"]; + setSatellites: SatelliteActions["setSatellites"]; + selectedSatelliteName?: SatelliteName; + satNumToEntry: SatelliteState["satNumToEntry"]; }; export default function SatDropdown({ - satelliteNames, selectedSatellite, setSelectedSatellite, setSatellites, + selectedSatelliteName, + satNumToEntry, }: DropdownProps) { const [isOpen, setIsOpen] = useState(false); - const [noradID, setNoradID] = useState(""); + const [noradID, setNoradID] = useState(); const [error, setError] = useState(""); const toggleDropdown = () => { @@ -28,12 +34,12 @@ export default function SatDropdown({ setIsOpen(!isOpen); }; - const handleSelect = (satellite: string) => { + const handleSelect = (satellite: SatelliteNumber) => { setSelectedSatellite(satellite); setIsOpen(false); }; - const handleAddSatellite = async (noradID: string) => { + const handleAddSatellite = async (noradID: SatelliteNumber) => { if (!noradID) { setError("Please enter a valid NORAD ID."); return; @@ -44,11 +50,12 @@ export default function SatDropdown({ if (data) { const newSatellite = { name: data.name, - id: noradID, - data: data, + num: noradID, + satrec: data.satrec, + timestamp: data.timestamp, }; setSatellites([newSatellite]); - setSelectedSatellite(newSatellite.name); + setSelectedSatellite(newSatellite.num); setError(""); } else { throw new Error("No data returned for the provided NORAD ID."); @@ -76,7 +83,9 @@ export default function SatDropdown({ const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === "Enter") { - handleAddSatellite(noradID); + if (noradID) { + handleAddSatellite(noradID); + } } }; @@ -84,7 +93,7 @@ export default function SatDropdown({ const value = event.target.value; // Allow only numeric input if (/^\d*$/.test(value)) { - setNoradID(value); + setNoradID(Number(value) as SatelliteNumber); } }; @@ -100,7 +109,7 @@ export default function SatDropdown({ onClick={toggleDropdown} >
-
{selectedSatellite || "Select a Satellite"}
+
{selectedSatelliteName || "Select a Satellite"}

Selected Satellite

- {satelliteNames.map((satellite) => ( -
handleSelect(satellite)} - > - {satellite !== selectedSatellite - ? satellite - : `${satellite} (Selected)`} -
- ))} + {Object.entries(satNumToEntry).map(([num]) => { + return ( +
+ handleSelect(Number(num) as SatelliteNumber) + } + > + {(Number(num) as SatelliteNumber) !== + selectedSatellite + ? num + : `${num} (Selected)`} +
+ ); + })}
@@ -158,7 +172,11 @@ export default function SatDropdown({ />
diff --git a/frontend/src/lib/data/fetchSatelliteInfo.ts b/frontend/src/lib/data/fetchSatelliteInfo.ts index 03aec15..e7c5a76 100644 --- a/frontend/src/lib/data/fetchSatelliteInfo.ts +++ b/frontend/src/lib/data/fetchSatelliteInfo.ts @@ -4,6 +4,7 @@ import { SatelliteInfo, } from "@/app/satellites/[satelliteSlug]/page"; import { getClient } from "../ApolloClient"; +import { SatelliteName, SatelliteNumber } from "../store"; const GET_SATELLITE_INFO = gql(`query GET_SATELLITE_INFO($filters: SatelliteFiltersInput) { @@ -82,13 +83,17 @@ export default async function fetchSatelliteInfo({ ); satelliteInfo = { - name: graphqlData?.data?.satellites?.data[0]?.attributes?.name ?? "", + name: + (graphqlData?.data?.satellites?.data[0]?.attributes + ?.name as SatelliteName) ?? "", content: graphqlData?.data?.satellites?.data[0]?.attributes?.content ?? "", relatedProjects: projects ?? [], noradId: - graphqlData?.data?.satellites?.data[0]?.attributes - ?.catalogNumberNORAD ?? undefined, + (Number( + graphqlData?.data?.satellites?.data[0]?.attributes + ?.catalogNumberNORAD, + ) as SatelliteNumber) ?? undefined, launchDate: graphqlData.data.satellites?.data[0]?.attributes?.launchDate ?? "", missionStatus: diff --git a/frontend/src/lib/data/fetchSatelliteNamesAndId.ts b/frontend/src/lib/data/fetchSatelliteNamesAndId.ts index 3b29a56..71212a8 100644 --- a/frontend/src/lib/data/fetchSatelliteNamesAndId.ts +++ b/frontend/src/lib/data/fetchSatelliteNamesAndId.ts @@ -1,5 +1,6 @@ import { getClient } from "@/lib/ApolloClient"; import { gql } from "@/__generated__/gql"; +import { SatelliteName, SatelliteNumber } from "../store"; const GET_SATELLITE_NAMES_AND_ID = gql(` query GET_SATELLITE_NAMES_AND_ID { @@ -15,7 +16,15 @@ const GET_SATELLITE_NAMES_AND_ID = gql(` } `); -export default async function fetchSatelliteNamesAndId() { +interface SatelliteNameAndNum { + name: SatelliteName; + num: SatelliteNumber; +} + +export default async function fetchSatelliteNamesAndId(): Promise< + SatelliteNameAndNum[] +> { + let retsats: SatelliteNameAndNum[] | undefined = undefined; try { const graphqlData = await getClient().query({ query: GET_SATELLITE_NAMES_AND_ID, @@ -24,12 +33,18 @@ export default async function fetchSatelliteNamesAndId() { const satellites = graphqlData?.data?.satellites?.data?.map( (satellite) => ({ name: satellite.attributes?.name, - id: satellite.attributes?.catalogNumberNORAD, + num: Number(satellite.attributes?.catalogNumberNORAD), }), - ); + ) as SatelliteNameAndNum[]; - return satellites; + retsats = satellites; } catch (error) { console.error("Error fetching satellites from strapi:", error); } + return new Promise((resolve, reject) => { + if (typeof retsats !== "undefined") { + resolve(retsats); + } + reject("Error fetching satellites from strapi"); + }); } diff --git a/frontend/src/lib/getSatelliteData.ts b/frontend/src/lib/getSatelliteData.ts index fd20a9e..9b10c99 100644 --- a/frontend/src/lib/getSatelliteData.ts +++ b/frontend/src/lib/getSatelliteData.ts @@ -1,16 +1,11 @@ import { twoline2satrec } from "satellite.js"; -import { SatRec } from "satellite.js"; +import { SatelliteEntry, SatelliteName, SatelliteNumber } from "./store"; -// Satellite data interface -interface SatelliteData { - satrec: SatRec; - name: string; - timestamp: Date; -} +// Satellite data interfac // Cache the satellite data let cachedData: { - data: Record; + data: Record; timestamp: Date; } = { data: {}, @@ -18,24 +13,28 @@ let cachedData: { }; // Map TLE data to satellite data -function mapTleToSatData(tleString: string): SatelliteData[] { +// https://en.wikipedia.org/wiki/Two-line_element_set +function mapTleToSatData(tleString: string): SatelliteEntry[] { const lines = tleString.trim().split("\n"); - const satellites: SatelliteData[] = []; + const satellites: SatelliteEntry[] = []; for (let i = 0; i < lines.length; i += 3) { - const name = lines[i].trim(); + const name: SatelliteName = lines[i].trim() as SatelliteName; const line1 = lines[i + 1].trim(); const line2 = lines[i + 2].trim(); const satrec = twoline2satrec(line1, line2); + const num: SatelliteNumber = Number(satrec.satnum) as SatelliteNumber; const timestamp = new Date(); - satellites.push({ satrec, name, timestamp }); + satellites.push({ satrec, name, timestamp, num }); } return satellites; } // fetch satellite data from celestrak by id -async function fetchSatelliteDataById(satId: string): Promise { +async function fetchSatelliteDataById( + satNum: SatelliteNumber, +): Promise { const response = await fetch( - `https://celestrak.org/NORAD/elements/gp.php?CATNR=${satId}&FORMAT=TLE`, + `https://celestrak.org/NORAD/elements/gp.php?CATNR=${satNum}&FORMAT=TLE`, { next: { revalidate: 60 * 60 * 24, // revalidate every 24 hours @@ -63,23 +62,23 @@ function isStale(timestamp: Date): boolean { } // Load satellite data by id -export async function satLoaderById(satId: string): Promise { +export async function satLoaderById( + satNum: SatelliteNumber, +): Promise { // The logic to check if data is stale and needs to be fetched if ( !cachedData || isStale(cachedData.timestamp) || - !(satId in cachedData.data) + !(satNum in cachedData.data) ) { // Fetch the data and update the cache - const newData = await fetchSatelliteDataById(satId); + const newData = await fetchSatelliteDataById(satNum); cachedData = { - data: { ...cachedData.data, [satId]: newData[0] }, + data: { ...cachedData.data, [satNum]: newData[0] }, timestamp: new Date(), }; } - return cachedData.data[satId]; + return cachedData.data[satNum]; } - -export type { SatelliteData }; diff --git a/frontend/src/lib/helpers.ts b/frontend/src/lib/helpers.ts index c773b2f..8dc94b7 100644 --- a/frontend/src/lib/helpers.ts +++ b/frontend/src/lib/helpers.ts @@ -1,16 +1,21 @@ -class Helpers { - static fullNameToInitials(name: string): string { - const names = name.split(" ").filter(Boolean); //Filter null or undefined +function fullNameToInitials(name: string | undefined): string { + // If undefined return default JD for John Doe + if (name === undefined) { + return "JD"; + } - let initials = ""; - if (names.length >= 3) { - initials = `${names[0][0]}${names[names.length - 1][0]}`; - } else { - initials = names.map((partialName) => partialName[0]).join(""); - } + const names = name.split(" ").filter(Boolean); //Filter null or undefined - return initials; + let initials = ""; + // If there are more than 3 names, use the first and last name + if (names.length >= 3) { + initials = `${names[0][0]}${names[names.length - 1][0]}`; + } else { + // Otherwise, use the first letter of each name + initials = names.map((partialName) => partialName[0]).join(""); } + + return initials; } -export default Helpers; +export default fullNameToInitials; diff --git a/frontend/src/lib/mapHelpers.ts b/frontend/src/lib/mapHelpers.ts deleted file mode 100644 index 2a9bf96..0000000 --- a/frontend/src/lib/mapHelpers.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { SatRec } from "satellite.js"; -import * as satellite from "satellite.js"; - -export function mapRawDataToTleData(rawData: string): string[][] { - return ( - rawData - // Remove any carriage returns - .replace(/\r/g, "") - // Split the data into individual TLEs (https://en.wikipedia.org/wiki/Two-line_element_set). - /* It splits the string at newline characters (\n) only if they are followed by a character that is not 1 or 2. The (?=[^12]) is a positive lookahead assertion, - ensuring that the newline is followed by a character that is not 1 or 2 without including that character in the split result.*/ - .split(/\n(?=[^12])/) - //This step filters out any empty lines from the array of substrings obtained in the previous step. The callback function (d) => d checks if the substring d is truthy, effectively removing empty lines. - .filter((d) => d) - /* Finally, this step maps each substring (now representing a line) into an array of lines. - It splits each substring again using the newline character (\n) as the delimiter. - This results in a two-dimensional array where each element is an array of lines from the original string. */ - .map((tle) => tle.split("\n")) - ); -} - -export type SatelliteData = { - satrec: SatRec; - name: string; -}; - -export function mapTleToSatData(tle: string[][]): SatelliteData[] { - const satData = tle - .map(([name, ...tle]) => ({ - satrec: satellite.twoline2satrec( - ...(tle as [string, string]), // spread the array as arguments to the function - ), - name: name.trim().replace(/^0 /, ""), // remove leading 0 from name - })) - // exclude those that can't be propagated - .filter((d) => !!satellite.propagate(d.satrec, new Date()).position); - return satData; -} - -export function mapRawDataToSatData(rawData: string): SatelliteData[] { - return mapTleToSatData(mapRawDataToTleData(rawData)); -} diff --git a/frontend/src/lib/store.ts b/frontend/src/lib/store.ts index 9b8cbc9..be761e3 100644 --- a/frontend/src/lib/store.ts +++ b/frontend/src/lib/store.ts @@ -1,91 +1,81 @@ -/* eslint-disable no-unused-vars */ +// A zustand store for satellite data +// https://github.com/pmndrs/zustand + +import { SatRec } from "satellite.js"; import { create } from "zustand"; -import type { SatelliteData } from "@/lib/getSatelliteData"; +// Define nominal types for satellite name and number +// Nominal types are used to create a new type that is distinct from an existing type +// This is useful for type safety and to prevent bugs +// For more information on nominal types, see the following blog post or github issue: +//https://dnlytras.com/blog/nominal-types or https://github.com/Microsoft/Typescript/issues/202 + +declare const __nominal__type: unique symbol; +type Nominal = Type & { + readonly [__nominal__type]: Identifier; +}; + +export type SatelliteName = Nominal; +export type SatelliteNumber = Nominal; // Satellite entry for setSatellites -interface SatelliteEntry { - name: string; - id: string; - data?: SatelliteData; +export interface SatelliteEntry { + name: SatelliteName; + num: SatelliteNumber; + satrec: SatRec; + timestamp: Date; } // Define the state -interface SatelliteState { - satelliteData: Record; - satelliteNameToId: Record; - satelliteNames: string[]; - selectedSatellite: string; +export interface SatelliteState { + selectedSatellite: SatelliteNumber | undefined; + satNumToEntry: Record; } +// Disable unused variables as the store actions defined here are used in other files +/* eslint-disable no-unused-vars */ // Define the actions -interface SatelliteActions { - setSatelliteData: (satName: string, data: SatelliteData) => void; - setSelectedSatellite: (satName: string) => void; +export interface SatelliteActions { + setSelectedSatellite: (SatId: SatelliteNumber) => void; setSatellites: (satellites: SatelliteEntry[]) => void; } +/* eslint-enable no-unused-vars */ type SatelliteStore = SatelliteState & SatelliteActions; // Create satellite store -export const useSatelliteStore = create((set) => ({ - satelliteData: {}, - satelliteNames: [], - satelliteNameToId: {}, - selectedSatellite: "", +export const useSatelliteStore = create()((set) => ({ + selectedSatellite: undefined, + satNumToEntry: {}, // Set the satellite names and id mapping, and selected satellite setSatellites: (satellites) => { set((state) => { - const newNames = satellites.map((sat) => sat.name); - const newNameToId = satellites.reduce>( - (acc, sat) => { - acc[sat.name] = sat.id; - return acc; - }, - {}, - ); + const selectedSatellite = + state.selectedSatellite || satellites.length > 0 + ? satellites[0].num + : undefined; - const newSatelliteData = satellites.reduce< - Record + const satNumToEntry = satellites.reduce< + Record >( - (acc, sat) => { - if (sat.data) { - acc[sat.name] = sat.data; - } - return acc; + (previous, entry) => { + previous[entry.num] = entry; + return previous; }, - { ...state.satelliteData }, + { ...state.satNumToEntry }, ); - const mergedNames = Array.from( - new Set([...state.satelliteNames, ...newNames]), - ); - const mergedNameToId = { - ...state.satelliteNameToId, - ...newNameToId, - }; - const selectedSatellite = state.selectedSatellite || newNames[0]; - return { - satelliteNames: mergedNames, - satelliteNameToId: mergedNameToId, - satelliteData: newSatelliteData, selectedSatellite: selectedSatellite, + satNumToEntry: satNumToEntry, }; }); }, - // Set the satellite data for a specific satellite - setSatelliteData: (satName, data) => { - set((state) => ({ - satelliteData: { ...state.satelliteData, [satName]: data }, - })); - }, - // Set the selected satellite - setSelectedSatellite: (satName) => { + setSelectedSatellite: (satNum: SatelliteNumber) => { set(() => ({ - selectedSatellite: satName, + selectedSatellite: satNum, })); }, })); diff --git a/frontend/src/components/SolarActivity/SolarData.tsx b/frontend/src/unused_work_for_later_improvements/SolarActivity/SolarData.tsx similarity index 100% rename from frontend/src/components/SolarActivity/SolarData.tsx rename to frontend/src/unused_work_for_later_improvements/SolarActivity/SolarData.tsx diff --git a/frontend/src/components/ui/scrollLinkedDiv.tsx b/frontend/src/unused_work_for_later_improvements/scrollLinkedDiv.tsx similarity index 100% rename from frontend/src/components/ui/scrollLinkedDiv.tsx rename to frontend/src/unused_work_for_later_improvements/scrollLinkedDiv.tsx diff --git a/frontend/src/components/ui/separator.tsx b/frontend/src/unused_work_for_later_improvements/separator.tsx similarity index 100% rename from frontend/src/components/ui/separator.tsx rename to frontend/src/unused_work_for_later_improvements/separator.tsx