diff --git a/deploy/ftp.js b/deploy/ftp.js
index 8c74e09..b1dffd8 100644
--- a/deploy/ftp.js
+++ b/deploy/ftp.js
@@ -1,5 +1,6 @@
const FtpDeploy = require("ftp-deploy");
-const ftpDeploy = new FtpDeploy();
+
+const ftp = new FtpDeploy();
const config = {
user: process.env.FTP_USER,
@@ -8,9 +9,7 @@ const config = {
port: process.env.FTP_PORT,
localRoot: __dirname + "/../frontend",
remoteRoot: "/public_html/car/",
- // include: ["*", "**/*"], // this would upload everything except dot files
include: ["build/**"],
- // e.g. exclude sourcemaps, and ALL files in node_modules (including dot files)
exclude: ["build/**/*.map", "node_modules/**", "node_modules/**/.*", ".git/**"],
// delete ALL existing files at destination before uploading, if true
deleteRemote: false,
@@ -18,9 +17,9 @@ const config = {
forcePasv: true
};
-ftpDeploy
+ftp
.deploy(config)
- .then(res => {
+ .then(() => {
console.log("Deployment to FTP finished");
return;
})
diff --git a/frontend/package.json b/frontend/package.json
index 5b958c3..b5e58c8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -23,7 +23,7 @@
},
"dependencies": {
"@fortawesome/fontawesome-free": "5.13.0",
- "@reduxjs/toolkit": "1.3.6",
+ "@reduxjs/toolkit": "^1.3.6",
"core-js": "3.6.5",
"react": "16.13.1",
"react-dom": "16.13.1",
diff --git a/frontend/src/actions/CaptureActions.js b/frontend/src/actions/CaptureActions.js
index 6875e0c..c2434cc 100644
--- a/frontend/src/actions/CaptureActions.js
+++ b/frontend/src/actions/CaptureActions.js
@@ -1,8 +1,14 @@
+import {
+ alprFetchSuccess, alprFetchStart,
+} from '@slice/RecognitionSlice';
+
const API_BASE_PATH = process.env.NODE_ENV === 'production'
? process.env.API_BASE_PATH
: 'http://localhost:4000';
-export const getPlateRecognized = async (image) => {
+export const getPlateRecognized = (image) => async (dispatch) => {
+ console.log(image);
+ dispatch(alprFetchStart());
const body = new FormData();
body.append('upload', image);
try {
@@ -12,6 +18,7 @@ export const getPlateRecognized = async (image) => {
});
console.log(response);
const data = await response.json();
+ dispatch(alprFetchSuccess(data));
console.log(data);
} catch (e) {
console.log(e);
diff --git a/frontend/src/components/alpr/RecognitionResults.jsx b/frontend/src/components/alpr/RecognitionResults.jsx
new file mode 100644
index 0000000..e58c6c5
--- /dev/null
+++ b/frontend/src/components/alpr/RecognitionResults.jsx
@@ -0,0 +1,37 @@
+import React, { useContext } from 'react';
+import RootContext from '@context/RootContext';
+import Button from '@components/common/Button';
+
+const RecognitionResults = () => {
+ const { state: { alpr: { results } } } = useContext(RootContext);
+
+ const getPlate = () => {
+ if (results.length === 0) {
+ return (
No plate detected
);
+ }
+ console.log(results);
+ const { score, plate } = results[0];
+ return (
+ <>
+
+
{plate.toUpperCase()}
+
+ Confidence
+ {' '}
+ {score}
+
+
+
+
+
+ >
+ );
+ };
+ return (
+
+ {getPlate()}
+
+ );
+};
+
+export default RecognitionResults;
diff --git a/frontend/src/components/camera/CameraContainer.jsx b/frontend/src/components/camera/CameraContainer.jsx
index acd1f5b..318e267 100644
--- a/frontend/src/components/camera/CameraContainer.jsx
+++ b/frontend/src/components/camera/CameraContainer.jsx
@@ -1,10 +1,12 @@
import React, {
- useState, useEffect, useRef, useCallback,
+ useState, useEffect, useRef, useCallback, useContext,
} from 'react';
import Webcam from 'react-webcam';
import FacingMode from '@constant/FacingMode';
-import Loader from '@components/Loader';
+import Loader from '@components/common/Loader';
import '@style/RootContainer.scss';
+import RootContext from '@context/RootContext';
+import { resetResults } from '@slice/RecognitionSlice';
import CameraOptions from './CameraOptions';
import Capture from './Capture';
@@ -17,6 +19,7 @@ const CAMERA_OPTIONS = {
};
const CameraContainer = () => {
+ const { dispatch } = useContext(RootContext);
const ref = useRef(null);
const [imgSrc, setImgSrc] = useState(null);
const [captureError, setCaptureError] = useState(null);
@@ -71,7 +74,10 @@ const CameraContainer = () => {
}
}, [ref, setImgSrc]);
- const onBackClick = () => setImgSrc(null);
+ const onBackClick = () => {
+ setImgSrc(null);
+ dispatch(resetResults());
+ };
const cameraView = () => (
<>
diff --git a/frontend/src/components/camera/CameraOptions.jsx b/frontend/src/components/camera/CameraOptions.jsx
index 56a1dac..7c46e69 100644
--- a/frontend/src/components/camera/CameraOptions.jsx
+++ b/frontend/src/components/camera/CameraOptions.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import Button from '@components/Button';
+import Button from '@components/common/Button';
const CameraOptions = ({ capture, changeCameraView }) => (
diff --git a/frontend/src/components/camera/Capture.jsx b/frontend/src/components/camera/Capture.jsx
index 9cfbf1a..0758f2e 100644
--- a/frontend/src/components/camera/Capture.jsx
+++ b/frontend/src/components/camera/Capture.jsx
@@ -1,20 +1,28 @@
-import React from 'react';
-import Loader from '@components/Loader';
+import React, { useContext, useState } from 'react';
+import Loader from '@components/common/Loader';
import { getPlateRecognized } from '@actions/CaptureActions';
-import Button from '@components/Button';
+import Button from '@components/common/Button';
+import RootContext from '@context/RootContext';
+import RecognitionResults from '@components/alpr/RecognitionResults';
const UploadCapture = ({ imgSrc, onBackClick }) => {
+ const [hasFetched, setHasFetched] = useState(false);
+ const { state: { alpr: { isFetchingALPR } }, dispatch } = useContext(RootContext);
const onUploadClick = () => {
- getPlateRecognized(imgSrc);
+ getPlateRecognized(imgSrc)(dispatch);
+ setHasFetched(true);
};
return (
-
-

-
+ {isFetchingALPR ?
: (
+
+

+
+ )}
+ {hasFetched && !isFetchingALPR && (
)}
-
+ {!hasFetched && }
);
diff --git a/frontend/src/components/Button.jsx b/frontend/src/components/common/Button.jsx
similarity index 100%
rename from frontend/src/components/Button.jsx
rename to frontend/src/components/common/Button.jsx
diff --git a/frontend/src/components/Loader.jsx b/frontend/src/components/common/Loader.jsx
similarity index 79%
rename from frontend/src/components/Loader.jsx
rename to frontend/src/components/common/Loader.jsx
index c6e9d3d..db9b065 100644
--- a/frontend/src/components/Loader.jsx
+++ b/frontend/src/components/common/Loader.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import '@style/spinner.scss';
+import './Loader.scss';
const Loader = () => (
Loading...
);
diff --git a/frontend/src/style/spinner.scss b/frontend/src/components/common/Loader.scss
similarity index 100%
rename from frontend/src/style/spinner.scss
rename to frontend/src/components/common/Loader.scss
diff --git a/frontend/src/container/App.jsx b/frontend/src/container/App.jsx
index 37d2c1d..5df02e9 100644
--- a/frontend/src/container/App.jsx
+++ b/frontend/src/container/App.jsx
@@ -1,21 +1,13 @@
import React, { useReducer, useContext } from 'react';
-import { usePersistedContext, usePersistedReducer } from '@hook/usePersist';
import RootContainer from '@container/RootContainer';
import RootContext from '@context/RootContext';
import RootReducer from '@slice/RootSlice';
-import Properties from '@constant/Properties';
const App = () => {
- const globalStore = usePersistedContext(
- useContext(RootContext),
- Properties.STORE_KEY,
- );
+ const globalStore = useContext(RootContext);
- const [state, dispatch] = usePersistedReducer(
- useReducer(RootReducer, globalStore),
- Properties.STORE_KEY,
- );
+ const [state, dispatch] = useReducer(RootReducer, globalStore);
return (
diff --git a/frontend/src/container/RootContainer.jsx b/frontend/src/container/RootContainer.jsx
index 7a2c2ad..ee6a8f6 100644
--- a/frontend/src/container/RootContainer.jsx
+++ b/frontend/src/container/RootContainer.jsx
@@ -2,14 +2,11 @@ import React from 'react';
import CameraContainer from '@components/camera/CameraContainer';
import '@style/RootContainer.scss';
-const RootContainer = () => {
- console.log('Hello wlrld');
- return (
-
- );
-};
+const RootContainer = () => (
+
+);
export default RootContainer;
diff --git a/frontend/src/context/RootContext.js b/frontend/src/context/RootContext.js
index 9632714..2d744d4 100644
--- a/frontend/src/context/RootContext.js
+++ b/frontend/src/context/RootContext.js
@@ -1,3 +1,6 @@
import { createContext } from 'react';
+import { initialState as alpr } from '@slice/RecognitionSlice';
-export default createContext({}); // include initialStates here
+export default createContext({
+ alpr,
+});
diff --git a/frontend/src/hook/useCanvas.js b/frontend/src/hook/useCanvas.js
deleted file mode 100644
index 9e36a31..0000000
--- a/frontend/src/hook/useCanvas.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React, { useState, useEffect, useRef } from 'react';
-
-// Path2D for a Heart SVG
-const heartSVG = 'M0 200 v-200 h200 a100,100 90 0,1 0,200 a100,100 90 0,1 -200,0 z';
-const SVG_PATH = new Path2D(heartSVG);
-
-// Scaling Constants for Canvas
-const SCALE = 0.1;
-const OFFSET = 80;
-export const canvasWidth = window.innerWidth * 0.7;
-export const canvasHeight = window.innerHeight * 0.7;
-
-export function draw(ctx, location) {
- console.log('attempting to draw');
- ctx.fillStyle = 'red';
- ctx.shadowColor = 'blue';
- ctx.shadowBlur = 15;
- ctx.save();
- ctx.scale(SCALE, SCALE);
- ctx.translate(location.x / SCALE - OFFSET, location.y / SCALE - OFFSET);
- ctx.rotate(225 * Math.PI / 180);
- ctx.fill(SVG_PATH);
- // .restore(): Canvas 2D API restores the most recently saved canvas state
- ctx.restore();
-}
-
-export function useCanvas() {
- const canvasRef = useRef(null);
- const [coordinates, setCoordinates] = useState([]);
-
- useEffect(() => {
- const canvasObj = canvasRef.current;
- const ctx = canvasObj.getContext('2d');
- // clear the canvas area before rendering the coordinates held in state
- ctx.clearRect(0, 0, canvasObj.parentNode.clientWidth, canvasObj.parentNode.clientHeight);
-
- // draw all coordinates held in state
- coordinates.forEach((coordinate) => { draw(ctx, coordinate); });
- });
-
- return [coordinates, setCoordinates, canvasRef, canvasWidth, canvasHeight];
-}
diff --git a/frontend/src/hook/useInterval.js b/frontend/src/hook/useInterval.js
deleted file mode 100644
index 389391f..0000000
--- a/frontend/src/hook/useInterval.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useEffect, useRef } from 'react';
-
-// https://overreacted.io/making-setinterval-declarative-with-react-hooks/
-const useInterval = (callback, delay) => {
- const savedCallback = useRef();
-
- // Remember the latest callback.
- useEffect(() => {
- savedCallback.current = callback;
- }, [callback]);
-
- // Set up the interval.
- useEffect(() => {
- const tick = () => savedCallback.current();
- if (delay !== null) {
- const id = setInterval(tick, delay);
- return () => clearInterval(id);
- }
- return () => {};
- }, [delay]);
-};
-
-export default useInterval;
diff --git a/frontend/src/slice/RecognitionSlice.js b/frontend/src/slice/RecognitionSlice.js
new file mode 100644
index 0000000..cc15e40
--- /dev/null
+++ b/frontend/src/slice/RecognitionSlice.js
@@ -0,0 +1,32 @@
+/* eslint-disable no-param-reassign */
+import { createSlice } from '@reduxjs/toolkit';
+
+export const initialState = {
+ isFetchingALPR: false,
+ results: [],
+};
+
+const recognitionSlice = createSlice({
+ name: 'alpr',
+ initialState,
+ reducers: {
+ alprFetchStart(state) {
+ state.isFetchingALPR = true;
+ },
+ alprFetchSuccess(state, { payload }) {
+ state.isFetchingALPR = false;
+ state.results = payload.results;
+ },
+ resetResults(state) {
+ state.results = [];
+ },
+ },
+});
+
+export const {
+ alprFetchStart,
+ alprFetchSuccess,
+ resetResults,
+} = recognitionSlice.actions;
+
+export default recognitionSlice.reducer;
diff --git a/frontend/src/slice/RootSlice.js b/frontend/src/slice/RootSlice.js
index 11708e4..2fb139f 100644
--- a/frontend/src/slice/RootSlice.js
+++ b/frontend/src/slice/RootSlice.js
@@ -1,3 +1,6 @@
import { combineReducers } from '@reduxjs/toolkit';
+import alpr from '@slice/RecognitionSlice';
-export default combineReducers({}); // include slices here
+export default combineReducers({
+ alpr,
+});
diff --git a/frontend/src/style/RootContainer.scss b/frontend/src/style/RootContainer.scss
index 11148f3..3cd1d35 100644
--- a/frontend/src/style/RootContainer.scss
+++ b/frontend/src/style/RootContainer.scss
@@ -1,6 +1,6 @@
-@import 'camphor.scss';
-@import 'palette.scss';
-@import 'constants.scss';
+@import './common/font/camphor.scss';
+@import './common/palette.scss';
+@import './common/constants.scss';
body {
margin: 0;
diff --git a/frontend/src/style/constants.scss b/frontend/src/style/common/constants.scss
similarity index 100%
rename from frontend/src/style/constants.scss
rename to frontend/src/style/common/constants.scss
diff --git a/frontend/src/style/camphor.scss b/frontend/src/style/common/font/camphor.scss
similarity index 100%
rename from frontend/src/style/camphor.scss
rename to frontend/src/style/common/font/camphor.scss
diff --git a/frontend/src/style/palette.scss b/frontend/src/style/common/palette.scss
similarity index 100%
rename from frontend/src/style/palette.scss
rename to frontend/src/style/common/palette.scss