initial commit
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { FC } from 'react';
|
||||
import { SharedConfig } from '../../configs/shared';
|
||||
|
||||
interface CGSelectProps {
|
||||
value: number;
|
||||
disabled: boolean;
|
||||
increase: () => void;
|
||||
decrease: () => void;
|
||||
}
|
||||
|
||||
const CGSelect: FC<CGSelectProps> = ({ value, disabled, increase, decrease }) => {
|
||||
return (
|
||||
<div className="relative">
|
||||
<input
|
||||
disabled
|
||||
className="w-full rounded-lg border border-white bg-zinc-700 px-3 py-2 text-white shadow-sm focus:border-blue-600 focus:outline-none focus:ring-blue-600"
|
||||
value={value.toFixed(1)}
|
||||
/>
|
||||
<button
|
||||
disabled={disabled || value <= SharedConfig.CGLimits.min}
|
||||
className="absolute right-2 top-0 -mt-[.5px] border-t bg-zinc-700 text-white disabled:text-zinc-400"
|
||||
onClick={increase}
|
||||
>
|
||||
{/* FIXME: FONTAWESOME IN EFB */}
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fas"
|
||||
data-icon="caret-up"
|
||||
className="svg-inline--fa fa-caret-up "
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
style={{
|
||||
height: '1em',
|
||||
verticalAlign: '-0.125em',
|
||||
display: 'inline-block',
|
||||
boxSizing: 'content-box',
|
||||
}}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M182.6 137.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8H288c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
disabled={disabled || value >= SharedConfig.CGLimits.max}
|
||||
className="absolute bottom-0 right-2 -mt-[.5px] border-b bg-zinc-700 text-white disabled:text-zinc-400"
|
||||
onClick={decrease}
|
||||
>
|
||||
{/* FIXME: FONTAWESOME IN EFB */}
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
className="svg-inline--fa fa-caret-down "
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
style={{
|
||||
height: '1em',
|
||||
verticalAlign: '-0.125em',
|
||||
display: 'inline-block',
|
||||
boxSizing: 'content-box',
|
||||
}}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M137.4 374.6c12.5 12.5 32.8 12.5 45.3 0l128-128c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8L32 192c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l128 128z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CGSelect;
|
||||
@@ -0,0 +1,294 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
||||
import { Fuel, SharedConfig } from '../../configs/shared';
|
||||
import { ImportFlightPlan } from '../../utils/TFDISBImport';
|
||||
import CGSelect from '../CGSelect/CGSelect';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface StationEntryProps {
|
||||
unit: 'kg' | 'lbs';
|
||||
isER: boolean;
|
||||
initialPayload: PayloadPax;
|
||||
fuelLive: Fuel;
|
||||
payloadLive: PayloadPax;
|
||||
loadingState: 'preview' | 'accepted' | 'loaded';
|
||||
username: string;
|
||||
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
|
||||
updateView: (payload: PayloadPax) => void;
|
||||
loadAircraft: () => void;
|
||||
}
|
||||
|
||||
const SBEntryPax: FC<StationEntryProps> = ({
|
||||
unit,
|
||||
isER,
|
||||
initialPayload,
|
||||
fuelLive,
|
||||
payloadLive,
|
||||
loadingState,
|
||||
username,
|
||||
setLoadingState,
|
||||
updateView,
|
||||
loadAircraft,
|
||||
}) => {
|
||||
const [targetZFWCG, setTargetZFWCG] = useState(SharedConfig.CGLimits.default);
|
||||
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 [ZFW, setZFW] = useState(
|
||||
Math.round(
|
||||
PaxConfig.weights.base[unit].total +
|
||||
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
|
||||
payloadLive.empty +
|
||||
initialPayload.business1Left +
|
||||
initialPayload.business1Center +
|
||||
initialPayload.business1Right +
|
||||
initialPayload.business2Left +
|
||||
initialPayload.business2Center +
|
||||
initialPayload.business2Right +
|
||||
initialPayload.economy1Left +
|
||||
initialPayload.economy1Center +
|
||||
initialPayload.economy1Right +
|
||||
initialPayload.economy2Left +
|
||||
initialPayload.economy2Center +
|
||||
initialPayload.economy2Right +
|
||||
initialPayload.forwardCargo +
|
||||
initialPayload.rearCargo
|
||||
)
|
||||
);
|
||||
const [SBPlan, setSBPlan] = useState<any>();
|
||||
const [SBInFlight, setSBInFlight] = useState(false);
|
||||
|
||||
const _ZFW = () => {
|
||||
if (loadingState !== 'loaded') return ZFW;
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
const ZFWValid = () => {
|
||||
return _ZFW() <= PaxConfig.maxZWF[unit];
|
||||
};
|
||||
|
||||
const GW = () => {
|
||||
return fuel + _ZFW();
|
||||
};
|
||||
const GWValid = () => {
|
||||
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
|
||||
};
|
||||
|
||||
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, PaxConfig, unit, isER);
|
||||
if (SBResponse.type === 'error') {
|
||||
console.error('TODO: ERROR', SBResponse.message);
|
||||
setSBInFlight(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const __ZFW = Math.round(
|
||||
PaxConfig.weights.base[unit].total +
|
||||
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
|
||||
payloadLive.empty +
|
||||
SBResponse.message.pax * (PaxConfig.weights.pax[unit] + PaxConfig.weights.baggage[unit]) +
|
||||
SBResponse.message.cargo
|
||||
);
|
||||
const _fuel = SBResponse.message.fuel;
|
||||
|
||||
updateView(
|
||||
PaxConfig.distribute(__ZFW, targetZFWCG, payloadLive.empty, fuelLive, unit, isER, SBResponse.message.pax)
|
||||
);
|
||||
|
||||
setSBPlan(SBResponse.message);
|
||||
setZFW(__ZFW);
|
||||
setFuel(_fuel);
|
||||
setSBInFlight(false);
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
setFuel((prev) =>
|
||||
prev > (isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit])
|
||||
? isER
|
||||
? SharedConfig.maxFuel.er[unit]
|
||||
: SharedConfig.maxFuel.norm[unit]
|
||||
: prev
|
||||
),
|
||||
[isER]
|
||||
);
|
||||
|
||||
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>Planned ZFW ({unit})</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={SBPlan?.plannedZFW ?? 0}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Planned ZFW ({unit})</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={SBPlan?.plannedGW ?? 0}
|
||||
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 ({SharedConfig.CGLimits.min} - {SharedConfig.CGLimits.max})
|
||||
</label>
|
||||
<CGSelect
|
||||
value={targetZFWCG}
|
||||
disabled={loadingState !== 'preview'}
|
||||
increase={() =>
|
||||
setTargetZFWCG((prev) => {
|
||||
const _new = prev + 0.1;
|
||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
||||
return _new;
|
||||
})
|
||||
}
|
||||
decrease={() =>
|
||||
setTargetZFWCG((prev) => {
|
||||
const _new = prev - 0.1;
|
||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
||||
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 ({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
|
||||
/>
|
||||
<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' || SBInFlight}
|
||||
>
|
||||
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})
|
||||
</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' ? 'Expected' : 'Actual'} GW ({unit})
|
||||
</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}
|
||||
acceptDisabled={!GWValid() || SBInFlight}
|
||||
//TODO: Make GSX optional (accepted state for NON GSX)
|
||||
accept={() => setLoadingState('loaded')}
|
||||
reject={() => setLoadingState('preview')}
|
||||
importSB={handleSB}
|
||||
load={() => {
|
||||
setLoadingState('loaded');
|
||||
|
||||
loadAircraft();
|
||||
}}
|
||||
unload={() => {
|
||||
setLoadingState('preview');
|
||||
|
||||
PaxConfig.unload(unit, isER);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SBEntryPax;
|
||||
@@ -0,0 +1,73 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
interface ActionBarProps {
|
||||
loadingState: 'preview' | 'accepted' | 'loaded';
|
||||
acceptDisabled: boolean;
|
||||
accept: () => void;
|
||||
reject: () => void;
|
||||
importSB?: () => void;
|
||||
load: () => void;
|
||||
unload: () => void;
|
||||
}
|
||||
|
||||
const ActionBar: FC<ActionBarProps> = ({ loadingState, acceptDisabled, accept, reject, importSB, load, unload }) => {
|
||||
return (
|
||||
<div className="relative flex w-full items-center justify-start gap-x-6">
|
||||
{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={accept}
|
||||
disabled={acceptDisabled}
|
||||
>
|
||||
Accept
|
||||
</button>
|
||||
)}
|
||||
{/*TODO: Make GSX optional (accepted state for NON GSX) */}
|
||||
{loadingState === 'loaded' && (
|
||||
<button
|
||||
className="middle none center rounded-lg bg-red-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-red-500/20 transition-all hover:shadow-lg hover:shadow-red-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={reject}
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="grow" />
|
||||
|
||||
{!!importSB && 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={importSB}
|
||||
>
|
||||
Import from SimBrief
|
||||
</button>
|
||||
)}
|
||||
{/*TODO: Make GSX optional */}
|
||||
{/*
|
||||
{loadingState === 'accepted' && (
|
||||
<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={load}
|
||||
>
|
||||
Load
|
||||
</button>
|
||||
)}
|
||||
{loadingState === 'loaded' && (
|
||||
<button
|
||||
className="middle none center rounded-lg bg-red-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-red-500/20 transition-all hover:shadow-lg hover:shadow-red-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={unload}
|
||||
>
|
||||
Unload
|
||||
</button>
|
||||
)}
|
||||
*/}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionBar;
|
||||
@@ -0,0 +1,92 @@
|
||||
import { FC, useState } from 'react';
|
||||
import { PayloadFreight } from '../../configs/freighter';
|
||||
import { initialPayload, SharedConfig } from '../../configs/shared';
|
||||
import Profile from '../profile/Profile';
|
||||
import Tabbar from '../tabbar/Tabbar';
|
||||
|
||||
interface FreightProps {
|
||||
isER: boolean;
|
||||
unit: 'kg' | 'lbs';
|
||||
OEW: number;
|
||||
CGs: [number, number];
|
||||
}
|
||||
|
||||
const Freight: FC<FreightProps> = ({ isER, unit, OEW, CGs }) => {
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [payload, setPayload] = useState<PayloadFreight>(initialPayload);
|
||||
const [inPreview, setInPreview] = useState(true);
|
||||
|
||||
const upper1 = () => {
|
||||
return Math.round(payload.upper1Left + payload.upper1Right);
|
||||
};
|
||||
const upper2 = () => {
|
||||
return Math.round(payload.upper2Left + payload.upper2Right);
|
||||
};
|
||||
const upper3 = () => {
|
||||
return Math.round(payload.upper3Left + payload.upper3Right);
|
||||
};
|
||||
const upper4 = () => {
|
||||
return Math.round(payload.upper4Left + payload.upper4Right);
|
||||
};
|
||||
const lower1 = () => {
|
||||
return Math.round(payload.lowerForward);
|
||||
};
|
||||
const lower2 = () => {
|
||||
return Math.round(payload.lowerRear);
|
||||
};
|
||||
const _OEW = () => {
|
||||
return Math.round(OEW + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 1));
|
||||
};
|
||||
const crew = () => {
|
||||
return Math.round(payload.pilot + payload.firstOfficer + payload.engineer);
|
||||
};
|
||||
const cgs = (): [string, string] => {
|
||||
return [CGs[0].toFixed(1), CGs[1].toFixed(1)];
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Profile
|
||||
type="F"
|
||||
isER={isER}
|
||||
upper1={`${upper1()}`}
|
||||
upper2={`${upper2()}`}
|
||||
upper3={`${upper3()}`}
|
||||
upper4={`${upper4()}`}
|
||||
lower1={`${lower1()}`}
|
||||
lower2={`${lower2()}`}
|
||||
OEW={`${_OEW()}`}
|
||||
crew={`${crew()}`}
|
||||
unit={unit.toUpperCase()}
|
||||
inPreview={inPreview}
|
||||
CGs={cgs()}
|
||||
/>
|
||||
<Tabbar tabs={['Simbrief', 'ZFW', 'Cargo']} selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
|
||||
|
||||
<div className="relative flex w-full items-center justify-start gap-x-6">
|
||||
<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={() => {
|
||||
console.log('TODO: SET PAYLOAD IN SIM');
|
||||
setInPreview(false);
|
||||
}}
|
||||
>
|
||||
Load
|
||||
</button>
|
||||
<button
|
||||
className="middle none center rounded-lg bg-red-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-red-500/20 transition-all hover:shadow-lg hover:shadow-red-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={() => {
|
||||
console.log('TODO: CLEAR PAYLOAD IN SIM');
|
||||
setInPreview(true);
|
||||
}}
|
||||
>
|
||||
Unload
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Freight;
|
||||
@@ -0,0 +1,235 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
||||
import { Fuel, initialPayload, SharedConfig } from '../../configs/shared';
|
||||
import Profile from '../profile/Profile';
|
||||
import SBEntryPax from '../SBEntry/SBEntryPax';
|
||||
import StationEntryPax from '../stationEntry/StationEntryPax';
|
||||
import Tabbar from '../tabbar/Tabbar';
|
||||
import ZFWEntryPax from '../ZFWEntry/ZFWEntryPax';
|
||||
|
||||
interface PaxProps {
|
||||
isER: boolean;
|
||||
unit: 'kg' | 'lbs';
|
||||
CGs: [number, number];
|
||||
payloadLive: PayloadPax;
|
||||
fuelLive: Fuel;
|
||||
username?: string;
|
||||
GSXPaxNum: number;
|
||||
GSXCargoPercent: number;
|
||||
GSXState: 'boarding' | 'deboarding' | 'idle';
|
||||
}
|
||||
|
||||
const Pax: FC<PaxProps> = ({
|
||||
isER,
|
||||
unit,
|
||||
CGs,
|
||||
fuelLive,
|
||||
payloadLive,
|
||||
username,
|
||||
GSXPaxNum,
|
||||
GSXCargoPercent,
|
||||
GSXState,
|
||||
}) => {
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [payload, setPayload] = useState<PayloadPax>(initialPayload);
|
||||
const [loadingState, setLoadingState] = useState<'preview' | 'accepted' | 'loaded'>('preview');
|
||||
|
||||
const upper1 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||
if (overrideState !== 'loaded')
|
||||
return PaxConfig.weightToPax(payload.business1Left + payload.business1Center + payload.business1Right, unit);
|
||||
|
||||
return PaxConfig.weightToPax(
|
||||
payloadLive.business1Left + payloadLive.business1Center + payloadLive.business1Right,
|
||||
unit
|
||||
);
|
||||
};
|
||||
const upper2 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||
if (overrideState !== 'loaded')
|
||||
return PaxConfig.weightToPax(payload.business2Left + payload.business2Center + payload.business2Right, unit);
|
||||
|
||||
return PaxConfig.weightToPax(
|
||||
payloadLive.business2Left + payloadLive.business2Center + payloadLive.business2Right,
|
||||
unit
|
||||
);
|
||||
};
|
||||
const upper3 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||
if (overrideState !== 'loaded')
|
||||
return PaxConfig.weightToPax(payload.economy1Left + payload.economy1Center + payload.economy1Right, unit);
|
||||
|
||||
return PaxConfig.weightToPax(
|
||||
payloadLive.economy1Left + payloadLive.economy1Center + payloadLive.economy1Right,
|
||||
unit
|
||||
);
|
||||
};
|
||||
const upper4 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||
if (overrideState !== 'loaded')
|
||||
return PaxConfig.weightToPax(payload.economy2Left + payload.economy2Center + payload.economy2Right, unit);
|
||||
|
||||
return PaxConfig.weightToPax(
|
||||
payloadLive.economy2Left + payloadLive.economy2Center + payloadLive.economy2Right,
|
||||
unit
|
||||
);
|
||||
};
|
||||
const lower1 = () => {
|
||||
if (loadingState !== 'loaded') return Math.round(payload.forwardCargo);
|
||||
|
||||
return Math.round(payloadLive.forwardCargo);
|
||||
};
|
||||
const lower2 = () => {
|
||||
if (loadingState !== 'loaded') return Math.round(payload.rearCargo);
|
||||
|
||||
return Math.round(payloadLive.rearCargo);
|
||||
};
|
||||
const _OEW = () => {
|
||||
if (loadingState !== 'loaded')
|
||||
return Math.round(payloadLive.empty + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 1));
|
||||
|
||||
return Math.round(payloadLive.empty + payloadLive.leftAuxPax + payloadLive.rightAuxPax);
|
||||
};
|
||||
const crew = () => {
|
||||
if (loadingState !== 'loaded') return PaxConfig.weights.base[unit].total;
|
||||
|
||||
return Math.round(
|
||||
payloadLive.cabinCrewFront +
|
||||
payloadLive.cabinCrewRear +
|
||||
payloadLive.pilot +
|
||||
payloadLive.firstOfficer +
|
||||
payloadLive.engineer
|
||||
);
|
||||
};
|
||||
|
||||
const _CGs = (): [string, boolean, string, boolean] => {
|
||||
if (loadingState !== 'loaded') {
|
||||
const __CGs = PaxConfig.calculateCGs(
|
||||
{
|
||||
...payload,
|
||||
empty: payloadLive.empty,
|
||||
cabinCrewFront: PaxConfig.weights.base[unit].cabinCrewFront,
|
||||
cabinCrewRear: PaxConfig.weights.base[unit].cabinCrewRear,
|
||||
pilot: PaxConfig.weights.base[unit].pilot,
|
||||
firstOfficer: PaxConfig.weights.base[unit].firstOfficer,
|
||||
engineer: PaxConfig.weights.base[unit].engineer,
|
||||
leftAuxPax: isER ? SharedConfig.erExtraWeight[unit] : 0,
|
||||
rightAuxPax: isER ? SharedConfig.erExtraWeight[unit] : 0,
|
||||
},
|
||||
fuelLive
|
||||
);
|
||||
return [
|
||||
__CGs[0].toFixed(1),
|
||||
__CGs[0] < SharedConfig.CGLimits.min || __CGs[0] > SharedConfig.CGLimits.max,
|
||||
__CGs[1].toFixed(1),
|
||||
__CGs[1] < SharedConfig.CGLimits.min || __CGs[1] > SharedConfig.CGLimits.max,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
CGs[0].toFixed(1),
|
||||
CGs[0] < SharedConfig.CGLimits.min || CGs[0] > SharedConfig.CGLimits.max,
|
||||
CGs[1].toFixed(1),
|
||||
CGs[1] < SharedConfig.CGLimits.min || CGs[1] > SharedConfig.CGLimits.max,
|
||||
];
|
||||
};
|
||||
|
||||
//TODO: Make GSX optional
|
||||
useEffect(() => {
|
||||
if (GSXState === 'idle') return;
|
||||
|
||||
PaxConfig.setWeightsProgressive(
|
||||
payload,
|
||||
GSXState === 'boarding' ? GSXPaxNum : payload.paxCount.total - GSXPaxNum,
|
||||
GSXCargoPercent,
|
||||
unit
|
||||
);
|
||||
}, [GSXPaxNum, GSXCargoPercent, GSXState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Profile
|
||||
type="PAX"
|
||||
isER={isER}
|
||||
upper1={`${upper1()}`}
|
||||
upper1max={loadingState === 'loaded' ? `${upper1('preview')}` : `${PaxConfig.stationMax.business1}`}
|
||||
upper2={`${upper2()}`}
|
||||
upper2max={loadingState === 'loaded' ? `${upper2('preview')}` : `${PaxConfig.stationMax.business2}`}
|
||||
upper3={`${upper3()}`}
|
||||
upper3max={loadingState === 'loaded' ? `${upper3('preview')}` : `${PaxConfig.stationMax.economy1}`}
|
||||
upper4={`${upper4()}`}
|
||||
upper4max={loadingState === 'loaded' ? `${upper4('preview')}` : `${PaxConfig.stationMax.economy2}`}
|
||||
lower1={`${lower1()}`}
|
||||
lower2={`${lower2()}`}
|
||||
OEW={`${_OEW()}`}
|
||||
crew={`${crew()}`}
|
||||
unit={unit.toUpperCase()}
|
||||
inPreview={loadingState !== 'loaded'}
|
||||
CGs={_CGs()}
|
||||
/>
|
||||
<Tabbar
|
||||
tabs={
|
||||
username ? ['Simbrief', 'ZFW', 'Passengers & Cargo', 'Options'] : ['ZFW', 'Passengers & Cargo', 'Options']
|
||||
}
|
||||
selectedTab={selectedTab}
|
||||
setSelectedTab={setSelectedTab}
|
||||
/>
|
||||
|
||||
{username && selectedTab === 0 && (
|
||||
<SBEntryPax
|
||||
unit={unit}
|
||||
isER={isER}
|
||||
initialPayload={payload}
|
||||
fuelLive={fuelLive}
|
||||
payloadLive={payloadLive}
|
||||
loadingState={loadingState}
|
||||
username={username}
|
||||
setLoadingState={setLoadingState}
|
||||
updateView={(_payload) => {
|
||||
setPayload(_payload);
|
||||
}}
|
||||
loadAircraft={() => {
|
||||
PaxConfig.setBaseWeight(unit, isER);
|
||||
PaxConfig.setWeights(payload, unit);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
|
||||
<ZFWEntryPax
|
||||
unit={unit}
|
||||
isER={isER}
|
||||
initialPayload={payload}
|
||||
fuelLive={fuelLive}
|
||||
payloadLive={payloadLive}
|
||||
loadingState={loadingState}
|
||||
setLoadingState={setLoadingState}
|
||||
updateView={(_payload) => {
|
||||
setPayload(_payload);
|
||||
}}
|
||||
loadAircraft={() => {
|
||||
PaxConfig.setBaseWeight(unit, isER);
|
||||
PaxConfig.setWeights(payload, unit);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
|
||||
<StationEntryPax
|
||||
unit={unit}
|
||||
isER={isER}
|
||||
initialPayload={payload}
|
||||
fuelLive={fuelLive}
|
||||
payloadLive={payloadLive}
|
||||
loadingState={loadingState}
|
||||
setLoadingState={setLoadingState}
|
||||
updateView={(_payload) => {
|
||||
setPayload(_payload);
|
||||
}}
|
||||
loadAircraft={() => {
|
||||
PaxConfig.setBaseWeight(unit, isER);
|
||||
PaxConfig.setWeights(payload, unit);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pax;
|
||||
@@ -0,0 +1,14 @@
|
||||
.stroke-zinc-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
stroke: rgba(82, 82, 91, var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.fill-neutral-500 {
|
||||
--tw-text-opacity: 1;
|
||||
fill: rgba(115, 115, 115, var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.fill-red-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
fill: rgba(239, 68, 68, var(--tw-bg-opacity));
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
import styles from './Profile.module.scss';
|
||||
|
||||
interface ProfileProps {
|
||||
type: 'F' | 'PAX';
|
||||
isER: boolean;
|
||||
upper1: string;
|
||||
upper1max?: string;
|
||||
upper2: string;
|
||||
upper2max?: string;
|
||||
upper3: string;
|
||||
upper3max?: string;
|
||||
upper4: string;
|
||||
upper4max?: string;
|
||||
lower1: string;
|
||||
lower2: string;
|
||||
OEW: string;
|
||||
crew: string;
|
||||
CGs: [string, boolean, string, boolean];
|
||||
unit: string;
|
||||
inPreview: boolean;
|
||||
}
|
||||
|
||||
const Profile: FC<ProfileProps> = ({
|
||||
type,
|
||||
isER,
|
||||
upper1,
|
||||
upper1max,
|
||||
upper2,
|
||||
upper2max,
|
||||
upper3,
|
||||
upper3max,
|
||||
upper4,
|
||||
upper4max,
|
||||
lower1,
|
||||
lower2,
|
||||
OEW,
|
||||
crew,
|
||||
CGs,
|
||||
unit,
|
||||
inPreview,
|
||||
}) => {
|
||||
const previewClass = inPreview ? styles['fill-neutral-500'] : undefined;
|
||||
const ZFWCGClass = CGs[1] ? styles['fill-red-500'] : previewClass;
|
||||
const TOCGClass = CGs[3] ? styles['fill-red-500'] : previewClass;
|
||||
|
||||
return (
|
||||
<svg viewBox="0 0 4002 780" version="1.1" xmlns="http://www.w3.org/2000/svg" className="mb-4">
|
||||
<path
|
||||
style={{
|
||||
fill: 'none',
|
||||
strokeWidth: 4,
|
||||
strokeLinecap: 'butt',
|
||||
strokeLinejoin: 'miter',
|
||||
}}
|
||||
className={styles['stroke-zinc-600']}
|
||||
d="m 1748.2487,624.45529 v 83.5816 z m 653.1368,98.40409 v 43.08593 z"
|
||||
transform="matrix(1.0068517,0,0,1.0069072,-24.265193,-12.003831)"
|
||||
/>
|
||||
<path
|
||||
style={{
|
||||
fill: 'none',
|
||||
stroke: 'white',
|
||||
strokeWidth: 4,
|
||||
strokeLinecap: 'butt',
|
||||
strokeLinejoin: 'round',
|
||||
}}
|
||||
d="m 119.50997,573.71703 h 128.0729 v 29.07865 h 119.1481 M 1922.9882,624.6584 V 378.08519 Z M 1143.9838,378.54476 v 246.57126 z m 1556.0004,1.0854 3e-4,245.70686 0.01,-245.70686 z M 119.47872,507.3493 V 686.42638 Z M 681.8277,784.08016 C 550.68986,778.56008 459.37243,767.83734 325.24777,742.2102 247.12441,727.28325 163.85922,704.53832 115.68874,684.96689 65.272866,664.48337 30.640554,635.98924 26.748642,611.79065 c -3.768329,-23.42962 7.455828,-38.32595 50.49813,-67.01953 6.041298,-4.02691 12.708263,-9.27073 14.816577,-11.65295 2.108023,-2.3822 4.524361,-4.48001 4.524361,-4.48001 0,0 45.05507,-44.22564 69.74451,-58.59581 72.48275,-42.18783 238.75927,-76.44031 425.63149,-87.67895 14.00372,-0.84197 33.99829,-2.07064 44.43261,-2.72959 26.21726,-1.65646 1973.24248,-2.45294 2062.36198,-0.84445 156.7316,2.82998 269.5005,7.74134 530.5511,23.10724 47.1495,2.7752 85.8534,4.90642 86.012,4.73564 0.6463,-0.69433 3.18,-46.35302 2.6116,-47.00235 -0.3392,-0.38606 -8.4798,-1.63074 -18.0917,-2.7653 -35.3422,-4.17401 -67.399,-11.82474 -77.0779,-18.39697 -3.9158,-2.65808 -3.9645,-3.95085 -1.9416,-51.11949 2.108,-49.16104 3.1187,-81.48815 3.1285,-100.00521 0,-21.77363 -0.1657,-21.37816 11.1206,-24.94772 37.4058,-11.83133 117.8811,-11.06942 171.1122,1.62031 15.227,3.62986 19.589,3.51496 35.5372,-0.93615 21.7001,-6.05753 21.0601,-5.51568 96.6373,-82.052719 33.1386,-33.558758 68.757,-66.037569 68.757,-66.037569 0,0 83.3796,-1.079949 169.2388,-1.079949 136.9782,0 171.6165,0.253341 171.2179,1.25017 -4.4107,11.004128 -56.5812,125.499597 -58.6917,128.808777 -4.6101,7.22481 -3.2139,7.88313 16.7587,7.90201 9.0622,0.008 22.5343,1.10293 37.2289,3.0234 4.1187,0.5386 15.3536,1.65343 24.9606,2.47749 9.6122,0.82422 19.8325,1.75756 22.7175,2.07418 5.0681,0.55713 9.0514,198.40717 3.9934,198.38178 -3.6049,-0.0227 -31.7008,3.23584 -34.6991,4.01865 -1.9198,0.50162 -6.9752,1.19264 -11.2312,1.53478 -7.7386,0.62215 -7.7386,0.62215 -7.7386,8.4184 0,8.93284 0.045,8.97847 9.985,9.03089 7.595,0.034 9.8124,1.63453 3.4137,2.45321 -2.7018,0.34575 -6.0356,0.83238 -7.4075,1.08266 -1.3721,0.25018 -13.4624,0.89408 -26.8658,1.43238 -13.4009,0.53851 -28.9024,1.4418 -34.4462,2.00812 -15.6072,1.59497 -41.7208,3.01042 -55.6346,3.01554 -20.6343,0.008 -19.0304,-1.48851 -18.6619,17.4164 0.3714,19.01843 2.3134,23.86211 11.5516,28.7958 5.5848,2.98376 0.3035,2.54795 88.3399,7.28999 84.7141,4.56302 75.158,-2.81091 75.158,57.97778 0,54.09028 0.038,53.96894 -18.7912,59.84504 -20.4081,6.36957 -118.4497,34.30825 -182.9044,52.12181 -74.4105,20.56545 -152.6321,42.51798 -160.2541,44.9738 -10.5871,3.41069 -57.1162,16.38817 -105.4333,29.40502 -184.6228,49.73829 -402.0471,89.78228 -516.1218,95.05681 -19.1654,0.88577 -2300.07154,1.25614 -2320.9699,0.37695 z m 1714.3911,-15.93638 c 14.3101,-1.72862 35.0046,-5.59211 45.932,-8.57466 47.3734,-12.93067 34.3571,-20.57346 -70.3941,-41.33854 -9.3343,-1.85054 -21.9156,-4.53045 -27.9568,-5.955 -119.2244,-28.11802 -135.9358,-31.16723 -227.3866,-41.48667 -32.4779,-3.66487 -84.0049,-11.3955 -126.5748,-18.9901 -77.6003,-13.84405 -129.5471,-21.9553 -156.762,-24.47858 -178.2016,-16.52165 -260.2497,38.68714 -109.1224,73.42801 7.2586,1.66798 18.9422,5.29576 25.9629,8.06195 39.3007,15.48166 111.0211,26.35086 233.4296,35.37682 97.5092,7.1897 247.1876,10.13705 247.9345,4.88196 0.6641,-4.66361 1.511,-4.79998 36.7154,-5.88569 22.9808,-0.70847 26.3783,-0.21481 26.3783,3.83836 0,2.5877 2.9594,14.02473 3.8762,14.97665 0.4007,0.41452 15.6685,2.27843 33.9288,4.14116 18.264,1.86268 33.4272,3.60903 33.698,3.88056 0.7657,0.76635 16.5438,-0.20912 30.341,-1.87623 z m -2029.36746,-359.3222 -0.0248,215.97654 1275.64716,-4.1e-4 h 1275.1949 l 132.9522,-2.46652 132.952,-2.4665 147.9241,-11.4452 147.9243,-11.4452 1.0236,-90.88061 1.0235,-90.88061 -83.3015,-4.35422 -83.3014,-4.35424 m -2614.52231,217.81122 -5e-5,159.11801 z M 1748.1434,708.5565 v 75.45385 z m 1663.0399,-106.30033 -1e-4,113.31756 z m -1009.9445,22.54108 v 99.39317 z m -4e-4,143.38207 v 15.78331 z"
|
||||
transform="matrix(1.0068517,0,0,1.0069072,-24.265193,-12.003831)"
|
||||
/>
|
||||
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="725.61609" y="591.34473" textAnchor="middle">
|
||||
<tspan className={previewClass}>{upper1}</tspan>
|
||||
{upper1max && <tspan>/{upper1max}</tspan>}
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1509.024" y="591.34473" textAnchor="middle">
|
||||
<tspan className={previewClass}>{upper2}</tspan>
|
||||
{upper2max && <tspan>/{upper2max}</tspan>}
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="2292.3511" y="591.34473" textAnchor="middle">
|
||||
<tspan className={previewClass}>{upper3}</tspan>
|
||||
{upper3max && <tspan>/{upper3max}</tspan>}
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="3075.8955" y="591.34473" textAnchor="middle">
|
||||
<tspan className={previewClass}>{upper4}</tspan>
|
||||
{upper4max && <tspan>/{upper4max}</tspan>}
|
||||
</text>
|
||||
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1197.6641" y="754.35504" textAnchor="middle">
|
||||
<tspan className={previewClass}>{lower1}</tspan>
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="2891.1475" y="754.35504" textAnchor="middle">
|
||||
<tspan className={previewClass}>{lower2}</tspan>
|
||||
</text>
|
||||
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="0" y="280.10175">
|
||||
{type === 'F' ? 'Pilots:' : 'Pilots & FAs:'}
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1476.2501" y="280.10175" textAnchor="end">
|
||||
<tspan className={previewClass}>{crew}</tspan>
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="0" y="130.625">
|
||||
OEW:
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1476.2501" y="130.625" textAnchor="end">
|
||||
{OEW}
|
||||
</text>
|
||||
|
||||
<text style={{ fill: 'white', fontSize: '100px' }} x="4002" y="778.24402" textAnchor="end">
|
||||
<tspan style={{ fontSize: '70px' }}>all in </tspan>
|
||||
<tspan>{unit}</tspan>
|
||||
</text>
|
||||
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1730.4194" y="142.15625">
|
||||
ZFWCG:
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="2540.771" y="142.15625">
|
||||
<tspan className={ZFWCGClass}>{CGs[0]}</tspan>
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="1730.4194" y="288.875">
|
||||
TOCG:
|
||||
</text>
|
||||
<text style={{ fill: 'white', fontSize: '160px' }} x="2540.771" y="288.875">
|
||||
<tspan className={TOCGClass}>{CGs[2]}</tspan>
|
||||
</text>
|
||||
|
||||
<path
|
||||
style={{
|
||||
fill: 'none',
|
||||
stroke: 'white',
|
||||
strokeWidth: 8,
|
||||
strokeLinecap: 'butt',
|
||||
strokeLinejoin: 'round',
|
||||
opacity: isER ? 1 : 0,
|
||||
}}
|
||||
d="m 3616.1269,203.67131 -115.4682,116.32951 h 76.6132 l 13.6484,-13.75016 h -61.1499 l 42.8836,-43.20365 h 61.1499 l 13.6485,-13.75016 h -61.1499 l 31.6393,-31.87538 h 61.1499 l 13.6484,-13.75016 z m 101.1357,0 -115.4682,116.32951 h 15.4631 l 45.9082,-46.25055 h 21.7891 l -7.0158,46.25055 h 20.0709 l 6.7491,-50.85999 c 10.2365,-2.8646 20.2552,-7.10948 30.0559,-12.73452 9.8522,-5.67714 18.9402,-12.70852 27.2636,-21.09401 6.1521,-6.19797 10.0211,-11.30222 11.6068,-15.31268 1.6896,-4.06255 1.7441,-7.42197 0.1635,-10.07824 -1.4223,-2.34378 -4.0367,-3.95839 -7.8438,-4.84382 -3.7552,-0.93749 -9.1472,-1.40626 -16.176,-1.40625 z m 2.2801,13.2814 h 18.1967 c 4.165,0 7.4735,0.31252 9.9248,0.93751 2.5032,0.57292 4.1244,1.61462 4.8641,3.12503 0.9495,1.77087 0.7045,3.9584 -0.735,6.56258 -1.3356,2.55212 -3.6579,5.49487 -6.9666,8.82824 -4.3426,4.37505 -8.5084,7.9949 -12.4972,10.8595 -3.8849,2.81253 -8.0847,5.31258 -12.5989,7.50009 -4.8776,2.34378 -9.5781,3.95838 -14.1015,4.84381 -4.4716,0.83333 -9.1546,1.25002 -14.0487,1.25002 h -15.6194 z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
@@ -0,0 +1,309 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
||||
import { Fuel, SharedConfig } from '../../configs/shared';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface StationEntryProps {
|
||||
unit: 'kg' | 'lbs';
|
||||
isER: boolean;
|
||||
initialPayload: PayloadPax;
|
||||
fuelLive: Fuel;
|
||||
payloadLive: PayloadPax;
|
||||
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 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
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
const ZFWValid = () => {
|
||||
return ZFW() <= PaxConfig.maxZWF[unit];
|
||||
};
|
||||
|
||||
const GW = () => {
|
||||
return fuel + ZFW();
|
||||
};
|
||||
const GWValid = () => {
|
||||
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => _updateView(), [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]
|
||||
);
|
||||
|
||||
const _updateView = () => {
|
||||
const payload = PaxConfig.generateDistribution(
|
||||
payloadLive.empty,
|
||||
business1,
|
||||
business2,
|
||||
economy1,
|
||||
economy2,
|
||||
forwardCargo,
|
||||
rearCargo,
|
||||
unit,
|
||||
isER
|
||||
);
|
||||
|
||||
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-t-md bg-zinc-600 p-2 px-4">
|
||||
<label>Business</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={business1}
|
||||
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.business1, setBusiness1)}
|
||||
disabled={loadingState !== 'preview'}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Premium Economy</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={business2}
|
||||
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.business2, setBusiness2)}
|
||||
disabled={loadingState !== 'preview'}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-600 p-2 px-4">
|
||||
<label>Forward Economy</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={economy1}
|
||||
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.economy1, setEconomy1)}
|
||||
disabled={loadingState !== 'preview'}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Aft Economy</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={economy2}
|
||||
onChange={(e) => handleInput(e.target.value, PaxConfig.stationMax.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>
|
||||
<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)}
|
||||
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>
|
||||
<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)}
|
||||
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})
|
||||
</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' ? 'Expected' : 'Actual'} GW ({unit})
|
||||
</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}
|
||||
acceptDisabled={!ZFWValid() || !GWValid()}
|
||||
accept={() => setLoadingState('accepted')}
|
||||
reject={() => setLoadingState('preview')}
|
||||
load={() => {
|
||||
setLoadingState('loaded');
|
||||
|
||||
loadAircraft();
|
||||
}}
|
||||
unload={() => {
|
||||
setLoadingState('preview');
|
||||
|
||||
PaxConfig.unload(unit, isER);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StationEntryPax;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
interface TabbarProps {
|
||||
tabs: string[];
|
||||
selectedTab: number;
|
||||
setSelectedTab: (tab: number) => void;
|
||||
}
|
||||
|
||||
const Tabbar: FC<TabbarProps> = ({ tabs, selectedTab, setSelectedTab }) => {
|
||||
return (
|
||||
<ul className="mb-4 flex list-none flex-row flex-wrap border-b-0 pl-0">
|
||||
{tabs.map((tab, i) => (
|
||||
<li key={`${tab}-${i}`}>
|
||||
<button
|
||||
key={i}
|
||||
className={`${selectedTab === i ? 'text-white underline' : 'text-neutral-500'} my-2 block border-x-0 border-b-2 border-t-0 border-slate-100 bg-zinc-900 px-7 text-sm font-medium uppercase`}
|
||||
onClick={() => setSelectedTab(i)}
|
||||
>
|
||||
{tab}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tabbar;
|
||||
@@ -0,0 +1,284 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
||||
import { Fuel, SharedConfig } from '../../configs/shared';
|
||||
import CGSelect from '../CGSelect/CGSelect';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface StationEntryProps {
|
||||
unit: 'kg' | 'lbs';
|
||||
isER: boolean;
|
||||
initialPayload: PayloadPax;
|
||||
fuelLive: Fuel;
|
||||
payloadLive: PayloadPax;
|
||||
loadingState: 'preview' | 'accepted' | 'loaded';
|
||||
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
|
||||
updateView: (payload: PayloadPax) => void;
|
||||
loadAircraft: () => void;
|
||||
}
|
||||
|
||||
const ZFWEntryPax: FC<StationEntryProps> = ({
|
||||
unit,
|
||||
isER,
|
||||
initialPayload,
|
||||
fuelLive,
|
||||
payloadLive,
|
||||
loadingState,
|
||||
setLoadingState,
|
||||
updateView,
|
||||
loadAircraft,
|
||||
}) => {
|
||||
const [targetZFWCG, setTargetZFWCG] = useState(SharedConfig.CGLimits.default);
|
||||
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 [ZFW, setZFW] = useState(
|
||||
Math.round(
|
||||
PaxConfig.weights.base[unit].total +
|
||||
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
|
||||
payloadLive.empty +
|
||||
initialPayload.business1Left +
|
||||
initialPayload.business1Center +
|
||||
initialPayload.business1Right +
|
||||
initialPayload.business2Left +
|
||||
initialPayload.business2Center +
|
||||
initialPayload.business2Right +
|
||||
initialPayload.economy1Left +
|
||||
initialPayload.economy1Center +
|
||||
initialPayload.economy1Right +
|
||||
initialPayload.economy2Left +
|
||||
initialPayload.economy2Center +
|
||||
initialPayload.economy2Right +
|
||||
initialPayload.forwardCargo +
|
||||
initialPayload.rearCargo
|
||||
)
|
||||
);
|
||||
|
||||
const _ZFW = () => {
|
||||
if (loadingState !== 'loaded') return ZFW;
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
const ZFWValid = () => {
|
||||
return _ZFW() <= PaxConfig.maxZWF[unit];
|
||||
};
|
||||
|
||||
const GW = () => {
|
||||
return fuel + _ZFW();
|
||||
};
|
||||
const GWValid = () => {
|
||||
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
|
||||
};
|
||||
|
||||
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 handleInputZFW = (input: string) => {
|
||||
if (!input) return;
|
||||
|
||||
const converted = parseInt(input);
|
||||
if (converted) {
|
||||
if (converted < 0)
|
||||
setZFW(
|
||||
Math.round(
|
||||
PaxConfig.weights.base[unit].total + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) + payloadLive.empty
|
||||
)
|
||||
);
|
||||
else if (converted > PaxConfig.maxZWF[unit]) setZFW(PaxConfig.maxZWF[unit]);
|
||||
else setZFW(converted);
|
||||
}
|
||||
};
|
||||
const handleBlur = (input: string) => {
|
||||
const minZFW = Math.round(
|
||||
PaxConfig.weights.base[unit].total + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) + payloadLive.empty
|
||||
);
|
||||
|
||||
if (!input) {
|
||||
setZFW(minZFW);
|
||||
return;
|
||||
}
|
||||
|
||||
const converted = parseInt(input);
|
||||
if (converted) {
|
||||
if (converted < minZFW) setZFW(minZFW);
|
||||
else if (converted > PaxConfig.maxZWF[unit]) setZFW(PaxConfig.maxZWF[unit]);
|
||||
else setZFW(converted);
|
||||
}
|
||||
|
||||
updateView(PaxConfig.distribute(converted, targetZFWCG, payloadLive.empty, fuelLive, unit, isER));
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
setFuel((prev) =>
|
||||
prev > (isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit])
|
||||
? isER
|
||||
? SharedConfig.maxFuel.er[unit]
|
||||
: SharedConfig.maxFuel.norm[unit]
|
||||
: prev
|
||||
),
|
||||
[isER]
|
||||
);
|
||||
|
||||
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 ({unit})</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 ({SharedConfig.CGLimits.min} - {SharedConfig.CGLimits.max})
|
||||
</label>
|
||||
<CGSelect
|
||||
value={targetZFWCG}
|
||||
disabled={loadingState !== 'preview'}
|
||||
increase={() =>
|
||||
setTargetZFWCG((prev) => {
|
||||
const _new = prev + 0.1;
|
||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
||||
return _new;
|
||||
})
|
||||
}
|
||||
decrease={() =>
|
||||
setTargetZFWCG((prev) => {
|
||||
const _new = prev - 0.1;
|
||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
||||
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 ({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})
|
||||
</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' ? 'Expected' : 'Actual'} GW ({unit})
|
||||
</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}
|
||||
acceptDisabled={!GWValid()}
|
||||
accept={() => setLoadingState('accepted')}
|
||||
reject={() => setLoadingState('preview')}
|
||||
load={() => {
|
||||
setLoadingState('loaded');
|
||||
|
||||
loadAircraft();
|
||||
}}
|
||||
unload={() => {
|
||||
setLoadingState('preview');
|
||||
|
||||
PaxConfig.unload(unit, isER);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ZFWEntryPax;
|
||||
Reference in New Issue
Block a user