zglaszansko-web/src/app.tsx

167 lines
5.3 KiB
TypeScript

import React, {
useState,
useReducer,
MouseEvent,
FC,
ChangeEvent,
FormEvent,
} from "react";
import * as ReactDOM from "react-dom";
import { offenses } from "./offenses";
//Importing fileReducer to use in useReducer hook, and File interface to use in looping over array of files
import { fileReducer, File } from "./fileReducer";
import "regenerator-runtime/runtime";
import { MapContainer, TileLayer, Marker, useMapEvents } from "react-leaflet";
import "./styles/reset.css";
import "./styles/app.scss";
const App: FC = () => {
//This reducer handles adding and selecting files.
//I'm passing in initial state "{files: []}" which can be changed by using dispatch function with object contaning right type and payload.
//Example: dispatch({type: "ADD_FILE", payload: {img: thisIsImgURL, selected: false})
//State can be accsesed by using fileState object
//Example: fileState.files
//Reducer it self is imported from fileReducer.ts in src/ dir
const [fileState, dispatch] = useReducer(fileReducer, { files: [] });
//This hook handles pining location on the map
const [mapPin, setMapPin] = useState([52, 16]);
const handleSubmit = async (
event: FormEvent<HTMLFormElement> | MouseEvent<HTMLButtonElement>
): Promise<void> => {
event.preventDefault();
};
const handleUpload = (e: ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
const readAndPreview = (file: any) => {
// Make sure `file.name` matches our extensions criteria
if (/\.(jpe?g|png|svg)$/i.test(file.name)) {
let reader = new FileReader();
reader.addEventListener(
"load",
function () {
dispatch({
type: "ADD_FILE",
payload: {
img: this.result,
//
id: Date.now().toString(),
selected: false,
},
});
},
false
);
reader.readAsDataURL(file);
}
};
if (files) {
[].forEach.call(files, readAndPreview);
}
};
const MapComponent = () => {
useMapEvents({
click: (e) => {
setMapPin([e.latlng.lat, e.latlng.lng]);
},
});
return null;
};
return (
<div className="container">
<section className="container__section">
<h2 className="container__section__title">Zdjęcia</h2>
<div className="container__section__photos">
{fileState.files.map((file: File, index: number) => (
<div
key={index}
onClick={(e: MouseEvent) =>
dispatch({
type: "SELECT_FILE",
payload: { id: (e.target as any).id },
})
}
className="section__photos__item"
>
<img
src={file.img}
id={file.id}
className={file.selected ? "img--active" : "img"}
/>
</div>
))}
</div>
<input
type="file"
name="image-upload"
id="input"
accept="image/*"
className="input"
multiple
onChange={(e) => handleUpload(e)}
/>
</section>
<section className="container__section">
<h2 className="container__section__title">Mapa</h2>
<div>
<MapContainer
center={[52.39663, 16.89866]}
className="container__section__map"
zoom={18}
scrollWheelZoom={true}
>
<TileLayer
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
<Marker position={mapPin as any}></Marker>
<MapComponent />
</MapContainer>
</div>
</section>
<section className="container__section">
<h2 className="container__section__title">Formularz zgłoszeniowy</h2>
<form
className="container__section__form"
onSubmit={(e) => handleSubmit(e)}
>
<label htmlFor="name">Twoje imię i nazwisko</label>
<input type="text" className="input" id="name" />
<label htmlFor="email">Twój adres email</label>
<input type="text" className="input" id="email" />
<label htmlFor="plate">Numer tablicy rejestracyjnej</label>
<input type="text" className="input" id="plate" />
<label htmlFor="message">Wiadomość dla straży miejskiej</label>
<textarea className="input input--textarea" id="message" />
<div>
{offenses.map((offence, index) => (
<div key={index}>
<input
type="checkbox"
id={offence.id}
value={offence.car_is}
name={offence.car_is}
/>
<label htmlFor={offence.id} className="label">
{offence.name}
</label>
;
</div>
))}
</div>
<button className="button" onClick={(e) => handleSubmit(e)}>
Wysłanie zgłoszenia
</button>
</form>
</section>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));