Skip to content

Commit

Permalink
refactor: use custom hook instead of breaking rules of hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
2hwk committed Oct 16, 2022
1 parent 9316a20 commit 68e6377
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 52 deletions.
185 changes: 185 additions & 0 deletions src/instruments/src/Common/seatMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { useUpdate } from '@instruments/common/hooks';
import { SimVarSetter, SimVarValue } from '@instruments/common/simVars';
import { BitFlags } from '@shared/bitFlags';
import { CargoStationInfo, PaxStationInfo } from '@shared/seatMap';
import { useCallback, useRef, useState } from 'react';

const getLocalFloat = (propertyName: string) => {
const value: string | null = localStorage.getItem(propertyName);
if (value) {
return parseFloat(value);
}
return 0;
};

export const useSeats = (
seatMap: PaxStationInfo[],
refreshInterval = 0,
): [
SimVarValue,
SimVarValue,
(newValueOrSetter: SimVarValue | SimVarSetter, index: number) => void,
BitFlags[],
BitFlags[],
(newValueOrSetter: SimVarValue | SimVarSetter, index: number) => void,
(newValueOrSetter: SimVarValue | SimVarSetter, index: number
) => void
] => {
const lastUpdate = useRef(Date.now() - refreshInterval - 1);

const [currentSeated, setCurrentSeated] = useState<number[]>(() => {
const stations: number[] = [];
seatMap.forEach((station: PaxStationInfo) => {
const stationSeated = SimVar.GetSimVarValue(`L:${station.simVar}`, 'Number');
stations.push(stationSeated);
});
return stations;
});

const [desiredSeated, setDesiredSeated] = useState<number[]>(() => {
const stations: number[] = [];
seatMap.forEach((station: PaxStationInfo) => {
const stationValue = SimVar.GetSimVarValue(`L:${station.simVar}_DESIRED`, 'Number');
stations.push(stationValue);
});
return stations;
});

const [currentFlags, setCurrentFlags] = useState<BitFlags[]>(() => {
const stations: BitFlags[] = [];
seatMap.forEach((station: PaxStationInfo) => {
const stationFlag = new BitFlags(getLocalFloat(station.bitFlags));
stations.push(stationFlag);
});
return stations;
});

const [desiredFlags, setDesiredFlags] = useState<BitFlags[]>(() => {
const stations: BitFlags[] = [];
seatMap.forEach((station: PaxStationInfo) => {
const stationFlag = new BitFlags(getLocalFloat(`${station.bitFlags}_DESIRED`));
stations.push(stationFlag);
});
return stations;
});

const updateCallback = useCallback(() => {
const delta = Date.now() - lastUpdate.current;

if (delta >= refreshInterval) {
lastUpdate.current = Date.now();
seatMap.forEach((station: PaxStationInfo, index: number) => {
const stationCurrentSeated = SimVar.GetSimVarValue(`L:${station.simVar}`, 'Number');
const stationDesiredSeated = SimVar.GetSimVarValue(`L:${station.simVar}_DESIRED`, 'Number');
const stationCurrentFloat = getLocalFloat(station.bitFlags);
const stationDesiredFloat = getLocalFloat(`${station.bitFlags}_DESIRED`);
currentSeated[index] = stationCurrentSeated;
desiredSeated[index] = stationDesiredSeated;
if (currentFlags[index].toDouble() !== stationCurrentFloat) {
currentFlags[index] = new BitFlags(stationCurrentFloat);
setCurrentFlags(currentFlags);
setCurrentSeated(currentSeated);
}
if (desiredFlags[index].toDouble() !== stationDesiredFloat) {
desiredFlags[index] = new BitFlags(stationDesiredFloat);
setDesiredFlags(desiredFlags);
setDesiredSeated(desiredSeated);
}
});
}
}, [seatMap, refreshInterval]);

const setter = useCallback((valueOrSetter: any | SimVarSetter, index: number) => {
const executedValue = typeof valueOrSetter === 'function' ? valueOrSetter(desiredSeated) : valueOrSetter;

SimVar.SetSimVarValue(`L:${seatMap[index].simVar}_DESIRED`, 'Number', executedValue);
desiredSeated[index] = executedValue;

setDesiredSeated(desiredSeated);

return desiredSeated;
}, [seatMap, desiredSeated]);

const setCurrent = useCallback((value: BitFlags, index: number) => {
localStorage.setItem(seatMap[index].bitFlags, value.toDouble().toString());
currentFlags[index] = value;

setCurrentFlags(currentFlags);

return currentFlags;
}, [seatMap, currentFlags]);

const setDesired = useCallback((value: BitFlags, index: number) => {
localStorage.setItem(`${seatMap[index].bitFlags}_DESIRED`, value.toDouble().toString());
desiredFlags[index] = value;

setDesiredFlags(desiredFlags);

return desiredFlags;
}, [seatMap, desiredFlags]);

useUpdate(updateCallback);

return [currentSeated, desiredSeated, setter, currentFlags, desiredFlags, setCurrent, setDesired];
};

