diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0635599b..6116fcee 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,8 +4,12 @@ import Footer from '@/components/Footer' import AppRoutes from '@/routes' import { BrowserRouter } from 'react-router-dom' import LeftDrawer from '@/components/LeftDrawer' -import { Divider } from '@mui/material' import { Stack } from '@mui/system' +import { useDispatch } from 'react-redux' +import { fetchOMRRData } from '@/features/omrr/omrr-slice' +import { useEffect } from 'react' +import apiService from '@/service/api-service' +import { AxiosResponse } from '~/axios' const styles = { container: { @@ -27,6 +31,11 @@ const styles = { } export default function App() { + const dispatch = useDispatch() + useEffect(() => { + //@ts-expect-error + dispatch(fetchOMRRData()) + }, [dispatch]) return (
diff --git a/frontend/src/app/store.ts b/frontend/src/app/store.ts index 331578e9..092da196 100644 --- a/frontend/src/app/store.ts +++ b/frontend/src/app/store.ts @@ -1,7 +1,8 @@ import { configureStore } from '@reduxjs/toolkit' import counterReducer from '@/features/counter/counter-slice' +import { omrrSlice } from '@/features/omrr/omrr-slice' export const store = configureStore({ - reducer: { counter: counterReducer }, + reducer: { counter: counterReducer, omrr: omrrSlice.reducer}, }) // Infer the `RootState` and `AppDispatch` types from the store itself diff --git a/frontend/src/components/DataTable.tsx b/frontend/src/components/DataTable.tsx index 9f01ad49..a815eb37 100644 --- a/frontend/src/components/DataTable.tsx +++ b/frontend/src/components/DataTable.tsx @@ -1,4 +1,5 @@ -import apiService from '@/service/api-service' +import { RootState } from '@/app/store' +import OmrrData from '@/interfaces/omrr' import Button from '@mui/material/Button' import Dialog from '@mui/material/Dialog' import DialogActions from '@mui/material/DialogActions' @@ -9,9 +10,8 @@ import TableBody from '@mui/material/TableBody' import TableCell from '@mui/material/TableCell' import TableRow from '@mui/material/TableRow' import { DataGrid, GridColDef, GridToolbar } from '@mui/x-data-grid' -import { useEffect, useState } from 'react' -import { AxiosResponse } from '~/axios' -import TextField from '@mui/material/TextField' +import { useState } from 'react' +import { useSelector } from 'react-redux' const columns: GridColDef[] = [ { field: 'Authorization Number', @@ -27,6 +27,13 @@ const columns: GridColDef[] = [ filterable: true, flex: 1, }, + { + field: 'Operation Type', + headerName: 'Operation Type', + sortable: true, + filterable: true, + flex: 1, + }, { field: 'Regulated Party', headerName: 'Regulated Party', @@ -78,23 +85,12 @@ const columns: GridColDef[] = [ filterable: true, flex: 1, }, - ] export default function DataTable() { - const [data, setData] = useState([]); + const data: OmrrData[] = useSelector((state: RootState) => state.omrr.value) + const status: string = useSelector((state: RootState) => state.omrr.status) - useEffect(() => { - apiService - .getAxiosInstance() - .get('/omrr') - .then((response: AxiosResponse) => { - setData(response?.data) - }) - .catch((error) => { - console.error(error) - }) - }, []) const [selectedRow, setSelectedRow] = useState(null) const handleClose = () => { diff --git a/frontend/src/components/MapView.jsx b/frontend/src/components/MapView.jsx index b0bb2305..95e361ae 100644 --- a/frontend/src/components/MapView.jsx +++ b/frontend/src/components/MapView.jsx @@ -1,50 +1,21 @@ -import 'leaflet/dist/leaflet.css' // Import Leaflet CSS +import Table from '@mui/material/Table' +import TableCell from '@mui/material/TableCell' +import TableRow from '@mui/material/TableRow' import L from 'leaflet' +import 'leaflet/dist/leaflet.css' // Import Leaflet CSS import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet' import MarkerClusterGroup from 'react-leaflet-cluster' -import { useEffect, useState } from 'react' -import apiService from '@/service/api-service' +import { useSelector } from 'react-redux' import pin from '../assets/marker-icon-2x-red.png' import shadow from '../assets/marker-shadow.png' -import Table from '@mui/material/Table' -import TableCell from '@mui/material/TableCell' -import TableRow from '@mui/material/TableRow' - /** * Renders a map with a marker at the supplied location * */ const LeafletMapWithPoint = () => { - const [data, setData] = useState([]) - const [dataFetched, setDataFetched] = useState(false) + const mapPopupValue = useSelector((state) => state.omrr.mapPopupValue) + const status = useSelector((state) => state.omrr.status) - useEffect(() => { - apiService - .getAxiosInstance() - .get('/omrr') - .then((response) => { - // iterate over the response data and set the state key is lat and long and details is rest of the data - const points = response?.data - ?.filter((item) => item.Latitude && item.Longitude) - ?.map((item) => { - return { - position: [item?.Latitude, item?.Longitude], - details: { - 'Authorization Number': item['Authorization Number'], - 'Authorization Type': item['Authorization Type'], - 'Authorization Status': item['Authorization Status'], - 'Regulated Party': item['Regulated Party'], - 'Facility Location': item['Facility Location'], - }, - } - }) - setData(points) - setDataFetched(true) - }) - .catch((error) => { - console.error(error) - }) - }, []) // Set the position of the marker for center of BC const position = [53.7267, -127.6476] @@ -65,7 +36,7 @@ const LeafletMapWithPoint = () => { id="map" center={position} zoom={6} - style={{ height: '60em', width: '100%', marginLeft: '4em' }} + style={{ height: '65em', width: '100%', marginLeft: '4em' }} className="map-container" > { url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> - {dataFetched && - data.map((item, index) => ( + {status === 'succeeded' && + mapPopupValue.map((item, index) => ( diff --git a/frontend/src/features/omrr/omrr-slice.ts b/frontend/src/features/omrr/omrr-slice.ts new file mode 100644 index 00000000..2ad09bc7 --- /dev/null +++ b/frontend/src/features/omrr/omrr-slice.ts @@ -0,0 +1,106 @@ +import OmrrData from '@/interfaces/omrr' +import { + createAsyncThunk, + PayloadAction, + ActionReducerMapBuilder, +} from '@reduxjs/toolkit' +import { createSlice } from '@reduxjs/toolkit' +import { RootState } from '@/app/store' +import apiService from '@/service/api-service' + +export interface OmrrSliceState { + value: OmrrData[] + status: 'idle' | 'loading' | 'failed' | 'succeeded' + error: string | null | undefined | object + mapValue: OmrrData[] + mapPopupValue: any[] +} +export const fetchOMRRData = createAsyncThunk( + 'data/fetchOMRRRecords', + async () => { + const result = await apiService.getAxiosInstance().get('/omrr') + + return result.data + }, +) + +export const initialState: OmrrSliceState = { + // The data array + value: [], + mapValue: [], + mapPopupValue: [], + // The status of the API call + status: 'idle', + // The error message if any + error: null, +} + +export const omrrSlice = createSlice({ + name: 'omrr', + initialState, + reducers: { + setOmrrData: (state, action: PayloadAction) => { + state.value = action.payload + }, + }, + extraReducers: (builder: ActionReducerMapBuilder) => { + // Handle the pending action + builder.addCase(fetchOMRRData.pending, (state, action) => { + // Set the status to loading + state.status = 'loading' + }) + // Handle the fulfilled action + builder.addCase(fetchOMRRData.fulfilled, (state, action) => { + console.log('received omrr data') + // Set the status to succeeded + state.status = 'succeeded' + // Store the data in the state + + let omrrData = []; + for(const item of action.payload){ + const individualData = { + ...item + } + if(individualData['Effective/Issue Date']){ + individualData['Effective/Issue Date'] = new Date(item['Effective/Issue Date']).toLocaleDateString(); + }else{ + individualData['Effective/Issue Date'] = undefined; + } + if(item['Last Amendment Date']){ + individualData['Last Amendment Date'] = new Date(item['Last Amendment Date']).toLocaleDateString(); + }else{ + individualData['Last Amendment Date'] = undefined; + } + + omrrData.push(individualData); + } + state.value = omrrData + state.mapValue = state.value?.filter( + (item: OmrrData) => item.Latitude && item.Longitude, + ) + state.mapPopupValue = state.mapValue?.map((item: OmrrData) => { + return { + position: [item?.Latitude, item?.Longitude], + details: { + 'Authorization Number': item['Authorization Number'], + 'Authorization Type': item['Authorization Type'], + 'Operation Type': item['Operation Type'], + 'Authorization Status': item['Authorization Status'], + 'Regulated Party': item['Regulated Party'], + 'Facility Location': item['Facility Location'], + }, + } + }) + }) + // Handle the rejected action + builder.addCase(fetchOMRRData.rejected, (state, action) => { + // Set the status to failed + state.status = 'failed' + // Store the error message in the state + state.error = action.error.message + }) + }, +}) +export const omrrData = (state: RootState) => state.omrr.value +export const { setOmrrData } = omrrSlice.actions +export default omrrSlice.reducer