From d684eb47e0628fb25177e78b88eb39f076294917 Mon Sep 17 00:00:00 2001 From: asm Date: Sat, 17 Aug 2024 10:56:37 +0200 Subject: [PATCH 1/2] DV-000301: refactoring main FE class. --- frontend/src/App.css | 236 ++++++------ frontend/src/App.js | 358 ++++-------------- frontend/src/api/http-common.js | 35 ++ frontend/src/components/CountrySelect.js | 18 + frontend/src/components/ImageManager.js | 2 +- frontend/src/components/Timer.js | 32 ++ .../countries/countriesForDiplomaticPlates.js | 21 + frontend/src/countries/countriesForPlates.js | 40 ++ frontend/src/http-common.js | 9 - .../src/service/DiplomaticPlateService.js | 9 + frontend/src/service/PlateService.js | 44 +++ frontend/src/service/RegularPlateService.js | 9 + 12 files changed, 408 insertions(+), 405 deletions(-) create mode 100644 frontend/src/api/http-common.js create mode 100644 frontend/src/components/CountrySelect.js create mode 100644 frontend/src/components/Timer.js create mode 100644 frontend/src/countries/countriesForDiplomaticPlates.js create mode 100644 frontend/src/countries/countriesForPlates.js delete mode 100644 frontend/src/http-common.js create mode 100644 frontend/src/service/DiplomaticPlateService.js create mode 100644 frontend/src/service/PlateService.js create mode 100644 frontend/src/service/RegularPlateService.js diff --git a/frontend/src/App.css b/frontend/src/App.css index 8ad0d8a5..8571da2a 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,87 +1,86 @@ .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } body { - margin: 0; - color: #444; - background-color: #f3f3f3; - font: 600 16px/18px 'Open Sans', sans-serif; + margin: 0; + color: #444; + background-color: #f3f3f3; + font: 600 16px/18px 'Open Sans', sans-serif; } select { - height: 50px; - line-height: 50px; - font-size: 12pt; + height: 50px; + line-height: 50px; + font-size: 12pt; } #image img { - padding-left: 60px; - position: absolute; - padding-top: -10px; + padding-left: 60px; + position: absolute; + padding-top: -10px; } .center { - display: block; - margin-left: auto; - margin-right: auto; - width: 50%; + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; } .image-upload > input { - display: none; + display: none; } h3, label { - display: flex; - justify-content: center; + display: flex; + justify-content: center; } .form__input { - height: 50px; - border: none; - background-color: rgba(255, 255, 255, 0.4); - font-family: inherit; - font-size: 1.5rem; - text-align: center; - color: #333; - padding: 0.3rem 1rem; - border-radius: 0.7rem; - transition: all 0.3s; + height: 50px; + border: none; + background-color: rgba(255, 255, 255, 0.4); + font-family: inherit; + font-size: 1.5rem; + text-align: center; + color: #333; + padding: 0.3rem 1rem; + border-radius: 0.7rem; + transition: all 0.3s; } .text-area { - resize: none; - overflow: hidden; - min-height: 30px; + resize: none; + overflow: hidden; + min-height: 30px; } #app { - max-width: 600px; + max-width: 600px; } -#menuToggle -{ +#menuToggle { display: block; position: absolute; top: 50px; @@ -93,8 +92,7 @@ h3, label { user-select: none; } -#menuToggle input -{ +#menuToggle input { display: block; width: 40px; height: 32px; @@ -113,8 +111,7 @@ h3, label { /* * Just a quick hamburger */ -#menuToggle span -{ +#menuToggle span { display: block; width: 33px; height: 4px; @@ -128,18 +125,16 @@ h3, label { transform-origin: 4px 0px; - transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), - background 0.5s cubic-bezier(0.77,0.2,0.05,1.0), + transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0), + background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0), opacity 0.55s ease; } -#menuToggle span:first-child -{ +#menuToggle span:first-child { transform-origin: 0% 0%; } -#menuToggle span:nth-last-child(2) -{ +#menuToggle span:nth-last-child(2) { transform-origin: 0% 100%; } @@ -147,8 +142,7 @@ h3, label { * Transform all the slices of hamburger * into a crossmark. */ -#menuToggle input:checked ~ span -{ +#menuToggle input:checked ~ span { opacity: 1; transform: rotate(45deg) translate(-2px, -1px); background: #232323; @@ -157,8 +151,7 @@ h3, label { /* * But let's hide the middle one. */ -#menuToggle input:checked ~ span:nth-last-child(3) -{ +#menuToggle input:checked ~ span:nth-last-child(3) { opacity: 0; transform: rotate(0deg) scale(0.2, 0.2); } @@ -166,8 +159,7 @@ h3, label { /* * Ohyeah and the last one should go the other direction */ -#menuToggle input:checked ~ span:nth-last-child(2) -{ +#menuToggle input:checked ~ span:nth-last-child(2) { opacity: 1; transform: rotate(-45deg) translate(0, -1px); } @@ -176,8 +168,7 @@ h3, label { * Make this absolute positioned * at the top left of the screen */ -#menu -{ +#menu { position: absolute; width: 300px; margin: -100px 0 0 0; @@ -192,11 +183,10 @@ h3, label { transform-origin: 0% 0%; transform: translate(100%, 0); - transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0); + transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0); } -#menu li -{ +#menu li { padding: 10px 0; font-size: 22px; } @@ -204,108 +194,120 @@ h3, label { /* * And let's fade it in from the left */ -#menuToggle input:checked ~ ul -{ +#menuToggle input:checked ~ ul { transform: none; opacity: 1; } [aria-hidden="true"] { - display: none; + display: none; } -img.zoom{ -transition: transform .2s; +img.zoom { + transition: transform .2s; } + img.zoom:hover { -transform: scale(3.5); + transform: scale(3.5); } .hidden { - display: none; + display: none; } nav .navbar-collapse { - position: fixed; - top: 56px; - background: #343a40; - right: -100%; - width: 100vw; - height: 100vh; - display: block; - transition: right 0.3s ease; + position: fixed; + top: 56px; + background: #343a40; + right: -100%; + width: 100vw; + height: 100vh; + display: block; + transition: right 0.3s ease; } nav .navbar-collapse.show { - right: 0; + right: 0; } .welcome { - font-size: 0.9rem; - font-weight: 500; - color: #f3f3f3; + font-size: 0.9rem; + font-weight: 500; + color: #f3f3f3; } .login { - display: flex; + display: flex; } .login__input { - border: none; - padding: 0.5rem 2rem; - font-size: 1.0rem; - font-family: inherit; - text-align: center; - width: 12rem; - border-radius: 10rem; - margin-right: 1rem; - color: inherit; - border: 1px solid #fff; - transition: all 0.3s; + padding: 0.5rem 2rem; + font-size: 1.0rem; + font-family: inherit; + text-align: center; + width: 12rem; + border-radius: 10rem; + margin-right: 1rem; + color: inherit; + border: 1px solid #fff; + transition: all 0.3s; } .login__input:focus { - outline: none; - border: 1px solid #ccc; + outline: none; + border: 1px solid #ccc; } .login__input::placeholder { - color: #bbb; + color: #bbb; } .login__btn { - border: none; - font-size: 1.4rem; - width: 5rem; - border-radius: 10rem; - margin-right: 1rem; - color: inherit; - cursor: pointer; - transition: all 0.3s; + border: none; + font-size: 1.4rem; + width: 5rem; + border-radius: 10rem; + margin-right: 1rem; + color: inherit; + cursor: pointer; + transition: all 0.3s; } .login__btn:hover, .login__btn:focus, .btn--sort:hover, .btn--sort:focus { - outline: none; - color: #777; + outline: none; + color: #777; } .logout-timer { - padding: 0 0.3rem; - margin-top: 1.9rem; - text-align: right; - font-size: 1.25rem; + padding: 0 0.3rem; + margin-top: 1.9rem; + text-align: right; + font-size: 1.25rem; } .leaflet-container { - width: 100%; - height: 60vh; - } + width: 100%; + height: 60vh; +} .leaflet-div-icon { background: transparent; border: none; } +.country-select-container { + display: flex; + align-items: center; + gap: 10px; /* Space between the dropdown and the flag */ +} + +.flag-container { + display: inline-block; + width: 30px; /* Adjust the size as needed */ + height: 20px; + overflow: hidden; +} + diff --git a/frontend/src/App.js b/frontend/src/App.js index 4dc89bb6..01fa021d 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,8 +1,7 @@ import './App.css'; import React, {useEffect, useRef, useState} from "react"; -import apiClient from "./http-common"; -import upload from './img/upload.png'; import logo from './img/europe-plates.jpg'; +import upload from './img/upload.png'; import $ from 'jquery'; import JSONPretty from 'react-json-pretty'; import {createWorker} from "tesseract.js"; @@ -12,29 +11,22 @@ import Popup from './components/Popup'; import '@popperjs/core'; import LocationMarker from './components/MapView'; import ImageManager from './components/ImageManager'; +import apiClient from './api/http-common'; +import countriesForPlates from './countries/countriesForPlates'; +import countriesForDiplomaticPlates from './countries/countriesForDiplomaticPlates'; +import CountrySelect from "./components/CountrySelect"; +import Timer from "./components/Timer"; function App() { const imageManager = new ImageManager(); const [plates, setPlates] = useState("Choose country"); - const [diplomatic, setDiplomatic] = useState("Choose country"); - - const getRegion = useRef(null); - const getDescription = useRef(null); + const [diplomatic, setDiplomatic] = useState("Choose country"); const image = useRef(null); - const typePlates = useRef(null); - - const getDiplomaticRegion = useRef(null); - const getDiplomaticDescription = useRef(null); - - const [getResult, setGetResult] = useState(null); - - - const regionRef = useRef(null); - const diplomaticRef = useRef(null); + const typePlates = useRef(null); const [selected, setSelected] = useState(""); @@ -44,186 +36,58 @@ function App() { const [imageData, setImageData] = useState(null); - const [seconds, setSeconds] = useState(0); - const [minutes, setMinutes] = useState(2); + const [getResult, setGetResult] = useState(''); const [isShown, setIsShown] = useState(false); - const changeHandler = e => { - setSelected(e.target.value); + const regionRef = useRef(); + + const getRegion = useRef(); + + const getDescription = useRef(); + + const diplomaticRef = useRef(); + + const getDiplomaticRegion = useRef(); + + const getDiplomaticDescription = useRef(); + const handleGetPlatesByRegion = () => { + const plateService = new RegularPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); + plateService.getPlatesByRegion(plates).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); + }; + + const handleGetDiplomaticPlatesByRegion = () => { + const diplomaticPlateService = new DiplomaticPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); + diplomaticPlateService.getPlatesByRegion(diplomatic).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); + }; + + const handleGetPlatesByDescription = () => { + const plateService = new RegularPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); + plateService.getPlatesByDescription(plates).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); }; - const formatResponse = (res) => { - return JSON.stringify(res, null, 2); + const handleGetDiplomaticPlatesByDescription = () => { + const diplomaticPlateService = new DiplomaticPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); + diplomaticPlateService.getPlatesByDescription(diplomatic).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); }; - async function getPlatesByRegion() { - const region = getRegion.current.value; - - const selectValue = regionRef.current.value; - - if (selectValue === 'None') { - alert('Choose any country first'); - return; - } - - if (region === '') { - alert('Choose region first'); - return; - } - - if (region) { - try { - const res = await apiClient.get(`/${plates}/plates/region/${region}`); - - const result = { - information: res.data - }; - - setGetResult(formatResponse(result)); - getRegion.current.value = ''; - setIsShown(true); - } catch (err) { - if (!err?.response) { - alert("No Server Response"); - return; - } - setGetResult(formatResponse(err.response?.data || err)); - getRegion.current.value = ''; - } - } - } - - async function getDiplomaticPlatesByRegion() { - const region = getDiplomaticRegion.current.value; - - const selectValue = diplomaticRef.current.value; - - if (selectValue === 'None') { - alert('Choose any country first'); - return; - } - - if (region === '') { - alert('Choose region first'); - return; - } - - if (region) { - try { - const res = await apiClient.get(`/${diplomatic}/diplomatic/plates/region/${region}`); - - const result = { - information: res.data - }; - - setGetResult(formatResponse(result)); - getDiplomaticRegion.current.value = ''; - setIsShown(true); - } catch (err) { - if (!err?.response) { - alert("No Server Response"); - return; - } - setGetResult(formatResponse(err.response?.data || err)); - getDiplomaticRegion.current.value = ''; - } - } - } - - async function getPlatesByDescription() { - const description = getDescription.current.value; - - const selectValue = regionRef.current.value; - - if (selectValue === 'None') { - alert('Choose any country first'); - return; - } - - if (description === '') { - alert('Choose region first'); - return; - - } - - if (description) { - try { - const res = await apiClient.get(`/${plates}/plates/description/${description}`); - - const result = { - information: res.data - }; - - setGetResult(formatResponse(result)); - getDescription.current.value = ''; - setIsShown(true); - } catch (err) { - if (!err?.response) { - alert("No Server Response"); - return; - } - setGetResult(formatResponse(err.response?.data || err)); - getDescription.current.value = ''; - } - } - } - - async function getDiplomaticPlatesByDescription() { - const description = getDiplomaticDescription.current.value; - - const selectValue = diplomaticRef.current.value; - - if (selectValue === 'None') { - alert('Choose any country first'); - return; - } - - - if (description === '') { - alert('Choose region first'); - return; - } - - if (description) { - try { - const res = await apiClient.get(`/${diplomatic}/diplomatic/plates/description/${description}`); - - const result = { - information: res.data - }; - - setGetResult(formatResponse(result)); - getDiplomaticDescription.current.value = ''; - setIsShown(true); - } catch (err) { - if (!err?.response) { - alert("No Server Response"); - return; - } - setGetResult(formatResponse(err.response?.data || err)); - getDiplomaticDescription.current.value = ''; - } - } - } - - function resetState() { + const clearGetOutputPlates = (plateSetter, regionRef, descriptionRef) => { setFile(''); image.current.src = logo; setGetResult(null); - setPlates(''); - getRegion.current.value = ''; - getDescription.current.value = ''; + plateSetter(''); + regionRef.current.value = ''; + descriptionRef.current.value = ''; typePlates.current.classList.remove('hidden'); setIsShown(false); - } + }; const clearGetOutputPrivatePlates = () => { - resetState(); + clearGetOutputPlates(setPlates, getRegion, getDescription) }; const clearGetOutputDiplomaticPlates = () => { - resetState(); + clearGetOutputPlates(setDiplomatic, getDiplomaticRegion, getDiplomaticDescription) }; const simplePlates = (e) => { @@ -265,6 +129,7 @@ function App() { }, [imageData]); const [showElement, setShowElement] = React.useState(true) + useEffect(() => { setTimeout(function () { setShowElement(false); @@ -274,85 +139,37 @@ function App() { }, []); - function updateTime() { - const shouldReset = minutes === 0 && seconds === 0; - const shouldDecrementMinutes = seconds === 0 && !shouldReset; - - setMinutes(shouldReset ? 5 : shouldDecrementMinutes ? minutes - 1 : minutes); - setSeconds(shouldReset ? 0 : shouldDecrementMinutes ? 59 : seconds - 1); - } - - useEffect(() => { - const timeOut = setTimeout(updateTime, 1000) - - return function cleanUp() { - clearTimeout(timeOut); - } - }); - return (
-
- - this is main image +
+ + this is main image {showElement ?
Please - choose - any type of plates + choose any type of plates
+ setSelected(e.target.value)} data-cy="private_radio_button" onClick={clearGetOutputPrivatePlates} />
- +
@@ -362,16 +179,15 @@ function App() { placeholder="Region" data-cy="region_plates_input"/>
-
@@ -386,41 +202,27 @@ function App() {
+ setSelected(e.target.value)} data-cy="diplomatic_radio_button" onClick={clearGetOutputDiplomaticPlates} />
- - +


@@ -431,7 +233,7 @@ function App() {
@@ -440,7 +242,7 @@ function App() { placeholder="Description" data-cy="get_by_diplomatic_description_input"/>
@@ -454,32 +256,32 @@ function App() { data-cy="clear_button">Clear
-
+ setSelected(e.target.value)} data-cy="upload_photo_radio_button" />

Upload photo with car plate

-

- You will be logged out in time: {minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')} + You will be logged out in

: <>} {isShown && } diff --git a/frontend/src/api/http-common.js b/frontend/src/api/http-common.js new file mode 100644 index 00000000..8f43ea97 --- /dev/null +++ b/frontend/src/api/http-common.js @@ -0,0 +1,35 @@ +import axios from "axios"; + +const apiToken = process.env.REACT_APP_TOKEN; +if (!apiToken) { + console.error("REACT_APP_TOKEN is not defined."); +} + +const apiClient = axios.create({ + baseURL: "/api/v1", + headers: { + "Content-Type": "application/json", + "X-API-KEY": apiToken, + }, + timeout: 5000, +}); +apiClient.interceptors.request.use( + (config) => { + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +apiClient.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + console.error("API Error: ", error); + return Promise.reject(error); + } +); + +export default apiClient; diff --git a/frontend/src/components/CountrySelect.js b/frontend/src/components/CountrySelect.js new file mode 100644 index 00000000..90fb580b --- /dev/null +++ b/frontend/src/components/CountrySelect.js @@ -0,0 +1,18 @@ +import React from 'react'; + +function CountrySelect({countries, value, onChange, id, selectRef, imageId}) { + return ( +
+ +
+ ); +} + +export default CountrySelect; diff --git a/frontend/src/components/ImageManager.js b/frontend/src/components/ImageManager.js index 9f34bf80..fc2cfe9f 100644 --- a/frontend/src/components/ImageManager.js +++ b/frontend/src/components/ImageManager.js @@ -18,7 +18,7 @@ class ImageManager { "ireland": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Revised_format_Republic_of_Ireland_numberplate_%282013-%29.svg/1920px-Revised_format_Republic_of_Ireland_numberplate_%282013-%29.svg.png", "italian": "https://cdn.skoda-storyboard.com/2019/06/Italy-license-plate-english.jpg", "kazakhstan": "https://upload.wikimedia.org/wikipedia/commons/f/fe/License_plate_Kazakhstan_2012.png", - "kosovo": "https://upload.wikimedia.org/wikipedia/en/thumb/a/a9/Kosovo_car_registration_plate_labels.svg/320px-Kosovo_car_registration_plate_labels.svg.png", + "kosovo": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Kosovar_license_plate.svg/640px-Kosovar_license_plate.svg.png", "kyrgyzstan": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Plak_shakhsi-KG.png/800px-Plak_shakhsi-KG.png", "lithuania": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Lithuanian_license_plate.svg/1280px-Lithuanian_license_plate.svg.png", "malaysia": "https://en.m.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#/media/File%3AMalaysia_penang_license_plate_front.JPG", diff --git a/frontend/src/components/Timer.js b/frontend/src/components/Timer.js new file mode 100644 index 00000000..06a7d1bb --- /dev/null +++ b/frontend/src/components/Timer.js @@ -0,0 +1,32 @@ +import React, {useEffect, useState} from "react"; + +const Timer = ({initialMinutes = 5, initialSeconds = 0}) => { + const [minutes, setMinutes] = useState(initialMinutes); + const [seconds, setSeconds] = useState(initialSeconds); + + useEffect(() => { + const updateTime = () => { + if (minutes === 0 && seconds === 0) { + setMinutes(initialMinutes); // Reset to initial values when time is up + setSeconds(0); + } else if (seconds === 0) { + setMinutes(minutes - 1); + setSeconds(59); + } else { + setSeconds(seconds - 1); + } + }; + + const timeoutId = setTimeout(updateTime, 1000); + + return () => clearTimeout(timeoutId); + }, [minutes, seconds, initialMinutes]); + + return ( +
+ Time Remaining: {minutes}:{seconds < 10 ? `0${seconds}` : seconds} +
+ ); +}; + +export default Timer; diff --git a/frontend/src/countries/countriesForDiplomaticPlates.js b/frontend/src/countries/countriesForDiplomaticPlates.js new file mode 100644 index 00000000..92d670ad --- /dev/null +++ b/frontend/src/countries/countriesForDiplomaticPlates.js @@ -0,0 +1,21 @@ +const countriesForDiplomaticPlates = [ + { value: 'austria', flag: '🇦🇹', label: 'Austria' }, + { value: 'croatia', flag: '🇭🇷', label: 'Croatia' }, + { value: 'estonia', flag: '🇪🇪', label: 'Estonia' }, + { value: 'france', flag: '🇫🇷', label: 'France' }, + { value: 'germany', flag: '🇩🇪', label: 'Germany' }, + { value: 'italian', flag: '🇮🇹', label: 'Italy' }, + { value: 'kyrgyzstan', flag: '🇰🇬', label: 'Kyrgyzstan' }, + { value: 'lithuania', flag: '🇱🇹', label: 'Lithuania' }, + { value: 'malaysia', flag: '🇲🇾', label: 'Malaysia' }, + { value: 'montenegro', flag: '🇲🇪', label: 'Montenegro' }, + { value: 'norway', flag: '🇳🇴', label: 'Norway' }, + { value: 'poland', flag: '🇵🇱', label: 'Poland' }, + { value: 'romania', flag: '🇷🇴', label: 'Romania' }, + { value: 'portugal', flag: '🇵🇹', label: 'Portugal' }, + { value: 'russia', flag: '🇷🇺', label: 'Russia' }, + { value: 'sweden', flag: '🇸🇪', label: 'Sweden' }, + { value: 'switzerland', flag: '🇨🇭', label: 'Switzerland' }, +]; + +export default countriesForDiplomaticPlates; diff --git a/frontend/src/countries/countriesForPlates.js b/frontend/src/countries/countriesForPlates.js new file mode 100644 index 00000000..7776a16e --- /dev/null +++ b/frontend/src/countries/countriesForPlates.js @@ -0,0 +1,40 @@ +const countriesForPlates = [ + { value: 'armenia', flag: '🇦🇲', label: 'Armenia' }, + { value: 'austria', flag: '🇦🇹', label: 'Austria' }, + { value: 'azerbaijan', flag: '🇦🇿', label: 'Azerbaijan' }, + { value: 'belarus', flag: '🇧🇾', label: 'Belarus' }, + { value: 'british', flag: '🇻🇬', label: 'Great Britain' }, + { value: 'bulgaria', flag: '🇧🇬', label: 'Bulgaria' }, + { value: 'croatia', flag: '🇭🇷', label: 'Croatia' }, + { value: 'czech', flag: '🇨🇿', label: 'Czech Republic' }, + { value: 'estonia', flag: '🇪🇪', label: 'Estonia' }, + { value: 'france', flag: '🇫🇷', label: 'France' }, + { value: 'germany', flag: '🇩🇪', label: 'Germany' }, + { value: 'greece', flag: '🇬🇷', label: 'Greece' }, + { value: 'hungary', flag: '🇭🇺', label: 'Hungary' }, + { value: 'ireland', flag: '🇮🇪', label: 'Ireland' }, + { value: 'italian', flag: '🇮🇹', label: 'Italy' }, + { value: 'kazakhstan', flag: '🇰🇿', label: 'Kazakhstan' }, + { value: 'kosovo', flag: '🇽🇰', label: 'Kosovo' }, + { value: 'kyrgyzstan', flag: '🇰🇬', label: 'Kyrgyzstan' }, + { value: 'lithuania', flag: '🇱🇹', label: 'Lithuania' }, + { value: 'malaysia', flag: '🇲🇾', label: 'Malaysia' }, + { value: 'moldova', flag: '🇲🇩', label: 'Moldova' }, + { value: 'montenegro', flag: '🇲🇪', label: 'Montenegro' }, + { value: 'norway', flag: '🇳🇴', label: 'Norway' }, + { value: 'macedonia', flag: '🇲🇰', label: 'North Macedonia' }, + { value: 'poland', flag: '🇵🇱', label: 'Poland' }, + { value: 'romania', flag: '🇷🇴', label: 'Romania' }, + { value: 'russia', flag: '🇷🇺', label: 'Russia' }, + { value: 'serbia', flag: '🇷🇸', label: 'Serbia' }, + { value: 'slovakia', flag: '🇸🇰', label: 'Slovakia' }, + { value: 'slovenia', flag: '🇸🇮', label: 'Slovenia' }, + { value: 'sweden', flag: '🇸🇪', label: 'Sweden' }, + { value: 'switzerland', flag: '🇨🇭', label: 'Switzerland' }, + { value: 'turkey', flag: '🇹🇷', label: 'Turkey' }, + { value: 'ukraine', flag: '🇺🇦', label: 'Ukraine' }, + { value: 'uzbekistan', flag: '🇺🇿', label: 'Uzbekistan' }, +]; + +export default countriesForPlates; + diff --git a/frontend/src/http-common.js b/frontend/src/http-common.js deleted file mode 100644 index 1aa1f3e0..00000000 --- a/frontend/src/http-common.js +++ /dev/null @@ -1,9 +0,0 @@ -import axios from "axios"; - -export default axios.create({ - baseURL: "/api/v1", - headers: { - "Content-type": "application/json", - "X-API-KEY": process.env.REACT_APP_TOKEN - } -}); \ No newline at end of file diff --git a/frontend/src/service/DiplomaticPlateService.js b/frontend/src/service/DiplomaticPlateService.js new file mode 100644 index 00000000..db43828d --- /dev/null +++ b/frontend/src/service/DiplomaticPlateService.js @@ -0,0 +1,9 @@ +class DiplomaticPlateService extends PlateService { + async getPlatesByRegion(diplomatic) { + await this.getPlates(`/${diplomatic}/diplomatic/plates/region/${this.getRegionRef.current.value}`); + } + + async getPlatesByDescription(diplomatic) { + await this.getPlates(`/${diplomatic}/diplomatic/plates/description/${this.getRegionRef.current.value}`); + } +} \ No newline at end of file diff --git a/frontend/src/service/PlateService.js b/frontend/src/service/PlateService.js new file mode 100644 index 00000000..9f79d35d --- /dev/null +++ b/frontend/src/service/PlateService.js @@ -0,0 +1,44 @@ +class PlateService { + constructor(apiClient, getRegionRef, setGetResult, setIsShown, regionRef) { + this.apiClient = apiClient; + this.getRegionRef = getRegionRef; + this.setGetResult = setGetResult; + this.setIsShown = setIsShown; + this.regionRef = regionRef; + } + + // Template method + async getPlates(endpoint) { + const regionValue = this.getRegionRef.current.value; + const selectValue = this.regionRef.current.value; + + if (selectValue === 'None') { + alert('Choose any country first'); + return; + } + + if (regionValue === '') { + alert('Choose region first'); + return; + } + + try { + const res = await this.apiClient.get(endpoint); + const result = { information: res.data }; + this.setGetResult(this.formatResponse(result)); + this.getRegionRef.current.value = ''; + this.setIsShown(true); + } catch (err) { + if (!err?.response) { + alert("No Server Response"); + return; + } + this.setGetResult(this.formatResponse(err.response?.data || err)); + this.getRegionRef.current.value = ''; + } + } + + formatResponse(res) { + return JSON.stringify(res, null, 2); + } +} \ No newline at end of file diff --git a/frontend/src/service/RegularPlateService.js b/frontend/src/service/RegularPlateService.js new file mode 100644 index 00000000..a0e6fd00 --- /dev/null +++ b/frontend/src/service/RegularPlateService.js @@ -0,0 +1,9 @@ +class RegularPlateService extends PlateService { + async getPlatesByRegion(plates) { + await this.getPlates(`/${plates}/plates/region/${this.getRegionRef.current.value}`); + } + + async getPlatesByDescription(plates) { + await this.getPlates(`/${plates}/plates/description/${this.getRegionRef.current.value}`); + } +} \ No newline at end of file From 84a41186e04ce91ed2170a37069ddbc2ce5beec5 Mon Sep 17 00:00:00 2001 From: asm Date: Sat, 17 Aug 2024 18:19:26 +0200 Subject: [PATCH 2/2] DV-000301: refactoring main FE class. --- frontend/src/App.js | 65 +++++++------------ frontend/src/api/http-common.js | 3 + frontend/src/components/CountrySelect.js | 2 +- .../src/service/DiplomaticPlateService.js | 4 +- frontend/src/service/PlateService.js | 2 +- frontend/src/service/RegularPlateService.js | 4 +- 6 files changed, 36 insertions(+), 44 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index 01fa021d..3eefe38c 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -4,7 +4,6 @@ import logo from './img/europe-plates.jpg'; import upload from './img/upload.png'; import $ from 'jquery'; import JSONPretty from 'react-json-pretty'; -import {createWorker} from "tesseract.js"; import 'bootstrap/dist/css/bootstrap.css'; import Header from './components/Header'; import Popup from './components/Popup'; @@ -16,6 +15,8 @@ import countriesForPlates from './countries/countriesForPlates'; import countriesForDiplomaticPlates from './countries/countriesForDiplomaticPlates'; import CountrySelect from "./components/CountrySelect"; import Timer from "./components/Timer"; +import {RegularPlateService} from './service/RegularPlateService'; +import {DiplomaticPlateService} from './service/DiplomaticPlateService'; function App() { const imageManager = new ImageManager(); @@ -32,43 +33,47 @@ function App() { const [file, setFile] = useState(""); - const [ocr, setOcr] = useState(""); - - const [imageData, setImageData] = useState(null); - const [getResult, setGetResult] = useState(''); const [isShown, setIsShown] = useState(false); const regionRef = useRef(); + const diplomaticRef = useRef(); + const getRegion = useRef(); const getDescription = useRef(); - const diplomaticRef = useRef(); - const getDiplomaticRegion = useRef(); const getDiplomaticDescription = useRef(); - const handleGetPlatesByRegion = () => { - const plateService = new RegularPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); - plateService.getPlatesByRegion(plates).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); - }; - const handleGetDiplomaticPlatesByRegion = () => { - const diplomaticPlateService = new DiplomaticPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); - diplomaticPlateService.getPlatesByRegion(diplomatic).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); + const handleGetPlatesByRegion = () => { + const plateService = new RegularPlateService(apiClient, getRegion, setGetResult, setIsShown, regionRef); + plateService.getPlatesByRegion(plates) + .then(result => console.log('Success:', result)) + .catch(error => console.error('Error:', error)); }; const handleGetPlatesByDescription = () => { - const plateService = new RegularPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); - plateService.getPlatesByDescription(plates).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); + const plateService = new RegularPlateService(apiClient, getDescription, setGetResult, setIsShown, regionRef); + plateService.getPlatesByDescription(plates) + .then(result => console.log('Success:', result)) + .catch(error => console.error('Error:', error)); }; + const handleGetDiplomaticPlatesByRegion = () => { + const diplomaticPlateService = new DiplomaticPlateService(apiClient, getDiplomaticRegion, setGetResult, setIsShown, diplomaticRef); + diplomaticPlateService.getPlatesByRegion(diplomatic) + .then(result => console.log('Success:', result)) + .catch(error => console.error('Error:', error)); + }; const handleGetDiplomaticPlatesByDescription = () => { - const diplomaticPlateService = new DiplomaticPlateService(apiClient, getRegionRef, setGetResult, setIsShown, regionRef); - diplomaticPlateService.getPlatesByDescription(diplomatic).then(result => console.log('Success:', result)).catch(error => console.error('Error:', error)); + const diplomaticPlateService = new DiplomaticPlateService(apiClient, getDiplomaticDescription, setGetResult, setIsShown, diplomaticRef); + diplomaticPlateService.getPlatesByDescription(diplomatic) + .then(result => console.log('Success:', result)) + .catch(error => console.error('Error:', error)); }; const clearGetOutputPlates = (plateSetter, regionRef, descriptionRef) => { @@ -102,32 +107,14 @@ function App() { typePlates.current.classList.add('hidden'); }; - $(document).on("change", "#countries_list", function (e) { + $(document).on("change", "#countries_list", () => { $('#countries_diplomatic_list').val('None'); }); - $(document).on("change", "#countries_diplomatic_list", function (e) { + $(document).on("change", "#countries_diplomatic_list", () => { $('#countries_list').val('None'); }); - const convertImageToText = async () => { - if (!imageData) return; - const worker = await createWorker(); - await worker.load(); - await worker.loadLanguage('eng'); - await worker.initialize('eng'); - const { - data: {text}, - } = await worker.recognize(imageData); - setOcr(text); - console.log(`This is result: ${text}`); - await worker.terminate(); - }; - - useEffect(() => { - convertImageToText().then() - }, [imageData]); - const [showElement, setShowElement] = React.useState(true) useEffect(() => { @@ -168,7 +155,6 @@ function App() { onChange={simplePlates} id="countries_list" selectRef={regionRef} - imageId="countries_image" />
@@ -221,7 +207,6 @@ function App() { onChange={diplomaticPlates} id="countries_diplomatic_list" selectRef={diplomaticRef} - imageId="countries_image" />


diff --git a/frontend/src/api/http-common.js b/frontend/src/api/http-common.js index 8f43ea97..8c3010f0 100644 --- a/frontend/src/api/http-common.js +++ b/frontend/src/api/http-common.js @@ -13,6 +13,8 @@ const apiClient = axios.create({ }, timeout: 5000, }); + + apiClient.interceptors.request.use( (config) => { return config; @@ -24,6 +26,7 @@ apiClient.interceptors.request.use( apiClient.interceptors.response.use( (response) => { + // Handle successful responses return response; }, (error) => { diff --git a/frontend/src/components/CountrySelect.js b/frontend/src/components/CountrySelect.js index 90fb580b..79e7bc1d 100644 --- a/frontend/src/components/CountrySelect.js +++ b/frontend/src/components/CountrySelect.js @@ -1,6 +1,6 @@ import React from 'react'; -function CountrySelect({countries, value, onChange, id, selectRef, imageId}) { +function CountrySelect({countries, value, onChange, id, selectRef}) { return (