export const useCargo = (
cargoMap: CargoStationInfo[],
): [
SimVarValue,
SimVarValue,
(newValueOrSetter: SimVarValue | SimVarSetter, index: number
) => void,
] => {
const lastUpdate = useRef(Date.now() - 1);

const [currentLoaded, setCurrentLoaded] = useState<number[]>(() => {
const stations: number[] = [];
cargoMap.forEach((station: CargoStationInfo) => {
const stationSeated = SimVar.GetSimVarValue(`L:${station.simVar}`, 'Number');
stations.push(stationSeated);
});
return stations;
});

const [desiredLoaded, setDesiredLoaded] = useState<number[]>(() => {
const stations: number[] = [];
cargoMap.forEach((station: CargoStationInfo) => {
const stationValue = SimVar.GetSimVarValue(`L:${station.simVar}_DESIRED`, 'Number');
stations.push(stationValue);
});
return stations;
});

const updateCallback = useCallback(() => {
const delta = Date.now() - lastUpdate.current;

if (delta >= 0) {
lastUpdate.current = Date.now();
cargoMap.forEach((station: CargoStationInfo, index: number) => {
const stationCurrentLoaded = SimVar.GetSimVarValue(`L:${station.simVar}`, 'Number');
const stationDesiredLoaded = SimVar.GetSimVarValue(`L:${station.simVar}_DESIRED`, 'Number');
currentLoaded[index] = stationCurrentLoaded;
desiredLoaded[index] = stationDesiredLoaded;
});

setCurrentLoaded(currentLoaded);
setDesiredLoaded(desiredLoaded);
}
}, [cargoMap]);

useUpdate(updateCallback);

const setter = useCallback((valueOrSetter: any | SimVarSetter, index: number) => {
const executedValue = typeof valueOrSetter === 'function' ? valueOrSetter(desiredLoaded) : valueOrSetter;

SimVar.SetSimVarValue(`L:${cargoMap[index].simVar}_DESIRED`, 'Number', executedValue);
desiredLoaded[index] = executedValue;

setDesiredLoaded(desiredLoaded);

return desiredLoaded;
}, [cargoMap, desiredLoaded]);

return [currentLoaded, desiredLoaded, setter];
};
4 changes: 2 additions & 2 deletions src/instruments/src/Common/simVars.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useInteractionEvents, useUpdate } from './hooks';

type SimVarSetter = <T extends SimVarValue>(oldValue: T) => T;
export type SimVarSetter = <T extends SimVarValue>(oldValue: T) => T;

type UnitName = SimVar.SimVarUnit;
type SimVarValue = number | any;
export type SimVarValue = number | any;

