228 lines
8.1 KiB
TypeScript
228 lines
8.1 KiB
TypeScript
import { FC, useEffect, useState } from 'react';
|
|
import { GSX_SERVICE_CALLED, GSX_SERVICE_FINISHED } from '../../constants';
|
|
import { WASMDataPax } from '../../types/WASMData';
|
|
import { LoadingState, SimBrief } from '../../types/general';
|
|
import { ImportFlightPlan } from '../../utils/TFDISBImport';
|
|
import { CoherentCallSBEntryPax, inRangeOf, loadAircraft, unloadAircraft } from '../../utils/utils';
|
|
import CGSelect from '../CGSelect/CGSelect';
|
|
import ActionBar from '../actionbar/ActionBar';
|
|
|
|
interface SBEntryProps {
|
|
WASMData: WASMDataPax;
|
|
loadingState: LoadingState;
|
|
username: string;
|
|
setLoadingState: (newState: LoadingState) => void;
|
|
}
|
|
|
|
const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoadingState }) => {
|
|
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
|
|
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
|
|
const [fuelEnabled, setFuelEnabled] = useState(true);
|
|
const [SBInFlight, setSBInFlight] = useState(false);
|
|
|
|
const ZFW = () => {
|
|
if (loadingState !== 'loaded' && !GSXActive()) return Math.round(WASMData.targetPayload.total);
|
|
|
|
return Math.round(WASMData.livePayload.total);
|
|
};
|
|
const ZFWValid = () => {
|
|
return ZFW() <= WASMData.limits.maxZFW;
|
|
};
|
|
const GW = () => {
|
|
return fuel + ZFW();
|
|
};
|
|
const GWValid = () => {
|
|
return GW() <= WASMData.limits.maxTOW;
|
|
};
|
|
|
|
const GSXActive = () => {
|
|
return (
|
|
(WASMData.GSX.boardingState >= GSX_SERVICE_CALLED || WASMData.GSX.deboardingState >= GSX_SERVICE_CALLED) &&
|
|
WASMData.GSX.deboardingState !== GSX_SERVICE_FINISHED
|
|
);
|
|
};
|
|
|
|
const handleInput = (input: string, maxValue: number, setter: (value: number) => void) => {
|
|
if (!input) {
|
|
setter(0);
|
|
return;
|
|
}
|
|
|
|
const converted = parseInt(input);
|
|
if (converted) {
|
|
if (converted < 0) setter(0);
|
|
else if (converted > maxValue) setter(maxValue);
|
|
else setter(converted);
|
|
}
|
|
};
|
|
|
|
const handleSB = async () => {
|
|
setSBInFlight(true);
|
|
|
|
const SBResponse = await ImportFlightPlan(
|
|
username,
|
|
WASMData.limits.maxZFW,
|
|
WASMData.limits.maxTOW,
|
|
WASMData.limits.maxFuel,
|
|
WASMData.userData.isImperial
|
|
);
|
|
if (SBResponse.type === 'error') {
|
|
console.error('TODO: ERROR', SBResponse.message);
|
|
setSBInFlight(false);
|
|
return;
|
|
}
|
|
|
|
updateData(undefined, SBResponse.message);
|
|
|
|
setFuel(parseFloat(SBResponse.message.fuel) ?? 0);
|
|
setSBInFlight(false);
|
|
};
|
|
|
|
useEffect(
|
|
() =>
|
|
setFuel((prev) => {
|
|
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
|
|
return prev;
|
|
}),
|
|
[WASMData.userData.isER]
|
|
);
|
|
useEffect(() => {
|
|
setFuelEnabled((prev) => (!prev ? inRangeOf(Math.round(WASMData.livePayload.fuel), fuel) : prev));
|
|
}, [WASMData.livePayload.fuel]);
|
|
|
|
const updateData = (_CGTarget?: number, SBPlan?: SimBrief) => {
|
|
CoherentCallSBEntryPax(_CGTarget ?? CGTarget, SBPlan);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
|
<div className="relative flex w-full items-center justify-between rounded-md bg-zinc-600 p-2 px-4">
|
|
<label>Fuel ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
|
<input
|
|
type="text"
|
|
placeholder=""
|
|
className={`w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right`}
|
|
value={fuel}
|
|
onChange={(e) => handleInput(e.target.value, WASMData.limits.maxFuel, setFuel)}
|
|
disabled={loadingState !== 'preview' || GSXActive()}
|
|
/>
|
|
<button
|
|
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
|
|
data-ripple-light="true"
|
|
onClick={() => {
|
|
SimVar.SetSimVarValue(
|
|
'L:MD11_EFB_PAYLOAD_FUEL',
|
|
'lbs',
|
|
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
|
|
);
|
|
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
|
setFuelEnabled(WASMData.livePayload.fuel === fuel);
|
|
}}
|
|
disabled={loadingState !== 'preview' || !fuelEnabled || GSXActive()}
|
|
>
|
|
Load Fuel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
|
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
|
<label>Planned ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
|
<input
|
|
type="text"
|
|
placeholder=""
|
|
className="w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right focus:border-blue-600 focus:ring-blue-600"
|
|
value={WASMData.sbPlanned.ZFW}
|
|
disabled
|
|
/>
|
|
</div>
|
|
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
|
<label>Planned GW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
|
<input
|
|
type="text"
|
|
placeholder=""
|
|
className="w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right focus:border-blue-600 focus:ring-blue-600"
|
|
value={WASMData.sbPlanned.GW}
|
|
disabled
|
|
/>
|
|
</div>
|
|
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-600 p-2 px-4">
|
|
<label>
|
|
Target ZFWCG ({WASMData.limits.minCG} - {WASMData.limits.maxCG})
|
|
</label>
|
|
<CGSelect
|
|
minCG={WASMData.limits.minCG}
|
|
maxCG={WASMData.limits.maxCG}
|
|
value={CGTarget}
|
|
disabled={loadingState !== 'preview' || GSXActive()}
|
|
increase={() =>
|
|
setCGTarget((prev) => {
|
|
const _new = prev + 0.1;
|
|
updateData(_new);
|
|
return _new;
|
|
})
|
|
}
|
|
decrease={() =>
|
|
setCGTarget((prev) => {
|
|
const _new = prev - 0.1;
|
|
updateData(_new);
|
|
return _new;
|
|
})
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
|
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
|
<label>
|
|
{loadingState !== 'loaded' && !GSXActive() ? 'Expected' : 'Actual'} ZFW (
|
|
{WASMData.userData.isImperial ? 'lbs' : 'kg'})
|
|
</label>
|
|
<input
|
|
type="text"
|
|
placeholder=""
|
|
className={`w-1/2 rounded-lg border ${ZFWValid() ? 'border-white' : 'border-red-500 text-red-500'} bg-zinc-700 px-3 py-2 text-right`}
|
|
disabled
|
|
value={ZFW()}
|
|
/>
|
|
</div>
|
|
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
|
|
<label>
|
|
{loadingState !== 'loaded' && !GSXActive() ? 'Expected' : 'Actual'} GW (
|
|
{WASMData.userData.isImperial ? 'lbs' : 'kg'})
|
|
</label>
|
|
<input
|
|
type="text"
|
|
placeholder=""
|
|
className={`w-1/2 rounded-lg border ${GWValid() ? 'border-white' : 'border-red-500 text-red-500'} bg-zinc-700 px-3 py-2 text-right`}
|
|
disabled
|
|
value={GW()}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<ActionBar
|
|
loadingState={loadingState}
|
|
loadDisabled={!GWValid() || SBInFlight}
|
|
GSXSync={WASMData.options.GSXSync}
|
|
GSXActive={GSXActive()}
|
|
importSB={handleSB}
|
|
load={() => {
|
|
setLoadingState('loaded');
|
|
|
|
loadAircraft();
|
|
}}
|
|
unload={() => {
|
|
setLoadingState('preview');
|
|
|
|
unloadAircraft();
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SBEntryPax;
|