diff --git a/app/components/Map.tsx b/app/components/Map.tsx index caae758..aee3971 100644 --- a/app/components/Map.tsx +++ b/app/components/Map.tsx @@ -29,6 +29,8 @@ import { initializePlayground, replacePlayground, replaceOldPlayground, + clearToUpdatePlayground, + replaceToUpdatePlayground, } from '../../lib/features/playground/playgroundSlice'; import { @@ -139,6 +141,8 @@ export default function Map() { const antennasData = useAppSelector((state) => state.currentAntennas.value); + const toBeUpdated = useAppSelector((state) => state.playground.toBeUpdated); + const dispatch = useAppDispatch(); useEffect(() => { @@ -151,7 +155,7 @@ export default function Map() { } const responseJson = (await response.json()) as Antenna[]; - console.log('Antennas Data:', responseJson); + return responseJson; } catch (e) { if (e instanceof Error) { @@ -182,9 +186,23 @@ export default function Map() { }) ); + const playgroundAntennasData: AccessPoint[] = accessPoints.map( + (ap: Antenna) => ({ + id: ap.id, + modelName: ap.modelname, + lat: ap.latitude, + lon: ap.longitude, + frequency: ap.playground_frequency || 0, + azimuth: ap.azimuth || 0, + antenna_status: ap.antenna_status || 'N/A', + cpu: ap.cpu || -1, + ram: ap.ram || -1, + }) + ); + if (!initialized.current) { store.dispatch(initializeActual(antennasData)); - store.dispatch(initializePlayground(antennasData)); + store.dispatch(initializePlayground(playgroundAntennasData)); store.dispatch(initializeCurrent(antennasData)); initialized.current = true; } @@ -212,7 +230,8 @@ export default function Map() { fetchDataAndSetAntennasData().catch((error) => { console.error(error); }); - }, [store]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); useEffect(() => { const sectorlobesData: SectorlobeData[] = antennasData.data.map((ap) => { @@ -346,6 +365,43 @@ export default function Map() { return amount; }, [intersections]); + const handleSavePlayground = async () => { + const url = '/api/v1/antenna/'; + if (toBeUpdated.length === 0) { + alert('No changes to save'); + return; + } + for (let i = 0; i < 3; i++) { + try { + const response = await fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ dataArray: toBeUpdated }), + }); + if (!response.ok) { + throw new Error( + `${response.status} error: Failed to save playground data` + ); + } + dispatch(replacePlayground(antennasData.data)); + dispatch(replaceOldPlayground(antennasData.data)); + dispatch(clearToUpdatePlayground()); + alert('Playground data saved successfully'); + break; + } catch (e) { + if (e instanceof Error) { + console.error(`Attempt ${i + 1} failed: ${e.message}`); + if (i === 2) { + alert('Failed to save playground data'); + } + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + } + }; + return ( <>
@@ -431,48 +487,88 @@ export default function Map() {
-

Current mode:

- +
+
+

Current mode:

+ +
+
+ {antennasData.mode === 'playground' ? ( +
+ -
- {antennasData.mode === 'playground' ? ( -
+ }} + > + Revert All Changes + diff --git a/app/components/SectorLobe.tsx b/app/components/SectorLobe.tsx index e07466b..98442e5 100644 --- a/app/components/SectorLobe.tsx +++ b/app/components/SectorLobe.tsx @@ -9,6 +9,7 @@ import { SectorLobeProps } from '../types'; import { useAppSelector, useAppDispatch } from '../../lib/hooks'; import { updateCurrent } from '@/lib/features/currentAntennas/currentAntennasSlice'; +import { addToUpdatePlayground } from '@/lib/features/playground/playgroundSlice'; export default function SectorLobe({ key_path, @@ -152,14 +153,17 @@ export default function SectorLobe({ const newAp = { ...currentAp }; newAp.azimuth = tempHeading; newAp.frequency = tempFreq; - setCurrentAp(newAp); if (currentMode === 'playground') { + dispatch(addToUpdatePlayground(newAp)); dispatch(updateCurrent(newAp)); } } - function handleCancel() { + function handleCancel( + e: React.FormEvent | React.MouseEvent + ) { + e.preventDefault(); setTempHeading(heading); setTempFreq(freq); } @@ -169,14 +173,14 @@ export default function SectorLobe({ positions={sectorVertices} color={color} fillOpacity={0.5} - weight={1} + weight={3} key={String(key_path)} >
handleCommit(e)} + // onSubmit={(e) => handleCommit(e)} >

Change Sector Lobe of {ap.id}

@@ -217,21 +221,25 @@ export default function SectorLobe({ )} °
-
- - -
+ {currentMode === 'playground' ? ( +
+ + +
+ ) : ( + <> + )}
diff --git a/lib/features/playground/playgroundSlice.ts b/lib/features/playground/playgroundSlice.ts index 594e374..d952114 100644 --- a/lib/features/playground/playgroundSlice.ts +++ b/lib/features/playground/playgroundSlice.ts @@ -2,13 +2,18 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { AccessPoint } from '../../../app/types'; -type PlaygroundState = { value: AccessPoint[]; old: AccessPoint[] }; +type PlaygroundState = { + value: AccessPoint[]; + old: AccessPoint[]; + toBeUpdated: AccessPoint[]; +}; export const playgroundSlice = createSlice({ name: 'playground', initialState: { value: [], old: [], + toBeUpdated: [], } satisfies PlaygroundState as PlaygroundState, reducers: { initializePlayground: (state, action: PayloadAction) => { @@ -38,6 +43,39 @@ export const playgroundSlice = createSlice({ replaceOldPlayground: (state, action: PayloadAction) => { return { ...state, old: action.payload }; }, + addToUpdatePlayground: (state, action: PayloadAction) => { + for (let i = 0; i < state.toBeUpdated.length; i++) { + if (state.toBeUpdated[i].id === action.payload.id) { + return { + ...state, + toBeUpdated: state.toBeUpdated.map((item) => { + if (item.id === action.payload.id) { + return action.payload; + } + return item; + }), + }; + } + } + return { ...state, toBeUpdated: [...state.toBeUpdated, action.payload] }; + }, + clearToUpdatePlayground: (state) => { + return { ...state, toBeUpdated: [] }; + }, + removeFromUpdatePlayground: (state, action: PayloadAction) => { + return { + ...state, + toBeUpdated: state.toBeUpdated.filter( + (item) => item !== action.payload + ), + }; + }, + replaceToUpdatePlayground: ( + state, + action: PayloadAction + ) => { + return { ...state, toBeUpdated: action.payload }; + }, }, }); @@ -48,6 +86,10 @@ export const { removePlayground, updatePlayground, replaceOldPlayground, + addToUpdatePlayground, + clearToUpdatePlayground, + removeFromUpdatePlayground, + replaceToUpdatePlayground, } = playgroundSlice.actions; export default playgroundSlice.reducer;