Repository: thenewboston-developers/Website
File: src/containers/Webmap/index.tsx (TypeScript)

Code before:
      const merged = nodeResponses.map((result: any, i: string | number) => ({
        ...result,
        ...resultBatch.data[i],
      }));
      setState(merged);
    }
    fetchData();
  }, []);

  return (
    <Map center={[37, -30]} zoom={3}>
      <TileLayer
        attribution="Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ"
        url="https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}'"
      />
      {state.map((node) => (
        <Marker
          key={node.query}
          position={[node.lat + Math.random() * (0.2 - 0.1) + 0.1, node.lon]}
          icon={node.root_account_file != null ? validatorIcon : bankIcon}
        >
          <Popup maxWidth={700} position={[node.lat + Math.random() * (0.2 - 0.1) + 0.1, node.lon]}>
            <div>
              <h2>Node Info</h2>
              <br />
              <h4>Node Type: {node.root_account_file != null ? 'Validator' : 'Bank'}</h4>
              <h4>Country: {node.country}</h4>
              <h4>City: {node.city}</h4>
              <h4>IP Address: {node.query}</h4>
              <h4>Account Number: {node.account_number}</h4>
              <h4>Default TX Fee: {node.default_transaction_fee}</h4>
              <h4>Provider: {node.org}</h4>
            </div>
          </Popup>
        </Marker>
      ))}
    </Map>
  );
};

export default Webmap;


Review comment (suggestion):
```suggestion
              <h4>Node Type: {node.root_account_file === null ? 'Bank' : 'Validator'}</h4>
```

Code after:
      const nodeResponses = nodeResponse[0].data.results.concat(nodeResponse[1].data.results);
      const validatorIps = [];
      for (let i = 0; i < nodeResponses.length; i += 1) {
        const ipAddress = nodeResponses[i].ip_address;
        validatorIps.push({query: ipAddress});
      }
      const resultBatch = await axios.post(apiEndpoints.IPAPI_ENDPOINT, validatorIps);
      const merged = nodeResponses.map((result: any, i: string | number) => ({
        ...result,
        ...resultBatch.data[i],
      }));
      setNodes(merged);
    }
    fetchData();
  }, []);

  const renderPopupContent = (node: Node) => (
    <div className="Map__Popup">
      <h2 className="Map__Popup-heading">{node.root_account_file ? 'Validator' : 'Bank'}</h2>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">IP Address</div>
        <div className="Map__Popup-info-value">{node.query}</div>
      </div>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">Account Number</div>
        <div className="Map__Popup-info-value">{node.account_number}</div>
      </div>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">Default Tx Fee</div>
        <div className="Map__Popup-info-value">{node.default_transaction_fee}</div>
      </div>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">City</div>
        <div className="Map__Popup-info-value">{node.city}</div>
      </div>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">Country</div>
        <div className="Map__Popup-info-value">{node.country}</div>
      </div>
      <div className="Map__Popup-info">
        <div className="Map__Popup-info-label">Provider</div>
        <div className="Map__Popup-info-value">{node.org}</div>
      </div>
    </div>
  );
  return (
    <Map
      className="Map"
      center={clientWidth > 450 ? [37, -30] : [45, -20]}
      zoom={clientWidth > 450 ? 2.5 : 1}
      minZoom={clientWidth > 450 ? 2.5 : 1}