167 lines
5.3 KiB
TypeScript
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='© <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"));
|