Skip to content

Commit

Permalink
feat(frontend): use redux store to remove multiple API calls and also…
Browse files Browse the repository at this point in the history
… add some extra fields to data table (#38)
  • Loading branch information
mishraomp authored Feb 26, 2024
1 parent 641630f commit 633b9d2
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 58 deletions.
11 changes: 10 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -27,6 +31,11 @@ const styles = {
}

export default function App() {
const dispatch = useDispatch()
useEffect(() => {
//@ts-expect-error
dispatch(fetchOMRRData())
}, [dispatch])
return (
<Box sx={styles.container}>
<Header />
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/app/store.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
30 changes: 13 additions & 17 deletions frontend/src/components/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -78,23 +85,12 @@ const columns: GridColDef[] = [
filterable: true,
flex: 1,
},

]

export default function DataTable() {
const [data, setData] = useState<any>([]);
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 = () => {
Expand Down
49 changes: 10 additions & 39 deletions frontend/src/components/MapView.jsx
Original file line number Diff line number Diff line change
@@ -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]

Expand All @@ -65,16 +36,16 @@ 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"
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerClusterGroup chunkedLoading>
{dataFetched &&
data.map((item, index) => (
{status === 'succeeded' &&
mapPopupValue.map((item, index) => (
<Marker key={index} position={item.position} icon={redIcon}>
<Popup sx={{ maxWidth: '50em' }}>
<Table key={index} size="small">
Expand Down
106 changes: 106 additions & 0 deletions frontend/src/features/omrr/omrr-slice.ts
Original file line number Diff line number Diff line change
@@ -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<OmrrData[]>) => {
state.value = action.payload
},
},
extraReducers: (builder: ActionReducerMapBuilder<OmrrSliceState>) => {
// 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

0 comments on commit 633b9d2

Please sign in to comment.