diff --git a/src/components/Peers/PeerCountryCell.tsx b/src/components/Peers/PeerCountryCell.tsx
new file mode 100644
index 0000000..9877c73
--- /dev/null
+++ b/src/components/Peers/PeerCountryCell.tsx
@@ -0,0 +1,50 @@
+import { Cell } from "@codex-storage/marketplace-ui-components";
+import { useEffect, useState } from "react";
+import { PeerPin } from "./types";
+import { countriesCoordinates } from "./countries";
+
+export type Props = {
+ address: string;
+ onPinAdd: (pin: PeerPin) => void;
+};
+
+const getFlagEmoji = (countryCode: string) => {
+ const codePoints = countryCode
+ .toUpperCase()
+ .split("")
+ .map((char) => 127397 + char.charCodeAt(0));
+ return String.fromCodePoint(...codePoints);
+};
+
+export function PeerCountryCell({ address, onPinAdd }: Props) {
+ const [country, setCountry] = useState("");
+
+ useEffect(() => {
+ const [ip] = address.split(":");
+
+ console.info(ip);
+
+ fetch("https://api.country.is/" + ip)
+ .then((res) => res.json())
+ .then((json) => {
+ setCountry(json.country);
+
+ const coordinate = countriesCoordinates.find(
+ (c) => c.iso === json.country
+ );
+
+ if (coordinate) {
+ onPinAdd({
+ lat: parseFloat(coordinate.lat),
+ lng: parseFloat(coordinate.lng),
+ });
+ }
+ });
+ }, [address]);
+
+ return (
+ |
+ {getFlagEmoji(country)} {address}
+ |
+ );
+}
diff --git a/src/components/Peers/countries.ts b/src/components/Peers/countries.ts
new file mode 100644
index 0000000..4c8ec26
--- /dev/null
+++ b/src/components/Peers/countries.ts
@@ -0,0 +1,1312 @@
+export const countriesCoordinates = [
+ {
+ "iso": "AF",
+ "lat": "33",
+ "lng": "65"
+ },
+ {
+ "iso": "AX",
+ "lat": "60.116667",
+ "lng": "19.9"
+ },
+ {
+ "iso": "AL",
+ "lat": "41",
+ "lng": "20"
+ },
+ {
+ "iso": "DZ",
+ "lat": "28",
+ "lng": "3"
+ },
+ {
+ "iso": "AS",
+ "lat": "-14.3333",
+ "lng": "-170"
+ },
+ {
+ "iso": "AD",
+ "lat": "42.5",
+ "lng": "1.6"
+ },
+ {
+ "iso": "AO",
+ "lat": "-12.5",
+ "lng": "18.5"
+ },
+ {
+ "iso": "AI",
+ "lat": "18.25",
+ "lng": "-63.1667"
+ },
+ {
+ "iso": "AQ",
+ "lat": "-90",
+ "lng": "0"
+ },
+ {
+ "iso": "AG",
+ "lat": "17.05",
+ "lng": "-61.8"
+ },
+ {
+ "iso": "AR",
+ "lat": "-34",
+ "lng": "-64"
+ },
+ {
+ "iso": "AM",
+ "lat": "40",
+ "lng": "45"
+ },
+ {
+ "iso": "AW",
+ "lat": "12.5",
+ "lng": "-69.9667"
+ },
+ {
+ "iso": "AU",
+ "lat": "-27",
+ "lng": "133"
+ },
+ {
+ "iso": "AT",
+ "lat": "47.3333",
+ "lng": "13.3333"
+ },
+ {
+ "iso": "AZ",
+ "lat": "40.5",
+ "lng": "47.5"
+ },
+ {
+ "iso": "BS",
+ "lat": "24.25",
+ "lng": "-76"
+ },
+ {
+ "iso": "BH",
+ "lat": "26",
+ "lng": "50.55"
+ },
+ {
+ "iso": "BD",
+ "lat": "24",
+ "lng": "90"
+ },
+ {
+ "iso": "BB",
+ "lat": "13.1667",
+ "lng": "-59.5333"
+ },
+ {
+ "iso": "BY",
+ "lat": "53",
+ "lng": "28"
+ },
+ {
+ "iso": "BE",
+ "lat": "50.8333",
+ "lng": "4"
+ },
+ {
+ "iso": "BZ",
+ "lat": "17.25",
+ "lng": "-88.75"
+ },
+ {
+ "iso": "BJ",
+ "lat": "9.5",
+ "lng": "2.25"
+ },
+ {
+ "iso": "BM",
+ "lat": "32.3333",
+ "lng": "-64.75"
+ },
+ {
+ "iso": "BT",
+ "lat": "27.5",
+ "lng": "90.5"
+ },
+ {
+ "iso": "Plurinational State of",
+ "lat": "68",
+ "lng": "-17"
+ },
+ {
+ "iso": "BO",
+ "lat": "-17",
+ "lng": "-65"
+ },
+ {
+ "iso": "Sint Eustatius and Saba",
+ "lat": "535",
+ "lng": "12.183333"
+ },
+ {
+ "iso": "BA",
+ "lat": "44",
+ "lng": "18"
+ },
+ {
+ "iso": "BW",
+ "lat": "-22",
+ "lng": "24"
+ },
+ {
+ "iso": "BV",
+ "lat": "-54.4333",
+ "lng": "3.4"
+ },
+ {
+ "iso": "BR",
+ "lat": "-10",
+ "lng": "-55"
+ },
+ {
+ "iso": "IO",
+ "lat": "-6",
+ "lng": "71.5"
+ },
+ {
+ "iso": "BN",
+ "lat": "4.5",
+ "lng": "114.6667"
+ },
+ {
+ "iso": "BN",
+ "lat": "4.5",
+ "lng": "114.6667"
+ },
+ {
+ "iso": "BG",
+ "lat": "43",
+ "lng": "25"
+ },
+ {
+ "iso": "BF",
+ "lat": "13",
+ "lng": "-2"
+ },
+ {
+ "iso": "MM",
+ "lat": "22",
+ "lng": "98"
+ },
+ {
+ "iso": "BI",
+ "lat": "-3.5",
+ "lng": "30"
+ },
+ {
+ "iso": "KH",
+ "lat": "13",
+ "lng": "105"
+ },
+ {
+ "iso": "CM",
+ "lat": "6",
+ "lng": "12"
+ },
+ {
+ "iso": "CA",
+ "lat": "60",
+ "lng": "-95"
+ },
+ {
+ "iso": "CV",
+ "lat": "16",
+ "lng": "-24"
+ },
+ {
+ "iso": "KY",
+ "lat": "19.5",
+ "lng": "-80.5"
+ },
+ {
+ "iso": "CF",
+ "lat": "7",
+ "lng": "21"
+ },
+ {
+ "iso": "TD",
+ "lat": "15",
+ "lng": "19"
+ },
+ {
+ "iso": "CL",
+ "lat": "-30",
+ "lng": "-71"
+ },
+ {
+ "iso": "CN",
+ "lat": "35",
+ "lng": "105"
+ },
+ {
+ "iso": "CX",
+ "lat": "-10.5",
+ "lng": "105.6667"
+ },
+ {
+ "iso": "CC",
+ "lat": "-12.5",
+ "lng": "96.8333"
+ },
+ {
+ "iso": "CO",
+ "lat": "4",
+ "lng": "-72"
+ },
+ {
+ "iso": "KM",
+ "lat": "-12.1667",
+ "lng": "44.25"
+ },
+ {
+ "iso": "the Democratic Republic of the",
+ "lat": "180",
+ "lng": "0"
+ },
+ {
+ "iso": "CG",
+ "lat": "-1",
+ "lng": "15"
+ },
+ {
+ "iso": "CK",
+ "lat": "-21.2333",
+ "lng": "-159.7667"
+ },
+ {
+ "iso": "CR",
+ "lat": "10",
+ "lng": "-84"
+ },
+ {
+ "iso": "CI",
+ "lat": "8",
+ "lng": "-5"
+ },
+ {
+ "iso": "HR",
+ "lat": "45.1667",
+ "lng": "15.5"
+ },
+ {
+ "iso": "CU",
+ "lat": "21.5",
+ "lng": "-80"
+ },
+ {
+ "iso": "CW",
+ "lat": "12.166667",
+ "lng": "-68.966667"
+ },
+ {
+ "iso": "CY",
+ "lat": "35",
+ "lng": "33"
+ },
+ {
+ "iso": "CZ",
+ "lat": "49.75",
+ "lng": "15.5"
+ },
+ {
+ "iso": "DK",
+ "lat": "56",
+ "lng": "10"
+ },
+ {
+ "iso": "DJ",
+ "lat": "11.5",
+ "lng": "43"
+ },
+ {
+ "iso": "DM",
+ "lat": "15.4167",
+ "lng": "-61.3333"
+ },
+ {
+ "iso": "DO",
+ "lat": "19",
+ "lng": "-70.6667"
+ },
+ {
+ "iso": "EC",
+ "lat": "-2",
+ "lng": "-77.5"
+ },
+ {
+ "iso": "EG",
+ "lat": "27",
+ "lng": "30"
+ },
+ {
+ "iso": "SV",
+ "lat": "13.8333",
+ "lng": "-88.9167"
+ },
+ {
+ "iso": "GQ",
+ "lat": "2",
+ "lng": "10"
+ },
+ {
+ "iso": "ER",
+ "lat": "15",
+ "lng": "39"
+ },
+ {
+ "iso": "EE",
+ "lat": "59",
+ "lng": "26"
+ },
+ {
+ "iso": "ET",
+ "lat": "8",
+ "lng": "38"
+ },
+ {
+ "iso": "FK",
+ "lat": "-51.75",
+ "lng": "-59"
+ },
+ {
+ "iso": "FO",
+ "lat": "62",
+ "lng": "-7"
+ },
+ {
+ "iso": "FJ",
+ "lat": "-18",
+ "lng": "175"
+ },
+ {
+ "iso": "FI",
+ "lat": "64",
+ "lng": "26"
+ },
+ {
+ "iso": "FR",
+ "lat": "46",
+ "lng": "2"
+ },
+ {
+ "iso": "GF",
+ "lat": "4",
+ "lng": "-53"
+ },
+ {
+ "iso": "PF",
+ "lat": "-15",
+ "lng": "-140"
+ },
+ {
+ "iso": "TF",
+ "lat": "-43",
+ "lng": "67"
+ },
+ {
+ "iso": "GA",
+ "lat": "-1",
+ "lng": "11.75"
+ },
+ {
+ "iso": "GM",
+ "lat": "13.4667",
+ "lng": "-16.5667"
+ },
+ {
+ "iso": "GE",
+ "lat": "42",
+ "lng": "43.5"
+ },
+ {
+ "iso": "DE",
+ "lat": "51",
+ "lng": "9"
+ },
+ {
+ "iso": "GH",
+ "lat": "8",
+ "lng": "-2"
+ },
+ {
+ "iso": "GI",
+ "lat": "36.1833",
+ "lng": "-5.3667"
+ },
+ {
+ "iso": "GR",
+ "lat": "39",
+ "lng": "22"
+ },
+ {
+ "iso": "GL",
+ "lat": "72",
+ "lng": "-40"
+ },
+ {
+ "iso": "GD",
+ "lat": "12.1167",
+ "lng": "-61.6667"
+ },
+ {
+ "iso": "GP",
+ "lat": "16.25",
+ "lng": "-61.5833"
+ },
+ {
+ "iso": "GU",
+ "lat": "13.4667",
+ "lng": "144.7833"
+ },
+ {
+ "iso": "GT",
+ "lat": "15.5",
+ "lng": "-90.25"
+ },
+ {
+ "iso": "GG",
+ "lat": "49.5",
+ "lng": "-2.56"
+ },
+ {
+ "iso": "GW",
+ "lat": "12",
+ "lng": "-15"
+ },
+ {
+ "iso": "GN",
+ "lat": "11",
+ "lng": "-10"
+ },
+ {
+ "iso": "GY",
+ "lat": "5",
+ "lng": "-59"
+ },
+ {
+ "iso": "HT",
+ "lat": "19",
+ "lng": "-72.4167"
+ },
+ {
+ "iso": "HM",
+ "lat": "-53.1",
+ "lng": "72.5167"
+ },
+ {
+ "iso": "VA",
+ "lat": "41.9",
+ "lng": "12.45"
+ },
+ {
+ "iso": "HN",
+ "lat": "15",
+ "lng": "-86.5"
+ },
+ {
+ "iso": "HK",
+ "lat": "22.25",
+ "lng": "114.1667"
+ },
+ {
+ "iso": "HU",
+ "lat": "47",
+ "lng": "20"
+ },
+ {
+ "iso": "IS",
+ "lat": "65",
+ "lng": "-18"
+ },
+ {
+ "iso": "IN",
+ "lat": "20",
+ "lng": "77"
+ },
+ {
+ "iso": "ID",
+ "lat": "-5",
+ "lng": "120"
+ },
+ {
+ "iso": "Islamic Republic of",
+ "lat": "364",
+ "lng": "32"
+ },
+ {
+ "iso": "IQ",
+ "lat": "33",
+ "lng": "44"
+ },
+ {
+ "iso": "IE",
+ "lat": "53",
+ "lng": "-8"
+ },
+ {
+ "iso": "IM",
+ "lat": "54.23",
+ "lng": "-4.55"
+ },
+ {
+ "iso": "IL",
+ "lat": "31.5",
+ "lng": "34.75"
+ },
+ {
+ "iso": "IT",
+ "lat": "42.8333",
+ "lng": "12.8333"
+ },
+ {
+ "iso": "CI",
+ "lat": "8",
+ "lng": "-5"
+ },
+ {
+ "iso": "JM",
+ "lat": "18.25",
+ "lng": "-77.5"
+ },
+ {
+ "iso": "JP",
+ "lat": "36",
+ "lng": "138"
+ },
+ {
+ "iso": "JE",
+ "lat": "49.21",
+ "lng": "-2.13"
+ },
+ {
+ "iso": "JO",
+ "lat": "31",
+ "lng": "36"
+ },
+ {
+ "iso": "KZ",
+ "lat": "48",
+ "lng": "68"
+ },
+ {
+ "iso": "KE",
+ "lat": "1",
+ "lng": "38"
+ },
+ {
+ "iso": "KI",
+ "lat": "1.4167",
+ "lng": "173"
+ },
+ {
+ "iso": "Democratic People's Republic of",
+ "lat": "408",
+ "lng": "40"
+ },
+ {
+ "iso": "Republic of",
+ "lat": "410",
+ "lng": "37"
+ },
+ {
+ "iso": "XK",
+ "lat": "42.583333",
+ "lng": "21"
+ },
+ {
+ "iso": "KW",
+ "lat": "29.3375",
+ "lng": "47.6581"
+ },
+ {
+ "iso": "KG",
+ "lat": "41",
+ "lng": "75"
+ },
+ {
+ "iso": "LA",
+ "lat": "18",
+ "lng": "105"
+ },
+ {
+ "iso": "LV",
+ "lat": "57",
+ "lng": "25"
+ },
+ {
+ "iso": "LB",
+ "lat": "33.8333",
+ "lng": "35.8333"
+ },
+ {
+ "iso": "LS",
+ "lat": "-29.5",
+ "lng": "28.5"
+ },
+ {
+ "iso": "LR",
+ "lat": "6.5",
+ "lng": "-9.5"
+ },
+ {
+ "iso": "LY",
+ "lat": "25",
+ "lng": "17"
+ },
+ {
+ "iso": "LY",
+ "lat": "25",
+ "lng": "17"
+ },
+ {
+ "iso": "LI",
+ "lat": "47.1667",
+ "lng": "9.5333"
+ },
+ {
+ "iso": "LT",
+ "lat": "56",
+ "lng": "24"
+ },
+ {
+ "iso": "LU",
+ "lat": "49.75",
+ "lng": "6.1667"
+ },
+ {
+ "iso": "MO",
+ "lat": "22.1667",
+ "lng": "113.55"
+ },
+ {
+ "iso": "the former Yugoslav Republic of",
+ "lat": "807",
+ "lng": "41.8333"
+ },
+ {
+ "iso": "MG",
+ "lat": "-20",
+ "lng": "47"
+ },
+ {
+ "iso": "MW",
+ "lat": "-13.5",
+ "lng": "34"
+ },
+ {
+ "iso": "MY",
+ "lat": "2.5",
+ "lng": "112.5"
+ },
+ {
+ "iso": "MV",
+ "lat": "3.25",
+ "lng": "73"
+ },
+ {
+ "iso": "ML",
+ "lat": "17",
+ "lng": "-4"
+ },
+ {
+ "iso": "MT",
+ "lat": "35.8333",
+ "lng": "14.5833"
+ },
+ {
+ "iso": "MH",
+ "lat": "9",
+ "lng": "168"
+ },
+ {
+ "iso": "MQ",
+ "lat": "14.6667",
+ "lng": "-61"
+ },
+ {
+ "iso": "MR",
+ "lat": "20",
+ "lng": "-12"
+ },
+ {
+ "iso": "MU",
+ "lat": "-20.2833",
+ "lng": "57.55"
+ },
+ {
+ "iso": "YT",
+ "lat": "-12.8333",
+ "lng": "45.1667"
+ },
+ {
+ "iso": "MX",
+ "lat": "23",
+ "lng": "-102"
+ },
+ {
+ "iso": "Federated States of",
+ "lat": "583",
+ "lng": "6.9167"
+ },
+ {
+ "iso": "Republic of",
+ "lat": "498",
+ "lng": "47"
+ },
+ {
+ "iso": "MC",
+ "lat": "43.7333",
+ "lng": "7.4"
+ },
+ {
+ "iso": "MN",
+ "lat": "46",
+ "lng": "105"
+ },
+ {
+ "iso": "ME",
+ "lat": "42",
+ "lng": "19"
+ },
+ {
+ "iso": "MS",
+ "lat": "16.75",
+ "lng": "-62.2"
+ },
+ {
+ "iso": "MA",
+ "lat": "32",
+ "lng": "-5"
+ },
+ {
+ "iso": "MZ",
+ "lat": "-18.25",
+ "lng": "35"
+ },
+ {
+ "iso": "MM",
+ "lat": "22",
+ "lng": "98"
+ },
+ {
+ "iso": "NA",
+ "lat": "-22",
+ "lng": "17"
+ },
+ {
+ "iso": "NR",
+ "lat": "-0.5333",
+ "lng": "166.9167"
+ },
+ {
+ "iso": "NP",
+ "lat": "28",
+ "lng": "84"
+ },
+ {
+ "iso": "AN",
+ "lat": "12.25",
+ "lng": "-68.75"
+ },
+ {
+ "iso": "NL",
+ "lat": "52.5",
+ "lng": "5.75"
+ },
+ {
+ "iso": "NC",
+ "lat": "-21.5",
+ "lng": "165.5"
+ },
+ {
+ "iso": "NZ",
+ "lat": "-41",
+ "lng": "174"
+ },
+ {
+ "iso": "NI",
+ "lat": "13",
+ "lng": "-85"
+ },
+ {
+ "iso": "NE",
+ "lat": "16",
+ "lng": "8"
+ },
+ {
+ "iso": "NG",
+ "lat": "10",
+ "lng": "8"
+ },
+ {
+ "iso": "NU",
+ "lat": "-19.0333",
+ "lng": "-169.8667"
+ },
+ {
+ "iso": "NF",
+ "lat": "-29.0333",
+ "lng": "167.95"
+ },
+ {
+ "iso": "MP",
+ "lat": "15.2",
+ "lng": "145.75"
+ },
+ {
+ "iso": "NO",
+ "lat": "62",
+ "lng": "10"
+ },
+ {
+ "iso": "OM",
+ "lat": "21",
+ "lng": "57"
+ },
+ {
+ "iso": "PK",
+ "lat": "30",
+ "lng": "70"
+ },
+ {
+ "iso": "PW",
+ "lat": "7.5",
+ "lng": "134.5"
+ },
+ {
+ "iso": "Occupied",
+ "lat": "275",
+ "lng": "32"
+ },
+ {
+ "iso": "PA",
+ "lat": "9",
+ "lng": "-80"
+ },
+ {
+ "iso": "PG",
+ "lat": "-6",
+ "lng": "147"
+ },
+ {
+ "iso": "PY",
+ "lat": "-23",
+ "lng": "-58"
+ },
+ {
+ "iso": "PE",
+ "lat": "-10",
+ "lng": "-76"
+ },
+ {
+ "iso": "PH",
+ "lat": "13",
+ "lng": "122"
+ },
+ {
+ "iso": "PN",
+ "lat": "-24.7",
+ "lng": "-127.4"
+ },
+ {
+ "iso": "PL",
+ "lat": "52",
+ "lng": "20"
+ },
+ {
+ "iso": "PT",
+ "lat": "39.5",
+ "lng": "-8"
+ },
+ {
+ "iso": "PR",
+ "lat": "18.25",
+ "lng": "-66.5"
+ },
+ {
+ "iso": "QA",
+ "lat": "25.5",
+ "lng": "51.25"
+ },
+ {
+ "iso": "RE",
+ "lat": "-21.1",
+ "lng": "55.6"
+ },
+ {
+ "iso": "RO",
+ "lat": "46",
+ "lng": "25"
+ },
+ {
+ "iso": "RU",
+ "lat": "60",
+ "lng": "100"
+ },
+ {
+ "iso": "RU",
+ "lat": "60",
+ "lng": "100"
+ },
+ {
+ "iso": "RW",
+ "lat": "-2",
+ "lng": "30"
+ },
+ {
+ "iso": "BL",
+ "lat": "17.897728",
+ "lng": "-62.834244"
+ },
+ {
+ "iso": "Ascension and Tristan da Cunha",
+ "lat": "654",
+ "lng": "-15.9333"
+ },
+ {
+ "iso": "KN",
+ "lat": "17.3333",
+ "lng": "-62.75"
+ },
+ {
+ "iso": "LC",
+ "lat": "13.8833",
+ "lng": "-61.1333"
+ },
+ {
+ "iso": "MF",
+ "lat": "18.075278",
+ "lng": "-63.06"
+ },
+ {
+ "iso": "PM",
+ "lat": "46.8333",
+ "lng": "-56.3333"
+ },
+ {
+ "iso": "VC",
+ "lat": "13.25",
+ "lng": "-61.2"
+ },
+ {
+ "iso": "VC",
+ "lat": "13.25",
+ "lng": "-61.2"
+ },
+ {
+ "iso": "WS",
+ "lat": "-13.5833",
+ "lng": "-172.3333"
+ },
+ {
+ "iso": "SM",
+ "lat": "43.7667",
+ "lng": "12.4167"
+ },
+ {
+ "iso": "ST",
+ "lat": "1",
+ "lng": "7"
+ },
+ {
+ "iso": "SA",
+ "lat": "25",
+ "lng": "45"
+ },
+ {
+ "iso": "SN",
+ "lat": "14",
+ "lng": "-14"
+ },
+ {
+ "iso": "RS",
+ "lat": "44",
+ "lng": "21"
+ },
+ {
+ "iso": "SC",
+ "lat": "-4.5833",
+ "lng": "55.6667"
+ },
+ {
+ "iso": "SL",
+ "lat": "8.5",
+ "lng": "-11.5"
+ },
+ {
+ "iso": "SG",
+ "lat": "1.3667",
+ "lng": "103.8"
+ },
+ {
+ "iso": "SX",
+ "lat": "18.033333",
+ "lng": "-63.05"
+ },
+ {
+ "iso": "SK",
+ "lat": "48.6667",
+ "lng": "19.5"
+ },
+ {
+ "iso": "SI",
+ "lat": "46",
+ "lng": "15"
+ },
+ {
+ "iso": "SB",
+ "lat": "-8",
+ "lng": "159"
+ },
+ {
+ "iso": "SO",
+ "lat": "10",
+ "lng": "49"
+ },
+ {
+ "iso": "ZA",
+ "lat": "-29",
+ "lng": "24"
+ },
+ {
+ "iso": "GS",
+ "lat": "-54.5",
+ "lng": "-37"
+ },
+ {
+ "iso": "KR",
+ "lat": "37",
+ "lng": "127.5"
+ },
+ {
+ "iso": "SS",
+ "lat": "8",
+ "lng": "30"
+ },
+ {
+ "iso": "ES",
+ "lat": "40",
+ "lng": "-4"
+ },
+ {
+ "iso": "LK",
+ "lat": "7",
+ "lng": "81"
+ },
+ {
+ "iso": "VC",
+ "lat": "13.25",
+ "lng": "-61.2"
+ },
+ {
+ "iso": "SD",
+ "lat": "15",
+ "lng": "30"
+ },
+ {
+ "iso": "SR",
+ "lat": "4",
+ "lng": "-56"
+ },
+ {
+ "iso": "SJ",
+ "lat": "78",
+ "lng": "20"
+ },
+ {
+ "iso": "SZ",
+ "lat": "-26.5",
+ "lng": "31.5"
+ },
+ {
+ "iso": "SE",
+ "lat": "62",
+ "lng": "15"
+ },
+ {
+ "iso": "CH",
+ "lat": "47",
+ "lng": "8"
+ },
+ {
+ "iso": "SY",
+ "lat": "35",
+ "lng": "38"
+ },
+ {
+ "iso": "TW",
+ "lat": "23.5",
+ "lng": "121"
+ },
+ {
+ "iso": "TJ",
+ "lat": "39",
+ "lng": "71"
+ },
+ {
+ "iso": "United Republic of",
+ "lat": "834",
+ "lng": "-6"
+ },
+ {
+ "iso": "TH",
+ "lat": "15",
+ "lng": "100"
+ },
+ {
+ "iso": "TL",
+ "lat": "-8.55",
+ "lng": "125.5167"
+ },
+ {
+ "iso": "TG",
+ "lat": "8",
+ "lng": "1.1667"
+ },
+ {
+ "iso": "TK",
+ "lat": "-9",
+ "lng": "-172"
+ },
+ {
+ "iso": "TO",
+ "lat": "-20",
+ "lng": "-175"
+ },
+ {
+ "iso": "TT",
+ "lat": "11",
+ "lng": "-61"
+ },
+ {
+ "iso": "TN",
+ "lat": "34",
+ "lng": "9"
+ },
+ {
+ "iso": "TR",
+ "lat": "39",
+ "lng": "35"
+ },
+ {
+ "iso": "TM",
+ "lat": "40",
+ "lng": "60"
+ },
+ {
+ "iso": "TC",
+ "lat": "21.75",
+ "lng": "-71.5833"
+ },
+ {
+ "iso": "TV",
+ "lat": "-8",
+ "lng": "178"
+ },
+ {
+ "iso": "UG",
+ "lat": "1",
+ "lng": "32"
+ },
+ {
+ "iso": "UA",
+ "lat": "49",
+ "lng": "32"
+ },
+ {
+ "iso": "AE",
+ "lat": "24",
+ "lng": "54"
+ },
+ {
+ "iso": "GB",
+ "lat": "54",
+ "lng": "-2"
+ },
+ {
+ "iso": "UM",
+ "lat": "19.2833",
+ "lng": "166.6"
+ },
+ {
+ "iso": "US",
+ "lat": "38",
+ "lng": "-97"
+ },
+ {
+ "iso": "UY",
+ "lat": "-33",
+ "lng": "-56"
+ },
+ {
+ "iso": "UZ",
+ "lat": "41",
+ "lng": "64"
+ },
+ {
+ "iso": "VU",
+ "lat": "-16",
+ "lng": "167"
+ },
+ {
+ "iso": "Bolivarian Republic of",
+ "lat": "862",
+ "lng": "8"
+ },
+ {
+ "iso": "VE",
+ "lat": "8",
+ "lng": "-66"
+ },
+ {
+ "iso": "VN",
+ "lat": "16",
+ "lng": "106"
+ },
+ {
+ "iso": "VN",
+ "lat": "16",
+ "lng": "106"
+ },
+ {
+ "iso": "British",
+ "lat": "92",
+ "lng": "18.5"
+ },
+ {
+ "iso": "U.S.",
+ "lat": "850",
+ "lng": "18.3333"
+ },
+ {
+ "iso": "WF",
+ "lat": "-13.3",
+ "lng": "-176.2"
+ },
+ {
+ "iso": "EH",
+ "lat": "24.5",
+ "lng": "-13"
+ },
+ {
+ "iso": "YE",
+ "lat": "15",
+ "lng": "48"
+ },
+ {
+ "iso": "ZM",
+ "lat": "-15",
+ "lng": "30"
+ },
+ {
+ "iso": "ZW",
+ "lat": "-20",
+ "lng": "30"
+ }
+]
\ No newline at end of file
diff --git a/src/components/Peers/types.ts b/src/components/Peers/types.ts
new file mode 100644
index 0000000..a3e1bea
--- /dev/null
+++ b/src/components/Peers/types.ts
@@ -0,0 +1,4 @@
+export type PeerPin = {
+ lat: number;
+ lng: number;
+};
\ No newline at end of file
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 2484188..3441411 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -17,6 +17,7 @@ import { Route as DashboardIndexImport } from './routes/dashboard/index'
import { Route as DashboardSettingsImport } from './routes/dashboard/settings'
import { Route as DashboardRequestsImport } from './routes/dashboard/requests'
import { Route as DashboardPurchasesImport } from './routes/dashboard/purchases'
+import { Route as DashboardPeersImport } from './routes/dashboard/peers'
import { Route as DashboardHelpImport } from './routes/dashboard/help'
import { Route as DashboardFavoritesImport } from './routes/dashboard/favorites'
import { Route as DashboardDisclaimerImport } from './routes/dashboard/disclaimer'
@@ -55,6 +56,11 @@ const DashboardPurchasesRoute = DashboardPurchasesImport.update({
getParentRoute: () => DashboardRoute,
} as any)
+const DashboardPeersRoute = DashboardPeersImport.update({
+ path: '/peers',
+ getParentRoute: () => DashboardRoute,
+} as any)
+
const DashboardHelpRoute = DashboardHelpImport.update({
path: '/help',
getParentRoute: () => DashboardRoute,
@@ -133,6 +139,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardHelpImport
parentRoute: typeof DashboardImport
}
+ '/dashboard/peers': {
+ id: '/dashboard/peers'
+ path: '/peers'
+ fullPath: '/dashboard/peers'
+ preLoaderRoute: typeof DashboardPeersImport
+ parentRoute: typeof DashboardImport
+ }
'/dashboard/purchases': {
id: '/dashboard/purchases'
path: '/purchases'
@@ -172,6 +185,7 @@ interface DashboardRouteChildren {
DashboardDisclaimerRoute: typeof DashboardDisclaimerRoute
DashboardFavoritesRoute: typeof DashboardFavoritesRoute
DashboardHelpRoute: typeof DashboardHelpRoute
+ DashboardPeersRoute: typeof DashboardPeersRoute
DashboardPurchasesRoute: typeof DashboardPurchasesRoute
DashboardRequestsRoute: typeof DashboardRequestsRoute
DashboardSettingsRoute: typeof DashboardSettingsRoute
@@ -184,6 +198,7 @@ const DashboardRouteChildren: DashboardRouteChildren = {
DashboardDisclaimerRoute: DashboardDisclaimerRoute,
DashboardFavoritesRoute: DashboardFavoritesRoute,
DashboardHelpRoute: DashboardHelpRoute,
+ DashboardPeersRoute: DashboardPeersRoute,
DashboardPurchasesRoute: DashboardPurchasesRoute,
DashboardRequestsRoute: DashboardRequestsRoute,
DashboardSettingsRoute: DashboardSettingsRoute,
@@ -202,6 +217,7 @@ export interface FileRoutesByFullPath {
'/dashboard/disclaimer': typeof DashboardDisclaimerRoute
'/dashboard/favorites': typeof DashboardFavoritesRoute
'/dashboard/help': typeof DashboardHelpRoute
+ '/dashboard/peers': typeof DashboardPeersRoute
'/dashboard/purchases': typeof DashboardPurchasesRoute
'/dashboard/requests': typeof DashboardRequestsRoute
'/dashboard/settings': typeof DashboardSettingsRoute
@@ -215,6 +231,7 @@ export interface FileRoutesByTo {
'/dashboard/disclaimer': typeof DashboardDisclaimerRoute
'/dashboard/favorites': typeof DashboardFavoritesRoute
'/dashboard/help': typeof DashboardHelpRoute
+ '/dashboard/peers': typeof DashboardPeersRoute
'/dashboard/purchases': typeof DashboardPurchasesRoute
'/dashboard/requests': typeof DashboardRequestsRoute
'/dashboard/settings': typeof DashboardSettingsRoute
@@ -230,6 +247,7 @@ export interface FileRoutesById {
'/dashboard/disclaimer': typeof DashboardDisclaimerRoute
'/dashboard/favorites': typeof DashboardFavoritesRoute
'/dashboard/help': typeof DashboardHelpRoute
+ '/dashboard/peers': typeof DashboardPeersRoute
'/dashboard/purchases': typeof DashboardPurchasesRoute
'/dashboard/requests': typeof DashboardRequestsRoute
'/dashboard/settings': typeof DashboardSettingsRoute
@@ -246,6 +264,7 @@ export interface FileRouteTypes {
| '/dashboard/disclaimer'
| '/dashboard/favorites'
| '/dashboard/help'
+ | '/dashboard/peers'
| '/dashboard/purchases'
| '/dashboard/requests'
| '/dashboard/settings'
@@ -258,6 +277,7 @@ export interface FileRouteTypes {
| '/dashboard/disclaimer'
| '/dashboard/favorites'
| '/dashboard/help'
+ | '/dashboard/peers'
| '/dashboard/purchases'
| '/dashboard/requests'
| '/dashboard/settings'
@@ -271,6 +291,7 @@ export interface FileRouteTypes {
| '/dashboard/disclaimer'
| '/dashboard/favorites'
| '/dashboard/help'
+ | '/dashboard/peers'
| '/dashboard/purchases'
| '/dashboard/requests'
| '/dashboard/settings'
@@ -315,6 +336,7 @@ export const routeTree = rootRoute
"/dashboard/disclaimer",
"/dashboard/favorites",
"/dashboard/help",
+ "/dashboard/peers",
"/dashboard/purchases",
"/dashboard/requests",
"/dashboard/settings",
@@ -341,6 +363,10 @@ export const routeTree = rootRoute
"filePath": "dashboard/help.tsx",
"parent": "/dashboard"
},
+ "/dashboard/peers": {
+ "filePath": "dashboard/peers.tsx",
+ "parent": "/dashboard"
+ },
"/dashboard/purchases": {
"filePath": "dashboard/purchases.tsx",
"parent": "/dashboard"
diff --git a/src/routes/dashboard.tsx b/src/routes/dashboard.tsx
index c50f33a..fea649d 100644
--- a/src/routes/dashboard.tsx
+++ b/src/routes/dashboard.tsx
@@ -12,6 +12,7 @@ import {
Settings,
HelpCircle,
TriangleAlert,
+ Earth,
} from "lucide-react";
import { ICON_SIZE } from "../utils/constants";
import { NodeIndicator } from "../components/NodeIndicator/NodeIndicator";
@@ -87,6 +88,15 @@ const Layout = () => {
),
},
+ {
+ type: "menu-item",
+ Component: (p: MenuItemComponentProps) => (
+
+
+ Peers
+
+ ),
+ },
{
type: "menu-item",
Component: (p: MenuItemComponentProps) => (
diff --git a/src/routes/dashboard/peers.css b/src/routes/dashboard/peers.css
new file mode 100644
index 0000000..e017a11
--- /dev/null
+++ b/src/routes/dashboard/peers.css
@@ -0,0 +1,10 @@
+.peers-map,
+.peers-table {
+ max-width: 1000px;
+ margin: auto;
+}
+
+.peers-table {
+ margin-top: 1rem;
+ width: 100%;
+}
diff --git a/src/routes/dashboard/peers.tsx b/src/routes/dashboard/peers.tsx
new file mode 100644
index 0000000..b0f836e
--- /dev/null
+++ b/src/routes/dashboard/peers.tsx
@@ -0,0 +1,98 @@
+import { Cell, Row, Table } from "@codex-storage/marketplace-ui-components";
+import { createFileRoute } from "@tanstack/react-router";
+import { getMapJSON } from "dotted-map";
+import DottedMap from "dotted-map/without-countries";
+import { Promises } from "../../utils/promises";
+import { useQuery } from "@tanstack/react-query";
+import { PeerCountryCell } from "../../components/Peers/PeerCountryCell";
+import { useCallback, useState } from "react";
+import { PeerPin } from "../../components/Peers/types";
+import "./peers.css";
+import { CodexSdk } from "../../sdk/codex";
+
+// This function accepts the same arguments as DottedMap in the example above.
+const mapJsonString = getMapJSON({ height: 60, grid: "diagonal" });
+
+export const Route = createFileRoute("/dashboard/peers")({
+ component: () => {
+ const [pins, setPins] = useState<[PeerPin, number][]>([]);
+ const { data } = useQuery({
+ queryFn: () =>
+ CodexSdk.debug.info().then((s) => Promises.rejectOnError(s)),
+ queryKey: ["debug"],
+
+ // No need to retry because if the connection to the node
+ // is back again, all the queries will be invalidated.
+ retry: false,
+
+ // The client node should be local, so display the cache value while
+ // making a background request looks good.
+ staleTime: 0,
+
+ // Refreshing when focus returns can be useful if a user comes back
+ // to the UI after performing an operation in the terminal.
+ refetchOnWindowFocus: true,
+
+ // Throw the error to the error boundary
+ throwOnError: true,
+ });
+
+ const onPinAdd = useCallback((pin: PeerPin) => {
+ setPins((val) => {
+ const [, quantity = 0] =
+ val.find(([p]) => p.lat === pin.lat && p.lng == pin.lng) || [];
+ return [...val, [pin, quantity + 1]];
+ });
+ }, []);
+
+ // It’s safe to re-create the map at each render, because of the
+ // pre-computation it’s super fast ⚡️
+ const map = new DottedMap({ map: JSON.parse(mapJsonString) });
+
+ pins.map(([pin, quantity]) =>
+ map.addPin({
+ lat: pin.lat,
+ lng: pin.lng,
+ svgOptions: { color: "#d6ff79", radius: 0.4 * quantity },
+ })
+ );
+
+ const svgMap = map.getSVG({
+ radius: 0.42,
+ color: "#423B38",
+ shape: "circle",
+ backgroundColor: "#020300",
+ });
+
+ const headers = ["Country", "PeerId", "Active"];
+
+ const rows =
+ ((data as any)?.table?.nodes || []).map((node: any) => (
+ ,
+ | {node.peerId} | ,
+
+ {node.seen ? (
+
+ ) : (
+
+ )}
+ | ,
+ ]}>
+ )) || [];
+
+ return (
+ <>
+
+
+
+ >
+ );
+ },
+});