/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ /* eslint-disable jsx-a11y/label-has-associated-control */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable no-use-before-define */ import React, { useState, useEffect, ChangeEvent, FormEvent, useCallback, } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { FiArrowLeft } from 'react-icons/fi'; import { Map, TileLayer, Marker } from 'react-leaflet'; import { LeafletMouseEvent } from 'leaflet'; import { toast } from 'react-toastify'; import api from '../../services/api'; import ibge from '../../services/ibge'; import Dropzone from '../../components/Dropzone'; import './styles.css'; import logo from '../../assets/logo.svg'; interface Item { id: number; title: string; image_url: string; } interface IBGEUFResponse { sigla: string; nome: string; } interface IBGECityResponse { nome: string; } const 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='&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> ); }; export default CreatePoint;