Skip to content

Commit 543e447

Browse files
committed
feat: add components
1 parent 0e51a6f commit 543e447

File tree

4 files changed

+327
-4
lines changed

4 files changed

+327
-4
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
- Copyright 2022 Sven Loesekann
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
.responseMsg {
14+
color: #ff0000;
15+
}
16+
17+
.toright {
18+
float: right;
19+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
- Copyright 2022 Sven Loesekann
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
import * as React from 'react';
14+
import GlobalState from "../GlobalState";
15+
import { type UserDataState} from "../GlobalState";
16+
import { useMemo,useEffect,useState,type FormEvent, type ChangeEvent,type SyntheticEvent } from "react";
17+
import {Box,TextField,Button,Dialog,DialogContent, Autocomplete} from '@mui/material';
18+
import styles from './location-modal.module.css';
19+
import { fetchLocation, postLocationRadius } from "../service/http-client";
20+
import { type PostCodeLocation } from "../model/location";
21+
import { type UserRequest } from "../model/user";
22+
import { useAtom } from "jotai";
23+
24+
const LocationModal = () => {
25+
let controller: AbortController | null = null;
26+
const [open, setOpen] = useState(false);
27+
const [searchRadius, setSearchRadius] = useState(0);
28+
const [longitude, setLongitude] = useState(0);
29+
const [latitude, setLatitude] = useState(0);
30+
const [postCode, setPostCode] = useState('');
31+
const [options, setOptions] = useState([] as PostCodeLocation[]);
32+
const [globalLocationModalState, setGlobalLocationModalState] = useAtom(GlobalState.locationModalState);
33+
const [globalJwtTokenState, setGlobalJwtTokenState] = useAtom(GlobalState.jwtTokenState);
34+
const [globalUserDataState, setGlobalUserDataState] = useAtom(GlobalState.userDataState);
35+
const [globalUserNameState, setGlobalUserNameState] = useAtom(GlobalState.userNameState);
36+
37+
useEffect(() => {
38+
if (!open) {
39+
setOptions([]);
40+
}
41+
}, [open]);
42+
43+
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
44+
event.preventDefault();
45+
if(!!controller) {
46+
controller.abort();
47+
}
48+
controller = new AbortController();
49+
//console.log("Submit: ",event);
50+
const requestString = JSON.stringify({Username: globalUserNameState, Password: '', Latitude: latitude, Longitude: longitude, SearchRadius: searchRadius, PostCode: parseInt(postCode)} as UserRequest);
51+
const userResponse = await postLocationRadius(globalJwtTokenState, controller, requestString);
52+
controller = null;
53+
setGlobalUserDataState({Latitude: userResponse.Latitude, Longitude: userResponse.Longitude, SearchRadius: userResponse.SearchRadius, PostCode: postCode.toString() || 0,
54+
TargetDiesel: globalUserDataState.TargetDiesel, TargetE10: globalUserDataState.TargetE10, TargetE5: globalUserDataState.TargetE5} as UserDataState);
55+
setGlobalLocationModalState(false);
56+
}
57+
/*
58+
const handleClose = (event: React.FormEvent) => {
59+
setGlobalLocationModalState(false);
60+
}
61+
*/
62+
const handleChange = async (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
63+
event.preventDefault();
64+
if(!event?.currentTarget?.value) {
65+
setOptions([]);
66+
return;
67+
}
68+
if(!!controller) {
69+
controller.abort();
70+
}
71+
controller = new AbortController();
72+
const locations = await fetchLocation(globalJwtTokenState, controller, event.currentTarget.value);
73+
setOptions(!locations ? [] : locations);
74+
controller = null;
75+
//console.log(locations);
76+
}
77+
78+
const handleSearchRadiusChange = (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
79+
//console.log(event?.currentTarget?.value);
80+
const mySearchRadius = parseFloat(event?.currentTarget?.value);
81+
setSearchRadius(Number.isNaN(mySearchRadius) ? searchRadius : mySearchRadius);
82+
}
83+
84+
const handleOptionChange = (event: SyntheticEvent<Element, Event>, value: string) =>{
85+
const filteredOptions = options.filter(option => option.Label === value);
86+
//console.log(filteredOptions);
87+
if(filteredOptions.length > 0) {
88+
setLongitude(filteredOptions[0].Longitude);
89+
setLatitude(filteredOptions[0].Latitude);
90+
setPostCode(formatPostCode(filteredOptions[0].PostCode));
91+
}
92+
}
93+
94+
const formatPostCode = (myPlz: number) => {
95+
return '00000'.substring(0, 5 - myPlz?.toString()?.length > 0 ? myPlz?.toString()?.length : 0) + myPlz.toString();
96+
}
97+
98+
const handleCancel = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
99+
setSearchRadius(0);
100+
setLongitude(0);
101+
setLatitude(0);
102+
setGlobalLocationModalState(false);
103+
}
104+
105+
const handleGetLocation = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
106+
if(!!navigator.geolocation) {
107+
navigator.geolocation.getCurrentPosition(result => {
108+
if(!!result?.coords?.longitude && !!result?.coords?.latitude) {
109+
setLongitude(result.coords.longitude);
110+
setLatitude(result.coords.latitude);
111+
}
112+
});
113+
}
114+
}
115+
116+
let dialogOpen = useMemo(() => {
117+
//console.log(globalUserDataState.Longitude+' '+globalUserDataState.Latitude);
118+
setLongitude(globalUserDataState.Longitude);
119+
setLatitude(globalUserDataState.Latitude);
120+
setSearchRadius(globalUserDataState.SearchRadius);
121+
setPostCode(formatPostCode(globalUserDataState.PostCode));
122+
return globalLocationModalState;
123+
}, [globalLocationModalState, globalUserDataState.Longitude, globalUserDataState.Latitude, globalUserDataState.SearchRadius, globalUserDataState.PostCode]);
124+
125+
return (<Dialog open={dialogOpen} className="backDrop">
126+
<DialogContent>
127+
<Box
128+
component="form"
129+
noValidate
130+
autoComplete="off"
131+
onSubmit={handleSubmit}>
132+
<Autocomplete
133+
open={open}
134+
onOpen={() => {
135+
setOpen(true);
136+
}}
137+
onClose={() => {
138+
setOpen(false);
139+
}}
140+
style={{ width: 300 }}
141+
onInputChange={handleOptionChange}
142+
getOptionLabel={option => option.Label}
143+
options={options}
144+
renderInput={(params) => <TextField {...params} label="Locations" onChange={handleChange} />}
145+
></Autocomplete>
146+
<div>
147+
<h3>Longitude: {longitude}</h3>
148+
<h3>Latitude: {latitude}</h3>
149+
<h3>Postcode: {postCode}</h3>
150+
</div>
151+
<TextField
152+
autoFocus
153+
margin="dense"
154+
value={searchRadius}
155+
onChange={handleSearchRadiusChange}
156+
label="Search Radius"
157+
type="string"
158+
fullWidth
159+
variant="standard"/>
160+
<div>
161+
<Button type="submit">Ok</Button>
162+
<Button onClick={handleCancel}>Cancel</Button>
163+
<Button className={styles.toright} onClick={handleGetLocation}>Get Location</Button>
164+
</div>
165+
</Box>
166+
</DialogContent>
167+
</Dialog>);
168+
}
169+
export default LocationModal;

