react-leaflet#TileLayer TypeScript Examples

The following examples show how to use react-leaflet#TileLayer. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MetroMap.tsx    From metro-fare with MIT License 6 votes vote down vote up
MetroMap = () => {
  const [mapCenter, setMapCenter] = useState<LatLngTuple>(DEFAULT_MAP_CENTER);
  const { setShowMetroLayers } = useMapContext();
  const { trip, journey } = useTripContext();

  useEffect(() => {
    if (
      !(
        mapCenter[0] === DEFAULT_MAP_CENTER[0] &&
        mapCenter[1] === DEFAULT_MAP_CENTER[1]
      )
    ) {
      setMapCenter(DEFAULT_MAP_CENTER);
    }
  }, [mapCenter]);

  useEffect(() => {
    const isVisible = journey.route.length === 0;
    setShowMetroLayers({
      mrtBlue: isVisible,
      btsSilom: isVisible,
      btsSukhumvit: isVisible,
      btsGold: isVisible,
      arl: isVisible,
      brt: isVisible,
    });
  }, [journey, setShowMetroLayers]);

  return (
    <div className="width-100 height-100">
      <Map
        className="width-100 height-100"
        center={mapCenter}
        zoom={12}
        minZoom={12}
        maxZoom={17}
        zoomControl={false}
      >
        <MapControl />
        <TileLayer
          attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <MetroLineLayers />
        {journey.route.length > 0 && <TravelRouteLayer />}
        <FromToStationLayer trip={trip} />
      </Map>
    </div>
  );
}
Example #2
Source File: OrphanagesMap.tsx    From NLW-3.0 with MIT License 6 votes vote down vote up
function OrphanagesMap() {
  const [orphanages, setOrphanages] = useState<Orphanage[]>([]);

  useEffect(() => {
    api.get('orphanages').then(response => {
      setOrphanages(response.data);
    });
  }, []);

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMarkerImg} alt="Happy" />

          <h2>Escolha um orfanato no mapa</h2>

          <p>Muitas crianças estão esperando a sua visita {':)'}</p>
        </header>

        <footer>
          <strong>Meia Praia</strong>
          <span>Santa Catarina</span>
        </footer>
      </aside>

      <Map
        center={[-27.1376523, -48.6087994]}
        zoom={15}
        style={{ width: '100%', height: '100%' }}
      >
        {/* <TileLayer url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" /> */}
        <TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
        />

        {orphanages.map(orphanage => (
          <Marker
            key={orphanage.id}
            icon={mapIcon}
            position={[orphanage.latitude, orphanage.longitude]}
          >
            <Popup closeButton={false} minWidth={240} maxWidth={240} className="map-popup">
              {orphanage.name}
              <Link to={`/orphanages/${orphanage.id}`}>
                <FiArrowRight size={20} color="#fff" />
              </Link>
            </Popup>
          </Marker>
        ))}
      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#fff" />
      </Link>
    </div>
  )
}
Example #3
Source File: index.tsx    From nlw-03-omnistack with MIT License 6 votes vote down vote up
export default function Map({ children, interactive = true, ...props }: MapProps) {
  return (
    <LeafletMap 
      center={[-27.2092052,-49.6401092]} 
      zoom={15} 
      style={{ width: '100%', height: '100%' }}
      dragging={interactive}
      touchZoom={interactive}
      zoomControl={interactive}
      scrollWheelZoom={interactive}
      doubleClickZoom={interactive}
      {...props}
    >
      <TileLayer 
        url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
      />
      {children}
    </LeafletMap>
  );
}
Example #4
Source File: Map.tsx    From MLH-Fellow-Map with MIT License 6 votes vote down vote up
Map: FunctionComponent<{
  defaultBaseMap: string;
  className?: string;
}> = ({
  children,
  className,
  defaultBaseMap = DEFAULT_MAP_SERVICE,
  ...rest
}) => {
  useConfigureLeaflet();

  const basemap = getMapServiceByName(defaultBaseMap);

  const mapClassName = `map`;

  if (!isDomAvailable()) {
    return (
      <div className={`${mapClassName} ${className || ''}`}>
        <p className="map-loading">Loading map...</p>
      </div>
    );
  }

  const mapSettings = {
    className: 'map-base',
    zoomControl: false,
    ...rest,
  };

  return (
    <div className={mapClassName}>
      <BaseMap {...mapSettings}>
        {basemap && <TileLayer {...basemap} />}
        {children}
        <ZoomControl position="bottomright" />
      </BaseMap>
    </div>
  );
}
Example #5
Source File: sofarLayers.tsx    From aqualink-app with MIT License 6 votes vote down vote up
SofarLayers = ({ defaultLayerName }: SofarLayersProps) => {
  return (
    <LayersControl position="topright">
      <LayersControl.BaseLayer
        checked={!defaultLayerName}
        name="Satellite Imagery"
        key="no-verlay"
      >
        <TileLayer url="" key="no-overlay" />
      </LayersControl.BaseLayer>
      {SOFAR_LAYERS.map((def) => (
        <LayersControl.BaseLayer
          checked={def.name === defaultLayerName}
          name={def.name}
          key={def.name}
        >
          <TileLayer
            // Sofar tiles have a max native zoom of 9
            maxNativeZoom={9}
            url={sofarUrlFromDef(def)}
            key={def.variableId}
            opacity={0.5}
          />
        </LayersControl.BaseLayer>
      ))}
    </LayersControl>
  );
}
Example #6
Source File: NodeMap.tsx    From nanolooker with MIT License 5 votes vote down vote up
NodeMap: React.FC<Props> = ({ nodeMonitors, isLoading }) => {
  const { t } = useTranslation();
  const [nodes, setNodes] = React.useState([] as NodeLocation[]);
  const { knownAccounts, isLoading: isKnownAccountsLoading } = React.useContext(
    KnownAccountsContext,
  );

  React.useEffect(() => {
    if (isKnownAccountsLoading || isLoading) return;

    getNodeLocations().then(nodeLocations => {
      const nodes = nodeLocations?.map(nodeLocation => {
        const nodeMonitor = nodeMonitors?.find(
          ({ rawIp }) => rawIp === nodeLocation.rawIp,
        );
        const knownAccount = nodeMonitor
          ? knownAccounts.find(({ account }) => account === nodeMonitor.account)
          : null;

        return {
          ...nodeLocation,
          ...nodeMonitor,
          ...knownAccount,
        };
      })!;

      setNodes(nodes);
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isLoading, isKnownAccountsLoading]);

  return (
    <>
      <Title level={3}>
        {t("pages.status.nodeLocations", {
          count: nodes.length,
        })}
      </Title>
      <div style={{ marginBottom: "12px" }}>
        <MapContainer
          center={[25, 0]}
          zoom={2}
          minZoom={2}
          style={{ height: "500px" }}
          scrollWheelZoom={false}
        >
          <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
          <Markers nodes={nodes} />
        </MapContainer>
      </div>
    </>
  );
}
Example #7
Source File: OrphanagesMap.tsx    From happy with MIT License 5 votes vote down vote up
function OrphanagesMap() {
  const [orphanages, setOrphanages] = useState<Orphanage[]>([]);

  useEffect(() => {
    api.get('orphanages').then(response => {
      setOrphanages(response.data);
    });
  }, []);

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMarkerImg} alt="Happy"/>

          <h2>Escolha um orfanato no mapa</h2>

          <p>Muitas crianças estão esperando a sua visita {':)'}</p>
        </header>

        <footer>
          <strong>Rio do Sul</strong>
          <span>Santa Catarina</span>
        </footer>
      </aside>

      <Map
        center={[-27.2092052, -49.6401092]}
        zoom={15}
        style={{ width: '100%', height: '100%'}}
      >
        <TileLayer url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" />
        {/* <TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
        /> */}

        {orphanages.map(orphanage => (
          <Marker
            key={orphanage.id}
            icon={mapIcon}
            position={[orphanage.latitude, orphanage.longitude]}
          >
            <Popup closeButton={false} minWidth={240} maxWidth={240} className="map-popup">
              {orphanage.name}
              <Link to={`/orphanages/${orphanage.id}`}>
                <FiArrowRight size={20} color="#fff" />
              </Link>
            </Popup>
          </Marker>
        ))}
      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#fff" />
      </Link>
    </div>
  )
}
Example #8
Source File: OrphanagesMap.tsx    From happy with MIT License 5 votes vote down vote up
function OrphanagesMap() {

  const [orphanages, setOrphaanges] = useState<Orphanage[]>([]);

  useEffect(() => {
    api.get("/orphanages").then(res => {
      setOrphaanges(res.data);
    });
  }, []);

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMakerImg} alt="Logo da plataforma Happy" />

          <h2>Escolha um orfanato no mapa</h2>
          <p>Muitas crianças estão esperando sua visita :)</p>
        </header>

        <footer>
          <strong>São Paulo</strong>
          <span>São Paulo</span>
        </footer>
      </aside>

      <Map
        center={[-23.6821604, -46.8754915]}
        zoom={10}
        style={{ width: "100%", height: "100%" }}
      >

        {/* Mapa alternativo: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" */}
        <TileLayer
          url={
            `https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`
          }
        />

        {orphanages.map(orphanage => {
          return (
            <Marker
              key={orphanage.id}
              icon={mapIcon}
              position={[orphanage.latitude, orphanage.longitude]}
            >
              <Popup
                closeButton={false}
                minWidth={240}
                maxWidth={240}
                className="map-popup"
              >
                {orphanage.name}
                <Link to={`/orphanages/${orphanage.id}`}>
                  <FiArrowRight size={20} color="#FFF" />
                </Link>
              </Popup>
            </Marker>
          )
        })}

      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#FFF" />
      </Link>

    </div>
  );
}
Example #9
Source File: SchoolsMap.tsx    From po8klasie with GNU General Public License v3.0 5 votes vote down vote up
SchoolsMap: FC<SchoolsMapProps> = ({ results, onExpandToggle, isExpanded, hideExpandBtn }) => {
  const [map, setMap] = useState<LeafletMap | null>(null);
  const { searchView: searchViewConfig } = useProjectConfig();
  const { mapOptions } = searchViewConfig as SearchViewConfig;

  useEffect(() => {
    setTimeout(() => {
      if (map) map.invalidateSize();
    }, 300);
  }, [isExpanded, map]);

  useEffect(() => {
    if (map && results.length > 0) {
      const lngLatExpressions = results.map((school) => parseCoords(school));
      map.fitBounds(latLngBounds(lngLatExpressions));
    }
  }, [results, map]);

  return (
    <div className={isExpanded ? styles.mapWrapperExpanded : styles.mapWrapper}>
      <MapContainer
        className={styles.map}
        zoomControl={false}
        whenCreated={setMap}
        fullscreenControl
        {...mapOptions}
      >
        <TileLayer {...tileLayerProps} />
        {results.map(({ latitude, longitude, name, id }) => {
          if (!latitude || !longitude) return null;

          return (
            <Marker
              position={{
                lat: parseFloat(latitude),
                lng: parseFloat(longitude),
              }}
              icon={marker}
              key={id}
            >
              <Popup className={styles.markerPopup}>
                <h4>{name}</h4>
              </Popup>
            </Marker>
          );
        })}
      </MapContainer>
      {
        !hideExpandBtn && (
          <button className={styles.mapExpandButton} onClick={onExpandToggle} type="button">
            <BsChevronRight />
          </button>
        )
      }
    </div>
  );
}
Example #10
Source File: SchoolLocationMap.tsx    From po8klasie with GNU General Public License v3.0 5 votes vote down vote up
SchoolLocationMap: FC<SchoolLocationMapProps> = ({ position }) => (
  <MapContainer center={position} zoom={13} className="w-full h-full rounded">
    <TileLayer {...tileLayerProps} />
    <Marker position={position} icon={marker} />
  </MapContainer>
)
Example #11
Source File: index.tsx    From aqualink-app with MIT License 5 votes vote down vote up
LocationMap = ({
  markerPositionLat,
  markerPositionLng,
  updateMarkerPosition,
  classes,
}: LocationMapProps) => {
  const [zoom, setZoom] = useState<number>(INITIAL_ZOOM);

  const onZoomEnd = useCallback(
    // eslint-disable-next-line no-underscore-dangle
    (event: LeafletEvent) => setZoom(event.target._zoom as number),
    []
  );

  function updateLatLng(event: L.LeafletMouseEvent) {
    const { lat, lng } = event.latlng.wrap();
    updateMarkerPosition([lat, lng]);
  }

  function parseCoordinates(coord: string, defaultValue: number) {
    const parsed = parseFloat(coord);
    return Number.isNaN(parsed) ? defaultValue : parsed;
  }

  const markerPosition: L.LatLngTuple = [
    parseCoordinates(markerPositionLat, 37.773972),
    parseCoordinates(markerPositionLng, -122.431297),
  ];

  return (
    <Map
      center={markerPosition}
      zoom={zoom}
      className={classes.map}
      onclick={updateLatLng}
      onzoomend={onZoomEnd}
      maxBounds={mapConstants.MAX_BOUNDS}
      maxBoundsViscosity={1.0}
      minZoom={1}
    >
      <TileLayer url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}" />
      {markerPosition && <Marker icon={pinIcon} position={markerPosition} />}
    </Map>
  );
}
Example #12
Source File: Map.tsx    From aqualink-app with MIT License 5 votes vote down vote up
SiteMap = ({ polygon, classes }: SiteMapProps) => {
  const mapRef = useRef<Map>(null);
  const diveLocation = useSelector(diveLocationSelector);
  const [markerLat, setMarkerLat] = useState<number | null>(null);
  const [markerLng, setMarkerLng] = useState<number | null>(null);
  const dispatch = useDispatch();

  useEffect(() => {
    const { current } = mapRef;
    if (current && current.leafletElement) {
      const map = current.leafletElement;
      // Initialize map's position to fit the given polygon
      if (polygon.type === "Polygon") {
        map.fitBounds(L.polygon(polygon.coordinates).getBounds());
      } else {
        map.panTo(new L.LatLng(polygon.coordinates[1], polygon.coordinates[0]));
      }
      const zoom = map.getZoom();
      if (zoom < Infinity) {
        // User can't zoom out from the initial frame
        map.setMinZoom(zoom);
      } else {
        map.setZoom(8);
        map.setMinZoom(8);
      }
    }
  }, [mapRef, polygon]);

  useEffect(() => {
    const { current } = mapRef;
    if (current && current.leafletElement) {
      const map = current.leafletElement;
      map.on("click", (event: any) => {
        setMarkerLat(event.latlng.lat);
        setMarkerLng(event.latlng.lng);
        dispatch(
          setDiveLocation({
            lat: event.latlng.lat,
            lng: event.latlng.lng,
          })
        );
      });
    }
  }, [dispatch]);

  useEffect(() => {
    if (polygon.type === "Point" && !diveLocation) {
      setMarkerLat(polygon.coordinates[1]);
      setMarkerLng(polygon.coordinates[0]);
      dispatch(
        setDiveLocation({
          lat: polygon.coordinates[1],
          lng: polygon.coordinates[0],
        })
      );
    }
  }, [polygon, diveLocation, dispatch]);

  useEffect(() => {
    if (diveLocation) {
      setMarkerLat(diveLocation.lat);
      setMarkerLng(diveLocation.lng);
    }
  }, [diveLocation]);

  return (
    <Map ref={mapRef} className={classes.map}>
      <TileLayer url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}" />
      {markerLat && markerLng && (
        <Marker icon={pinIcon} position={[markerLat, markerLng]} />
      )}
    </Map>
  );
}
Example #13
Source File: index.tsx    From NextLevelWeek with MIT License 5 votes vote down vote up
OrphanagesMap: React.FC = () => {
    const [orphanages, setOrphanages] = useState<IOpharnage[]>([]);

    useEffect(() => {
        api.get('/orphanages').then(res => {
            // console.log(res.data);
            setOrphanages(res.data);
        });
    }, []);

    return (
        <Container>
            <SideBar>
                <header>
                    <img src={mapMarkerImg} alt="" />

                    <h2>Escolha um orfanato no mapa</h2>
                    <p>Muitas crianças estão esperando a sua visita <span role="img" aria-label="happy">?</span></p>
                </header>

                <footer>
                    <strong>Natal</strong>
                    <span>Rio Grande do Norte</span>
                </footer>
            </SideBar>

            <Map
                center={[-5.8044209, -35.263095]}
                zoom={12}
                style={{ width: '100%', height: '100%' }}
            >
                <TileLayer url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`} />

                {orphanages.map(orphanage => {
                    return (
                        <Marker
                            key={orphanage.id}
                            position={[orphanage.latitude, orphanage.longitude]}
                            icon={happyMapIcon}
                        >
                            <Popup closeButton={false} minWidth={240} maxHeight={240} className="map-popup">
                                {orphanage.name}
                                <Link to={`/orphanages/${orphanage.id}`}>
                                    <FiArrowRight size={20} color="#fff" />
                                </Link>
                            </Popup>
                        </Marker>
                    );
                })}
            </Map>

            <Link to="/orphanages/create">
                <FiPlus size={32} color="#FFF" />
            </Link>
        </Container>
    );
}
Example #14
Source File: Orphanage.tsx    From happy with MIT License 4 votes vote down vote up
export default function Orphanage() {
  const params = useParams<OrphanageParams>();
  const [orphanage, setOrphaange] = useState<Orphanage>();
  const [activeImageIndex, setActiveImageIndex] = useState(0);

  useEffect(() => {
    api.get(`/orphanages/${params.id}`).then(res => {
      setOrphaange(res.data);
    });
  }, [params.id]);

  if (!orphanage) {
    return <p>Carregando...</p>
  }

  return (
    <div id="page-orphanage">
      <Sidebar />

      <main>
        <div className="orphanage-details">
          <img src={orphanage.images[activeImageIndex].url} alt={orphanage.name} />

          <div className="images">
            {orphanage.images.map((image, index) => {
              return (
                <button
                  key={image.id}
                  className={activeImageIndex === index ? "active" : ""}
                  type="button"
                  onClick={() => {
                    setActiveImageIndex(index);
                  }}
                >
                  <img src={image.url} alt={orphanage.name} />
                </button>
              )
            })}
          </div>

          <div className="orphanage-details-content">
            <h1>{orphanage.name}</h1>
            <p>{orphanage.about}</p>

            <div className="map-container">
              <Map
                center={[orphanage.latitude, orphanage.longitude]}
                zoom={16}
                style={{ width: '100%', height: 280 }}
                dragging={false}
                touchZoom={false}
                zoomControl={false}
                scrollWheelZoom={false}
                doubleClickZoom={false}
              >
                <TileLayer
                  url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
                />
                <Marker interactive={false} icon={mapIcon} position={[orphanage.latitude, orphanage.longitude]} />
              </Map>

              <footer>
                <a target="_blank" rel="noopener noreferrer" href={`https://google.com/maps/dir/?api=1&destination=${orphanage.latitude},${orphanage.longitude}`}>Ver rotas no Google Maps</a>
              </footer>
            </div>

            <hr />

            <h2>Instruções para visita</h2>
            <p>{orphanage.instructions}</p>

            <div className="open-details">
              <div className="hour">
                <FiClock size={32} color="#15B6D6" />
                Segunda à Sexta <br />
                {orphanage.opening_hours}
              </div>

              {orphanage.open_on_weekends ? (
                <div className="open-on-weekends">
                  <FiInfo size={32} color="#39CC83" />
                Atendemos <br />
                fim de semana
                </div>
              ) : (
                  <div className="open-on-weekends dont-open">
                    <FiInfo size={32} color="#FF6690" />
                Não Atendemos <br />
                fim de semana
                  </div>
                )}

            </div>

            {/* <button type="button" className="contact-button">
              <FaWhatsapp size={20} color="#FFF" />
              Entrar em contato
            </button> */}
          </div>
        </div>
      </main>
    </div>
  );
}
Example #15
Source File: index.tsx    From ecoleta with MIT License 4 votes vote down vote up
CreatePoint: React.FC = () => {

  const [items, setItems] = useState<Item[]>([]);
  const [selectedItems, setSelectedItems] = useState<number[]>([]);  
  
  const [ufs, setUfs] = useState<string[]>([]);
  const [selectedUf, setSelectedUf] = useState('0');
  const [cities, setCities] = useState<string[]>([]);
  const [selectedCity, setSelectedCity] = useState('0');
  
  const [selectedPosition, setSelectedPosition] = useState<[number, number]>([0, 0]);
  const [initialMapPosition, setInitialMapPosition] = useState<[number, number]>([0, 0]);

  const [selectedFile, setSelectedFile] = useState<File>();

  const [formData, setFormData] = useState({
    name: '',
    email: '',
    whatsapp: '',
  });

  const history = useHistory();

  useEffect(() => {
    navigator.geolocation.getCurrentPosition(position => {
      const { latitude, longitude } = position.coords;
      setInitialMapPosition([latitude, longitude]);
    });
  }, []);

  useEffect(() => {
    api.get('items').then(response => {
      setItems(response.data);
    });
  }, []);

  useEffect(() => {
    axios
      .get<IBGEUFResponse[]>('https://servicodados.ibge.gov.br/api/v1/localidades/estados')
      .then(response => {
        const ufInitials = response.data.map(uf => uf.sigla);
        setUfs(ufInitials);
      });
  }, []);

  useEffect(() => {
    if (selectedUf === '0') {
      return;
    }
    axios
      .get<IBGECityResponse[]>(`https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`)
      .then(response => {
        const cityNames = response.data.map(city => city.nome);
        setCities(cityNames);
      });
  }, [selectedUf]);

  function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
    const uf = event.target.value;
    setSelectedUf(uf);
  }

  function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
    const city = event.target.value;
    setSelectedCity(city);
  }

  function handleMapClick(event: LeafletMouseEvent) {
    setSelectedPosition([
      event.latlng.lat,
      event.latlng.lng
    ])
  }

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
    const { name, value } = event.target;
    setFormData({ ...formData, [name]: value });
  }

  function handleSelectItem(id: number) {
    const alreadSelected = selectedItems.findIndex(item => item === id);

    if (alreadSelected >= 0) {
      const filteredItems = selectedItems.filter(item => item !== id);
      setSelectedItems(filteredItems);
    } else {
      setSelectedItems([ ...selectedItems, id]);
    }
  }

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();

    const { name, email, whatsapp } = formData;
    const uf = selectedUf;
    const city = selectedCity;
    const [latitude, longitude] = selectedPosition;
    const items = selectedItems;

    const data = new FormData();

    data.append('name', name);
    data.append('email', email);
    data.append('whatsapp', whatsapp);
    data.append('uf', uf);
    data.append('city', city);
    data.append('latitude', String(latitude));
    data.append('longitude', String(longitude));
    data.append('items', items.join(','));
    
    if (selectedFile) {
      data.append('image', selectedFile);
    }

    await api.post('points', data);

    alert('Ponto de Coleta Criado!');
    
    history.push('/');
  }

  return (
    <div id="page-create-point">
      <header>
        <img src={logo} alt="Ecoleta Logo"/>

        <Link to="/">
          <FiArrowLeft />
          Voltar para home
        </Link>
      </header>

      <form onSubmit={handleSubmit}>
        <h1>Cadastro do <br />ponto de coleta</h1>

        <Dropzone onFileUploaded={setSelectedFile} />

        <fieldset>
          <legend>
            <h2>Dados</h2>
          </legend>

          <div className="field">
            <label htmlFor="name">Nome da entidade</label>
            <input 
              type="text"
              name="name"
              id="name"
              onChange={handleInputChange}
            />
          </div>

          <div className="field-group">
            <div className="field">
              <label htmlFor="email">E-mail</label>
              <input 
                type="email"
                name="email"
                id="email"
                onChange={handleInputChange}
              />
            </div>
            <div className="field">
              <label htmlFor="whatsapp">Whatsapp</label>
              <input 
                type="text"
                name="whatsapp"
                id="whatsapp"
                onChange={handleInputChange}
              />
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Endereço</h2>
            <span>Selecione o endereço no mapa</span>
          </legend>

          <Map center={initialMapPosition} zoom={15} onClick={handleMapClick}>
            <TileLayer
              attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
            <Marker position={selectedPosition}/>
          </Map>

          <div className="field-group">
            <div className="field">
              <label htmlFor="uf">Estado (UF)</label>
              <select 
                name="uf" 
                id="uf" 
                value={selectedUf} 
                onChange={handleSelectUf}
              >
                <option value="0">Selecione uma UF</option>
                {ufs.map(uf => (
                  <option key={uf} value={uf}>{uf}</option>
                ))}
              </select>
            </div>
            <div className="field">
              <label htmlFor="city">Cidade</label>
              <select 
                name="city" 
                id="city"
                value={selectedCity}
                onChange={handleSelectCity}
              >
                <option value="0">Selecione uma cidade</option>
                {cities.map(city => (
                  <option key={city} value={city}>{city}</option>
                ))}
              </select>
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Ítens de coleta</h2>
            <span>Selecione um ou mais ítens abaixo</span>
          </legend>

          <ul className="items-grid">
            {items.map(item => (
              <li 
                key={item.id} 
                onClick={() => handleSelectItem(item.id)}
                className={selectedItems.includes(item.id) ? 'selected' : ''}
              >
                <img src={item.image_url} alt={item.title}/>
                <span>{item.title}</span>
              </li>
            ))}
          </ul>
        </fieldset>

        <button type="submit">
          Cadastrar ponto de coleta
        </button>
      </form>
    </div>
  );
}
Example #16
Source File: index.tsx    From nlw-ecoleta with MIT License 4 votes vote down vote up
export function CreatePoint() {
	const [items, setItems] = useState<Item[]>([]);
	const [ufs, setUfs] = useState<string[]>([]);
	const [cities, setCities] = useState<string[]>([]);

	const [selectedItems, setSelectedItems] = useState<number[]>([]);
	const [initialPosition, setInitialPosition] = useState<[number, number]>([0, 0]);
	const [selectedFile, setSelectedFile] = useState<File>();
    
	const [formData, setFormData] = useState({
		name: '',
		email: '',
		whatsapp: '',
	});

	const [selectedUf, setSelectedUf] = useState('0');
	const [selectedCity, setSelectedCity] = useState('0');
	const [selectedPosition, setSelectedPosition] = useState<[number, number]>([0, 0]);

	const history = useNavigate();

	useEffect (() => {
		navigator.geolocation.getCurrentPosition(position => {
			const { latitude, longitude } = position.coords;
			setInitialPosition([latitude, longitude]);
		});
	}, []);

	useEffect(() => { 
		api.get('items').then(response => {
			setItems(response.data);
		});
	}, []);

	useEffect(() => { 
		axios
			.get<IBGEUFResponse[]>('https://servicodados.ibge.gov.br/api/v1/localidades/estados')
			.then(response => {
				const ufInitials = response.data.map(uf => uf.sigla);

				setUfs(ufInitials);
			});
	}, []);

	useEffect(() => {
		if(selectedUf === '0') {
			return;
		}

		axios
			.get<IBGECityResponse[]>(`https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`)
			.then(response => {
				const cityNames = response.data.map(city => city.nome);

				setCities(cityNames);
			});
	} , [selectedUf]);

	function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
		const uf = event.target.value;

		setSelectedUf(uf);
	}

	function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
		const city = event.target.value;

		setSelectedCity(city);
	}

	function handleMapClick(event: LeafletMouseEvent) {
		setSelectedPosition([
			event.latlng.lat,
			event.latlng.lng,
		]);
	}

	function handleInputChange(event: ChangeEvent<HTMLInputElement>){
		const { name, value } = event.target;

		setFormData({ ...formData, [name]: value });
	}

	function handleSelectItem(id: number) {
		const alreadySelected = selectedItems.findIndex(item => item === id);

		if (alreadySelected >= 0) {
			const filteredItems = selectedItems.filter(item => item  !== id);
			setSelectedItems(filteredItems);
		}

		else {
			setSelectedItems([ ...selectedItems, id ]);
		}
	}

	async function handleSubmit(event: FormEvent) {
		event.preventDefault();

		const { name, email, whatsapp } = formData;
		const uf = selectedUf;
		const city = selectedCity;
		const [ latitude, longitude ] = selectedPosition;
		const items = selectedItems;

		const data = new FormData();

		data.append('name', name);
		data.append('email', email);
		data.append('whatsapp', whatsapp);
		data.append('uf', uf);
		data.append('city', city);
		data.append('latitude', String(latitude));
		data.append('longitude', String(longitude));
		data.append('items', items.join(','));

		if (selectedFile) {
			data.append('image', selectedFile);
		}

		await api.post('points', data);

		alert('Ponto de coleta criado.');
		history('/');
	}

	// function LocationMarker() {
	// 	const map = useMapEvents({
	// 		click() {
	// 			map.locate();
	// 		},
	// 		locationfound(e) {
	// 			setSelectedPosition(e.latlng as any);
	// 			map.flyTo(e.latlng, map.getZoom());
	// 		},
	// 	});
	
	// 	return selectedPosition === null ? null : (
	// 		<Marker position={selectedPosition} />
	// 	);
	// }

	return (
		<div id='page-create-point'>
			<header>
				<img src={ logo } alt="Ecoleta" />

				<Link to='/'>
					<FiArrowLeft />
                    Voltar para home
				</Link>
			</header>

			<form onSubmit={handleSubmit}>
				<h1>Cadastro do <br /> ponto de coleta</h1>

				<Dropzone onFileUploaded={setSelectedFile} />

				<fieldset>
					<legend>
						<h2> Dados </h2>
					</legend>

					<div className='field'> 
						<label htmlFor="name"> Nome da entidade</label>
						<input 
							type="text"
							name="name"
							id="name"
							onChange={handleInputChange}
						/>
					</div>

					<div className="field-group">
						<div className='field'> 
							<label htmlFor="email"> E-mail</label>
							<input 
								type="email"
								name="email"
								id="email"
								onChange={handleInputChange}
							/>
						</div>

						<div className='field'> 
							<label htmlFor="name"> Whatsapp</label>
							<input 
								type="text"
								name="whatsapp"
								id="whatsapp"
								onChange={handleInputChange}
							/>
						</div>
					</div>
				</fieldset>

				<fieldset>
					<legend>
						<h2> Endereço </h2>
						<span>Selecione o endereço no mapa</span>
					</legend>

					<MapContainer center={initialPosition} zoom={5} onClick={handleMapClick}>
						<TileLayer
							attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
							url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
						/>

						<Marker position={selectedPosition}></Marker>
					</MapContainer>

					<div className="field-group">
						<div className="field">
							<label htmlFor="uf"> Estado (UF)</label>
							<select 
								name="uf" 
								id="uf"  
								value={selectedUf} 
								onChange={handleSelectUf}
							>
								<option value="0"> Selecione um UF</option>
								{ufs.map(uf => (
									<option key={uf} value={uf}> {uf}</option>
								))}
							</select>
						</div>
						<div className="field">
							<label htmlFor="city"> Cidade</label>
							<select 
								name="city" 
								id="city"
								value={selectedCity}
								onChange={handleSelectCity}
							>
								<option value="0"> Selecione uma cidade</option>
								{cities.map(city => (
									<option key={city} value={city}> {city}</option>
								))}
							</select>
						</div>
					</div>
				</fieldset>

				<fieldset>
					<legend>
						<h2> Itens de coleta </h2>
						<span>Selecione um ou mais itens abaixo</span>
					</legend>

					<ul className='items-grid'>
						{items.map(item =>(
							<li 
								key={item.id} 
								onClick={() => handleSelectItem(item.id)}
								className={selectedItems.includes(item.id) ? 'selected' : ''}
							>
								<img src={item.image_url} alt={item.title}/>
								<span>{item.title}</span>
							</li>
						))}
                        
					</ul>
				</fieldset>

				<button type="submit">Cadastrar ponto de coleta</button>
			</form>
		</div>
	);
}
Example #17
Source File: MapChart.tsx    From neodash with Apache License 2.0 4 votes vote down vote up
NeoMapChart = (props: ChartProps) => {

    // Retrieve config from advanced settings
    const nodeColorProp = props.settings && props.settings.nodeColorProp ? props.settings.nodeColorProp : "color";
    const defaultNodeSize = props.settings && props.settings.defaultNodeSize ? props.settings.defaultNodeSize : "large";
    const relWidthProp = props.settings && props.settings.relWidthProp ? props.settings.relWidthProp : "width";
    const relColorProp = props.settings && props.settings.relColorProp ? props.settings.relColorProp : "color";
    const defaultRelWidth = props.settings && props.settings.defaultRelWidth ? props.settings.defaultRelWidth : 3.5;
    const defaultRelColor = props.settings && props.settings.defaultRelColor ? props.settings.defaultRelColor : "#666";
    const nodeColorScheme = props.settings && props.settings.nodeColorScheme ? props.settings.nodeColorScheme : "neodash";
    const styleRules = props.settings && props.settings.styleRules ? props.settings.styleRules : [];
    const defaultNodeColor = "grey"; // Color of nodes without labels
    const dimensions = props.dimensions ? props.dimensions : {width: 100, height: 100};

    const [data, setData] = React.useState({ nodes: [], links: [], zoom: 0, centerLatitude: 0, centerLongitude: 0 });

    // Per pixel, scaling factors for the latitude/longitude mapping function.
    const widthScale = 8.55;
    const heightScale = 6.7;

    var key = dimensions.width + "," + dimensions.height + ","+ data.centerLatitude + "," + data.centerLongitude + "," + props.fullscreen;
    useEffect(() => {
        data.centerLatitude + "," + data.centerLongitude + "," + props.fullscreen;
    }, [props.fullscreen])

    useEffect(() => {
        buildVisualizationDictionaryFromRecords(props.records);
    }, [])

    var nodes = {};
    var nodeLabels = {};
    var links = {};
    var linkTypes = {};

    // Gets all graphy objects (nodes/relationships) from the complete set of return values.
    function extractGraphEntitiesFromField(value) {
        if (value == undefined) {
            return
        }
        if (valueIsArray(value)) {
            value.forEach((v, i) => extractGraphEntitiesFromField(v));
        } else if (valueIsObject(value)) {
            if (value["label"] && value["id"]) {
                // Override for adding point nodes using a manually constructed dict.
                nodeLabels[value["label"]] = true;
                nodes[value["id"]] = {
                    id: value["id"],
                    labels: [value["label"]],
                    size: defaultNodeSize,
                    properties: value,
                    firstLabel: value["label"]
                };
            } else if (value["type"] && value["id"] && value["start"] && value["end"]) {
                // Override for adding relationships using a manually constructed dict.
                if (links[value["start"] + "," + value["end"]] == undefined) {
                    links[value["start"] + "," + value["end"]] = [];
                }
                const addItem = (arr, item) => arr.find((x) => x.id === item.id) || arr.push(item);
                addItem(links[value["start"] + "," + value["end"]], {
                    id: value["id"],
                    source: value["start"],
                    target: value["end"],
                    type: value["type"],
                    width: value[relWidthProp] ? value[relWidthProp] : defaultRelWidth,
                    color: value[relColorProp] ? value[relColorProp] : defaultRelColor,
                    properties: value
                });
            }
        } else if (valueIsNode(value)) {
            value.labels.forEach(l => nodeLabels[l] = true)
            nodes[value.identity.low] = {
                id: value.identity.low,
                labels: value.labels,
                size: defaultNodeSize,
                properties: value.properties,
                firstLabel: value.labels[0]
            };
        } else if (valueIsRelationship(value)) {
            if (links[value.start.low + "," + value.end.low] == undefined) {
                links[value.start.low + "," + value.end.low] = [];
            }
            const addItem = (arr, item) => arr.find((x) => x.id === item.id) || arr.push(item);
            addItem(links[value.start.low + "," + value.end.low], {
                id: value.identity.low,
                source: value.start.low,
                target: value.end.low,
                type: value.type,
                width: value.properties[relWidthProp] ? value.properties[relWidthProp] : defaultRelWidth,
                color: value.properties[relColorProp] ? value.properties[relColorProp] : defaultRelColor,
                properties: value.properties
            });

        } else if (valueIsPath(value)) {
            value.segments.map((segment, i) => {
                extractGraphEntitiesFromField(segment.start);
                extractGraphEntitiesFromField(segment.relationship);
                extractGraphEntitiesFromField(segment.end);
            });
        }
    }

    function buildVisualizationDictionaryFromRecords(records) {


        // Extract graph objects from result set.
        records.forEach((record, rownumber) => {
            record._fields && record._fields.forEach((field, i) => {
                extractGraphEntitiesFromField(field);
            })
        });

        // Assign proper colors & coordinates to nodes.
        const totalColors = categoricalColorSchemes[nodeColorScheme].length;
        const nodeLabelsList = Object.keys(nodeLabels);
        const nodesList = Object.values(nodes).map(node => {
            const assignPosition = (node) => {
                if (node.properties.latitude && node.properties.longitude) {
                    nodes[node.id].pos = [parseFloat(node.properties.latitude), parseFloat(node.properties.longitude)];
                    return nodes[node.id].pos;
                }
                if (node.properties.lat && node.properties.long) {
                    nodes[node.id].pos = [parseFloat(node.properties.lat), parseFloat(node.properties.long)];
                    return nodes[node.id].pos;
                }
                Object.values(node.properties).forEach(p => {
                    if (p != null && p.srid != null && p.x != null && p.y != null) {
                        if (!isNaN(p.x) && !isNaN(p.y)) {
                            nodes[node.id].pos = [p.y, p.x];
                            return [p.y, p.x];
                        }
                    }
                })
            }

            var assignedColor = node.properties[nodeColorProp] ? node.properties[nodeColorProp] :
                categoricalColorSchemes[nodeColorScheme][nodeLabelsList.indexOf(node.firstLabel) % totalColors];
           
            assignedColor = evaluateRulesOnNode(node, 'marker color', assignedColor, styleRules);
            const assignedPos = assignPosition(node);
            return update(node, { pos: node.pos ? node.pos : assignedPos, color: assignedColor ? assignedColor : defaultNodeColor });

        });

        // Assign proper curvatures to relationships.
        const linksList = Object.values(links).map(nodePair => {
            return nodePair.map((link, i) => {
                if (nodes[link.source] && nodes[link.source].pos && nodes[link.target] && nodes[link.target].pos) {
                    return update(link, { start: nodes[link.source].pos, end: nodes[link.target].pos });
                }
            });
        }).flat();

        // Calculate center latitude and center longitude:

        const latitudes = nodesList.reduce((a, b) => {
            if (b["pos"] == undefined) {
                return a;
            }
            a.push(b["pos"][0])
            return a;
        }, []);
        const longitudes = nodesList.reduce((a, b) => {
            if (b["pos"] == undefined) {
                return a;
            }
            a.push(b["pos"][1])
            return a;
        }, []);
        const maxLat = Math.max(...latitudes);
        const minLat = Math.min(...latitudes);
        const avgLat = maxLat - (maxLat - minLat) / 2.0;

        let latWidthScaleFactor = (dimensions.width ? dimensions.width : 300) / widthScale;
        let latDiff = maxLat - avgLat;
        let latProjectedWidth = latDiff / latWidthScaleFactor;
        let latZoomFit = Math.ceil(Math.log2(1.0 / latProjectedWidth));

        const maxLong = Math.min(...longitudes);
        const minLong = Math.min(...longitudes);
        const avgLong = maxLong - (maxLong - minLong) / 2.0;

        let longHeightScaleFactor = (dimensions.height ? dimensions.height : 300) / heightScale;
        let longDiff = maxLong - avgLong;
        let longProjectedHeight = longDiff / longHeightScaleFactor;
        let longZoomFit = Math.ceil(Math.log2(1.0 / longProjectedHeight));
        // Set data based on result values.
        setData({
            zoom: Math.min(latZoomFit, longZoomFit),
            centerLatitude: latitudes ? latitudes.reduce((a, b) => a + b, 0) / latitudes.length : 0,
            centerLongitude: longitudes ? longitudes.reduce((a, b) => a + b, 0) / longitudes.length : 0,
            nodes: nodesList,
            links: linksList
        });
    }

    // Render a node label tooltip
    const renderNodeLabel = (node) => {
        const selectedProp = props.selection && props.selection[node.firstLabel];
        if (selectedProp == "(id)") {
            return node.id;
        }
        if (selectedProp == "(label)") {
            return node.labels;
        }
        if (selectedProp == "(no label)") {
            return "";
        }
        return node.properties[selectedProp] ? node.properties[selectedProp].toString() : "";
    }

    var markerMarginTop = "6px";
    switch (defaultNodeSize) {
        case "large":
            markerMarginTop = "-5px";
            break;
        case "medium":
            markerMarginTop = "3px";
            break;
        default:
            break;
    }

    function createMarkers() {
        // Create markers to plot on the map

        return data.nodes.filter(node => node.pos && !isNaN(node.pos[0]) && !isNaN(node.pos[1])).map((node, i) =>
            <Marker position={node.pos} key={i}
                icon={<div style={{ color: node.color, textAlign: "center", marginTop: markerMarginTop }}>
                    <LocationOnIcon fontSize={node.size}></LocationOnIcon>
                </div>}>
                {props.selection && props.selection[node.firstLabel] && props.selection[node.firstLabel] != "(no label)" ?
                    <Tooltip direction='bottom' permanent className={"leaflet-custom-tooltip"}> {renderNodeLabel(node)}   </Tooltip>
                    : <></>}
                {createPopupFromNodeProperties(node)}
            </Marker>);
    }

    function createLines() {
        // Create lines to plot on the map.
        return data.links.filter(link => link).map((rel, i) => {
            if (rel.start && rel.end) {
                return <Polyline weight={rel.width} key={i} positions={[rel.start, rel.end]} color={rel.color}>
                    {createPopupFromRelProperties(rel)}
                </Polyline>
            }
        });
    }


    // Helper function to convert property values to string for the pop-ups.
    function convertMapPropertyToString(property) {
        if (property.srid) {
            return "(lat:" + property.y + ", long:" + property.x + ")";
        }
        return property;
    }

    function createPopupFromRelProperties(value) {
        return <Popup className={"leaflet-custom-rel-popup"}>
            <h3><b>{value.type}</b></h3>
            <table><tbody>{Object.keys(value.properties).length == 0 ? <tr><td>(No properties)</td></tr> : Object.keys(value.properties).map((k, i) => <tr key={i}><td style={{ marginRight: "10px" }} key={0}>{k.toString()}:</td><td key={1}>{value.properties[k].toString()}</td></tr>)}</tbody></table>
        </Popup>;
    }

    function createPopupFromNodeProperties(value) {
        return <Popup className={"leaflet-custom-node-popup"}>
            <h3><b>{(value.labels.length > 0) ? value.labels.map(b => b + " ") : "(No labels)"}</b></h3>
            <table><tbody>{Object.keys(value.properties).length == 0 ? <tr><td>(No properties)</td></tr> : Object.keys(value.properties).map((k, i) => <tr key={i}><td style={{ marginRight: "10px" }} key={0}>{k.toString()}:</td><td key={1}>{value.properties[k].toString()}</td></tr>)}</tbody></table>
        </Popup>;
    }




    const markers = createMarkers();
    const lines = createLines();
    const fullscreen = props.fullscreen ? props.fullscreen : true;

    // Draw the component.
    return <MapContainer key={key} style={{ width: "100%", height: "100%" }}
        center={[data.centerLatitude ? data.centerLatitude : 0, data.centerLongitude ? data.centerLongitude : 0]}
        zoom={data.zoom ? data.zoom : 0}
        maxZoom={18}
        scrollWheelZoom={false}>
        <TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        {markers}
        {lines}
    </MapContainer>;
}
Example #18
Source File: location.admin.tsx    From ui with GNU Affero General Public License v3.0 4 votes vote down vote up
LocationAdmin: React.FC<FieldAdminProps> = (props) => {
  const { t } = useTranslation()

  return (
    <div>
      <Form.Item
        label={t('type:location:default')}
        labelCol={{ span: 6 }}
      >
        <Space>
          <Form.Item
            name={[
              props.field.name as string,
              'defaultValue',
              'lat',
            ]}
            noStyle
          >
            <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} />
          </Form.Item>

          <Form.Item
            name={[
              props.field.name as string,
              'defaultValue',
              'lng',
            ]}
            noStyle
          >
            <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} />
          </Form.Item>
        </Space>
      </Form.Item>

      <Form.Item
        label={t('type:location.initialZoom')}
        name={[
          props.field.name as string,
          'optionKeys',
          'initialZoom',
        ]}
        labelCol={{ span: 6 }}
        initialValue={1}
      >
        <InputNumber precision={0} min={1} max={18} />
      </Form.Item>

      <Form.Item
        label={t('type:location.tiles')}
        name={[
          props.field.name as string,
          'optionKeys',
          'tiles',
        ]}
        labelCol={{ span: 6 }}
        initialValue={'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'}
      >
        <Input placeholder={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'} />
      </Form.Item>

      <Form.Item shouldUpdate>
        {(form) => {
          //const prefix = React.useContext(FormItemContext).prefixName
          const prefix = (form as any).prefixName

          const zoom = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'optionKeys',
            'initialZoom',
          ])

          const center = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'defaultValue',
          ])

          const tiles = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'optionKeys',
            'tiles',
          ])

          if (!tiles) {
            return <Alert message={'Tiles missing!'} />
          }

          return (
            <div>
              <MapContainer
                center={center}
                zoom={zoom}
                style={{ height: 300, width: '100%' }}
              >
                <TileLayer
                  attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                  url={tiles}
                />
                {center?.lat && center?.lng && (
                  <DraggableMarker
                    value={center}
                    onChange={next => {
                      form.setFields([
                        {
                          name: [
                            ...prefix,
                            props.field.name as string,
                            'defaultValue',
                            'lng',
                          ],
                          value: next.lng,
                        },
                        {
                          name: [
                            ...prefix,
                            props.field.name as string,
                            'defaultValue',
                            'lat',
                          ],
                          value: next.lat,
                        },
                      ])
                    }}
                  />
                )}
              </MapContainer>
            </div>
          )
        }}
      </Form.Item>
    </div>
  )
}
Example #19
Source File: location.input.tsx    From ui with GNU Affero General Public License v3.0 4 votes vote down vote up
builder: FieldInputBuilderType = ({
  parseUrlValue,
  parseValue,
}) => function LocationInput ({
  field,
  urlValue,
}) {
  const [initialZoom, setInitialZoom] = useState<number>(13)
  const [tiles, setTiles] = useState<string>()
  const [loading, setLoading] = useState(true)

  const { t } = useTranslation()


  useEffect(() => {
    field.options.forEach((option) => {
      if (option.key === 'initialZoom') {
        try {
          setInitialZoom(JSON.parse(option.value))
        } catch (e) {
          logger('invalid initialZoom value %O', e)
        }
      }

      if (option.key === 'tiles') {
        try {
          setTiles(JSON.parse(option.value))
        } catch (e) {
          logger('invalid tiles value %O', e)
        }
      }
    })

    setLoading(false)
  }, [field])

  let initialValue: { lat: number, lng: number } = undefined

  if (field.defaultValue) {
    try {
      initialValue = parseValue(field.defaultValue)
    } catch (e) {
      logger('invalid default value %O', e)
    }
  }

  if (urlValue) {
    try {
      initialValue = parseUrlValue(urlValue)
    } catch (e) {
      logger('invalid url value %O', e)
    }
  }

  if (loading) {
    return (
      <div>
        <Spin />
      </div>
    )
  }

  if (!tiles) {
    return <Alert message={'Tiles missing!'} />
  }

  return (
    <div>
      <Form.Item>
        <Space>
          <Form.Item
            rules={[{ required: field.required, message: t('validation:valueRequired') }]}
            name={[
              field.id,
              'lat',
            ]}
            initialValue={initialValue?.lat}
            noStyle
          >
            <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} />
          </Form.Item>

          <Form.Item
            rules={[{ required: field.required, message: t('validation:valueRequired') }]}
            name={[
              field.id,
              'lng',
            ]}
            initialValue={initialValue?.lng}
            noStyle
          >
            <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} />
          </Form.Item>
        </Space>
      </Form.Item>
      <Form.Item dependencies={[[field.id, 'lat'], [field.id, 'lng']]}>
        {(form) => {
          const center = form.getFieldValue([field.id])

          return (
            <div>
              <MapContainer
                center={initialValue}
                zoom={initialZoom}
                style={{ height: 300, width: '100%' }}
              >
                <TileLayer
                  attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                  url={tiles}
                />
                {center.lat && center.lng && (
                  <DraggableMarker
                    value={center}
                    onChange={next => {
                      form.setFields([
                        {
                          name: [
                            field.id,
                            'lng',
                          ],
                          value: next.lng,
                        },
                        {
                          name: [
                            field.id,
                            'lat',
                          ],
                          value: next.lat,
                        },
                      ])
                    }}
                  />
                )}
              </MapContainer>
            </div>
          )
        }}
      </Form.Item>
    </div>
  )
}
Example #20
Source File: index.tsx    From nlw-01-omnistack with MIT License 4 votes vote down vote up
CreatePoint = () => {
  const [items, setItems] = useState<Item[]>([]);
  const [ufs, setUfs] = useState<string[]>([]);
  const [cities, setCities] = useState<string[]>([]);

  const [initialPosition, setInitialPosition] = useState<[number, number]>([0, 0]);

  const [formData, setFormData] = useState({
    name: '',
    email: '',
    whatsapp: '',
  });

  const [selectedUf, setSelectedUf] = useState('0');
  const [selectedCity, setSelectedCity] = useState('0');
  const [selectedItems, setSelectedItems] = useState<number[]>([]);
  const [selectedPosition, setSelectedPosition] = useState<[number, number]>([0, 0]);
  const [selectedFile, setSelectedFile] = useState<File>();

  const history = useHistory();

  useEffect(() => {
    navigator.geolocation.getCurrentPosition(position => {
      const { latitude, longitude } = position.coords;

      setInitialPosition([latitude, longitude]);
    });
  }, []);

  useEffect(() => {
    api.get('items').then(response => {
      setItems(response.data);
    });
  }, []);

  useEffect(() => {
    axios.get<IBGEUFResponse[]>('https://servicodados.ibge.gov.br/api/v1/localidades/estados').then(response => {
      const ufInitials = response.data.map(uf => uf.sigla);

      setUfs(ufInitials);
    });
  }, []);

  useEffect(() => {
    if (selectedUf === '0') {
      return;
    }

    axios
      .get<IBGECityResponse[]>(`https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`)
      .then(response => {
        const cityNames = response.data.map(city => city.nome);

        setCities(cityNames);
      });
  }, [selectedUf]);

  function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
    const uf = event.target.value;

    setSelectedUf(uf);
  }

  function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
    const city = event.target.value;

    setSelectedCity(city);
  }

  function handleMapClick(event: LeafletMouseEvent) {
    setSelectedPosition([
      event.latlng.lat,
      event.latlng.lng,
    ])
  }

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
    const { name, value } = event.target;

    setFormData({ ...formData, [name]: value });
  }

  function handleSelectItem(id: number) {
    const alreadySelected = selectedItems.findIndex(item => item === id);

    if (alreadySelected >= 0) {
      const filteredItems = selectedItems.filter(item => item !== id);

      setSelectedItems(filteredItems);
    } else {
      setSelectedItems([ ...selectedItems, id ]);
    }
  }

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();

    const { name, email, whatsapp } = formData;
    const uf = selectedUf;
    const city = selectedCity;
    const [latitude, longitude] = selectedPosition;
    const items = selectedItems;

    const data = new FormData();

    data.append('name', name);
    data.append('email', email);
    data.append('whatsapp', whatsapp);
    data.append('uf', uf);
    data.append('city', city);
    data.append('latitude', String(latitude));
    data.append('longitude', String(longitude));
    data.append('items', items.join(','));
    
    if (selectedFile) {
      data.append('image', selectedFile)
    }

    await api.post('points', data);

    alert('Ponto de coleta criado!');

    history.push('/');
  }

  return (
    <div id="page-create-point">
      <header>
        <img src={logo} alt="Ecoleta" />

        <Link to="/">
          <FiArrowLeft />
          Voltar para home
        </Link>
      </header>

      <form onSubmit={handleSubmit}>
        <h1>Cadastro do <br /> ponto de coleta</h1>

        <Dropzone onFileUploaded={setSelectedFile} />

        <fieldset>
          <header role="legend">
            <h2>Dados</h2>
          </header>

          <div className="field">
            <label htmlFor="name">Nome da entidade</label>
            <input 
              type="text"
              name="name"
              id="name"
              onChange={handleInputChange}
            />
          </div>

          <div className="field-group">
            <div className="field">
              <label htmlFor="email">E-mail</label>
              <input 
                type="email"
                name="email"
                id="email"
                onChange={handleInputChange}
              />
            </div>
            <div className="field">
              <label htmlFor="whatsapp">Whatsapp</label>
              <input 
                type="text"
                name="whatsapp"
                id="whatsapp"
                onChange={handleInputChange}
              />
            </div>
          </div>
        </fieldset>

        <fieldset>
          <header role="legend">
            <h2>Endereço</h2>
            <span>Selecione o endereço no mapa</span>
          </header>

          <Map center={initialPosition} zoom={15} onClick={handleMapClick}>
            <TileLayer
              attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />  

            <Marker position={selectedPosition} />
          </Map>

          <div className="field-group">
            <div className="field">
              <label htmlFor="uf">Estado (UF)</label>
              <select 
                name="uf" 
                id="uf" 
                value={selectedUf} 
                onChange={handleSelectUf}
              >
                <option value="0">Selecione uma UF</option>
                {ufs.map(uf => (
                  <option key={uf} value={uf}>{uf}</option>
                ))}
              </select>
            </div>
            <div className="field">
              <label htmlFor="city">Cidade</label>
              <select 
                name="city" 
                id="city"
                value={selectedCity}
                onChange={handleSelectCity}
              >
                <option value="0">Selecione uma cidade</option>
                {cities.map(city => (
                  <option key={city} value={city}>{city}</option>
                ))}
              </select>
            </div>
          </div>
        </fieldset>

        <fieldset>
          <header role="legend">
            <h2>Ítens de coleta</h2>
            <span>Selecione um ou mais ítens abaixo</span>
          </header>

          <ul className="items-grid">
            {items.map(item => (
              <li 
                key={item.id} 
                onClick={() => handleSelectItem(item.id)}
                className={selectedItems.includes(item.id) ? 'selected' : ''}
              >
                <img src={item.image_url} alt={item.title} />
                <span>{item.title}</span>
              </li>
            ))}
          </ul>
        </fieldset>

        <button type="submit">
          Cadastrar ponto de coleta
        </button>
      </form>
    </div>
  );
}
Example #21
Source File: index.tsx    From ecoleta with MIT License 4 votes vote down vote up
CreatePoint = () => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    whatsapp: '',
  });

  const [initialPosition, setInitialPosition] = useState<[number, number]>([
    0,
    0,
  ]);

  const [ufs, setUfs] = useState<string[]>([]);
  const [cities, setCities] = useState<string[]>([]);
  const [items, setItems] = useState<Item[]>([]);

  const [selectedUf, setSelectedUf] = useState('0');
  const [selectedCity, setSelectedCity] = useState('0');
  const [selectedItems, setSelectedItems] = useState<number[]>([]);

  const [selectedPosition, setSelectedPosition] = useState<[number, number]>([
    0,
    0,
  ]);

  const [selectedFile, setSelectedFile] = useState<File>();

  const history = useHistory();

  useEffect(() => {
    navigator.geolocation.getCurrentPosition((position) => {
      const { latitude, longitude } = position.coords;

      setInitialPosition([latitude, longitude]);
    });
  }, []);

  useEffect(() => {
    api.get('/items').then((response) => {
      setItems(response.data);
    });
  }, []);

  useEffect(() => {
    axios
      .get<IBGEUFResponse[]>(
        'https://servicodados.ibge.gov.br/api/v1/localidades/estados'
      )
      .then((response) => {
        const ufInitials = response.data.map((uf) => uf.sigla);
        setUfs(ufInitials);
      });
  }, []);

  useEffect(() => {
    if (selectedUf === '0') {
      return;
    }

    axios
      .get<IBGECityResponse[]>(
        `https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`
      )
      .then((response) => {
        const cityNames = response.data.map((city) => city.nome);
        setCities(cityNames);
      });
  }, [selectedUf]);

  function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
    const uf = event.target.value;
    setSelectedUf(uf);
  }

  function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
    const city = event.target.value;
    setSelectedCity(city);
  }

  function handleMapClick(event: LeafletMouseEvent) {
    setSelectedPosition([event.latlng.lat, event.latlng.lng]);
  }

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
    const { name, value } = event.target;

    setFormData({ ...formData, [name]: value });
  }

  function handleSelectItem(id: number) {
    const alreadySelected = selectedItems.findIndex((item) => item === id);

    if (alreadySelected >= 0) {
      const filteredItems = selectedItems.filter((item) => item !== id);

      setSelectedItems(filteredItems);
    } else {
      setSelectedItems([...selectedItems, id]);
    }
  }

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();

    const { name, email, whatsapp } = formData;
    const uf = selectedUf;
    const city = selectedCity;
    const [latitude, longitude] = selectedPosition;
    const items = selectedItems;

    const data = new FormData();

    data.append('name', name);
    data.append('email', email);
    data.append('whatsapp', whatsapp);
    data.append('uf', uf);
    data.append('city', city);
    data.append('latitude', String(latitude));
    data.append('longitude', String(longitude));
    data.append('items', items.join(','));

    if (selectedFile) {
      data.append('image', selectedFile);
    }

    await api.post('/points', data);

    alert('Ponto de coleta criado');

    history.push('/');
  }

  return (
    <div id="page-create-point">
      <header>
        <img src={logo} alt="Ecoleta" />

        <Link to="/">
          <FiArrowLeft />
          Voltar para home
        </Link>
      </header>

      <form onSubmit={handleSubmit} autoComplete="off">
        <h1>
          Cadastro do <br />
          ponto de coleta
        </h1>

        <Dropzone onFileUploaded={setSelectedFile} />

        <fieldset>
          <legend>
            <h2>Dados</h2>
          </legend>

          <div className="field">
            <label htmlFor="name">Nome da entidade</label>
            <input
              type="text"
              name="name"
              id="name"
              onChange={handleInputChange}
            />
          </div>

          <div className="field-group">
            <div className="field">
              <label htmlFor="email">E-mail</label>
              <input
                type="email"
                name="email"
                id="email"
                onChange={handleInputChange}
              />
            </div>
            <div className="field">
              <label htmlFor="whatsapp">Whatsapp</label>
              <input
                type="text"
                name="whatsapp"
                id="whatsapp"
                onChange={handleInputChange}
              />
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Endereço</h2>
            <span>Selecione o endereço no mapa</span>
          </legend>

          <Map center={initialPosition} zoom={15} onClick={handleMapClick}>
            <TileLayer
              attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />

            <Marker position={selectedPosition} />
          </Map>

          <div className="field-group">
            <div className="field">
              <label htmlFor="uf">Estado (UF)</label>
              <select
                name="uf"
                id="uf"
                value={selectedUf}
                onChange={handleSelectUf}
              >
                <option value="0">Selecione uma UF</option>

                {ufs.map((uf) => (
                  <option key={uf} value={uf}>
                    {uf}
                  </option>
                ))}
              </select>
            </div>

            <div className="field">
              <label htmlFor="city">Cidade</label>
              <select
                name="city"
                id="city"
                value={selectedCity}
                onChange={handleSelectCity}
              >
                <option value="0">Selecione uma cidade</option>

                {cities.map((city) => (
                  <option key={city} value={city}>
                    {city}
                  </option>
                ))}
              </select>
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Itens de coleta</h2>
            <span>Selecione um ou mais itens abaixo</span>
          </legend>

          <ul className="items-grid">
            {items.map((item) => (
              <li
                key={item.id}
                className={selectedItems.includes(item.id) ? 'selected' : ''}
                onClick={() => handleSelectItem(item.id)}
              >
                <img src={item.image_url} alt={item.title} />
                <span>{item.title}</span>
              </li>
            ))}
          </ul>
        </fieldset>

        <button type="submit">Cadastrar ponto de coleta</button>
      </form>
    </div>
  );
}
Example #22
Source File: index.tsx    From NLW-1.0 with MIT License 4 votes vote down vote up
CreatePoint: React.FC = () => {
  const [items, setItems] = useState<Item[]>([]);
  const [ufs, setUfs] = useState<IBGEUFResponse[]>([]);
  const [cities, setCities] = useState<IBGECityResponse[]>([]);

  const [formData, setFormData] = useState({
    name: '',
    email: '',
    whatsapp: '',
  });

  const [selectedFile, setSelectedFile] = useState<File>();
  const [selectedItems, setSelectedItems] = useState<number[]>([]);
  const [selectedUf, setSelectedUf] = useState<string>('0');
  const [selectedCity, setSelectedCity] = useState<string>('0');
  const [selectedPosition, setSelectedPosition] = useState<[number, number]>([
    0,
    0,
  ]);
  const [initialPosition, setInitialPosition] = useState<[number, number]>([
    0,
    0,
  ]);

  const history = useHistory();

  // Get Current Position
  useEffect(() => {
    navigator.geolocation.getCurrentPosition(
      position => {
        const { latitude, longitude } = position.coords;

        setInitialPosition([latitude, longitude]);
      },
      () => {
        toast.error('❌ Oops! Algo deu errado =/', toastOptions);
      },
      {
        timeout: 30000,
        enableHighAccuracy: true,
      },
    );
  }, []);

  // Load items
  useEffect(() => {
    async function loadItems() {
      const response = await api.get('/items');

      setItems(response.data);
    }

    loadItems();
  }, []);

  // Load UFs
  useEffect(() => {
    async function loadUfs() {
      const response = await ibge.get<IBGEUFResponse[]>(
        'localidades/estados?orderBy=nome',
      );

      const ufInitials = response.data.map(uf => {
        return {
          sigla: uf.sigla,
          nome: uf.nome,
        };
      });

      setUfs(ufInitials);
    }

    loadUfs();
  }, []);

  // Load Cities
  useEffect(() => {
    async function loadCities() {
      if (selectedUf === '0') return;

      const response = await ibge.get<IBGECityResponse[]>(
        `localidades/estados/${selectedUf}/municipios`,
      );

      const cityNames = response.data.map(city => {
        return { nome: city.nome };
      });

      setCities(cityNames);
    }

    loadCities();
  }, [selectedUf]);

  function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
    setSelectedUf(event.target.value);
  }

  function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
    setSelectedCity(event.target.value);
  }

  function handleMapClick(event: LeafletMouseEvent) {
    setSelectedPosition([event.latlng.lat, event.latlng.lng]);
  }

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
    const { name, value } = event.target;

    setFormData({ ...formData, [name]: value });
  }

  function handleSelectItem(id: number) {
    const alreadySelected = selectedItems.findIndex(item => item === id);

    if (alreadySelected >= 0) {
      const filteredItems = selectedItems.filter(item => item !== id);

      setSelectedItems(filteredItems);
    } else {
      setSelectedItems([...selectedItems, id]);
    }
  }

  // Toastify configurations
  const toastOptions = {
    autoClose: 5000,
    hideProgressBar: false,
    closeOnClick: true,
    pauseOnHover: true,
    draggable: true,
    progress: undefined,
  };

  const handleSubmit = useCallback(
    async (event: FormEvent) => {
      event.preventDefault();

      try {
        const { name, email, whatsapp } = formData;
        const [latitude, longitude] = selectedPosition;

        const data = new FormData();

        data.append('name', name);
        data.append('email', email);
        data.append('whatsapp', whatsapp);
        data.append('latitude', String(latitude));
        data.append('longitude', String(longitude));
        data.append('uf', selectedUf);
        data.append('city', selectedCity);
        data.append('items', selectedItems.join(','));

        if (selectedFile) {
          data.append('image', selectedFile);
        }

        await api.post('points', data);
        toast('✅ Criado com sucesso!', toastOptions);

        history.push('/');
      } catch (err) {
        toast.error('❌ Erro!', toastOptions);
      }
    },
    [
      formData,
      selectedCity,
      selectedItems,
      selectedPosition,
      selectedUf,
      history,
      selectedFile,
    ],
  );

  return (
    <div id="page-create-point">
      <header>
        <img src={logo} alt="Ecoleta" />

        <Link to="/">
          <FiArrowLeft />
          Voltar para home
        </Link>
      </header>

      <form onSubmit={handleSubmit}>
        <h1>
          Cadastro do
          <br /> ponto de coleta
        </h1>

        <Dropzone onFileUploaded={setSelectedFile} />

        <fieldset>
          <legend>
            <h2>Dados</h2>
          </legend>

          <div className="field">
            <label htmlFor="name">Nome da entidade</label>
            <input
              onChange={handleInputChange}
              type="text"
              name="name"
              id="name"
            />
          </div>

          <div className="field-group">
            <div className="field">
              <label htmlFor="email">E-mail</label>
              <input
                onChange={handleInputChange}
                type="text"
                name="email"
                id="email"
              />
            </div>

            <div className="field">
              <label htmlFor="whatsapp">Whatsapp</label>
              <input
                onChange={handleInputChange}
                type="text"
                name="whatsapp"
                id="whatsapp"
              />
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Endereço</h2>
            <span>Selecione o endereço no mapa</span>
          </legend>

          <Map center={initialPosition} zoom={15} onClick={handleMapClick}>
            <TileLayer
              attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
            <Marker position={selectedPosition} />
          </Map>

          <div className="field-group">
            <div className="field">
              <label htmlFor="uf">Estado (UF)</label>

              <select onChange={handleSelectUf} name="uf" id="uf">
                <option value="0">Selecione uma UF</option>
                {ufs?.map(uf => (
                  <option key={uf.nome} value={uf.sigla}>
                    {uf.sigla}
                  </option>
                ))}
              </select>
            </div>

            <div className="field">
              <label htmlFor="city">Cidade</label>
              <select onChange={handleSelectCity} name="city" id="city">
                <option value="0">Selecione uma cidade</option>

                {cities.map(city => (
                  <option key={city.nome} value={city.nome}>
                    {city.nome}
                  </option>
                ))}
              </select>
            </div>
          </div>
        </fieldset>

        <fieldset>
          <legend>
            <h2>Itens de coleta</h2>
            <span>Selecione um ou mais itens abaixo</span>
          </legend>

          <ul className="items-grid">
            {items.map(item => (
              <li
                key={item.id}
                onClick={() => handleSelectItem(item.id)}
                className={selectedItems.includes(item.id) ? 'selected' : ''}
              >
                <img src={item.image_url} alt={item.title} />
                <span>{item.title}</span>
              </li>
            ))}
          </ul>
        </fieldset>

        <button type="submit">Cadastrar novo ponto de coleta</button>
      </form>
    </div>
  );
}
Example #23
Source File: CreateOrphanage.tsx    From happy with MIT License 4 votes vote down vote up
export default function CreateOrphanage() {
  const history = useHistory();

  const [position, setPosition] = useState({ latitude: 0, longitude: 0 });

  const [name, setName] = useState('');
  const [about, setAbout] = useState('');
  const [instructions, setInstructions] = useState('');
  const [opening_hours, setOpeningHours] = useState('');
  const [open_on_weekends, setOpenOnWeekends] = useState(true);
  const [images, setImages] = useState<File[]>([]);
  const [previewImages, setPreviewImages] = useState<PreviewImage[]>([]);

  function handleMapClick(event: LeafletMouseEvent) {
    const { lat, lng } = event.latlng;

    setPosition({
      latitude: lat,
      longitude: lng
    });
  }

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();

    const { latitude, longitude } = position;

    const data = new FormData();

    data.append('name', name);
    data.append('about', about);
    data.append('latitude', String(latitude));
    data.append('longitude', String(longitude));
    data.append('instructions', instructions);
    data.append('opening_hours', opening_hours);
    data.append('open_on_weekends', String(open_on_weekends));

    images.forEach(image => {
      data.append('images', image);
    });

    await api.post('/orphanages', data);

    alert('Orfanato cadastrado com sucesso!');

    history.push('/app');
  }

  function handleSelectImages(event: ChangeEvent<HTMLInputElement>) {
    if (!event.target.files) {
      return;
    }
    const selectedImages = Array.from(event.target.files);

    event.target.value = "";

    setImages(selectedImages);

    const selectedImagesPreview = selectedImages.map(image => {
      return { name: image.name, url: URL.createObjectURL(image) };
    });

    setPreviewImages(selectedImagesPreview);
  }

  function handleRemoveImage(image: PreviewImage) {
    setPreviewImages(
      previewImages.map((image) => image).filter((img) => img.url !== image.url)
    );
    setImages(
      images.map((image) => image).filter((img) => img.name !== image.name)
    );
  }

  return (
    <div id="page-create-orphanage">
      <Sidebar />

      <main>
        <form onSubmit={handleSubmit} className="create-orphanage-form">
          <fieldset>
            <legend>Dados</legend>

            <Map
              center={[-27.2092052, -49.6401092]}
              style={{ width: '100%', height: 280 }}
              zoom={15}
              onclick={handleMapClick}
            >
              <TileLayer
                url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
              />

              {position.latitude !== 0 && (
                <Marker
                  interactive={false}
                  icon={mapIcon}
                  position={[
                    position.latitude,
                    position.longitude
                  ]}
                />
              )}

            </Map>

            <div className="input-block">
              <label htmlFor="name">Nome</label>
              <input
                id="name"
                value={name}
                onChange={event => setName(event.target.value)}
              />
            </div>

            <div className="input-block">
              <label htmlFor="about">Sobre <span>Máximo de 300 caracteres</span></label>
              <textarea
                id="name"
                maxLength={300}
                value={about}
                onChange={event => setAbout(event.target.value)}
              />
            </div>

            <div className="input-block">
              <label htmlFor="images">Fotos</label>

              <div className="images-container">
                {previewImages.map((image) => {
                  return (
                    <div key={image.url}>
                      <span
                        className="remove-image"
                        onClick={() => handleRemoveImage(image)}
                      >
                        <FiX size={18} color="#ff669d" />
                      </span>
                      <img src={image.url} alt={name} className="new-image" />
                    </div>
                  );
                })}

                <label htmlFor="image[]" className="new-image">
                  <FiPlus size={24} color="#15b6d6" />
                </label>
              </div>

              <input
                type="file"
                multiple
                accept=".png, .jpg, .jpeg"
                onChange={handleSelectImages}
                id="image[]"
              />
            </div>
          </fieldset>

          <fieldset>
            <legend>Visitação</legend>

            <div className="input-block">
              <label htmlFor="instructions">Instruções</label>
              <textarea
                id="instructions"
                value={instructions}
                onChange={event => setInstructions(event.target.value)}
              />
            </div>

            <div className="input-block">
              <label htmlFor="opening_hours">Horário de Funcionamento</label>
              <input
                id="opening_hours"
                value={opening_hours}
                onChange={event => setOpeningHours(event.target.value)}
              />
            </div>

            <div className="input-block">
              <label htmlFor="open_on_weekends">Atende fim de semana</label>

              <div className="button-select">
                <button
                  type="button"
                  className={open_on_weekends ? 'active' : ''}
                  onClick={() => setOpenOnWeekends(true)}
                >
                  Sim
                </button>
                <button
                  type="button"
                  className={!open_on_weekends ? 'active' : ''}
                  onClick={() => setOpenOnWeekends(false)}
                >
                  Não
                </button>
              </div>
            </div>
          </fieldset>

          <button className="confirm-button" type="submit">
            Confirmar
          </button>
        </form>
      </main>
    </div>
  );
}
Example #24
Source File: Maps.tsx    From roamjs-com with MIT License 4 votes vote down vote up
Maps = ({ blockId }: { blockId: string }): JSX.Element => {
  const id = useMemo(() => `roamjs-maps-container-id-${blockId}`, [blockId]);
  const mapInstance = useRef<Map>(null);
  const initialTree = useTreeByHtmlId(blockId);
  const [height, setHeight] = useState(DEFAULT_HEIGHT);
  const fixHeight = useCallback(() => {
    setHeight(
      parseInt(
        getComputedStyle(document.getElementById(id)).width.match(
          /^(.*)px$/
        )?.[1] || `${Math.round((DEFAULT_HEIGHT * 4) / 3)}`
      ) * 0.75
    );
    mapInstance.current?.invalidateSize?.();
  }, [setHeight]);
  const initialZoom = useMemo(() => getZoom(initialTree), [initialTree]);
  const initialCenter = useMemo(() => getCenter(initialTree), [initialTree]);
  const [markers, setMarkers] = useState<RoamMarker[]>([]);
  const [loaded, setLoaded] = useState(false);
  const [filter, setFilter] = useState(getFilter(initialTree));
  const isShift = useRef(false);
  const load = useCallback(() => setLoaded(true), [setLoaded]);
  const refresh = useCallback(() => {
    const tree = getTreeByHtmlId(blockId);
    mapInstance.current.setZoom(getZoom(tree));
    mapInstance.current.panTo(getCenter(tree));
    setFilter(getFilter(tree));
    getMarkers(tree).then((newMarkers) => {
      setMarkers(newMarkers);
    });
    fixHeight();
  }, [mapInstance, setMarkers, blockId, fixHeight]);

  const [href, setHref] = useState("https://roamresearch.com");
  useEffect(() => {
    const windowHref = window.location.href;
    setHref(
      windowHref.includes("/page/")
        ? windowHref.substring(0, windowHref.indexOf("/page/"))
        : windowHref
    );
  }, [setHref]);
  const shiftKeyCallback = useCallback(
    (e: KeyboardEvent) => (isShift.current = e.shiftKey),
    [isShift]
  );
  useEffect(() => {
    if (!loaded) {
      load();
      getMarkers(initialTree).then((newMarkers) => {
        setMarkers(newMarkers);
      });
      document.addEventListener("keydown", shiftKeyCallback);
      document.addEventListener("keyup", shiftKeyCallback);
      fixHeight();
    }
  }, [load, loaded, initialTree, setMarkers, shiftKeyCallback, id, fixHeight]);
  const filteredMarkers = useMemo(
    () =>
      filter
        ? markers.filter((m) =>
            isTagOnPage({ tag: filter, title: extractTag(m.tag) })
          )
        : markers,
    [markers, filter]
  );
  const filterOnBlur = useCallback(
    (value: string) => {
      setInputSetting({
        blockUid: getUidsFromId(blockId).blockUid,
        value,
        key: "filter",
      });
      setFilter(value);
    },
    [blockId]
  );
  const whenCreated = useCallback(
    (m) => {
      mapInstance.current = m;
      mapInstance.current.invalidateSize();
    },
    [mapInstance]
  );
  return (
    <EditContainer
      blockId={blockId}
      refresh={refresh}
      Settings={
        <>
          <Label>
            Filter
            <PageInput
              value={filter}
              setValue={setFilter}
              onBlur={filterOnBlur}
            />
          </Label>
        </>
      }
    >
      <MapContainer
        center={initialCenter}
        zoom={initialZoom}
        id={id}
        style={{ height }}
        whenCreated={whenCreated}
      >
        <LayersControl position="bottomleft">
          <LayersControl.BaseLayer checked name="Streets">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/streets-v11"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Outdoors">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/outdoors-v11"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Light">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/light-v10"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Dark">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/dark-v10"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Satellite">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/satellite-v9"
            />
          </LayersControl.BaseLayer>
        </LayersControl>
        <Markers href={href} markers={filteredMarkers} id={id} />
      </MapContainer>
    </EditContainer>
  );
}
Example #25
Source File: Map.tsx    From covid19map with MIT License 4 votes vote down vote up
Map = ({
  center,
  zoom,
  markers = [],
  clusters = {},
  onMarkerClick,
  maxCases,
  outerBounds,
  innerBounds,
  location
}: {
  center: any;
  zoom: number;
  markers: any[];
  clusters: any;
  onMarkerClick: any;
  maxCases: number;
  outerBounds: any;
  innerBounds: any;
  location: any;
}) => {
  const theme = useTheme();
  const mapRef = useRef<any>(null);
  const [currentLocation, setCurrentLocation] = useState<string>();
  const [currentZoom, setCurrentZoom] = useState(100);

  useEffect(() => {
    mapRef?.current?.leafletElement.fitBounds(innerBounds);
  }, [mapRef.current]);

  useEffect(() => {
    mapRef?.current?.leafletElement.closePopup();
    setCurrentLocation('');
  }, [location]);

  const getRegionIcon = (
    className: string,
    totalCases: number,
    name: string
  ) => {
    const iconSize = 24;
    return L.divIcon({
      className: `marker ${className}`,
      iconSize: [iconSize, iconSize],
      html: `<div>${
        name === 'Managed Isolation' ? 'MIQ: ' : ''
      }${totalCases}</div>`
    });
  };

  const getClusterIcon = (className: string, totalCases: number) => {
    const normalise = totalCases / 100;
    const iconSize = 24 + normalise * 15;
    return L.divIcon({
      className: `marker ${className}`,
      iconSize: [iconSize, iconSize],
      html: `<div></div>`
    });
  };

  const onLocationClick = (name: string) => {
    setCurrentLocation(name);
    onMarkerClick(name);
  };

  const onZoomend = () => {
    if (mapRef.current) {
      setCurrentZoom(mapRef.current?.leafletElement.getZoom());
    }
  };

  return (
    <div style={{ position: 'relative' }}>
      <LeafletMap
        // onClick={() => onLocationClick('')}
        ref={mapRef}
        maxBounds={outerBounds}
        center={center}
        zoom={zoom}
        maxZoom={7}
        minZoom={5}
        zoomControl={true}
        doubleClickZoom={true}
        scrollWheelZoom={true}
        dragging={true}
        animate={true}
        easeLinearity={0.35}
        onZoomend={onZoomend}
      >
        <TileLayer
          url="//{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png"
          attribution='&copy; <a href="//www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
        />
        {markers.map(
          (
            {
              name,
              latlng,
              boundary,
              totalCases,
              active,
              recovered,
              deaths,
              inHospital,
              level
            },
            i
          ) => (
            <>
              {latlng && (
                <FeatureGroup key={i}>
                  <Marker
                    position={latlng}
                    icon={getRegionIcon(
                      `region ${inHospital > 0 ? 'hospital' : ''}`,
                      active,
                      name
                    )}
                    zIndexOffset={100}
                    // onClick={() => {
                    //   onLocationClick(name);
                    //   gtag.event('Marker', 'Map', name);
                    // }}
                  />
                  <Popup>
                    <StyledPopup>
                      <div className="location">{name}</div>
                      <div className="cases">
                        {active} active case{active > 1 && 's'}
                        <br />
                        {recovered} recovered
                        <br />
                        {totalCases} total case{totalCases > 1 && 's'}
                        {deaths > 0 && (
                          <>
                            <br />
                            {deaths} death{deaths > 1 && 's'}
                          </>
                        )}
                      </div>
                      {inHospital > 0 && (
                        <div className="cases">{inHospital} in hospital</div>
                      )}
                    </StyledPopup>
                  </Popup>
                  {boundary && (
                    <Polygon
                      color={currentLocation === name ? 'white' : 'black'}
                      opacity={currentLocation === name ? 1 : 0.2}
                      weight={currentLocation === name ? 3 : 1}
                      fillColor={theme[alertColours[level - 1]]}
                      // fillOpacity={((active || 0) - -10) / (maxCases + 10 - 1)}
                      // fillOpacity={(level - 1) / (4 - 1)}
                      fillOpacity={0.8}
                      positions={boundary[0]}
                      // smoothFactor={10}
                      // onClick={() => {
                      //   onLocationClick(name);
                      //   gtag.event('Region', 'Map', name);
                      // }}
                    />
                  )}
                </FeatureGroup>
              )}
            </>
          )
        )}
        {Object.keys(clusters).map((regionName: string, j: number) =>
          Object.keys(clusters[regionName]).map(
            (clustLocName: string, k: number) => {
              const { latlng, count, items } = clusters[regionName][
                clustLocName
              ];

              return items.filter((x: any) => x.ongoing === 'Yes').length >
                0 ? (
                <Marker
                  key={k}
                  position={latlng}
                  icon={getClusterIcon('cluster', count)}
                  // onClick={() => gtag.event('Cluster', 'Map', clustLocName)}
                >
                  <Popup>
                    <StyledPopup>
                      <div className="head">
                        {clustLocName} cluster{items.length > 1 && 's'}
                      </div>
                      {items
                        .filter((x: any) => x.ongoing === 'Yes')
                        .map(
                          (
                            {
                              name,
                              totalCases
                            }: { name: string; totalCases: number },
                            l: number
                          ) => (
                            <div className="cluster-desc" key={l}>
                              <div className="location">{name}</div>
                              <div className="cases">{totalCases} cases</div>
                            </div>
                          )
                        )}
                    </StyledPopup>
                  </Popup>
                </Marker>
              ) : (
                <div key={k} />
              );
            }
          )
        )}
      </LeafletMap>
      <Styles currentZoom={currentZoom} />
    </div>
  );
}
Example #26
Source File: index.tsx    From NextLevelWeek with MIT License 4 votes vote down vote up
OrphanageCreate: React.FC = () => {
    const history = useHistory();

    const [position, setPosition] = useState({ latitude: 0, longitude: 0 });
    // Função para quando clicar no mapa
    function handleMapClick(e: LeafletMouseEvent) {
        // console.log(e);
        const { lat, lng } = e.latlng;

        setPosition({
            latitude: lat,
            longitude: lng,
        });
    }

    // Campos do formulário
    const [name, setName] = useState('');
    const [about, setAbout] = useState('');
    const [instructions, setInstructions] = useState('');
    const [opening_hours, setOpeningHours] = useState('');
    const [open_on_weekends, setOpenOnWeekends] = useState(true);

    // Função para o envio do fomulário
    async function handleSubmit(e: FormEvent) {
        e.preventDefault();

        const { latitude, longitude } = position;

        const data = new FormData();

        data.append('name', name);
        data.append('about', about);
        data.append('latitude', String(latitude));
        data.append('longitude', String(longitude));
        data.append('instructions', instructions);
        data.append('opening_hours', opening_hours);
        data.append('open_on_weekends', String(open_on_weekends));

        images.forEach(image => {
            data.append('images', image);
        });

        await api.post('/orphanages', data);

        history.push('/app');
    }

    // Função quando seleciona a imagem
    const [images, setImages] = useState<File[]>([]);
    const [previewImages, setPreviewImages] = useState<string[]>([]);
    function handleSelectImages(e: ChangeEvent<HTMLInputElement>) {
        // console.log(e.target.files);
        if (!e.target.files) {
            return;
        }

        // Array de imagens
        const selectedImages = Array.from(e.target.files)

        setImages(selectedImages);

        // Preview das imagens
        const selectedImagesPreview = selectedImages.map(image => {
            return URL.createObjectURL(image);
        });

        setPreviewImages(selectedImagesPreview);
    }

    return (
        <Container>
            <Sidebar />
            <Content>
                <Form onSubmit={handleSubmit}>
                    <fieldset>
                        <legend>Dados</legend>

                        <Map
                            center={[-5.8044209, -35.263095]}
                            style={{ width: '100%', height: 280 }}
                            zoom={15}
                            onclick={handleMapClick}
                        >
                            <TileLayer
                                url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
                            />

                            {
                                position.latitude !== 0 &&
                                <Marker
                                    interactive={false}
                                    icon={happyMapIcon}
                                    position={[position.latitude, position.longitude]}
                                />
                            }
                        </Map>

                        <InputContainer>
                            <label htmlFor="name">Nome</label>
                            <input
                                id="name"
                                value={name}
                                onChange={e => setName(e.target.value)}
                            />
                        </InputContainer>

                        <InputContainer>
                            <label htmlFor="about">Sobre <span>Máximo de 300 caracteres</span></label>
                            <textarea
                                id="about"
                                maxLength={300}
                                value={about}
                                onChange={e => setAbout(e.target.value)}
                            />
                        </InputContainer>

                        <InputContainer>
                            <label htmlFor="images">Fotos</label>
                            <ImagesContainer>
                                {previewImages.map(image => {
                                    return (
                                        <img
                                            key={image}
                                            src={image}
                                            alt={name}
                                        />
                                    )
                                })}

                                <label htmlFor="image[]">
                                    <FiPlus size={24} color="#15b6d6" />
                                </label>
                            </ImagesContainer>
                            <input
                                type="file"
                                id="image[]"
                                multiple
                                onChange={handleSelectImages}
                            />
                        </InputContainer>
                    </fieldset>

                    <fieldset>
                        <legend>Visitação</legend>

                        <InputContainer>
                            <label htmlFor="instructions">Instruções</label>
                            <textarea
                                id="instructions"
                                value={instructions}
                                onChange={e => setInstructions(e.target.value)}
                            />
                        </InputContainer>

                        <InputContainer>
                            <label htmlFor="opening_hours">Horário de funcionamento</label>
                            <input
                                id="opening_hours"
                                value={opening_hours}
                                onChange={e => setOpeningHours(e.target.value)}
                            />
                        </InputContainer>

                        <InputContainer>
                            <label htmlFor="open_on_weekends">Atende no fim de semana</label>

                            <OpenOnWeekendContainer>
                                <SelectButton
                                    type="button"
                                    active={open_on_weekends}
                                    onClick={() => setOpenOnWeekends(true)}
                                >Sim</SelectButton>
                                <SelectButton
                                    type="button"
                                    active={!open_on_weekends}
                                    onClick={() => setOpenOnWeekends(false)}
                                >Não</SelectButton>
                            </OpenOnWeekendContainer>
                        </InputContainer>
                    </fieldset>

                    <button type="submit">Confirmar</button>
                </Form>
            </Content>
        </Container>
    );
}
Example #27
Source File: index.tsx    From NextLevelWeek with MIT License 4 votes vote down vote up
Orphanage: React.FC = () => {
    const params = useParams<IOrphanageParams>();
    const [orphanage, setOrphanage] = useState<IOpharnage>();
    const [activeImageIndex, setActiveImageIndex] = useState(0);

    useEffect(() => {
        api.get(`/orphanages/${params.id}`).then(res => {
            // console.log(res.data);
            setOrphanage(res.data);
        });
    }, [params.id]);

    if (!orphanage) {
        return <p>Carregando..</p>;
        // Fazer em Shimmer
    }

    return (
        <Container>
            <Sidebar />
            <Content>
                <DetailsContainer>
                    <img src={orphanage.images[activeImageIndex].url} alt={orphanage.name} />

                    <ImagesContainer>
                        {orphanage.images.map((image, index) => {
                            return (
                                <ButtonImage
                                    key={image.id}
                                    type="button"
                                    active={activeImageIndex === index}
                                    onClick={() => {
                                        setActiveImageIndex(index);
                                    }}
                                >
                                    <img src={image.url} alt={orphanage.name} />
                                </ButtonImage>
                            );
                        })}
                    </ImagesContainer>

                    <OrphanageDetails>
                        <h1>{orphanage.name}</h1>
                        <p>{orphanage.about}</p>

                        <MapContainer>
                            <Map
                                center={[orphanage.latitude, orphanage.longitude]}
                                zoom={16}
                                style={{ width: '100%', height: 280 }}
                                dragging={false}
                                touchZoom={false}
                                zoomControl={false}
                                scrollWheelZoom={false}
                                doubleClickZoom={false}
                            >
                                <TileLayer
                                    url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
                                />
                                <Marker interactive={false} icon={happyMapIcon} position={[orphanage.latitude, orphanage.longitude]} />
                            </Map>

                            <footer>
                                <a target="_blank" rel="noopener noreferrer" href={`https://www.google.com/maps/dir/?api=1&destination=${orphanage.latitude},${orphanage.longitude}`}>Ver rotas no Google Maps</a>
                            </footer>
                        </MapContainer>

                        <hr />

                        <h2>Instruções para visita</h2>
                        <p>{orphanage.instructions}</p>

                        <OpenDetails>
                            <OpeningHoursContainer>
                                <FiClock size={32} color="#15B6D6" />
                                Segunda à Sexta <br />
                                {orphanage.opening_hours}
                            </OpeningHoursContainer>

                            {orphanage.open_on_weekends ? (
                                <OpenWeekends open={orphanage.open_on_weekends}>
                                    <FiInfo size={32} />
                                    Atendemos <br />
                                    fim de semanada
                                </OpenWeekends>
                            ) : (
                                    <OpenWeekends open={orphanage.open_on_weekends}>
                                        <FiInfo size={32} />
                                        Não atendemos <br />
                                        no fim de semanada
                                    </OpenWeekends>
                                )
                            }

                            <button type="button">
                                <FaWhatsapp size={20} color="#FFF" />
                                Entrar em contato
                            </button>
                        </OpenDetails>
                    </OrphanageDetails>
                </DetailsContainer>
            </Content>
        </Container>
    );
}
Example #28
Source File: index.tsx    From NextLevelWeek with MIT License 4 votes vote down vote up
CreatePoint = () => {
    const [items, setItems] = useState<Item[]>([]);
    const [ufs, setUfs] = useState<string[]>([]);
    const [cities, setCities] = useState<string[]>([]);

    const [selectedItems, setSelectedItems] = useState<number[]>([]);

    const [initialPosition, setInitialPosition] = useState<[number, number]>([
        0,
        0,
    ]);
    const [selectedPosition, setSelectedPosition] = useState<[number, number]>([
        0,
        0,
    ]);

    const [formData, setFormData] = useState({
        name: "",
        email: "",
        whatsapp: "",
    });

    const [selectedUf, setCity] = useState("0");
    const [selectedCity, setSelectedCity] = useState("0");

    const [selectedFile, setSelectFile] = useState<File>();

    // Permite navegar de um componente para outro sem ter um botão.
    const history = useHistory();

    /**
     * UseEffect para pegar a localização atual do usuário
     */
    useEffect(() => {
        navigator.geolocation.getCurrentPosition((position) => {
            // console.log(position);
            const { latitude, longitude } = position.coords;

            setInitialPosition([latitude, longitude]);
        });
    }, []);

    /**
     * Evitar que toda vez que o componente mude, chame a API local.
     */
    useEffect(() => {
        api.get("/items").then((res) => {
            // console.log(res);
            setItems(res.data);
        });
    }, []);

    /**
     * Chamanda da API do IBGE para UFs.
     */
    useEffect(() => {
        axios
            .get<IBGEUF[]>(
                "https://servicodados.ibge.gov.br/api/v1/localidades/estados?orderBy=nome"
            )
            .then((res) => {
                // console.log(res);
                const ufInitials = res.data.map((uf) => uf.sigla);

                // console.log(ufInitials);
                setUfs(ufInitials);
            });
    }, []);

    /**
     * Chamada da API do IBGE por municípios.
     */
    useEffect(() => {
        // Carregar as cidades sempre que alterar as UF.
        // console.log("Funfou", selectedUf);

        if (selectedUf === "0") {
            return;
        }

        axios
            .get<IBGECity[]>(
                `https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`
            )
            .then((res) => {
                // console.log(res);
                const cityName = res.data.map((city) => city.nome);

                setCities(cityName);
            });
    }, [selectedUf]);

    /**
     * Toda vez que o usuário altera a UF chama esta função.
     */
    function handleSelectUf(e: ChangeEvent<HTMLSelectElement>) {
        // console.log(e.target.value);
        const uf = e.target.value;

        setCity(uf);
    }

    /**
     * Armazenando a cidade.
     */
    function handleSelectCity(e: ChangeEvent<HTMLSelectElement>) {
        const city = e.target.value;

        // console.log(city);

        setSelectedCity(city);
    }

    /**
     * Função para colocar o pin no mapa.
     */
    function handleMapClick(e: LeafletMouseEvent) {
        // console.log(e.latlng);
        setSelectedPosition([e.latlng.lat, e.latlng.lng]);
    }

    /**
     * Função para armazenar os inputs.
     */
    function handleInputChange(e: ChangeEvent<HTMLInputElement>) {
        // console.log(e.target.name, e.target.value);
        const { name, value } = e.target;

        setFormData({
            ...formData,
            [name]: value,
        });
    }

    /**
     * Função para armazenar os itens selecionados.
     */
    function handleSelectItem(id: number) {
        // console.log("Foi", id);
        const alreadySelected = selectedItems.findIndex((item) => item === id);

        if (alreadySelected >= 0) {
            const filteredItems = selectedItems.filter((item) => item !== id);

            setSelectedItems(filteredItems);
        } else {
            setSelectedItems([...selectedItems, id]);
        }
    }

    /**
     * Função do submit.
     */
    async function handleSubmit(e: FormEvent) {
        // console.log("E aí ?");
        // Evitando que a tela seja recarregada no submit.
        e.preventDefault();

        // console.log(selectedFile);

        const { name, email, whatsapp } = formData;
        const [latitude, longitude] = selectedPosition;
        const uf = selectedUf;
        const city = selectedCity;
        const items = selectedItems;

        const data = new FormData();

        data.append("name", name);
        data.append("email", email);
        data.append("whatsapp", whatsapp);
        data.append("latitude", String(latitude));
        data.append("longitude", String(longitude));
        data.append("uf", uf);
        data.append("city", city);
        data.append("items", items.join(","));

        if (selectedFile) {
            data.append("image", selectedFile);
        }

        /* const data = {
            name,
            email,
            whatsapp,
            latitude,
            longitude,
            uf,
            city,
            items,
        }; */

        // console.log(data);
        await api.post("/points", data);

        alert("Ponto de coleta criado!");

        history.push("/");
    }

    return (
        <div id="page-create-point">
            <header>
                <img src={logo} alt="Ecoleta" />

                <Link to="/">
                    <FiArrowLeft />
                    Voltar para home
                </Link>
            </header>

            <form onSubmit={handleSubmit}>
                <h1>
                    Cadastro do <br /> ponto de coleta
                </h1>

                <Dropzone onFileUploaded={setSelectFile} />

                <fieldset>
                    <legend>
                        <h2>Dados</h2>
                    </legend>

                    <div className="field">
                        <label htmlFor="name">Nome da entidade</label>
                        <input
                            type="text"
                            name="name"
                            id="name"
                            onChange={handleInputChange}
                        />
                    </div>

                    <div className="field-group">
                        <div className="field">
                            <label htmlFor="email">E-mail</label>
                            <input
                                type="text"
                                name="email"
                                id="email"
                                onChange={handleInputChange}
                            />
                        </div>
                        <div className="field">
                            <label htmlFor="whatsapp">WhatsApp</label>
                            <input
                                type="text"
                                name="whatsapp"
                                id="whatsapp"
                                onChange={handleInputChange}
                            />
                        </div>
                    </div>
                </fieldset>

                <fieldset>
                    <legend>
                        <h2>Endereço</h2>
                        <span>Selecione o endereço no mapa.</span>
                    </legend>

                    <Map
                        center={initialPosition}
                        zoom={15}
                        onClick={handleMapClick}
                    >
                        <TileLayer
                            attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                        />

                        <Marker position={selectedPosition} />
                    </Map>

                    <div className="field-group">
                        <div className="field">
                            <label htmlFor="uf">Estado</label>
                            <select
                                name="uf"
                                id="uf"
                                value={selectedUf}
                                onChange={handleSelectUf}
                            >
                                <option value="0">Selecione um estado</option>
                                {ufs.map((uf) => (
                                    <option key={uf} value={uf}>
                                        {uf}
                                    </option>
                                ))}
                            </select>
                        </div>

                        <div className="field">
                            <label htmlFor="city">Cidade</label>
                            <select
                                name="city"
                                id="city"
                                value={selectedCity}
                                onChange={handleSelectCity}
                            >
                                <option value="0">Selecione uma cidade</option>
                                {cities.map((city) => (
                                    <option key={city} value={city}>
                                        {city}
                                    </option>
                                ))}
                            </select>
                        </div>
                    </div>
                </fieldset>

                <fieldset>
                    <legend>
                        <h2>Itens de coleta</h2>
                        <span>Selecione um ou mais itens a baixo.</span>
                    </legend>

                    <ul className="items-grid">
                        {items.map((item) => (
                            <li
                                key={item.id}
                                onClick={() => handleSelectItem(item.id)}
                                className={
                                    selectedItems.includes(item.id)
                                        ? "selected"
                                        : ""
                                }
                            >
                                <img src={item.image_url} alt={item.title} />
                                <span>{item.title}</span>
                            </li>
                        ))}
                    </ul>
                </fieldset>

                <button type="submit">Cadastrar ponto de coleta</button>
            </form>
        </div>
    );
}
Example #29
Source File: index.tsx    From aqualink-app with MIT License 4 votes vote down vote up
HomepageMap = ({
  initialCenter,
  initialZoom,
  initialBounds,
  collection,
  showAlertLevelLegend,
  showWaterMark,
  geolocationEnabled,
  defaultLayerName,
  legendBottom,
  legendLeft,
  classes,
}: HomepageMapProps) => {
  const [legendName, setLegendName] = useState<string>(defaultLayerName || "");
  const [currentLocation, setCurrentLocation] = useState<[number, number]>();
  const [currentLocationAccuracy, setCurrentLocationAccuracy] =
    useState<number>();
  const [currentLocationErrorMessage, setCurrentLocationErrorMessage] =
    useState<string>();
  const loading = useSelector(sitesListLoadingSelector);
  const searchResult = useSelector(searchResultSelector);
  const ref = useRef<Map>(null);

  const onLocationSearch = () => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const latLng = [
            position.coords.latitude,
            position.coords.longitude,
          ] as [number, number];
          setCurrentLocation(latLng);
          setCurrentLocationAccuracy(position.coords.accuracy);

          // zoom to user location
          const { current } = ref;
          if (current && current.leafletElement) {
            const map = current.leafletElement;
            const newZoom = Math.max(map.getZoom() || 6, 8);
            map.flyTo(latLng, newZoom, { duration: 2 });
          }
        },
        () => {
          setCurrentLocationErrorMessage("Unable to find your location");
        }
      );
    } else {
      setCurrentLocationErrorMessage(
        "Geolocation is not supported by your browser"
      );
    }
  };

  const onLocationErrorAlertClose = () =>
    setCurrentLocationErrorMessage(undefined);

  useEffect(() => {
    const { current } = ref;
    if (current && current.leafletElement) {
      const map = current.leafletElement;
      if (searchResult) {
        map.fitBounds([
          searchResult.bbox.southWest,
          searchResult.bbox.northEast,
        ]);
      }
    }
  }, [searchResult]);

  const onBaseLayerChange = ({ name }: LayersControlEvent) => {
    setLegendName(name);
  };

  return loading ? (
    <div className={classes.loading}>
      <CircularProgress size="4rem" thickness={1} />
    </div>
  ) : (
    <Map
      id="sites-map"
      ref={ref}
      preferCanvas
      maxBoundsViscosity={1.0}
      className={classes.map}
      center={initialCenter}
      zoom={initialZoom}
      minZoom={collection ? 1 : 2} // If we're on dashboard page, the map's wrapping div is smaller, so we need to allow higher zoom
      worldCopyJump
      onbaselayerchange={onBaseLayerChange}
      bounds={initialBounds}
      maxBounds={mapConstants.MAX_BOUNDS}
    >
      <Snackbar
        open={Boolean(currentLocationErrorMessage)}
        autoHideDuration={5000}
        anchorOrigin={{ vertical: "top", horizontal: "right" }}
        onClose={onLocationErrorAlertClose}
      >
        <Alert severity="error" onClose={onLocationErrorAlertClose}>
          {currentLocationErrorMessage}
        </Alert>
      </Snackbar>
      <TileLayer attribution={attribution} url={tileURL} />
      <SofarLayers defaultLayerName={defaultLayerName} />
      <SiteMarkers collection={collection} />
      {currentLocation && (
        <Marker icon={currentLocationMarker} position={currentLocation} />
      )}
      {currentLocation && currentLocationAccuracy && (
        <Circle
          center={{ lat: currentLocation[0], lng: currentLocation[1] }}
          radius={currentLocationAccuracy}
        />
      )}
      <Legend legendName={legendName} bottom={legendBottom} left={legendLeft} />
      {showAlertLevelLegend && <AlertLevelLegend />}
      {showWaterMark && <div className="mapbox-wordmark" />}
      {geolocationEnabled && (
        <div className={classes.locationIconButton}>
          <IconButton onClick={onLocationSearch}>
            <MyLocationIcon color="primary" />
          </IconButton>
        </div>
      )}
    </Map>
  );
}