Reducer for files and correct types

master
franciszek 4 years ago
parent df52776c28
commit 724b047eaa

@ -1,38 +1,56 @@
import React, { useState, useReducer } from "react";
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,
Popup,
useMapEvents,
} from "react-leaflet";
import { MapContainer, TileLayer, Marker, useMapEvents } from "react-leaflet";
import "./styles/reset.css";
import "./styles/app.scss";
const App: React.FC = () => {
const [files, setFiles] = useState([]);
const [mapPin, setMapPin] = useState([52.39663, 16.89866]);
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: React.FormEvent<HTMLFormElement>
event: FormEvent<HTMLFormElement> | MouseEvent<HTMLButtonElement>
): Promise<void> => {
event.preventDefault();
};
const handleUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleUpload = (e: ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
const newstate = [];
const readAndPreview = (file) => {
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 () {
newstate.push(this.result);
setFiles([...newstate]);
dispatch({
type: "ADD_FILE",
payload: {
img: this.result,
//
id: Date.now().toString(),
selected: false,
},
});
},
false
);
@ -43,23 +61,37 @@ const App: React.FC = () => {
[].forEach.call(files, readAndPreview);
}
};
const MapComponent = () => {
useMapEvents({
click: (e) => {
setMapPin([e.latlng.lat, e.latlng.lng]);
console.log(mapPin);
},
});
return null;
};
return (
<div className="container">
<section className="container__section">
<h2 className="container__section__title">Zdjęcia</h2>
<div className="container__section__photos">
{files.map((file) => (
<div className="section__photos__item">
<img src={file} id="img" className="img" />
{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>
@ -68,6 +100,7 @@ const App: React.FC = () => {
name="image-upload"
id="input"
accept="image/*"
className="input"
multiple
onChange={(e) => handleUpload(e)}
/>
@ -85,7 +118,7 @@ const App: React.FC = () => {
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
<Marker position={mapPin}></Marker>
<Marker position={mapPin as any}></Marker>
<MapComponent />
</MapContainer>
</div>
@ -104,10 +137,26 @@ const App: React.FC = () => {
<input type="text" className="input" id="plate" />
<label htmlFor="message">Wiadomość dla straży miejskiej</label>
<textarea className="input input--textarea" id="message" />
<select className="input" id="reason">
<option value="0">Wybierz powód wysłania zgłoszenia</option>
</select>
<button className="button">Wysłanie zgłoszenia</button>
<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>

@ -0,0 +1,47 @@
export interface File {
img: string;
id: string;
selected: boolean;
}
interface FilesState {
files: Array<File>;
}
interface FilesAction {
type: string;
payload: {
img?: any;
id: string;
selected?: boolean;
};
}
export function fileReducer(state: FilesState, action: FilesAction) {
switch (action.type) {
case "ADD_FILE":
return {
...state,
files: [
...state.files,
{
img: action.payload.img,
id: action.payload.id,
selected: action.payload.selected,
},
],
};
case "SELECT_FILE":
return {
...state,
files: state.files.map((file: File) =>
file.id == action.payload.id
? { ...file, selected: true }
: { ...file, selected: false }
),
};
case "CLEAR_FILES":
return {
files: [],
};
default:
throw new Error();
}
}

@ -0,0 +1,110 @@
export type Offense = {
name: string;
car_is: string;
id: string;
implies?: string[];
};
export const offenses: Offense[] = [
{
id: "obszar_wyłączony",
name: "Parkowanie na obszarze wyłączonym z ruchu",
car_is: "jest zaparkowany na obszarze wyłączonym z ruchu",
},
{
id: "widoczność_pasy",
name: "Ograniczanie widoczności na pasach",
car_is:
"ogranicza widoczność na przejściu dla pieszych, powodując zagrożenie osób korzystających z przejścia",
},
{
id: "widoczność_skrz",
name: "Ograniczanie widoczności na skrzyżowaniu",
car_is:
"ogranicza widoczność na skrzyżowaniu, powodując zagrożenie dla uczestników ruchu",
},
{
id: "utrudnia_ruch_rowerom",
name: "Utrudnianie ruchu rowerowego",
car_is: "utrudnia ruch rowerowy",
},
{
id: "utrudnia_ruch_pieszym",
name: "Utrudnianie ruchu pieszego",
car_is: "utrudnia ruch pieszych",
},
{
id: "poza_wyzn",
name: "Parkowanie poza wyznaczonym miejscem",
car_is: "jest zaparkowany poza wyznaczonym miejscem parkingowym",
},
{
id: "przed_przejsc",
name: "Parkowanie <10m przed przejściem dla pieszych",
car_is: "jest zaparkowany mniej niż 10m przed przejściem dla pieszych",
implies: ["widoczność_pasy"],
},
{
id: "na_zakazie",
name: "Parkowanie za znakiem zakazu parkowania",
car_is: "jest zaparkowany za znakiem zakazu parkowania",
},
{
id: "brama",
name: "Blokowanie bramy wjazdowej",
car_is: "blokuje bramę wjazdową",
},
{
id: "na_chodzie",
name: "Postój na chodzie",
car_is: "ma włączony silnik podczas postoju",
},
{
id: "blk_chodnik",
name: "Blokowanie chodnika",
car_is:
"jest zaparkowany na chodniku pozostawiając mniej niż 1,5m dla pieszych",
implies: ["utrudnia_ruch_pieszym"],
},
{
id: "chyba2.5t",
name: "Duży samochód dostawczy na chodniku",
car_is:
"najprawdopodobniej przekracza dopuszczalną całkowitą masę 2,5t będąc zaparkowanym na chodniku",
},
{
id: "hydrant",
name: "Blokowanie hydrantu",
car_is: "blokuje dostęp do hydrantu",
},
{
id: "przystanek_15",
name: "Parkowanie <15m od przystanku",
car_is:
"jest zaparkowany w odległości mniejszej niż 15m od tablicy oznaczającej przystanek",
},
{
id: "utr_innym_zapark",
name: "Utrudnianie wyjazdu innym zaparkowanym samochodom",
car_is:
"dokonuje postoju w miejscu utrudniającym dostęp do innych, prawidłowo zaparkowanych pojazdów lub wyjazd tych pojazdów",
},
{
id: "pas_rowerow",
name: "blokuje pas rowerów",
car_is: "zaparkowany na pasie dla rowerów",
implies: ["utrudnia_ruch_rowerom"],
},
{
id: "t30",
name: "Parkowanie niezgodnie z rysunkiem na tabliczce (T-30)",
car_is:
"nie stosuje się do znaku T-30, wskazującego sposób ustawienia pojazdu względem krawędzi jezdni",
},
{
id: "blokuje_znak",
name: "Zasłanianie znaku drogowego",
car_is:
"zaparkowany w odległości mniejszej niż 10m od przedniej strony znaku drogowego, zasłaniając go (Art 49, punkt 1, ust. 6)",
},
];
Loading…
Cancel
Save