Pax Station Entry

This commit is contained in:
2025-06-11 17:30:36 +02:00
parent 890622453e
commit 896a459bba
8 changed files with 181 additions and 257 deletions
@@ -1,6 +1,7 @@
import { FC, useState } from 'react';
import { WASMDataPax } from '../../types/WASMData';
import Profile from '../profile/Profile';
import StationEntryPax from '../stationEntry/StationEntryPax';
import Tabbar from '../tabbar/Tabbar';
import ZFWEntryPax from '../zfwEntry/ZFWEntryPax';
@@ -128,30 +129,20 @@ const Pax: FC<PaxProps> = ({ WASMData, username }) => {
loadingState={loadingState}
setLoadingState={setLoadingState}
loadAircraft={() => {
console.log('SET WEIGHT');
console.log('SET WEIGHT ZFW');
}}
/>
)}
{/*
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
<StationEntryPax
unit={unit}
isER={isER}
initialPayload={payload}
fuelLive={fuelLive}
payloadLive={payloadLive}
WASMData={WASMData}
loadingState={loadingState}
setLoadingState={setLoadingState}
updateView={(_payload) => {
setPayload(_payload);
}}
loadAircraft={() => {
PaxConfig.setBaseWeight(unit, isER);
PaxConfig.setWeights(payload, unit);
console.log('SET WEIGHT STATIONS');
}}
/>
)}
*/}
</>
);
};
@@ -1,117 +1,39 @@
import { FC, useEffect, useState } from 'react';
import { PaxConfig, PayloadPax } from '../../configs/pax';
import { Fuel, SharedConfig } from '../../configs/shared';
import { emptyAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { WASMDataPax } from '../../types/WASMData';
import ActionBar from '../actionbar/ActionBar';
interface StationEntryProps {
unit: 'kg' | 'lbs';
isER: boolean;
initialPayload: PayloadPax;
fuelLive: Fuel;
payloadLive: PayloadPax;
WASMData: WASMDataPax;
loadingState: 'preview' | 'accepted' | 'loaded';
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
updateView: (payload: PayloadPax) => void;
loadAircraft: () => void;
}
const StationEntryPax: FC<StationEntryProps> = ({
unit,
isER,
initialPayload,
fuelLive,
payloadLive,
loadingState,
setLoadingState,
updateView,
loadAircraft,
}) => {
const [business1, setBusiness1] = useState(
PaxConfig.weightToPax(
initialPayload.business1Left + initialPayload.business1Center + initialPayload.business1Right,
unit
)
);
const [business2, setBusiness2] = useState(
PaxConfig.weightToPax(
initialPayload.business2Left + initialPayload.business2Center + initialPayload.business2Right,
unit
)
);
const [economy1, setEconomy1] = useState(
PaxConfig.weightToPax(
initialPayload.economy1Left + initialPayload.economy1Center + initialPayload.economy1Right,
unit
)
);
const [economy2, setEconomy2] = useState(
PaxConfig.weightToPax(
initialPayload.economy2Left + initialPayload.economy2Center + initialPayload.economy2Right,
unit
)
);
const [forwardCargo, setForwardCargo] = useState(initialPayload.forwardCargo);
const [rearCargo, setRearCargo] = useState(initialPayload.rearCargo);
const [fuel, setFuel] = useState(
Math.round(
fuelLive.main1 +
fuelLive.main1Tip +
fuelLive.main2 +
fuelLive.main3 +
fuelLive.main3Tip +
fuelLive.upperAux +
fuelLive.lowerAux +
fuelLive.tail +
fuelLive.forwardAux1 +
fuelLive.forwardAux2
)
);
const StationEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoadingState, loadAircraft }) => {
const [business1, setBusiness1] = useState(WASMData.targetPayload.business1);
const [business2, setBusiness2] = useState(WASMData.targetPayload.business2);
const [economy1, setEconomy1] = useState(WASMData.targetPayload.economy1);
const [economy2, setEconomy2] = useState(WASMData.targetPayload.economy2);
const [forwardCargo, setForwardCargo] = useState(WASMData.targetPayload.forwardCargo);
const [rearCargo, setRearCargo] = useState(WASMData.targetPayload.rearCargo);
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
const [fuelEnabled, setFuelEnabled] = useState(true);
const ZFW = () => {
if (loadingState !== 'loaded')
return Math.round(
(business1 + business2 + economy1 + economy2) * PaxConfig.weights.pax[unit] +
forwardCargo +
rearCargo +
PaxConfig.weights.base[unit].total +
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
payloadLive.empty
);
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.total);
return Math.round(
payloadLive.empty +
payloadLive.pilot +
payloadLive.firstOfficer +
payloadLive.engineer +
payloadLive.cabinCrewFront +
payloadLive.business1Left +
payloadLive.business1Center +
payloadLive.business1Right +
payloadLive.business2Left +
payloadLive.business2Center +
payloadLive.business2Right +
payloadLive.economy1Left +
payloadLive.economy1Center +
payloadLive.economy1Right +
payloadLive.economy2Left +
payloadLive.economy2Center +
payloadLive.economy2Right +
payloadLive.cabinCrewRear +
payloadLive.forwardCargo +
payloadLive.rearCargo +
payloadLive.leftAuxPax +
payloadLive.rightAuxPax
);
return Math.round(WASMData.livePayload.total);
};
const ZFWValid = () => {
return ZFW() <= PaxConfig.maxZWF[unit];
return ZFW() <= WASMData.limits.maxZFW;
};
const GW = () => {
return fuel + ZFW();
};
const GWValid = () => {
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
return GW() <= WASMData.limits.maxTOW;
};
const handleInput = (input: string, maxValue: number, setter: (value: number) => void) => {
@@ -128,37 +50,67 @@ const StationEntryPax: FC<StationEntryProps> = ({
}
};
useEffect(() => _updateView(), [business1, business2, economy1, economy2, forwardCargo, rearCargo]);
useEffect(() => updateData(), [business1, business2, economy1, economy2, forwardCargo, rearCargo]);
useEffect(
() =>
setFuel((prev) =>
prev > (isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit])
? isER
? SharedConfig.maxFuel.er[unit]
: SharedConfig.maxFuel.norm[unit]
: prev
),
[isER]
setFuel((prev) => {
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
return prev;
}),
[WASMData.userData.isER]
);
useEffect(() => {
setFuelEnabled(Math.round(WASMData.livePayload.fuel) === fuel);
}, [WASMData.livePayload.fuel]);
const _updateView = () => {
const payload = PaxConfig.generateDistribution(
payloadLive.empty,
business1,
business2,
economy1,
economy2,
forwardCargo,
rearCargo,
unit,
isER
const updateData = () => {
Coherent.call(
COHERENT_COMBUS_WASM_CALL,
COMM_BUS_UPDATE_TARGET_EVENT,
JSON.stringify({
mode: 2,
business1,
business2,
economy1,
economy2,
forwardCargo,
rearCargo,
})
);
updateView(payload);
};
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'}
/>
<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(false);
}}
disabled={loadingState !== 'preview' || !fuelEnabled}
>
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>Business</label>
@@ -167,7 +119,7 @@ const StationEntryPax: FC<StationEntryProps> = ({
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={business1}
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.business1, setBusiness1)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.business1, setBusiness1)}
disabled={loadingState !== 'preview'}
/>
</div>
@@ -178,7 +130,7 @@ const StationEntryPax: FC<StationEntryProps> = ({
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={business2}
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.business2, setBusiness2)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.business2, setBusiness2)}
disabled={loadingState !== 'preview'}
/>
</div>
@@ -189,7 +141,7 @@ const StationEntryPax: FC<StationEntryProps> = ({
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={economy1}
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.economy1, setEconomy1)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.economy1, setEconomy1)}
disabled={loadingState !== 'preview'}
/>
</div>
@@ -200,69 +152,38 @@ const StationEntryPax: FC<StationEntryProps> = ({
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={economy2}
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.economy2, setEconomy2)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.economy2, setEconomy2)}
disabled={loadingState !== 'preview'}
/>
</div>
<div className="relative flex w-full items-center justify-between bg-zinc-600 p-2 px-4">
<label>Forward Cargo ({unit})</label>
<label>Forward Cargo ({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={forwardCargo}
onChange={(e) => handleInput(e.target.value, SharedConfig.stationMax.forward[unit], setForwardCargo)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.forwardCargo, setForwardCargo)}
disabled={loadingState !== 'preview'}
/>
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
<label>Aft Cargo ({unit})</label>
<label>Aft Cargo ({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={rearCargo}
onChange={(e) => handleInput(e.target.value, SharedConfig.stationMax.rear[unit], setRearCargo)}
onChange={(e) => handleInput(e.target.value, WASMData.limits.rearCargo, setRearCargo)}
disabled={loadingState !== 'preview'}
/>
</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-md bg-zinc-600 p-2 px-4">
<label>Fuel ({unit})</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,
isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit],
setFuel
)
}
disabled={loadingState !== 'preview'}
/>
<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', unit === 'kg' ? fuel * 2.20462262185 : fuel);
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
}}
disabled={loadingState !== 'preview'}
>
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>
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({unit})
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
</label>
<input
type="text"
@@ -274,7 +195,7 @@ const StationEntryPax: FC<StationEntryProps> = ({
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
<label>
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({unit})
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
</label>
<input
type="text"
@@ -299,7 +220,7 @@ const StationEntryPax: FC<StationEntryProps> = ({
unload={() => {
setLoadingState('preview');
PaxConfig.unload(unit, isER);
emptyAircraft();
}}
/>
</>
@@ -13,21 +13,23 @@ interface StationEntryProps {
}
const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoadingState, loadAircraft }) => {
const [targetZFWCG, setTargetZFWCG] = useState(WASMData.targetPayload.ZFWCG);
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
const [ZFW, setZFW] = useState(Math.round(Math.max(WASMData.limits.minZFW, WASMData.targetPayload.total)));
const [ZFWTarget, setZFWTarget] = useState(
Math.round(Math.max(WASMData.limits.minZFW, WASMData.targetPayload.total))
);
const [fuelEnabled, setFuelEnabled] = useState(true);
const _ZFW = () => {
if (loadingState !== 'loaded') return ZFW;
const ZFW = () => {
if (loadingState !== 'loaded') return ZFWTarget;
return Math.round(WASMData.livePayload.total);
};
const ZFWValid = () => {
return _ZFW() <= WASMData.limits.maxZFW;
return ZFW() <= WASMData.limits.maxZFW;
};
const GW = () => {
return fuel + _ZFW();
return fuel + ZFW();
};
const GWValid = () => {
return GW() <= WASMData.limits.maxTOW;
@@ -51,24 +53,24 @@ const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoading
const converted = parseInt(input);
if (converted) {
if (converted < 0) setZFW(Math.round(WASMData.targetPayload.empty + WASMData.targetPayload.crew));
else if (converted > WASMData.limits.maxZFW) setZFW(WASMData.limits.maxZFW);
else setZFW(converted);
if (converted < 0) setZFWTarget(Math.round(WASMData.targetPayload.empty + WASMData.targetPayload.crew));
else if (converted > WASMData.limits.maxZFW) setZFWTarget(WASMData.limits.maxZFW);
else setZFWTarget(converted);
}
};
const handleBlur = (input: string) => {
const minZFW = Math.round(WASMData.targetPayload.empty + WASMData.targetPayload.crew);
if (!input) {
setZFW(minZFW);
setZFWTarget(minZFW);
return;
}
const converted = parseInt(input);
if (converted) {
if (converted < minZFW) setZFW(minZFW);
else if (converted > WASMData.limits.maxZFW) setZFW(WASMData.limits.maxZFW);
else setZFW(converted);
if (converted < minZFW) setZFWTarget(minZFW);
else if (converted > WASMData.limits.maxZFW) setZFWTarget(WASMData.limits.maxZFW);
else setZFWTarget(converted);
}
updateData(converted);
@@ -82,61 +84,24 @@ const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoading
}),
[WASMData.userData.isER]
);
useEffect(() => {
setFuelEnabled(Math.round(WASMData.livePayload.fuel) === fuel);
}, [WASMData.livePayload.fuel]);
const updateData = (ZFWTarget?: number, CGTarget?: number) => {
const updateData = (_ZFWTarget?: number, _CGTarget?: number) => {
Coherent.call(
COHERENT_COMBUS_WASM_CALL,
COMM_BUS_UPDATE_TARGET_EVENT,
JSON.stringify({
mode: 1,
ZFWTarget: ZFWTarget ?? ZFW,
CGTarget: CGTarget ?? targetZFWCG,
ZFWTarget: _ZFWTarget ?? ZFWTarget,
CGTarget: _CGTarget ?? CGTarget,
})
);
};
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-t-md bg-zinc-600 p-2 px-4">
<label>Target 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={ZFW}
onChange={(e) => handleInputZFW(e.target.value)}
onBlur={(e) => handleBlur(e.target.value)}
disabled={loadingState !== 'preview'}
/>
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
<label>
Target ZFWCG ({WASMData.limits.minCG} - {WASMData.limits.maxCG})
</label>
<CGSelect
minCG={WASMData.limits.minCG}
maxCG={WASMData.limits.maxCG}
value={targetZFWCG}
disabled={loadingState !== 'preview'}
increase={() =>
setTargetZFWCG((prev) => {
const _new = prev + 0.1;
updateData(undefined, _new);
return _new;
})
}
decrease={() =>
setTargetZFWCG((prev) => {
const _new = prev - 0.1;
updateData(undefined, _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-md bg-zinc-600 p-2 px-4">
<label>Fuel ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
@@ -158,14 +123,55 @@ const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoading
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
);
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
setFuelEnabled(false);
}}
disabled={loadingState !== 'preview' || fuel === Math.round(WASMData.livePayload.fuel)}
disabled={loadingState !== 'preview' || !fuelEnabled}
>
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>Target 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={ZFWTarget}
onChange={(e) => handleInputZFW(e.target.value)}
onBlur={(e) => handleBlur(e.target.value)}
disabled={loadingState !== 'preview'}
/>
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 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'}
increase={() =>
setCGTarget((prev) => {
const _new = prev + 0.1;
updateData(undefined, _new);
return _new;
})
}
decrease={() =>
setCGTarget((prev) => {
const _new = prev - 0.1;
updateData(undefined, _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>
@@ -176,7 +182,7 @@ const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoading
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()}
value={ZFW()}
/>
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
+9 -8
View File
@@ -6,7 +6,14 @@ export interface WASMDataPax {
limits: LimitsPax;
}
interface TargetPayloadPax {
interface TargetPayload {
CGTarget: number;
ZFWCG: number;
TOCG: number;
total: number;
}
interface TargetPayloadPax extends TargetPayload {
empty: number;
crew: number;
business1: number;
@@ -15,16 +22,13 @@ interface TargetPayloadPax {
economy2: number;
forwardCargo: number;
rearCargo: number;
ZFWCG: number;
TOCG: number;
total: number;
}
interface LivePayloadPax extends TargetPayloadPax {
fuel: number;
}
interface TargetPayloadF {
interface TargetPayloadF extends TargetPayload {
empty: number;
crew: number;
upper1: number;
@@ -33,9 +37,6 @@ interface TargetPayloadF {
upper4: number;
lowerForward: number;
lowerRear: number;
ZFWCG: number;
TOCG: number;
total: number;
}
interface LivePayloadF extends TargetPayloadF {