Freighter
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import Freighter from './components/freighter/Freighter';
|
||||
import Pax from './components/pax/Pax';
|
||||
import {
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
@@ -6,7 +7,7 @@ import {
|
||||
TFDI_SIMBRIEF_USERNAME_CALL,
|
||||
TFDI_SIMBRIEF_USERNAME_EVENT,
|
||||
} from './constants';
|
||||
import { WASMDataPax } from './types/WASMData';
|
||||
import { WASMDataF, WASMDataPax } from './types/WASMData';
|
||||
|
||||
interface IAppProps {
|
||||
commBus: ViewListener.ViewListener;
|
||||
@@ -14,7 +15,7 @@ interface IAppProps {
|
||||
|
||||
const App: FC<IAppProps> = ({ commBus }) => {
|
||||
const [SBUsername, setSBUsername] = useState<string>();
|
||||
const [WASMData, setWASMData] = useState<WASMDataPax>();
|
||||
const [WASMData, setWASMData] = useState<WASMDataPax | WASMDataF>();
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
// CommBus
|
||||
@@ -46,9 +47,9 @@ const App: FC<IAppProps> = ({ commBus }) => {
|
||||
<div className="flex w-3/4 flex-col items-center">
|
||||
{isReady && WASMData ? (
|
||||
WASMData.userData.isCargo ? (
|
||||
<>Not yet Implemented</>
|
||||
<Freighter WASMData={WASMData as WASMDataF} username={SBUsername} />
|
||||
) : (
|
||||
<Pax WASMData={WASMData} username={SBUsername} />
|
||||
<Pax WASMData={WASMData as WASMDataPax} username={SBUsername} />
|
||||
)
|
||||
) : (
|
||||
<h1 className="text-sm font-medium">LOADING</h1>
|
||||
|
||||
@@ -1,44 +1,40 @@
|
||||
| Department | Related to | Name | License period | Material not material | License type | Link | Remote version | Installed version | Defined version | Author |
|
||||
| :--------- | :--------- | :------------------------------- | :------------- | :-------------------- | :----------- | :------------------------------------------------------------------------ | :------------- | :---------------- | :-------------- | :---------------------------------------------------------- |
|
||||
| kessler | stuff | @emotion/react | perpetual | material | MIT | git+https://github.com/emotion-js/emotion.git#main | 11.14.0 | 11.14.0 | ^11.11.1 | Emotion Contributors |
|
||||
| kessler | stuff | @emotion/styled | perpetual | material | MIT | git+https://github.com/emotion-js/emotion.git#main | 11.14.0 | 11.14.0 | ^11.11.0 | n/a |
|
||||
| kessler | stuff | @mui/icons-material | perpetual | material | MIT | git+https://github.com/mui/material-ui.git | 5.17.1 | 5.17.1 | ^5.14.16 | MUI Team |
|
||||
| kessler | stuff | @mui/material | perpetual | material | MIT | git+https://github.com/mui/material-ui.git | 5.17.1 | 5.17.1 | ^5.14.17 | MUI Team |
|
||||
| kessler | stuff | postcss-import | perpetual | material | MIT | git+https://github.com/postcss/postcss-import.git | 15.1.0 | 15.1.0 | ^15.1.0 | Maxime Thirouin |
|
||||
| kessler | stuff | react | perpetual | material | MIT | git+https://github.com/facebook/react.git | 18.3.1 | 18.3.1 | ^18.2.0 | n/a |
|
||||
| kessler | stuff | react-dom | perpetual | material | MIT | git+https://github.com/facebook/react.git | 18.3.1 | 18.3.1 | ^18.2.0 | n/a |
|
||||
| kessler | stuff | uuid | perpetual | material | MIT | git+https://github.com/uuidjs/uuid.git | 9.0.1 | 9.0.1 | ^9.0.1 | n/a |
|
||||
| kessler | stuff | react | perpetual | material | MIT | git+https://github.com/facebook/react.git | 19.1.0 | 19.1.0 | ^19.1.0 | n/a |
|
||||
| kessler | stuff | react-dom | perpetual | material | MIT | git+https://github.com/facebook/react.git | 19.1.0 | 19.1.0 | ^19.1.0 | n/a |
|
||||
| kessler | stuff | uuid | perpetual | material | MIT | git+https://github.com/uuidjs/uuid.git | 11.1.0 | 11.1.0 | ^11.1.0 | n/a |
|
||||
| kessler | stuff | @microsoft/msfs-types | perpetual | material | MIT | git+https://github.com/microsoft/msfs-avionics-mirror.git | 1.14.6 | 1.14.6 | ^1.14.6 | Asobo Studio / Working Title Simulations |
|
||||
| kessler | stuff | @rollup/plugin-commonjs | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 25.0.8 | 25.0.8 | ^25.0.0 | Rich Harris <richard.a.harris@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-json | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 6.1.0 | 6.1.0 | ^6.0.0 | rollup |
|
||||
| kessler | stuff | @rollup/plugin-node-resolve | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 15.3.1 | 15.3.1 | ^15.1.0 | Rich Harris <richard.a.harris@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-commonjs | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 28.0.5 | 28.0.3 | ^28.0.3 | Rich Harris <richard.a.harris@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-json | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 6.1.0 | 6.1.0 | ^6.1.0 | rollup |
|
||||
| kessler | stuff | @rollup/plugin-node-resolve | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 16.0.1 | 16.0.1 | ^16.0.1 | Rich Harris <richard.a.harris@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-replace | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 6.0.2 | 6.0.2 | ^6.0.2 | Rich Harris <richard.a.harris@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-terser | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 0.4.4 | 0.4.4 | ^0.4.3 | Peter Placzek <peter.placzek1996@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-typescript | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 11.1.6 | 11.1.6 | ^11.1.1 | Oskar Segersvärd |
|
||||
| kessler | stuff | @types/react | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 18.3.23 | 18.3.23 | ^18.2.8 | n/a |
|
||||
| kessler | stuff | @types/react-dom | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 18.3.7 | 18.3.7 | ^18.2.4 | n/a |
|
||||
| kessler | stuff | @types/uuid | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 9.0.8 | 9.0.8 | ^9.0.7 | n/a |
|
||||
| kessler | stuff | @typescript-eslint/eslint-plugin | perpetual | material | MIT | git+https://github.com/typescript-eslint/typescript-eslint.git | 6.21.0 | 6.21.0 | ^6.10.0 | n/a |
|
||||
| kessler | stuff | @typescript-eslint/parser | perpetual | material | BSD-2-Clause | git+https://github.com/typescript-eslint/typescript-eslint.git | 6.21.0 | 6.21.0 | ^6.10.0 | n/a |
|
||||
| kessler | stuff | autoprefixer | perpetual | material | MIT | git+https://github.com/postcss/autoprefixer.git | 10.4.21 | 10.4.21 | ^10.4.14 | Andrey Sitnik <andrey@sitnik.ru> |
|
||||
| kessler | stuff | @rollup/plugin-terser | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 0.4.4 | 0.4.4 | ^0.4.4 | Peter Placzek <peter.placzek1996@gmail.com> |
|
||||
| kessler | stuff | @rollup/plugin-typescript | perpetual | material | MIT | git+https://github.com/rollup/plugins.git | 12.1.2 | 12.1.2 | ^12.1.2 | Oskar Segersvärd |
|
||||
| kessler | stuff | @types/react | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 19.1.8 | 19.1.6 | ^19.1.6 | n/a |
|
||||
| kessler | stuff | @types/react-dom | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 19.1.6 | 19.1.6 | ^19.1.6 | n/a |
|
||||
| kessler | stuff | @types/uuid | perpetual | material | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped.git | 10.0.0 | 10.0.0 | ^10.0.0 | n/a |
|
||||
| kessler | stuff | @typescript-eslint/eslint-plugin | perpetual | material | MIT | git+https://github.com/typescript-eslint/typescript-eslint.git | 6.21.0 | 6.21.0 | ^6.21.0 | n/a |
|
||||
| kessler | stuff | @typescript-eslint/parser | perpetual | material | BSD-2-Clause | git+https://github.com/typescript-eslint/typescript-eslint.git | 6.21.0 | 6.21.0 | ^6.21.0 | n/a |
|
||||
| kessler | stuff | autoprefixer | perpetual | material | MIT | git+https://github.com/postcss/autoprefixer.git | 10.4.21 | 10.4.21 | ^10.4.21 | Andrey Sitnik <andrey@sitnik.ru> |
|
||||
| kessler | stuff | cross-env | perpetual | material | MIT | git+https://github.com/kentcdodds/cross-env.git | 7.0.3 | 7.0.3 | ^7.0.3 | Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com) |
|
||||
| kessler | stuff | eslint | perpetual | material | MIT | git+https://github.com/eslint/eslint.git | 8.57.1 | 8.57.1 | ^8.42.0 | Nicholas C. Zakas <nicholas+npm@nczconsulting.com> |
|
||||
| kessler | stuff | eslint-plugin-import | perpetual | material | MIT | git+https://github.com/import-js/eslint-plugin-import.git | 2.31.0 | 2.31.0 | ^2.27.5 | Ben Mosher <me@benmosher.com> |
|
||||
| kessler | stuff | eslint-plugin-react | perpetual | material | MIT | git+https://github.com/jsx-eslint/eslint-plugin-react.git | 7.37.5 | 7.37.5 | ^7.32.2 | Yannick Croissant <yannick.croissant+npm@gmail.com> |
|
||||
| kessler | stuff | eslint-plugin-react-hooks | perpetual | material | MIT | git+https://github.com/facebook/react.git | 4.6.2 | 4.6.2 | ^4.6.0 | n/a |
|
||||
| kessler | stuff | license-report | perpetual | material | MIT | git+https://github.com/kessler/license-report.git | 6.7.2 | 6.7.2 | ^6.5.0 | Yaniv Kessler |
|
||||
| kessler | stuff | postcss | perpetual | material | MIT | git+https://github.com/postcss/postcss.git | 8.5.4 | 8.5.4 | ^8.4.24 | Andrey Sitnik <andrey@sitnik.ru> |
|
||||
| kessler | stuff | prettier | perpetual | material | MIT | git+https://github.com/prettier/prettier.git | 3.5.3 | 3.5.3 | ^3.0.3 | James Long |
|
||||
| kessler | stuff | prettier-plugin-organize-imports | perpetual | material | MIT | git+https://github.com/simonhaenisch/prettier-plugin-organize-imports.git | 3.2.4 | 3.2.4 | ^3.2.4 | Simon Haenisch (https://github.com/simonhaenisch) |
|
||||
| kessler | stuff | rimraf | perpetual | material | ISC | git://github.com/isaacs/rimraf.git | 5.0.10 | 5.0.10 | ^5.0.1 | Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/) |
|
||||
| kessler | stuff | rollup | perpetual | material | MIT | git+https://github.com/rollup/rollup.git | 4.41.1 | 4.41.1 | ^4.3.1 | Rich Harris |
|
||||
| kessler | stuff | rollup-plugin-copy | perpetual | material | MIT | git+https://github.com/vladshcherbin/rollup-plugin-copy.git | 3.5.0 | 3.5.0 | ^3.4.0 | Vlad Shcherbin <vlad.shcherbin@gmail.com> |
|
||||
| kessler | stuff | eslint | perpetual | material | MIT | git+https://github.com/eslint/eslint.git | 8.57.1 | 8.57.1 | ^8.57.1 | Nicholas C. Zakas <nicholas+npm@nczconsulting.com> |
|
||||
| kessler | stuff | eslint-plugin-import | perpetual | material | MIT | git+https://github.com/import-js/eslint-plugin-import.git | 2.31.0 | 2.31.0 | ^2.31.0 | Ben Mosher <me@benmosher.com> |
|
||||
| kessler | stuff | eslint-plugin-react | perpetual | material | MIT | git+https://github.com/jsx-eslint/eslint-plugin-react.git | 7.37.5 | 7.37.5 | ^7.37.5 | Yannick Croissant <yannick.croissant+npm@gmail.com> |
|
||||
| kessler | stuff | eslint-plugin-react-hooks | perpetual | material | MIT | git+https://github.com/facebook/react.git | 4.6.2 | 4.6.2 | ^4.6.2 | n/a |
|
||||
| kessler | stuff | license-report | perpetual | material | MIT | git+https://github.com/kessler/license-report.git | 6.8.0 | 6.7.2 | ^6.7.2 | Yaniv Kessler |
|
||||
| kessler | stuff | postcss | perpetual | material | MIT | git+https://github.com/postcss/postcss.git | 8.5.5 | 8.5.4 | ^8.5.4 | Andrey Sitnik <andrey@sitnik.ru> |
|
||||
| kessler | stuff | postcss-import | perpetual | material | MIT | git+https://github.com/postcss/postcss-import.git | 16.1.0 | 16.1.0 | ^16.1.0 | Maxime Thirouin |
|
||||
| kessler | stuff | prettier | perpetual | material | MIT | git+https://github.com/prettier/prettier.git | 3.5.3 | 3.5.3 | ^3.5.3 | James Long |
|
||||
| kessler | stuff | prettier-plugin-organize-imports | perpetual | material | MIT | git+https://github.com/simonhaenisch/prettier-plugin-organize-imports.git | 4.1.0 | 4.1.0 | ^4.1.0 | Simon Haenisch (https://github.com/simonhaenisch) |
|
||||
| kessler | stuff | rimraf | perpetual | material | ISC | git://github.com/isaacs/rimraf.git | 6.0.1 | 6.0.1 | ^6.0.1 | Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/) |
|
||||
| kessler | stuff | rollup | perpetual | material | MIT | git+https://github.com/rollup/rollup.git | 4.43.0 | 4.42.0 | ^4.42.0 | Rich Harris |
|
||||
| kessler | stuff | rollup-plugin-copy | perpetual | material | MIT | git+https://github.com/vladshcherbin/rollup-plugin-copy.git | 3.5.0 | 3.5.0 | ^3.5.0 | Vlad Shcherbin <vlad.shcherbin@gmail.com> |
|
||||
| kessler | stuff | rollup-plugin-postcss | perpetual | material | MIT | git+https://github.com/egoist/rollup-plugin-postcss.git | 4.0.2 | 4.0.2 | ^4.0.2 | EGOIST <0x142857@gmail.com> |
|
||||
| kessler | stuff | rollup-plugin-react-svg | perpetual | material | MIT | git+https://github.com/boopathi/react-svg-loader.git | 3.0.3 | 3.0.3 | ^3.0.3 | boopathi |
|
||||
| kessler | stuff | rollup-plugin-version-injector | perpetual | material | ISC | git+https://github.com/djhouseknecht/rollup-plugin-version-injector.git | 1.3.3 | 1.3.3 | ^1.3.3 | David Houseknecht <david.j.houseknecht@gmail.com> |
|
||||
| kessler | stuff | sass | perpetual | material | MIT | git+https://github.com/sass/dart-sass.git | 1.89.1 | 1.89.1 | ^1.89.1 | Natalie Weizenbaum nweiz@google.com https://github.com/nex3 |
|
||||
| kessler | stuff | sass | perpetual | material | MIT | git+https://github.com/sass/dart-sass.git | 1.89.2 | 1.89.1 | ^1.89.1 | Natalie Weizenbaum nweiz@google.com https://github.com/nex3 |
|
||||
| kessler | stuff | svg-slim | perpetual | material | MIT | git+https://github.com/benboba/svg-slim.git | 2.0.5 | 2.0.5 | ^2.0.5 | Wang Feng <benboba@gmail.com> |
|
||||
| kessler | stuff | tslib | perpetual | material | 0BSD | git+https://github.com/Microsoft/tslib.git | 2.8.1 | 2.8.1 | ^2.5.3 | Microsoft Corp. |
|
||||
| kessler | stuff | typed-scss-modules | perpetual | material | MIT | git+https://github.com/skovy/typed-scss-modules.git | 7.1.4 | 7.1.4 | ^7.1.0 | Spencer Miskoviak <smiskoviak@gmail.com> |
|
||||
| kessler | stuff | typescript | perpetual | material | Apache-2.0 | git+https://github.com/Microsoft/TypeScript.git | 5.2.2 | 5.2.2 | 5.2.2 | Microsoft Corp. |
|
||||
| kessler | stuff | tslib | perpetual | material | 0BSD | git+https://github.com/Microsoft/tslib.git | 2.8.1 | 2.8.1 | ^2.8.1 | Microsoft Corp. |
|
||||
| kessler | stuff | typed-scss-modules | perpetual | material | MIT | git+https://github.com/skovy/typed-scss-modules.git | 8.1.1 | 8.1.1 | ^8.1.1 | Spencer Miskoviak <smiskoviak@gmail.com> |
|
||||
| kessler | stuff | typescript | perpetual | material | Apache-2.0 | git+https://github.com/microsoft/TypeScript.git | 5.8.3 | 5.8.3 | 5.8.3 | Microsoft Corp. |
|
||||
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
import { FC, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
GSX_SERVICE_CALLED,
|
||||
GSX_SERVICE_FINISHED,
|
||||
} from '../../constants';
|
||||
import { WASMDataF } from '../../types/WASMData';
|
||||
import { LoadingState } from '../../types/general';
|
||||
import { ImportFlightPlan } from '../../utils/TFDISBImport';
|
||||
import { inRangeOf, loadAircraft, unloadAircraft } from '../../utils/utils';
|
||||
import CGSelect from '../CGSelect/CGSelect';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface SBEntryProps {
|
||||
WASMData: WASMDataF;
|
||||
loadingState: LoadingState;
|
||||
username: string;
|
||||
setLoadingState: (newState: LoadingState) => void;
|
||||
}
|
||||
|
||||
const SBEntryF: 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);
|
||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [SBPlan, setSBPlan] = useState<any>();
|
||||
const [SBInFlight, setSBInFlight] = useState(false);
|
||||
|
||||
const cargo = useRef(0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cargo.current = parseFloat(SBResponse.message.cargo) ?? 0;
|
||||
|
||||
updateData();
|
||||
|
||||
setSBPlan(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(inRangeOf(Math.round(WASMData.livePayload.fuel), fuel));
|
||||
}, [WASMData.livePayload.fuel]);
|
||||
|
||||
const updateData = (_CGTarget?: number) => {
|
||||
Coherent.call(
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
JSON.stringify({
|
||||
mode: 0,
|
||||
cargo: cargo.current ?? 0,
|
||||
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-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={SBPlan?.plannedZFW ?? 0}
|
||||
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={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 ({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 SBEntryF;
|
||||
@@ -23,6 +23,7 @@ const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoa
|
||||
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
|
||||
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
|
||||
const [fuelEnabled, setFuelEnabled] = useState(true);
|
||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [SBPlan, setSBPlan] = useState<any>();
|
||||
const [SBInFlight, setSBInFlight] = useState(false);
|
||||
|
||||
@@ -139,7 +140,7 @@ const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoa
|
||||
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
|
||||
);
|
||||
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
||||
setFuelEnabled(false);
|
||||
setFuelEnabled(WASMData.livePayload.fuel === fuel);
|
||||
}}
|
||||
disabled={loadingState !== 'preview' || !fuelEnabled || GSXActive()}
|
||||
>
|
||||
@@ -160,7 +161,7 @@ const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoa
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Planned ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
||||
<label>Planned GW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder=""
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import { FC, useState } from 'react';
|
||||
import { GSX_SERVICE_CALLED, GSX_SERVICE_FINISHED } from '../../constants';
|
||||
import { LoadingState } from '../../types/general';
|
||||
import { WASMDataF } from '../../types/WASMData';
|
||||
import Profile from '../profile/Profile';
|
||||
import SBEntryF from '../SBEntry/SBEntryF';
|
||||
import StationEntryF from '../stationEntry/StationEntryF';
|
||||
import Tabbar from '../tabbar/Tabbar';
|
||||
import ZFWEntryF from '../zfwEntry/ZFWEntryF';
|
||||
|
||||
interface FreighterProps {
|
||||
WASMData: WASMDataF;
|
||||
username?: string;
|
||||
}
|
||||
|
||||
const Freighter: FC<FreighterProps> = ({ WASMData, username }) => {
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [loadingState, setLoadingState] = useState<LoadingState>('preview');
|
||||
|
||||
const upper1 = (overrideState: LoadingState = loadingState) => {
|
||||
if (overrideState !== 'loaded') return Math.round(WASMData.targetPayload.upper1);
|
||||
|
||||
return Math.round(WASMData.livePayload.upper1);
|
||||
};
|
||||
const upper2 = (overrideState: LoadingState = loadingState) => {
|
||||
if (overrideState !== 'loaded') return Math.round(WASMData.targetPayload.upper2);
|
||||
|
||||
return Math.round(WASMData.livePayload.upper2);
|
||||
};
|
||||
const upper3 = (overrideState: LoadingState = loadingState) => {
|
||||
if (overrideState !== 'loaded') return Math.round(WASMData.targetPayload.upper3);
|
||||
|
||||
return Math.round(WASMData.livePayload.upper3);
|
||||
};
|
||||
const upper4 = (overrideState: LoadingState = loadingState) => {
|
||||
if (overrideState !== 'loaded') return Math.round(WASMData.targetPayload.upper4);
|
||||
|
||||
return Math.round(WASMData.livePayload.upper4);
|
||||
};
|
||||
const lower1 = () => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) return Math.round(WASMData.targetPayload.lowerForward);
|
||||
|
||||
return Math.round(WASMData.livePayload.lowerForward);
|
||||
};
|
||||
const lower2 = () => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) return Math.round(WASMData.targetPayload.lowerRear);
|
||||
|
||||
return Math.round(WASMData.livePayload.lowerRear);
|
||||
};
|
||||
const OEW = () => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) return Math.round(WASMData.targetPayload.empty);
|
||||
|
||||
return Math.round(WASMData.livePayload.empty);
|
||||
};
|
||||
const crew = () => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) return Math.round(WASMData.targetPayload.crew);
|
||||
|
||||
return Math.round(WASMData.livePayload.crew);
|
||||
};
|
||||
|
||||
const GSXActive = () => {
|
||||
return (
|
||||
(WASMData.GSX.boardingState >= GSX_SERVICE_CALLED || WASMData.GSX.deboardingState >= GSX_SERVICE_CALLED) &&
|
||||
WASMData.GSX.deboardingState !== GSX_SERVICE_FINISHED
|
||||
);
|
||||
};
|
||||
|
||||
const CGs = (): [string, boolean, string, boolean] => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) {
|
||||
return [
|
||||
WASMData.targetPayload.ZFWCG.toFixed(1),
|
||||
WASMData.targetPayload.ZFWCG < WASMData.limits.minCG || WASMData.targetPayload.ZFWCG > WASMData.limits.maxCG,
|
||||
WASMData.targetPayload.TOCG.toFixed(1),
|
||||
WASMData.targetPayload.TOCG < WASMData.limits.minCG || WASMData.targetPayload.TOCG > WASMData.limits.maxCG,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
WASMData.livePayload.ZFWCG.toFixed(1),
|
||||
WASMData.livePayload.ZFWCG < WASMData.limits.minCG || WASMData.livePayload.ZFWCG > WASMData.limits.maxCG,
|
||||
WASMData.livePayload.TOCG.toFixed(1),
|
||||
WASMData.livePayload.TOCG < WASMData.limits.minCG || WASMData.livePayload.TOCG > WASMData.limits.maxCG,
|
||||
];
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Profile
|
||||
type="PAX"
|
||||
isER={WASMData.userData.isER}
|
||||
upper1={`${upper1(GSXActive() ? 'loaded' : loadingState)}`}
|
||||
upper2={`${upper2(GSXActive() ? 'loaded' : loadingState)}`}
|
||||
upper3={`${upper3(GSXActive() ? 'loaded' : loadingState)}`}
|
||||
upper4={`${upper4(GSXActive() ? 'loaded' : loadingState)}`}
|
||||
lower1={`${lower1()}`}
|
||||
lower2={`${lower2()}`}
|
||||
OEW={`${OEW()}`}
|
||||
crew={`${crew()}`}
|
||||
unit={WASMData.userData.isImperial ? 'LBS' : 'KG'}
|
||||
inPreview={loadingState !== 'loaded' && !GSXActive()}
|
||||
CGs={CGs()}
|
||||
/>
|
||||
<Tabbar
|
||||
tabs={
|
||||
username ? ['Simbrief', 'ZFW', 'Passengers & Cargo', 'Options'] : ['ZFW', 'Passengers & Cargo', 'Options']
|
||||
}
|
||||
selectedTab={selectedTab}
|
||||
setSelectedTab={setSelectedTab}
|
||||
/>
|
||||
{username && selectedTab === 0 && (
|
||||
<SBEntryF
|
||||
WASMData={WASMData}
|
||||
loadingState={loadingState}
|
||||
username={username}
|
||||
setLoadingState={setLoadingState}
|
||||
/>
|
||||
)}
|
||||
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
|
||||
<ZFWEntryF WASMData={WASMData} loadingState={loadingState} setLoadingState={setLoadingState} />
|
||||
)}
|
||||
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
|
||||
<StationEntryF WASMData={WASMData} loadingState={loadingState} setLoadingState={setLoadingState} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Freighter;
|
||||
@@ -0,0 +1,244 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import {
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
GSX_SERVICE_CALLED,
|
||||
GSX_SERVICE_FINISHED,
|
||||
} from '../../constants';
|
||||
import { LoadingState } from '../../types/general';
|
||||
import { WASMDataF } from '../../types/WASMData';
|
||||
import { inRangeOf, loadAircraft, unloadAircraft } from '../../utils/utils';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface StationEntryProps {
|
||||
WASMData: WASMDataF;
|
||||
loadingState: LoadingState;
|
||||
setLoadingState: (newState: LoadingState) => void;
|
||||
}
|
||||
|
||||
const StationEntryF: FC<StationEntryProps> = ({ WASMData, loadingState, setLoadingState }) => {
|
||||
const [upper1, setUpper1] = useState(WASMData.targetPayload.upper1);
|
||||
const [upper2, setUpper2] = useState(WASMData.targetPayload.upper2);
|
||||
const [upper3, setUpper3] = useState(WASMData.targetPayload.upper3);
|
||||
const [upper4, setUpper4] = useState(WASMData.targetPayload.upper4);
|
||||
const [lowerForward, setLowerForward] = useState(WASMData.targetPayload.lowerForward);
|
||||
const [lowerRear, setLowerRear] = useState(WASMData.targetPayload.lowerRear);
|
||||
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
|
||||
const [fuelEnabled, setFuelEnabled] = useState(true);
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => updateData(), [upper1, upper2, upper3, upper4, lowerForward, lowerRear]);
|
||||
useEffect(
|
||||
() =>
|
||||
setFuel((prev) => {
|
||||
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
|
||||
return prev;
|
||||
}),
|
||||
[WASMData.userData.isER]
|
||||
);
|
||||
useEffect(() => {
|
||||
setFuelEnabled(inRangeOf(Math.round(WASMData.livePayload.fuel), fuel));
|
||||
}, [WASMData.livePayload.fuel]);
|
||||
|
||||
const updateData = () => {
|
||||
Coherent.call(
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
JSON.stringify({
|
||||
mode: 2,
|
||||
business1: upper1,
|
||||
business2: upper2,
|
||||
economy1: upper3,
|
||||
economy2: upper4,
|
||||
forwardCargo: lowerForward,
|
||||
rearCargo: lowerRear,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
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>Upper 1</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={upper1}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.upper1, setUpper1)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Upper 2</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={upper2}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.upper2, setUpper2)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-600 p-2 px-4">
|
||||
<label>Upper 3</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={upper3}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.upper3, setUpper3)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
|
||||
<label>Upper 4</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={upper4}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.upper4, setUpper4)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between bg-zinc-600 p-2 px-4">
|
||||
<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={lowerForward}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.lowerForward, setLowerForward)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
|
||||
<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={lowerRear}
|
||||
onChange={(e) => handleInput(e.target.value, WASMData.limits.lowerRear, setLowerRear)}
|
||||
disabled={loadingState !== 'preview' || GSXActive()}
|
||||
/>
|
||||
</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={!ZFWValid() || !GWValid()}
|
||||
GSXSync={WASMData.options.GSXSync}
|
||||
GSXActive={GSXActive()}
|
||||
load={() => {
|
||||
setLoadingState('loaded');
|
||||
|
||||
loadAircraft();
|
||||
}}
|
||||
unload={() => {
|
||||
setLoadingState('preview');
|
||||
|
||||
unloadAircraft();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StationEntryF;
|
||||
@@ -114,7 +114,7 @@ const StationEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoa
|
||||
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
|
||||
);
|
||||
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
||||
setFuelEnabled(false);
|
||||
setFuelEnabled(WASMData.livePayload.fuel === fuel);
|
||||
}}
|
||||
disabled={loadingState !== 'preview' || !fuelEnabled || GSXActive()}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import {
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
GSX_SERVICE_CALLED,
|
||||
GSX_SERVICE_FINISHED,
|
||||
} from '../../constants';
|
||||
import { WASMDataF } from '../../types/WASMData';
|
||||
import { LoadingState } from '../../types/general';
|
||||
import { inRangeOf, loadAircraft, unloadAircraft } from '../../utils/utils';
|
||||
import CGSelect from '../CGSelect/CGSelect';
|
||||
import ActionBar from '../actionbar/ActionBar';
|
||||
|
||||
interface ZFWEntryProps {
|
||||
WASMData: WASMDataF;
|
||||
loadingState: LoadingState;
|
||||
setLoadingState: (newState: LoadingState) => void;
|
||||
}
|
||||
|
||||
const ZFWEntryF: FC<ZFWEntryProps> = ({ WASMData, loadingState, setLoadingState }) => {
|
||||
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
|
||||
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
|
||||
const [ZFWTarget, setZFWTarget] = useState(Math.round(WASMData.targetPayload.total));
|
||||
const [fuelEnabled, setFuelEnabled] = useState(true);
|
||||
|
||||
const ZFW = () => {
|
||||
if (loadingState !== 'loaded' && !GSXActive()) return ZFWTarget;
|
||||
|
||||
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 handleInputZFW = (input: string) => {
|
||||
if (!input) return;
|
||||
|
||||
const converted = parseInt(input);
|
||||
if (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) {
|
||||
setZFWTarget(minZFW);
|
||||
return;
|
||||
}
|
||||
|
||||
const converted = parseInt(input);
|
||||
if (converted) {
|
||||
if (converted < minZFW) setZFWTarget(minZFW);
|
||||
else if (converted > WASMData.limits.maxZFW) setZFWTarget(WASMData.limits.maxZFW);
|
||||
else setZFWTarget(converted);
|
||||
}
|
||||
|
||||
updateData(converted);
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
setFuel((prev) => {
|
||||
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
|
||||
return prev;
|
||||
}),
|
||||
[WASMData.userData.isER]
|
||||
);
|
||||
useEffect(() => {
|
||||
setFuelEnabled(inRangeOf(Math.round(WASMData.livePayload.fuel), fuel));
|
||||
}, [WASMData.livePayload.fuel]);
|
||||
|
||||
const updateData = (_ZFWTarget?: number, _CGTarget?: number) => {
|
||||
Coherent.call(
|
||||
COHERENT_COMM_BUS_WASM_CALL,
|
||||
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||
JSON.stringify({
|
||||
mode: 1,
|
||||
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-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>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' || GSXActive()}
|
||||
/>
|
||||
</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' || GSXActive()}
|
||||
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>
|
||||
{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()}
|
||||
GSXSync={WASMData.options.GSXSync}
|
||||
GSXActive={GSXActive()}
|
||||
load={() => {
|
||||
setLoadingState('loaded');
|
||||
|
||||
loadAircraft();
|
||||
}}
|
||||
unload={() => {
|
||||
setLoadingState('preview');
|
||||
|
||||
unloadAircraft();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ZFWEntryF;
|
||||
@@ -133,7 +133,7 @@ const ZFWEntryPax: FC<ZFWEntryProps> = ({ WASMData, loadingState, setLoadingStat
|
||||
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
|
||||
);
|
||||
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
||||
setFuelEnabled(false);
|
||||
setFuelEnabled(WASMData.livePayload.fuel === fuel);
|
||||
}}
|
||||
disabled={loadingState !== 'preview' || !fuelEnabled || GSXActive()}
|
||||
>
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
import { ArmsFuel, Fuel, toPercentMAC } from './shared';
|
||||
|
||||
// TODO: Extract from CFG at runtime.
|
||||
const ArmsFreight = {
|
||||
empty: -159.6,
|
||||
pilot: 984,
|
||||
firstOfficer: 984,
|
||||
engineer: 960,
|
||||
upper1Left: 660,
|
||||
upper1Right: 660,
|
||||
upper2Left: 240,
|
||||
upper2Right: 240,
|
||||
upper3Left: -240,
|
||||
upper3Right: -240,
|
||||
upper4Left: -600,
|
||||
upper4Right: -600,
|
||||
lowerForward: 360,
|
||||
lowerRear: -360,
|
||||
leftAuxF: 60,
|
||||
rightAuxF: 60,
|
||||
};
|
||||
|
||||
export interface PayloadFreight {
|
||||
empty: number;
|
||||
pilot: number;
|
||||
firstOfficer: number;
|
||||
engineer: number;
|
||||
upper1Left: number;
|
||||
upper1Right: number;
|
||||
upper2Left: number;
|
||||
upper2Right: number;
|
||||
upper3Left: number;
|
||||
upper3Right: number;
|
||||
upper4Left: number;
|
||||
upper4Right: number;
|
||||
lowerForward: number;
|
||||
lowerRear: number;
|
||||
leftAuxF: number;
|
||||
rightAuxF: number;
|
||||
}
|
||||
|
||||
//PMC pallet
|
||||
export const maxUpperStationWeight = {
|
||||
lbs: (26 / 8) * 15000,
|
||||
kg: (26 / 8) * 6804,
|
||||
};
|
||||
|
||||
export const baseWeightFreight = {
|
||||
pilot: {
|
||||
lbs: 190,
|
||||
kg: 86,
|
||||
},
|
||||
firstOfficer: {
|
||||
lbs: 190,
|
||||
kg: 86,
|
||||
},
|
||||
};
|
||||
|
||||
export const maxZFWFreight = {
|
||||
lbs: 451300,
|
||||
kg: 204706,
|
||||
};
|
||||
|
||||
export const calculateCGsFreight = (payload: PayloadFreight, fuel: Fuel): [number, number] => {
|
||||
let totalMoment =
|
||||
payload.empty * ArmsFreight.empty +
|
||||
payload.pilot * ArmsFreight.pilot +
|
||||
payload.firstOfficer * ArmsFreight.firstOfficer +
|
||||
payload.engineer * ArmsFreight.engineer +
|
||||
payload.upper1Left * ArmsFreight.upper1Left +
|
||||
payload.upper1Right * ArmsFreight.upper1Right +
|
||||
payload.upper2Left * ArmsFreight.upper2Left +
|
||||
payload.upper2Right * ArmsFreight.upper2Right +
|
||||
payload.upper3Left * ArmsFreight.upper3Left +
|
||||
payload.upper3Right * ArmsFreight.upper3Right +
|
||||
payload.upper4Left * ArmsFreight.upper4Left +
|
||||
payload.upper4Right * ArmsFreight.upper4Right +
|
||||
payload.lowerForward * ArmsFreight.lowerForward +
|
||||
payload.lowerRear * ArmsFreight.lowerRear +
|
||||
payload.leftAuxF * ArmsFreight.leftAuxF +
|
||||
payload.rightAuxF * ArmsFreight.rightAuxF;
|
||||
|
||||
let totalWeight =
|
||||
payload.empty +
|
||||
payload.pilot +
|
||||
payload.firstOfficer +
|
||||
payload.engineer +
|
||||
payload.upper1Left +
|
||||
payload.upper1Right +
|
||||
payload.upper2Left +
|
||||
payload.upper2Right +
|
||||
payload.upper3Left +
|
||||
payload.upper3Right +
|
||||
payload.upper4Left +
|
||||
payload.upper4Right +
|
||||
payload.lowerForward +
|
||||
payload.lowerRear +
|
||||
payload.leftAuxF +
|
||||
payload.rightAuxF;
|
||||
|
||||
const ZFWCG = toPercentMAC(totalMoment / totalWeight);
|
||||
|
||||
totalMoment +=
|
||||
fuel.main1 * ArmsFuel.main1 +
|
||||
fuel.main3 * ArmsFuel.main3 +
|
||||
fuel.main2 * ArmsFuel.main2 +
|
||||
fuel.upperAux * ArmsFuel.upperAux +
|
||||
fuel.lowerAux * ArmsFuel.lowerAux +
|
||||
fuel.main1Tip * ArmsFuel.main1Tip +
|
||||
fuel.main3Tip * ArmsFuel.main3Tip +
|
||||
fuel.tail * ArmsFuel.tail +
|
||||
fuel.forwardAux1 * ArmsFuel.forwardAux1 +
|
||||
fuel.forwardAux2 * ArmsFuel.forwardAux2;
|
||||
|
||||
totalWeight +=
|
||||
fuel.main1 +
|
||||
fuel.main3 +
|
||||
fuel.main2 +
|
||||
fuel.upperAux +
|
||||
fuel.lowerAux +
|
||||
fuel.main1Tip +
|
||||
fuel.main3Tip +
|
||||
fuel.tail +
|
||||
fuel.forwardAux1 +
|
||||
fuel.forwardAux2;
|
||||
|
||||
const TOCG = toPercentMAC(totalMoment / totalWeight);
|
||||
|
||||
return [ZFWCG, TOCG];
|
||||
};
|
||||
|
||||
export const getWeightsFreight = (unit: 'kg' | 'lbs') => {
|
||||
const payload: PayloadFreight = {
|
||||
empty: SimVar.GetSimVarValue('EMPTY WEIGHT', unit),
|
||||
pilot: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:1', unit),
|
||||
firstOfficer: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:2', unit),
|
||||
engineer: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:3', unit),
|
||||
upper1Left: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:4', unit),
|
||||
upper1Right: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:5', unit),
|
||||
upper2Left: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:6', unit),
|
||||
upper2Right: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:7', unit),
|
||||
upper3Left: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:8', unit),
|
||||
upper3Right: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:9', unit),
|
||||
upper4Left: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:10', unit),
|
||||
upper4Right: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:11', unit),
|
||||
lowerForward: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:12', unit),
|
||||
lowerRear: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:13', unit),
|
||||
leftAuxF: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:14', unit),
|
||||
rightAuxF: SimVar.GetSimVarValue('PAYLOAD STATION WEIGHT:15', unit),
|
||||
};
|
||||
|
||||
return payload;
|
||||
};
|
||||
+9
@@ -7,6 +7,15 @@ export interface WASMDataPax {
|
||||
options: Options;
|
||||
}
|
||||
|
||||
export interface WASMDataF {
|
||||
livePayload: LivePayloadF;
|
||||
targetPayload: TargetPayloadF;
|
||||
GSX: GSX;
|
||||
userData: UserData;
|
||||
limits: LimitsF;
|
||||
options: Options;
|
||||
}
|
||||
|
||||
interface TargetPayload {
|
||||
CGTarget: number;
|
||||
ZFWCG: number;
|
||||
@@ -5,6 +5,7 @@ const getSimBriefFlightPlan = async (simBriefUsername: string) => {
|
||||
try {
|
||||
response = await fetch(flightPlanURL);
|
||||
success = true;
|
||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
response = e.response;
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ export const unloadAircraft = () => {
|
||||
};
|
||||
|
||||
export const inRangeOf = (value: number, target: number, tolerance: number = 10) => {
|
||||
return Math.abs(value - target) < 10;
|
||||
return Math.abs(value - target) < tolerance;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user