/**
* The useSimVar hook provides an easy way to read and write SimVars from React.
Expand Down
69 changes: 19 additions & 50 deletions src/instruments/src/EFB/Ground/Pages/Payload/Payload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useSimVar } from '@instruments/common/simVars';
import { Units } from '@shared/units';
import { usePersistentProperty } from '@instruments/common/persistence';
import { BitFlags } from '@shared/bitFlags';
import { useBitFlags } from '@instruments/common/bitFlags';
import { round } from 'lodash';
import { useCargo, useSeats } from '@instruments/common/seatMap';
import { CargoWidget } from './Seating/CargoWidget';
import { ChartWidget } from './Chart/ChartWidget';
import { PaxStationInfo, CargoStationInfo } from './Seating/Constants';
Expand All @@ -23,39 +23,8 @@ import { useAppSelector } from '../../../Store/store';
export const Payload = () => {
const { usingMetric } = Units;

const pax: number[] = [];
const paxDesired: number[] = [];
const setPaxDesired: ((newValueOrSetter: any) => void)[] = [];
const activeFlags: BitFlags[] = [];
const setActiveFlags: ((newValueOrSetter: any) => void)[] = [];
const desiredFlags: BitFlags[] = [];
const setDesiredFlags: ((newValueOrSetter: any) => void)[] = [];

const cargo: number[] = [];
const cargoDesired: number[] = [];
const setCargoDesired: ((newValueOrSetter: any) => void)[] = [];

Loadsheet.seatMap.forEach((station) => {
const [stationPax] = useSimVar(`L:${station.simVar}`, 'Number', 300);
pax.push(stationPax);
const [stationPaxDesired, setStationPaxDesired] = useSimVar(`L:${station.simVar}_DESIRED`, 'Number', 300);
paxDesired.push(stationPaxDesired);
setPaxDesired.push(setStationPaxDesired);
const [pFlg, setPFlg] = useBitFlags(station.bitFlags);
activeFlags.push(pFlg);
setActiveFlags.push(setPFlg);
const [pFlgDesired, setPFlgDesired] = useBitFlags(`${station.bitFlags}_DESIRED`);
desiredFlags.push(pFlgDesired);
setDesiredFlags.push(setPFlgDesired);
});

Loadsheet.cargoMap.forEach((station) => {
const [stationWeight] = useSimVar(`L:${station.simVar}`, 'Number', 300);
cargo.push(stationWeight);
const [stationWeightDesired, setStationWeightDesired] = useSimVar(`L:${station.simVar}_DESIRED`, 'Number', 300);
cargoDesired.push(stationWeightDesired);
setCargoDesired.push(setStationWeightDesired);
});
const [pax, paxDesired, setPaxDesired, activeFlags, desiredFlags, setActiveFlags, setDesiredFlags] = useSeats(Loadsheet.seatMap);
const [cargo, cargoDesired, setCargoDesired] = useCargo(Loadsheet.cargoMap);

const massUnitForDisplay = usingMetric ? 'KGS' : 'LBS';

Expand Down Expand Up @@ -86,11 +55,11 @@ export const Payload = () => {
}, [...paxDesired]);
const [clicked, setClicked] = useState(false);

const totalCargoDesired = useMemo(() => ((cargoDesired && cargoDesired.length > 0) ? cargoDesired.reduce((a, b) => parseInt(a) + parseInt(b)) : -1), [...cargoDesired, ...paxDesired]);
const totalCargoDesired = useMemo(() => ((cargoDesired && cargoDesired.length > 0) ? cargoDesired.reduce((a, b) => a + b) : -1), [...cargoDesired, ...paxDesired]);

const [cargoStationSize, setCargoStationLen] = useState<number[]>([]);

const totalCargo = useMemo(() => ((cargo && cargo.length > 0) ? cargo.reduce((a, b) => parseInt(a) + parseInt(b)) : -1), [...cargo, ...pax]);
const totalCargo = useMemo(() => ((cargo && cargo.length > 0) ? cargo.reduce((a, b) => a + b) : -1), [...cargo, ...pax]);
const maxCargo = useMemo(() => ((cargoStationSize && cargoStationSize.length > 0) ? cargoStationSize.reduce((a, b) => a + b) : -1), [cargoStationSize]);

const [centerCurrent] = useSimVar('FUEL TANK CENTER QUANTITY', 'Gallons', 2_000);
Expand Down Expand Up @@ -188,7 +157,7 @@ export const Payload = () => {
choices.splice(chosen, 1);
}
}
setActiveFlags[stationIndex](bitFlags);
setActiveFlags(bitFlags, stationIndex);
}, [...pax, ...activeFlags]);

const chooseDesiredSeats = useCallback((stationIndex: number, choices: number[], numChoose: number) => {
Expand All @@ -200,7 +169,7 @@ export const Payload = () => {
choices.splice(chosen, 1);
}
}
setDesiredFlags[stationIndex](bitFlags);
setDesiredFlags(bitFlags, stationIndex);
}, [...paxDesired, ...desiredFlags]);

const calculateSeatOptions = useCallback((stationIndex: number, increase: boolean): number[] => {
Expand All @@ -218,7 +187,7 @@ export const Payload = () => {

const fillStation = (stationIndex: number, percent: number, paxToFill: number) => {
const pax = Math.min(Math.trunc(percent * paxToFill), stationSize[stationIndex]);
setPaxDesired[stationIndex](pax);
setPaxDesired(pax, stationIndex);
paxRemaining -= pax;

const paxCount = returnNumSeats(stationIndex, false, activeFlags);
Expand All @@ -238,10 +207,10 @@ export const Payload = () => {

let remainingWeight = loadableCargoWeight;

async function fillCargo(station: number, percent: number, loadableCargoWeight: number) {
const c = Math.round(percent * loadableCargoWeight);
remainingWeight -= c;
setCargoDesired[station](c);
async function fillCargo(cargoStation: number, percent: number, loadableCargoWeight: number) {
const cargoWeight = Math.round(percent * loadableCargoWeight);
remainingWeight -= cargoWeight;
setCargoDesired(cargoWeight, cargoStation);
}

for (let i = cargoDesired.length - 1; i > 0; i--) {
Expand Down Expand Up @@ -300,7 +269,7 @@ export const Payload = () => {

const onClickCargo = useCallback((cargoStation, e) => {
const cargoPercent = Math.min(Math.max(0, e.nativeEvent.offsetX / cargoMap[cargoStation].progressBarWidth), 1);
setCargoDesired[cargoStation](Math.round(Units.kilogramToUser(cargoMap[cargoStation].weight) * cargoPercent));
setCargoDesired(Math.round(Units.kilogramToUser(cargoMap[cargoStation].weight) * cargoPercent), cargoStation);
}, [cargoMap]);

const onClickSeat = useCallback((station: number, seatId: number) => {
Expand All @@ -312,15 +281,15 @@ export const Payload = () => {

if (bitFlags.getBitIndex(seatId)) {
newPax -= 1;
setPaxDesired[station](Math.max(paxDesired[station] - 1, 0));
setPaxDesired(Math.max(paxDesired[station] - 1, 0), station);
} else {
newPax += 1;
setPaxDesired[station](Math.min(paxDesired[station] + 1, stationSize[station]));
setPaxDesired(Math.min(paxDesired[station] + 1, stationSize[station]), station);
}

setTargetCargo(newPax, freight);
bitFlags.toggleBitIndex(seatId);
setDesiredFlags[station](bitFlags);
setDesiredFlags(bitFlags, station);
setTimeout(() => setClicked(false), 500);
}, [
totalPaxDesired, paxBagWeight,
Expand Down Expand Up @@ -396,14 +365,14 @@ export const Payload = () => {
pax.forEach((stationPaxNum: number, stationIndex: number) => {
const paxCount = returnNumSeats(stationIndex, false, activeFlags);
if (stationPaxNum === 0 && paxCount !== stationPaxNum) {
setActiveFlags[stationIndex](new BitFlags(0));
setActiveFlags(new BitFlags(0), stationIndex);
}
});

paxDesired.forEach((stationPaxNum, stationIndex) => {
const paxCount = returnNumSeats(stationIndex, false, desiredFlags);
if (stationPaxNum === 0 && paxCount !== stationPaxNum) {
setDesiredFlags[stationIndex](new BitFlags(0));
setDesiredFlags(new BitFlags(0), stationIndex);
}
});
if (!boardingStarted) {
Expand Down Expand Up @@ -465,7 +434,7 @@ export const Payload = () => {
pax.forEach((stationNumPax: number, stationIndex: number) => {
// Sync active to desired layout if pax is equal to desired
if (stationNumPax === paxDesired[stationIndex]) {
setActiveFlags[stationIndex](desiredFlags[stationIndex]);
setActiveFlags(desiredFlags[stationIndex], stationIndex);
}
});
}, [boardingStarted]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface PaxStationInfo {
name: string,
rows: RowInfo[],
simVar: string,
bitFlags: string,
index: number,
fill: number,
stationIndex: number,
Expand Down
Loading

0 comments on commit 68e6377

Please sign in to comment.