frontend/app/main-container/main-container.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
import * as React from 'react';
1414
import styles from './main-container.module.css';
1515
import Header from '../header/header';
16-
//import LocationModal from './components/LocationModal';
17-
//import TargetPriceModal from './components/TargetPriceModal';
1816
import Main from '../main/main';
1917
import { useAtom } from "jotai";
2018
import GlobalState from '../GlobalState';
2119
import { useEffect } from 'react';
2220
import { useNavigate } from 'react-router';
21+
import LocationModal from '../location-modal/location-modal';
22+
import TargetPriceModal from '../target-price-modal/target-price-modal';
2323

2424
export interface TodoItem1 {
2525
name: string;
@@ -40,8 +40,8 @@ function MainContainer() {
4040
return (
4141
<div className="App">
4242
<Header/>
43-
{/* <LocationModal/> */}
44-
{/* <TargetPriceModal/> */}
43+
<LocationModal/>
44+
<TargetPriceModal/>
4545
<Main/>
4646
</div>
4747
);
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
- Copyright 2022 Sven Loesekann
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
import * as React from 'react';
14+
import GlobalState from "../GlobalState";
15+
import { Box, TextField, Button, Dialog, DialogContent } from '@mui/material';
16+
import { useState, useMemo, type ChangeEventHandler, type FormEvent } from "react";
17+
import { postTargetPrices } from "../service/http-client";
18+
import { type UserRequest } from "../model/user";
19+
import { useAtom } from 'jotai';
20+
21+
22+
const TargetPriceModal = () => {
23+
let controller: AbortController | null = null;
24+
const [targetDiesel, setTargetDiesel] = useState('0');
25+
const [targetE5, setTargetE5] = useState('0');
26+
const [targetE10, setTargetE10] = useState('0');
27+
const [globalTargetPriceModalState, setGlobalTargetPriceModalState] = useAtom(GlobalState.targetPriceModalState);
28+
const [globalJwtTokenState, setGlobalJwtTokenState] = useAtom(GlobalState.jwtTokenState);
29+
const [globalUserNameState, setGlobalUserNameState] = useAtom(GlobalState.userNameState);
30+
const [globalUserDataState, setGlobalUserDataState] = useAtom(GlobalState.userDataState);
31+
32+
let dialogOpen = useMemo(() => {
33+
setTargetDiesel('' + globalUserDataState.TargetDiesel);
34+
setTargetE10('' + globalUserDataState.TargetE10);
35+
setTargetE5('' + globalUserDataState.TargetE5);
36+
return globalTargetPriceModalState;
37+
}, [globalTargetPriceModalState, globalUserDataState.TargetDiesel, globalUserDataState.TargetE10, globalUserDataState.TargetE5]);
38+
39+
const handleTargetDieselChange: ChangeEventHandler<HTMLInputElement> = (event) => {
40+
event.preventDefault();
41+
setTargetDiesel(event.currentTarget.value);
42+
}
43+
44+
const handleTargetE10Change: ChangeEventHandler<HTMLInputElement> = (event) => {
45+
event.preventDefault();
46+
setTargetE10(event.currentTarget.value);
47+
}
48+
49+
const handleTargetE5Change: ChangeEventHandler<HTMLInputElement> = (event) => {
50+
event.preventDefault();
51+
setTargetE5(event.currentTarget.value);
52+
}
53+
54+
const updatePrice = (priceStr: string) => {
55+
let myPrice = priceStr.replace(/\.|,/, '');
56+
while (myPrice.length < 4) {
57+
myPrice = myPrice + '0';
58+
}
59+
return myPrice;
60+
}
61+
62+
const handleSubmit = async (event: FormEvent) => {
63+
event.preventDefault();
64+
if (!!controller) {
65+
controller.abort();
66+
}
67+
const myDiesel = updatePrice(targetDiesel);
68+
const myE5 = updatePrice(targetE5);
69+
const myE10 = updatePrice(targetE10);
70+
controller = new AbortController();
71+
const requestString = JSON.stringify({ Username: globalUserNameState, Password: '', TargetDiesel: myDiesel, TargetE10: myE10, TargetE5: myE5 } as UserRequest);
72+
const result = await postTargetPrices(globalJwtTokenState, controller, requestString);
73+
controller = null;
74+
setGlobalUserDataState({
75+
Latitude: globalUserDataState.Latitude, Longitude: globalUserDataState.Longitude, SearchRadius: globalUserDataState.SearchRadius, PostCode: globalUserDataState.PostCode,
76+
TargetDiesel: !result.TargetDiesel ? 0 : result.TargetDiesel, TargetE10: !result.TargetE10 ? 0 : result.TargetE10, TargetE5: !result.TargetE5 ? 0 : result.TargetE5
77+
});
78+
setGlobalTargetPriceModalState(false);
79+
//console.log(result.TargetDiesel+' '+result.TargetE10+' '+result.TargetE5);
80+
};
81+
82+
const handleCancel = (event: FormEvent) => {
83+
event.preventDefault();
84+
setGlobalTargetPriceModalState(false);
85+
setTargetDiesel('0');
86+
setTargetE10('0');
87+
setTargetE5('0');
88+
}
89+
90+
return (<Dialog open={dialogOpen} className="backDrop">
91+
<DialogContent>
92+
<Box
93+
component="form"
94+
noValidate
95+
autoComplete="off"
96+
onSubmit={handleSubmit}>
97+
<div>
98+
<TextField
99+
autoFocus
100+
margin="dense"
101+
value={targetDiesel}
102+
onChange={handleTargetDieselChange}
103+
label="Targetprice Diesel"
104+
type="string"
105+
fullWidth
106+
variant="standard" />
107+
<TextField
108+
autoFocus
109+
margin="dense"
110+
value={targetE5}
111+
onChange={handleTargetE5Change}
112+
label="Targetprice E5"
113+
type="string"
114+
fullWidth
115+
variant="standard" />
116+
<TextField
117+
autoFocus
118+
margin="dense"
119+
value={targetE10}
120+
onChange={handleTargetE10Change}
121+
label="Targetprice E10"
122+
type="string"
123+
fullWidth
124+
variant="standard" />
125+
</div>
126+
<div>
127+
<Button type="submit">Ok</Button>
128+
<Button onClick={handleCancel}>Cancel</Button>
129+
</div>
130+
</Box>
131+
</DialogContent>
132+
</Dialog>);
133+
}
134+
135+
export default TargetPriceModal;

0 commit comments

Comments
 (0)