diff --git a/frontend/.env.production b/frontend/.env.production
index ba9e7ab..e75b046 100644
--- a/frontend/.env.production
+++ b/frontend/.env.production
@@ -1,2 +1,2 @@
# Database url
-HOST_URL=http://backend-app:1337
+HOST_URL=http://localhost:1337
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index c4420ad..c4570c6 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -15,6 +15,7 @@
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@strapi/blocks-react-renderer": "^1.0.0",
@@ -23,6 +24,7 @@
"chartjs-adapter-luxon": "^1.3.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
+ "cmdk": "0.2.0",
"framer-motion": "^11.0.24",
"globe.gl": "^2.32.2",
"gsap": "^3.12.5",
@@ -4241,6 +4243,43 @@
}
}
},
+ "node_modules/@radix-ui/react-popover": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.7.tgz",
+ "integrity": "sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-popper": "1.1.3",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-popper": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz",
@@ -7668,6 +7707,252 @@
"node": ">=6"
}
},
+ "node_modules/cmdk": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.0.tgz",
+ "integrity": "sha512-JQpKvEOb86SnvMZbYaFKYhvzFntWBeSZdyii0rZPhKJj9uwJBxu4DaVYDrRN7r3mPop56oPhRw+JYWTKs66TYw==",
+ "dependencies": {
+ "@radix-ui/react-dialog": "1.0.0",
+ "command-score": "0.1.2"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/primitive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",
+ "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
+ "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-context": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
+ "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-dialog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.0.tgz",
+ "integrity": "sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.0",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-context": "1.0.0",
+ "@radix-ui/react-dismissable-layer": "1.0.0",
+ "@radix-ui/react-focus-guards": "1.0.0",
+ "@radix-ui/react-focus-scope": "1.0.0",
+ "@radix-ui/react-id": "1.0.0",
+ "@radix-ui/react-portal": "1.0.0",
+ "@radix-ui/react-presence": "1.0.0",
+ "@radix-ui/react-primitive": "1.0.0",
+ "@radix-ui/react-slot": "1.0.0",
+ "@radix-ui/react-use-controllable-state": "1.0.0",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.4"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz",
+ "integrity": "sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.0",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-primitive": "1.0.0",
+ "@radix-ui/react-use-callback-ref": "1.0.0",
+ "@radix-ui/react-use-escape-keydown": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz",
+ "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz",
+ "integrity": "sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-primitive": "1.0.0",
+ "@radix-ui/react-use-callback-ref": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-id": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
+ "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-layout-effect": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-portal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.0.tgz",
+ "integrity": "sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-presence": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz",
+ "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-use-layout-effect": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-primitive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz",
+ "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-slot": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-slot": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz",
+ "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz",
+ "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz",
+ "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz",
+ "integrity": "sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
+ "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/react-remove-scroll": {
+ "version": "2.5.4",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz",
+ "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.3",
+ "react-style-singleton": "^2.2.1",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.0",
+ "use-sidecar": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/code-block-writer": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz",
@@ -7795,6 +8080,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/command-score": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/command-score/-/command-score-0.1.2.tgz",
+ "integrity": "sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w=="
+ },
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index cef4828..17c961c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -20,6 +20,7 @@
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@strapi/blocks-react-renderer": "^1.0.0",
@@ -28,6 +29,7 @@
"chartjs-adapter-luxon": "^1.3.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
+ "cmdk": "0.2.0",
"framer-motion": "^11.0.24",
"globe.gl": "^2.32.2",
"gsap": "^3.12.5",
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 5aa6866..1da071b 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -3,9 +3,8 @@ import ColoredSection from "@/components/ui/coloredSection";
import Image from "next/image";
import Link from "next/link";
-
-import SatelliteFetcher from "@/components/map/SatelliteFetcher";
-import SatelliteDataTable from "@/components/satelliteData/SatelliteDataTable";
+import SatelliteDataTable from "@/components/satelliteData/SatelliteDataTableMultiple";
+import fetchSatelliteData from "@components/map/SatelliteFetcher";
import fetchMostRecentImage from "@/lib/data/fetchMostRecentImage";
@@ -16,15 +15,10 @@ export default async function Home() {
<>
void;
+}
+
+export function Combobox({ data, onSelect }: ComboboxDemoProps) {
+ console.log();
+
+ const [open, setOpen] = useState(false);
+ const [value, setValue] = useState("");
+
+ const handleSelect = (currentValue: SatelliteData) => {
+ setValue(currentValue.name === value ? "" : currentValue.name);
+ setOpen(false);
+ onSelect(currentValue); // Call the passed onSelect function with the selected value
+ };
+
+ return (
+
+
+
+
+
+
+
+ No framework found.
+
+ {data.map((item) => (
+ handleSelect(item)}
+ >
+
+ {item.name}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/map/MyGlobe.tsx b/frontend/src/components/map/MyGlobe.tsx
index 5f59312..9859cb0 100644
--- a/frontend/src/components/map/MyGlobe.tsx
+++ b/frontend/src/components/map/MyGlobe.tsx
@@ -3,6 +3,7 @@ import Globe, { GlobeInstance } from "globe.gl";
import * as THREE from "three";
import React, { useEffect } from "react";
import * as satellite from "satellite.js";
+import { SatelliteData } from "@/lib/mapHelpers";
// made with the following packages:
// https://www.npmjs.com/package/globe.gl
@@ -14,9 +15,9 @@ import * as satellite from "satellite.js";
const EARTH_RADIUS_KM = 6371; // km
const SAT_SIZE = 500; // km
const TIME_STEP = 1 * 1000; // per frame
-const SATELLITE_AMOUNT = 100; // amount of satellites to display
+//const SATELLITE_AMOUNT = 100; // amount of satellites to display
-function mapRawDataToTleData(rawData: string): string[][] {
+export function mapRawDataToTleData(rawData: string): string[][] {
return (
rawData
// Remove any carriage returns
@@ -34,11 +35,15 @@ function mapRawDataToTleData(rawData: string): string[][] {
);
}
+interface MyGlobeProps {
+ satelliteDatas: SatelliteData[]; // Existing prop: a string of TLE strings
+ selectedSatellite?: SatelliteData;
+}
+
export default function MyGlobe({
- satelliteDatas: satelliteDatas,
-}: {
- satelliteDatas: string; // Expects a string of TLE strings such as the example files in the datasets folder
-}) {
+ satelliteDatas,
+ selectedSatellite,
+}: MyGlobeProps) {
const chart = React.useRef(null);
// useEffect is used because we want to run the code only once when the component is mounted
@@ -53,21 +58,26 @@ export default function MyGlobe({
.objectLng("lng")
.objectAltitude("alt")
.objectFacesSurface(false)
- .objectLabel("name")
.backgroundColor("rgba(0,0,0,0)")
- .width(window.innerWidth / 2);
-
- window.addEventListener("resize", (event) => {
- let target = event.target as Window;
- if (target.innerWidth != null && target.innerHeight != null) {
- myGlobe.width(target.innerWidth / 2);
- // myGlobe.height(event.target.innerHeight / 2);
- }
- });
+ .objectLabel("name");
// Set initial camera distance
setTimeout(() => myGlobe.pointOfView({ altitude: 3.5 }));
+ const handleResize = () => {
+ //Making it responsive like this
+
+ if (window.innerWidth <= 768) {
+ myGlobe.width(window.innerWidth);
+ myGlobe.height(window.innerHeight / 2);
+ } else {
+ myGlobe.width(window.innerWidth / 2);
+ myGlobe.height(window.innerHeight / 2);
+ }
+ };
+ handleResize();
+ window.addEventListener("resize", handleResize);
+
// Disable OrbitControls and enable auto-rotation
// myGlobe.controls().autoRotate = true;
myGlobe.controls().enabled = true;
@@ -92,20 +102,7 @@ export default function MyGlobe({
myGlobe.objectThreeObject(
() => new THREE.Mesh(satGeometry, satMaterial),
);
-
- const tleData = mapRawDataToTleData(satelliteDatas);
- const satData = tleData
- .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,
- )
- .slice(0, SATELLITE_AMOUNT);
+ const satData = satelliteDatas;
// time ticker
let time = new Date();
@@ -115,6 +112,7 @@ export default function MyGlobe({
time = new Date(+time + TIME_STEP);
// Update satellite positions
+
const gmst = satellite.gstime(time);
satData.forEach((d: any) => {
const eci = satellite.propagate(d.satrec, time);
@@ -123,16 +121,24 @@ export default function MyGlobe({
eci.position as satellite.EciVec3,
gmst,
);
+
d.lat = THREE.MathUtils.radToDeg(gdPos.latitude);
d.lng = THREE.MathUtils.radToDeg(gdPos.longitude);
d.alt = gdPos.height / EARTH_RADIUS_KM;
+
+ if (d.name == selectedSatellite?.name) {
+ myGlobe.pointOfView(
+ { lat: d.lat, lng: d.lng, altitude: 2 },
+ 0,
+ );
+ }
}
});
myGlobe.objectsData(satData);
})();
}
- }, [satelliteDatas]);
+ }, [selectedSatellite, satelliteDatas]);
return (
<>
diff --git a/frontend/src/components/map/SatelliteFetcher.tsx b/frontend/src/components/map/SatelliteFetcher.tsx
index 6fc4209..d33c297 100644
--- a/frontend/src/components/map/SatelliteFetcher.tsx
+++ b/frontend/src/components/map/SatelliteFetcher.tsx
@@ -1,12 +1,8 @@
-export const runtime = "edge";
+"use server";
import { gql } from "@/__generated__/gql";
import { getClient } from "@/lib/ApolloClient";
// Dynamic import because of leaflet and globe.gl ssr problem with next.js
-import dynamic from "next/dynamic";
-const MyGlobe = dynamic(() => import("@/components/map/MyGlobe"), {
- ssr: false,
-});
// Example Datasources
import { exampleData } from "./exampleSatData";
@@ -28,16 +24,17 @@ const GET_ALL_SATELLITE_DATA =
}
`);
-export default async function SatelliteFetcher({
- useExampleData,
- filterList = [],
-}: {
+interface SatelliteFetcherInterface {
useExampleData: boolean;
filterList?: string[];
-}) {
- // Fetch the data, either from the example file or from strapi then celestrak
+}
+
+export default async function fetchSatelliteData({
+ useExampleData,
+ filterList = [],
+}: SatelliteFetcherInterface): Promise {
if (useExampleData) {
- return ;
+ return exampleData;
} else {
let graphqlData;
@@ -96,6 +93,6 @@ export default async function SatelliteFetcher({
let combinedSatelliteDatas = data.join("\n");
- return ;
+ return combinedSatelliteDatas;
}
}
diff --git a/frontend/src/components/satelliteData/SatelliteDataTableMultiple.tsx b/frontend/src/components/satelliteData/SatelliteDataTableMultiple.tsx
new file mode 100644
index 0000000..7074730
--- /dev/null
+++ b/frontend/src/components/satelliteData/SatelliteDataTableMultiple.tsx
@@ -0,0 +1,140 @@
+// Ensure all necessary imports are present
+"use client";
+import React, { useState, useEffect } from "react";
+import dynamic from "next/dynamic";
+import { Combobox } from "../Combobox"; // Adjust the path as necessary
+import {
+ mapRawDataToTleData,
+ mapTleToSatData,
+ SatelliteData,
+} from "@/lib/mapHelpers";
+import { convertSatrec, SatelliteInfo } from "@/lib/convertSatrec";
+
+// Define the MyGlobe component with dynamic import
+const MyGlobe = dynamic(() => import("@/components/map/MyGlobe"), {
+ ssr: false,
+});
+const updateInterval = 10;
+
+interface ClientOnlyComponentProps {
+ fetchSatelliteData: ({
+ // eslint-disable-next-line no-unused-vars
+ useExampleData,
+ }: {
+ useExampleData: boolean;
+ filterList?: string[];
+ }) => Promise;
+}
+
+const SatelliteDataTableMultiple: React.FC = ({
+ fetchSatelliteData,
+}) => {
+ const [satelliteData, setSatelliteData] = useState([]);
+ const [selectedSatellite, setSelectedSatellite] = useState<
+ SatelliteData | undefined
+ >();
+ const [satelliteInfo, setSatelliteInfo] = useState(
+ null,
+ );
+
+ // Fetch satellite data on component mount
+ useEffect(() => {
+ const fetchData = async () => {
+ const rawData = await fetchSatelliteData({ useExampleData: true });
+
+ const tleData = mapRawDataToTleData(rawData);
+
+ const mappedData = mapTleToSatData(tleData).slice(0, 10);
+ setSatelliteData(mappedData);
+ if (mappedData.length > 0) {
+ updateSatelliteInfo(mappedData[0]);
+ setSelectedSatellite(mappedData[0]); // Ensure the first satellite is selected by default
+ }
+ };
+
+ fetchData();
+ }, [fetchSatelliteData]);
+
+ // Function to update satellite info based on selected satellite
+ const updateSatelliteInfo = (satellite: SatelliteData) => {
+ const sat = satelliteData.find((s) => s.name === satellite.name);
+ if (sat) {
+ const info = convertSatrec(sat.satrec, sat.name);
+ setSatelliteInfo(info);
+ }
+ };
+
+ // Handle satellite selection from Combobox
+ const handleSelectSatellite = (value: SatelliteData) => {
+ setSelectedSatellite(value);
+ updateSatelliteInfo(value);
+ };
+
+ // Map satellite data for Combobox options
+
+ useEffect(() => {
+ const intervalId = setInterval(() => {
+ // Access satellite data by name
+ if (selectedSatellite) {
+ const updatedInfo = convertSatrec(
+ selectedSatellite.satrec,
+ selectedSatellite.name,
+ );
+ setSatelliteInfo(updatedInfo);
+ }
+ }, updateInterval);
+
+ // Clear interval on component unmount
+ return () => clearInterval(intervalId);
+ }, [selectedSatellite]);
+
+ return satelliteData.length > 0 && selectedSatellite && satelliteInfo ? (
+ <>
+
+
+
+
{/* Include the dropdown arrow icon here */}
+
+
+
+
+
{satelliteInfo.velocity} km/s
+
Velocity
+
+
+
{satelliteInfo.altitude} km
+
Altitude
+
+
+
+ {satelliteInfo.latitudeDeg}° N
+
+
Latitude
+
+
+
+ {satelliteInfo.longitudeDeg}° E
+
+
Longitude
+
+
+
+
+
Above {satelliteInfo.country}
+
+
{/* Include the flag icon here */}
+
+
+ >
+ ) : (
+ Loading...
+ );
+};
+
+export default SatelliteDataTableMultiple;
diff --git a/frontend/src/components/ui/command.tsx b/frontend/src/components/ui/command.tsx
new file mode 100644
index 0000000..01543eb
--- /dev/null
+++ b/frontend/src/components/ui/command.tsx
@@ -0,0 +1,158 @@
+"use client";
+
+import * as React from "react";
+import { type DialogProps } from "@radix-ui/react-dialog";
+import { Command as CommandPrimitive } from "cmdk";
+import { Search } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+import { Dialog, DialogContent } from "@/components/ui/dialog";
+
+const Command = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+Command.displayName = CommandPrimitive.displayName;
+
+interface CommandDialogProps extends DialogProps {}
+
+const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
+ return (
+
+ );
+};
+
+const CommandInput = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+));
+
+CommandInput.displayName = CommandPrimitive.Input.displayName;
+
+const CommandList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandList.displayName = CommandPrimitive.List.displayName;
+
+const CommandEmpty = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>((props, ref) => (
+
+));
+
+CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
+
+const CommandGroup = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandGroup.displayName = CommandPrimitive.Group.displayName;
+
+const CommandSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
+
+const CommandItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandItem.displayName = CommandPrimitive.Item.displayName;
+
+const CommandShortcut = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => {
+ return (
+
+ );
+};
+CommandShortcut.displayName = "CommandShortcut";
+
+export {
+ Command,
+ CommandDialog,
+ CommandInput,
+ CommandList,
+ CommandEmpty,
+ CommandGroup,
+ CommandItem,
+ CommandShortcut,
+ CommandSeparator,
+};
diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..47bd7e3
--- /dev/null
+++ b/frontend/src/components/ui/dialog.tsx
@@ -0,0 +1,122 @@
+"use client";
+
+import * as React from "react";
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { X } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
+
+const DialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogHeader.displayName = "DialogHeader";
+
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogFooter.displayName = "DialogFooter";
+
+const DialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+ Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogClose,
+ DialogTrigger,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+};
diff --git a/frontend/src/components/ui/popover.tsx b/frontend/src/components/ui/popover.tsx
new file mode 100644
index 0000000..f2de260
--- /dev/null
+++ b/frontend/src/components/ui/popover.tsx
@@ -0,0 +1,31 @@
+"use client";
+
+import * as React from "react";
+import * as PopoverPrimitive from "@radix-ui/react-popover";
+
+import { cn } from "@/lib/utils";
+
+const Popover = PopoverPrimitive.Root;
+
+const PopoverTrigger = PopoverPrimitive.Trigger;
+
+const PopoverContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+
+
+));
+PopoverContent.displayName = PopoverPrimitive.Content.displayName;
+
+export { Popover, PopoverTrigger, PopoverContent };
diff --git a/frontend/src/lib/store.ts b/frontend/src/lib/store.ts
index 0161b2c..130e774 100644
--- a/frontend/src/lib/store.ts
+++ b/frontend/src/lib/store.ts
@@ -5,12 +5,17 @@ import { satLoader } from "@/lib/getSatelliteData";
interface SatelliteStore {
satelliteData: Record;
+ satelliteNames: string[];
+
setSatelliteData: (satName: string, data: SatelliteData) => void;
fetchAndSetSatelliteData: (satName: string) => Promise;
+
+ getSatelliteNames: () => void;
}
export const useSatelliteStore = create((set) => ({
satelliteData: {},
+ satelliteNames: [],
setSatelliteData: (satName, data) =>
set((state) => ({
satelliteData: { ...state.satelliteData, [satName]: data },
@@ -22,4 +27,6 @@ export const useSatelliteStore = create((set) => ({
satelliteData: { ...state.satelliteData, [satName]: newData },
}));
},
+
+ getSatelliteNames: () => {},
}));