From 68bb2de5e6c73ca71f8d83da467536b548197769 Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi <90936742+Reckless-Satoshi@users.noreply.github.com> Date: Fri, 11 Aug 2023 23:13:30 +0000 Subject: [PATCH] Fix linting errors on federation-layer (#776) * Fix lint errors * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues * Fix more linting issues, only 1 left * Last fix --- .github/workflows/js-linter.yml | 7 +- frontend/.eslintrc.json | 11 +- frontend/package.json | 4 +- frontend/src/App.tsx | 2 +- frontend/src/basic/BookPage/index.tsx | 8 +- frontend/src/basic/Main.tsx | 10 +- frontend/src/basic/MainDialogs/index.tsx | 3 +- frontend/src/basic/MakerPage/index.tsx | 8 +- frontend/src/basic/NavBar/NavBar.tsx | 26 +- frontend/src/basic/NavBar/index.tsx | 4 + frontend/src/basic/OrderPage/index.tsx | 27 +- frontend/src/basic/RobotPage/Onboarding.tsx | 14 +- frontend/src/basic/RobotPage/Recovery.tsx | 9 +- frontend/src/basic/RobotPage/RobotProfile.tsx | 22 +- frontend/src/basic/RobotPage/TokenInput.tsx | 8 +- frontend/src/basic/RobotPage/Welcome.tsx | 2 +- frontend/src/basic/RobotPage/index.tsx | 40 +-- frontend/src/basic/SettingsPage/index.tsx | 2 + .../src/components/BookTable/BookControl.tsx | 26 +- frontend/src/components/BookTable/index.tsx | 62 +++-- .../components/Charts/DepthChart/index.tsx | 36 +-- frontend/src/components/Dialogs/AuditPGP.tsx | 30 +-- frontend/src/components/Dialogs/Community.tsx | 4 +- .../src/components/Dialogs/Coordinator.tsx | 78 +++--- .../src/components/Dialogs/EnableTelegram.tsx | 4 +- frontend/src/components/Dialogs/Exchange.tsx | 2 +- frontend/src/components/Dialogs/Profile.tsx | 14 +- frontend/src/components/Dialogs/Update.tsx | 2 +- frontend/src/components/ErrorBoundary.tsx | 2 +- .../src/components/FederationTable/index.tsx | 87 +++--- .../components/HostAlert/SelfhostedAlert.tsx | 2 +- .../src/components/HostAlert/UnsafeAlert.tsx | 11 +- frontend/src/components/HostAlert/index.tsx | 2 +- frontend/src/components/Icons/Amboss.tsx | 8 +- .../src/components/Icons/BadgeDevFund.tsx | 8 +- .../src/components/Icons/BadgeFounder.tsx | 8 +- frontend/src/components/Icons/BadgeLimits.tsx | 8 +- frontend/src/components/Icons/BadgeLoved.tsx | 8 +- .../src/components/Icons/BadgePrivacy.tsx | 8 +- .../components/Icons/BasqueCountryFlag.tsx | 8 +- frontend/src/components/Icons/Bitcoin.tsx | 8 +- frontend/src/components/Icons/BitcoinSign.tsx | 8 +- frontend/src/components/Icons/BuySats.tsx | 8 +- .../src/components/Icons/BuySatsChecked.tsx | 8 +- .../src/components/Icons/CataloniaFlag.tsx | 8 +- frontend/src/components/Icons/Earth.tsx | 10 +- frontend/src/components/Icons/Export.tsx | 8 +- frontend/src/components/Icons/Gold.tsx | 8 +- frontend/src/components/Icons/NewTab.tsx | 8 +- frontend/src/components/Icons/Nostr.tsx | 8 +- frontend/src/components/Icons/RoboSats.tsx | 8 +- .../src/components/Icons/RoboSatsNoText.tsx | 10 +- .../src/components/Icons/RoboSatsText.tsx | 8 +- frontend/src/components/Icons/SellSats.tsx | 8 +- .../src/components/Icons/SellSatsChecked.tsx | 8 +- frontend/src/components/Icons/SendReceive.tsx | 8 +- frontend/src/components/Icons/Simplex.tsx | 8 +- frontend/src/components/Icons/Tor.tsx | 8 +- frontend/src/components/Icons/UserNinja.tsx | 8 +- .../src/components/MakerForm/AmountRange.tsx | 14 +- .../MakerForm/AutocompletePayments.tsx | 121 ++++++--- .../src/components/MakerForm/MakerForm.tsx | 147 +++++----- .../src/components/Notifications/index.tsx | 56 ++-- .../OrderDetails/LinearDeterminate.tsx | 6 +- .../components/OrderDetails/TakeButton.tsx | 55 ++-- .../src/components/OrderDetails/index.tsx | 58 ++-- .../PaymentMethods/StringAsIcons.tsx | 12 +- frontend/src/components/RobotAvatar/index.tsx | 14 +- frontend/src/components/RobotInfo/index.tsx | 89 ++++--- .../SettingsForm/SelectLanguage.tsx | 19 +- .../src/components/SettingsForm/index.tsx | 4 +- .../src/components/TradeBox/BondStatus.tsx | 4 +- .../components/TradeBox/CollabCancelAlert.tsx | 2 +- .../TradeBox/Dialogs/ConfirmFiatReceived.tsx | 2 +- .../TradeBox/Dialogs/ConfirmFiatSent.tsx | 2 +- .../TradeBox/Dialogs/ConfirmUndoFiatSent.tsx | 2 +- .../EncryptedChat/ChatBottom/index.tsx | 7 +- .../EncryptedSocketChat/index.tsx | 91 ++++--- .../EncryptedTurtleChat/index.tsx | 93 ++++--- .../EncryptedChat/MessageCard/index.tsx | 4 +- .../src/components/TradeBox/Forms/Dispute.tsx | 4 +- .../TradeBox/Forms/LightningPayout.tsx | 74 ++--- .../TradeBox/Forms/OnchainPayout.tsx | 24 +- .../src/components/TradeBox/Prompts/Chat.tsx | 24 +- .../TradeBox/Prompts/LockInvoice.tsx | 13 +- .../components/TradeBox/Prompts/Payout.tsx | 8 +- .../TradeBox/Prompts/PublicWait.tsx | 5 +- .../TradeBox/Prompts/RoutingFailed.tsx | 8 +- .../TradeBox/Prompts/Successful.tsx | 21 +- .../src/components/TradeBox/Title/index.tsx | 6 +- .../src/components/TradeBox/TradeSummary.tsx | 25 +- frontend/src/components/TradeBox/index.tsx | 85 +++--- frontend/src/contexts/AppContext.ts | 252 ++++++++++++------ frontend/src/i18n/Native.js | 3 +- frontend/src/i18n/Web.js | 2 +- frontend/src/models/Coordinator.model.ts | 12 +- frontend/src/models/Exchange.model.ts | 11 +- frontend/src/models/Garage.model.ts | 8 +- frontend/src/models/Limit.model.ts | 22 +- frontend/src/models/Order.model.ts | 1 + frontend/src/models/Settings.model.ts | 2 +- frontend/src/pgp/{index.js => index.ts} | 51 ++-- frontend/src/pro/Main.tsx | 8 +- frontend/src/pro/ToolBar/index.tsx | 16 +- frontend/src/pro/Widgets/Book.tsx | 64 +++-- frontend/src/pro/Widgets/Depth.tsx | 56 ++-- frontend/src/pro/Widgets/Federation.tsx | 72 +++-- frontend/src/pro/Widgets/Maker.tsx | 30 +-- frontend/src/pro/Widgets/Placeholder.tsx | 49 ++-- frontend/src/pro/Widgets/Settings.tsx | 33 +-- frontend/src/services/Native/index.d.ts | 2 +- frontend/src/services/Native/index.ts | 30 +-- .../System/SystemNativeClient/index.ts | 6 +- .../services/System/SystemWebClient/index.ts | 10 +- .../Websocket/WebsocketWebClient/index.ts | 4 +- .../src/services/api/ApiNativeClient/index.ts | 54 ++-- frontend/src/utils/aggregateInfo.ts | 7 +- frontend/src/utils/checkVer.ts | 6 +- frontend/src/utils/filterOrders.ts | 18 +- frontend/src/utils/getHost.ts | 4 +- .../src/utils/{hexToRgb.js => hexToRgb.ts} | 5 +- frontend/src/utils/match.ts | 2 +- frontend/src/utils/prettyNumbers.test.ts | 6 +- frontend/src/utils/prettyNumbers.ts | 6 +- .../src/utils/{saveFile.js => saveFile.ts} | 2 +- frontend/src/utils/statusBadgeColor.ts | 2 +- frontend/src/utils/token.ts | 2 +- frontend/src/utils/webln.ts | 31 ++- frontend/src/utils/weightedMean.ts | 2 +- 129 files changed, 1537 insertions(+), 1234 deletions(-) rename frontend/src/pgp/{index.js => index.ts} (71%) rename frontend/src/utils/{hexToRgb.js => hexToRgb.ts} (76%) rename frontend/src/utils/{saveFile.js => saveFile.ts} (89%) diff --git a/.github/workflows/js-linter.yml b/.github/workflows/js-linter.yml index bc704fb69..f6ff7b90f 100644 --- a/.github/workflows/js-linter.yml +++ b/.github/workflows/js-linter.yml @@ -11,6 +11,7 @@ on: pull_request: branches: - main + - the-federation-layer-v0.5.0 paths: - frontend @@ -41,7 +42,5 @@ jobs: with: prettier: true prettier_dir: frontend - - ## Disabled due to error - # eslint: true - # eslint_dir: frontend \ No newline at end of file + eslint: true + eslint_dir: frontend \ No newline at end of file diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index ca31c5905..5dfa5412d 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -19,12 +19,21 @@ "sourceType": "module", "project": "./tsconfig.json" }, + "ignorePatterns": ["index.js", "**/PaymentMethods/Icons/code/code.js"], "plugins": ["react", "react-hooks", "@typescript-eslint", "prettier"], "rules": { "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", "react/prop-types": "off", - "react/react-in-jsx-scope": "off" + "react/react-in-jsx-scope": "off", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variableLike", + "format": ["camelCase", "snake_case", "PascalCase", "UPPER_CASE"], + "leadingUnderscore": "allow" + } + ] }, "settings": { "import/resolver": { diff --git a/frontend/package.json b/frontend/package.json index f48a0ee87..a704407c0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,8 +7,8 @@ "dev": "webpack --watch --progress --mode development", "test": "jest", "build": "webpack --mode production", - "lint": "eslint src/**/*.{js,ts,tsx}", - "lint:fix": "eslint --fix 'src/**/*.{js,ts,tsx}'", + "lint": "eslint src/**/*.{js,ts,tsx} --quiet", + "lint:fix": "eslint --fix 'src/**/*.{js,ts,tsx}' --quiet", "format": "prettier --write '**/**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc" }, "keywords": [], diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ea18c7f60..80bae37d3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -33,7 +33,7 @@ const App = (): JSX.Element => { ); }; -const loadApp = () => { +const loadApp = (): void => { // waits until the environment is ready for the Android WebView app if (systemClient.loading) { setTimeout(loadApp, 200); diff --git a/frontend/src/basic/BookPage/index.tsx b/frontend/src/basic/BookPage/index.tsx index 923c35dfd..e87e8f403 100644 --- a/frontend/src/basic/BookPage/index.tsx +++ b/frontend/src/basic/BookPage/index.tsx @@ -30,7 +30,7 @@ const BookPage = (): JSX.Element => { fetchFederationBook(); }, []); - const onOrderClicked = function (id: number, shortAlias: string) { + const onOrderClicked = function (id: number, shortAlias: string): void { if (robot.avatarLoaded) { clearOrder(); setDelay(10000); @@ -40,7 +40,7 @@ const BookPage = (): JSX.Element => { } }; - const NavButtons = function () { + const NavButtons = function (): JSX.Element { return ( diff --git a/frontend/src/basic/RobotPage/RobotProfile.tsx b/frontend/src/basic/RobotPage/RobotProfile.tsx index da276529d..5e9121969 100644 --- a/frontend/src/basic/RobotPage/RobotProfile.tsx +++ b/frontend/src/basic/RobotPage/RobotProfile.tsx @@ -51,19 +51,19 @@ const RobotProfile = ({ const [loading, setLoading] = useState(true); useEffect(() => { - if (robot.nickname && robot.avatarLoaded) { + if (Boolean(robot.nickname) && robot.avatarLoaded) { setLoading(false); } }, [robot]); - const handleAddRobot = () => { + const handleAddRobot = (): void => { getGenerateRobot(genBase62Token(36), garage.slots.length); setLoading(true); }; - const handleChangeSlot = (e) => { - const slot = e.target.value; - getGenerateRobot(garage.slots[slot].robot.token, slot); + const handleChangeSlot = (e: React.ChangeEvent): void => { + const slot = Number(e.target.value); + getGenerateRobot(garage.slots[slot].robot.token ?? '', slot); setLoading(true); }; @@ -78,7 +78,7 @@ const RobotProfile = ({ sx={{ width: '100%' }} > - {robot.avatarLoaded && robot.nickname ? ( + {robot.avatarLoaded && robot.nickname !== undefined ? (
- {robot.found && !robot.lastOrderId ? ( + {robot.found && Number(robot.lastOrderId) > 0 ? ( {t('Welcome back!')} @@ -143,11 +143,11 @@ const RobotProfile = ({ )} - {robot.activeOrderId && robot.avatarLoaded && robot.nickname ? ( + {Boolean(robot.activeOrderId) && robot.avatarLoaded && Boolean(robot.nickname) ? ( @@ -349,7 +395,12 @@ export default function AutocompletePayments(props) { {/* Here goes what happens if there is no fewerOptions */} 0 && !props.isFilter && fewerOptions.length === 0}> - @@ -357,4 +408,6 @@ export default function AutocompletePayments(props) { ); -} +}; + +export default AutocompletePayments; diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index 138091aa9..57db9bc32 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -84,7 +84,7 @@ const MakerForm = ({ const amountSafeThresholds = [1.03, 0.98]; useEffect(() => { - setCurrencyCode(currencyDict[fav.currency == 0 ? 1 : fav.currency]); + setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]); if (Object.keys(limits.list).length === 0) { // fetchFederationLimits().then((data) => { // updateAmountLimits(data, fav.currency, maker.premium); @@ -100,8 +100,12 @@ const MakerForm = ({ } }, []); - const updateAmountLimits = function (limitList: LimitList, currency: number, premium: number) { - const index = currency == 0 ? 1 : currency; + const updateAmountLimits = function ( + limitList: LimitList, + currency: number, + premium: number, + ): void { + const index = currency === 0 ? 1 : currency; let minAmountLimit: number = limitList[index].min_amount * (1 + premium / 100); let maxAmountLimit: number = limitList[index].max_amount * (1 + premium / 100); @@ -111,24 +115,28 @@ const MakerForm = ({ setAmountLimits([minAmountLimit, maxAmountLimit]); }; - const updateSatoshisLimits = function (limitList: LimitList) { + const updateSatoshisLimits = function (limitList: LimitList): void { const minAmount: number = limitList[1000].min_amount * 100000000; const maxAmount: number = limitList[1000].max_amount * 100000000; setSatoshisLimits([minAmount, maxAmount]); }; - const updateCurrentPrice = function (limitsList: LimitList, currency: number, premium: number) { - const index = currency == 0 ? 1 : currency; + const updateCurrentPrice = function ( + limitsList: LimitList, + currency: number, + premium: number, + ): void { + const index = currency === 0 ? 1 : currency; let price = '...'; if (maker.isExplicit && maker.amount > 0 && maker.satoshis > 0) { price = maker.amount / (maker.satoshis / 100000000); - } else if (!maker.is_explicit) { + } else if (!maker.isExplicit) { price = limitsList[index].price * (1 + premium / 100); } setCurrentPrice(parseFloat(Number(price).toPrecision(5))); }; - const handleCurrencyChange = function (newCurrency: number) { + const handleCurrencyChange = function (newCurrency: number): void { const currencyCode: string = currencyDict[newCurrency]; setCurrencyCode(currencyCode); setFav({ @@ -161,7 +169,9 @@ const MakerForm = ({ return maker.advancedOptions && amountRangeEnabled; }, [maker.advancedOptions, amountRangeEnabled]); - const handlePaymentMethodChange = function (paymentArray: string[]) { + const handlePaymentMethodChange = function ( + paymentArray: Array<{ name: string; icon: string }>, + ): void { let str = ''; const arrayLength = paymentArray.length; for (let i = 0; i < arrayLength; i++) { @@ -176,14 +186,14 @@ const MakerForm = ({ }); }; - const handleMinAmountChange = function (e) { + const handleMinAmountChange = function (e): void { setMaker({ ...maker, minAmount: parseFloat(Number(e.target.value).toPrecision(e.target.value < 100 ? 2 : 3)), }); }; - const handleMaxAmountChange = function (e) { + const handleMaxAmountChange = function (e): void { setMaker({ ...maker, maxAmount: parseFloat(Number(e.target.value).toPrecision(e.target.value < 100 ? 2 : 3)), @@ -191,7 +201,7 @@ const MakerForm = ({ }; const handlePremiumChange: React.ChangeEventHandler = - function ({ target: { value } }) { + function ({ target: { value } }): void { const max = fav.mode === 'fiat' ? 999 : 99; const min = -100; const newPremium = Math.floor(Number(value) * Math.pow(10, 2)) / Math.pow(10, 2); @@ -213,7 +223,7 @@ const MakerForm = ({ }); }; - const handleSatoshisChange = function (e: object) { + const handleSatoshisChange = function (e: object): void { const newSatoshis = e.target.value; let badSatoshisText: string = ''; let satoshis: string = newSatoshis; @@ -233,14 +243,14 @@ const MakerForm = ({ }); }; - const handleClickRelative = function () { + const handleClickRelative = function (): void { setMaker({ ...maker, isExplicit: false, }); }; - const handleClickExplicit = function () { + const handleClickExplicit = function (): void { if (!maker.advancedOptions) { setMaker({ ...maker, @@ -249,12 +259,12 @@ const MakerForm = ({ } }; - const handleCreateOrder = function () { + const handleCreateOrder = function (): void { if (!disableRequest) { setSubmittingRequest(true); const body = { - type: fav.type == 0 ? 1 : 0, - currency: fav.currency == 0 ? 1 : fav.currency, + type: fav.type === 0 ? 1 : 0, + currency: fav.currency === 0 ? 1 : fav.currency, amount: makerHasAmountRange ? null : maker.amount, has_range: makerHasAmountRange, min_amount: makerHasAmountRange ? maker.minAmount : null, @@ -262,7 +272,7 @@ const MakerForm = ({ payment_method: maker.paymentMethodsText === '' ? 'not specified' : maker.paymentMethodsText, is_explicit: maker.isExplicit, - premium: maker.isExplicit ? null : maker.premium == '' ? 0 : maker.premium, + premium: maker.isExplicit ? null : maker.premium === '' ? 0 : maker.premium, satoshis: maker.isExplicit ? maker.satoshis : null, public_duration: maker.publicDuration, escrow_duration: maker.escrowDuration, @@ -270,46 +280,49 @@ const MakerForm = ({ }; apiClient .post(hostUrl, '/api/make/', body, { tokenSHA256: robot.tokenSHA256 }) - .then((data: object) => { + .then((data: any) => { setBadRequest(data.bad_request); - if (data.id) { + if (data.id !== undefined) { onOrderCreated(data.id); } setSubmittingRequest(false); + }) + .catch(() => { + setBadRequest('Request error'); }); } setOpenDialogs(false); }; - const handleChangePublicDuration = function (date: Date) { + const handleChangePublicDuration = function (date: Date): void { const d = new Date(date); const hours: number = d.getHours(); const minutes: number = d.getMinutes(); - const total_secs: number = hours * 60 * 60 + minutes * 60; + const totalSecs: number = hours * 60 * 60 + minutes * 60; setMaker({ ...maker, publicExpiryTime: date, - publicDuration: total_secs, + publicDuration: totalSecs, }); }; - const handleChangeEscrowDuration = function (date: Date) { + const handleChangeEscrowDuration = function (date: Date): void { const d = new Date(date); const hours: number = d.getHours(); const minutes: number = d.getMinutes(); - const total_secs: number = hours * 60 * 60 + minutes * 60; + const totalSecs: number = hours * 60 * 60 + minutes * 60; setMaker({ ...maker, escrowExpiryTime: date, - escrowDuration: total_secs, + escrowDuration: totalSecs, }); }; - const handleClickAdvanced = function () { + const handleClickAdvanced = function (): void { if (maker.advancedOptions) { handleClickRelative(); setMaker({ ...maker, advancedOptions: false }); @@ -336,14 +349,16 @@ const MakerForm = ({ ); }, [maker.minAmount, maker.maxAmount, amountLimits]); - const resetRange = function (advancedOptions: boolean) { + const resetRange = function (advancedOptions: boolean): void { const index = fav.currency === 0 ? 1 : fav.currency; - const minAmount = maker.amount - ? parseFloat((maker.amount / 2).toPrecision(2)) - : parseFloat(Number(limits.list[index].max_amount * 0.25).toPrecision(2)); - const maxAmount = maker.amount - ? parseFloat(maker.amount) - : parseFloat(Number(limits.list[index].max_amount * 0.75).toPrecision(2)); + const minAmount = + maker.amount !== '' + ? parseFloat((maker.amount / 2).toPrecision(2)) + : parseFloat(Number(limits.list[index].max_amount * 0.25).toPrecision(2)); + const maxAmount = + maker.amount !== '' + ? parseFloat(maker.amount) + : parseFloat(Number(limits.list[index].max_amount * 0.75).toPrecision(2)); setMaker({ ...maker, @@ -353,7 +368,7 @@ const MakerForm = ({ }); }; - const handleRangeAmountChange = function (e: any, newValue, activeThumb: number) { + const handleRangeAmountChange = function (e: any, newValue, activeThumb: number): void { let minAmount = e.target.value[0]; let maxAmount = e.target.value[1]; @@ -390,7 +405,7 @@ const MakerForm = ({ const handleClickAmountRangeEnabled = function ( _e: React.ChangeEvent, checked: boolean, - ) { + ): void { setAmountRangeEnabled(checked); }; @@ -430,23 +445,23 @@ const MakerForm = ({ return ( fav.type == null || (!makerHasAmountRange && - maker.amount != '' && + maker.amount !== '' && (maker.amount < amountLimits[0] || maker.amount > amountLimits[1])) || maker.badPaymentMethod || (maker.amount == null && (!makerHasAmountRange || limits.loading)) || (makerHasAmountRange && (minAmountError || maxAmountError)) || (!makerHasAmountRange && maker.amount <= 0) || - (maker.isExplicit && (maker.badSatoshisText != '' || maker.satoshis == '')) || - (!maker.isExplicit && maker.badPremiumText != '') + (maker.isExplicit && (maker.badSatoshisText !== '' || maker.satoshis === '')) || + (!maker.isExplicit && maker.badPremiumText !== '') ); }, [maker, amountLimits, limits, fav.type, makerHasAmountRange]); - const clearMaker = function () { + const clearMaker = function (): void { setFav({ ...fav, type: null }); setMaker(defaultMaker); }; - const SummaryText = function () { + const SummaryText = (): JSX.Element => { return ( - -
+ +
- + @@ -560,9 +575,9 @@ const MakerForm = ({ {t('Swap?')} { - handleCurrencyChange(fav.mode == 'swap' ? 1 : 1000); + handleCurrencyChange(fav.mode === 'swap' ? 1 : 1000); }} /> @@ -585,10 +600,10 @@ const MakerForm = ({ type: 1, }); }} - disableElevation={fav.type == 1} + disableElevation={fav.type === 1} sx={{ - backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper', - color: fav.type == 1 ? 'background.paper' : 'text.secondary', + backgroundColor: fav.type === 1 ? 'primary.main' : 'background.paper', + color: fav.type === 1 ? 'background.paper' : 'text.secondary', ':hover': { color: 'background.paper', }, @@ -605,11 +620,11 @@ const MakerForm = ({ type: 0, }); }} - disableElevation={fav.type == 0} + disableElevation={fav.type === 0} color='secondary' sx={{ - backgroundColor: fav.type == 0 ? 'secondary.main' : 'background.paper', - color: fav.type == 0 ? 'background.secondary' : 'text.secondary', + backgroundColor: fav.type === 0 ? 'secondary.main' : 'background.paper', + color: fav.type === 0 ? 'background.secondary' : 'text.secondary', ':hover': { color: 'background.paper', }, @@ -679,15 +694,15 @@ const MakerForm = ({ disabled={makerHasAmountRange} variant={makerHasAmountRange ? 'filled' : 'outlined'} error={ - maker.amount != '' && + maker.amount !== '' && (maker.amount < amountLimits[0] || maker.amount > amountLimits[1]) } helperText={ - maker.amount < amountLimits[0] && maker.amount != '' + maker.amount < amountLimits[0] && maker.amount !== '' ? t('Must be more than {{minAmount}}', { minAmount: pn(parseFloat(amountLimits[0].toPrecision(2))), }) - : maker.amount > amountLimits[1] && maker.amount != '' + : maker.amount > amountLimits[1] && maker.amount !== '' ? t('Must be less than {{maxAmount}}', { maxAmount: pn(parseFloat(amountLimits[1].toPrecision(2))), }) @@ -710,7 +725,7 @@ const MakerForm = ({ }} /> - {fav.mode === 'swap' && maker.amount != '' ? ( + {fav.mode === 'swap' && maker.amount !== '' ? ( {amountLabel.helper} @@ -729,7 +744,7 @@ const MakerForm = ({ inputProps={{ style: { textAlign: 'center' }, }} - value={fav.currency == 0 ? 1 : fav.currency} + value={fav.currency === 0 ? 1 : fav.currency} onChange={(e) => { handleCurrencyChange(e.target.value); }} @@ -758,9 +773,9 @@ const MakerForm = ({ optionsType={fav.mode} error={maker.badPaymentMethod} helperText={maker.badPaymentMethod ? t('Must be shorter than 65 characters') : ''} - label={fav.mode == 'swap' ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')} + label={fav.mode === 'swap' ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')} tooltipTitle={t( - fav.mode == 'swap' + fav.mode === 'swap' ? t('Enter the destination of the Lightning swap') : 'Enter your preferred fiat payment methods. Fast methods are highly recommended.', )} @@ -837,7 +852,7 @@ const MakerForm = ({ - + 60 ? { top: '4em', right: '0em' } : { top: '0.5em', left: '50%' }; const basePageTitle = t('RoboSats - Simple and Private Bitcoin Exchange'); - const moveToOrderPage = function () { - navigate(`/order/${order?.id}`); + const moveToOrderPage = function (): void { + navigate(`/order/${String(order?.id)}`); setShow(false); }; @@ -108,7 +107,7 @@ const Notifications = ({ const Messages: MessagesProps = { bondLocked: { - title: t(`${order?.is_maker ? 'Maker' : 'Taker'} bond locked`), + title: t(`${order?.is_maker === true ? 'Maker' : 'Taker'} bond locked`), severity: 'info', onClick: moveToOrderPage, sound: audio.ding, @@ -208,28 +207,31 @@ const Notifications = ({ }, }; - const notify = function (message: NotificationMessage) { - if (message.title != '') { + const notify = function (message: NotificationMessage): void { + if (message.title !== '') { setMessage(message); setShow(true); setTimeout(() => { setShow(false); }, message.timeout); if (message.sound != null) { - message.sound.play(); + void message.sound.play(); } if (!inFocus) { setTitleAnimation( setInterval(function () { const title = document.title; - document.title = title == basePageTitle ? message.pageTitle : basePageTitle; + document.title = title === basePageTitle ? message.pageTitle : basePageTitle; }, 1000), ); } } }; - const handleStatusChange = function (oldStatus: number | undefined, status: number) { + const handleStatusChange = function (oldStatus: number | undefined, status: number): void { + if (order === undefined) { + return; + } let message = emptyNotificationMessage; // Order status descriptions: @@ -252,37 +254,35 @@ const Notifications = ({ // 17: 'Maker lost dispute' // 18: 'Taker lost dispute' - if (status == 5 && oldStatus != 5) { + if (status === 5 && oldStatus !== 5) { message = Messages.expired; - } else if (oldStatus == undefined) { + } else if (oldStatus === undefined) { message = emptyNotificationMessage; - } else if (order?.is_maker && status > 0 && oldStatus == 0) { + } else if (order.is_maker && status > 0 && oldStatus === 0) { message = Messages.bondLocked; - } else if (order?.is_taker && status > 5 && oldStatus <= 5) { + } else if (order.is_taker && status > 5 && oldStatus <= 5) { message = Messages.bondLocked; - } else if (order?.is_maker && status > 5 && oldStatus <= 5) { + } else if (order.is_maker && status > 5 && oldStatus <= 5) { message = Messages.taken; - } else if (order?.is_seller && status > 7 && oldStatus < 7) { + } else if (order.is_seller && status > 7 && oldStatus < 7) { message = Messages.escrowLocked; } else if ([9, 10].includes(status) && oldStatus < 9) { message = Messages.chat; - } else if (order?.is_seller && [13, 14, 15].includes(status) && oldStatus < 13) { + } else if (order.is_seller && [13, 14, 15].includes(status) && oldStatus < 13) { message = Messages.successful; - } else if (order?.is_buyer && status == 14 && oldStatus != 14) { + } else if (order.is_buyer && status === 14 && oldStatus !== 14) { message = Messages.successful; - } else if (order?.is_buyer && status == 15 && oldStatus < 14) { + } else if (order.is_buyer && status === 15 && oldStatus < 14) { message = Messages.routingFailed; - } else if (status == 11 && oldStatus < 11) { - message = Messages.dispute; - } else if (status == 11 && oldStatus < 11) { + } else if (status === 11 && oldStatus < 11) { message = Messages.dispute; } else if ( - ((order?.is_maker && status == 18) || (order?.is_taker && status == 17)) && + ((order.is_maker && status === 18) || (order.is_taker && status === 17)) && oldStatus < 17 ) { message = Messages.disputeWinner; } else if ( - ((order?.is_maker && status == 17) || (order?.is_taker && status == 18)) && + ((order.is_maker && status === 17) || (order.is_taker && status === 18)) && oldStatus < 17 ) { message = Messages.disputeLoser; @@ -293,11 +293,11 @@ const Notifications = ({ // Notify on order status change useEffect(() => { - if (order != undefined && order.status != oldOrderStatus) { + if (order !== undefined && order.status !== oldOrderStatus) { handleStatusChange(oldOrderStatus, order.status); setOldOrderStatus(order.status); - } else if (order != undefined && order.chat_last_index > oldChatIndex) { - if (page != 'order') { + } else if (order !== undefined && order.chat_last_index > oldChatIndex) { + if (page !== 'order') { notify(Messages.chatMessage); } setOldChatIndex(order.chat_last_index); @@ -306,7 +306,7 @@ const Notifications = ({ // Notify on rewards change useEffect(() => { - if (rewards != undefined) { + if (rewards !== undefined) { if (rewards > oldRewards) { notify(Messages.rewards); } @@ -316,7 +316,7 @@ const Notifications = ({ // Set blinking page title and clear on visibility change > infocus useEffect(() => { - if (titleAnimation != undefined && inFocus) { + if (titleAnimation !== undefined && inFocus) { clearInterval(titleAnimation); } }, [inFocus]); diff --git a/frontend/src/components/OrderDetails/LinearDeterminate.tsx b/frontend/src/components/OrderDetails/LinearDeterminate.tsx index 62c0f5118..3dbec0f5c 100644 --- a/frontend/src/components/OrderDetails/LinearDeterminate.tsx +++ b/frontend/src/components/OrderDetails/LinearDeterminate.tsx @@ -7,9 +7,9 @@ interface Props { totalSecsExp: number; } -const LinearDeterminate = ({ expiresAt, totalSecsExp }: Props): JSX.Element => { - const timePercentLeft = function () { - if (expiresAt && totalSecsExp) { +const LinearDeterminate: React.FC = ({ expiresAt, totalSecsExp }) => { + const timePercentLeft = function (): number { + if (Boolean(expiresAt) && Boolean(totalSecsExp)) { const lapseTime = calcTimeDelta(new Date(expiresAt)).total / 1000; return (lapseTime / totalSecsExp) * 100; } else { diff --git a/frontend/src/components/OrderDetails/TakeButton.tsx b/frontend/src/components/OrderDetails/TakeButton.tsx index f006d463e..cd3c8fec3 100644 --- a/frontend/src/components/OrderDetails/TakeButton.tsx +++ b/frontend/src/components/OrderDetails/TakeButton.tsx @@ -58,11 +58,11 @@ const TakeButton = ({ const [open, setOpen] = useState(closeAll); const [satoshis, setSatoshis] = useState(''); - const satoshisNow = () => { + const satoshisNow = (): string | undefined => { const tradeFee = info?.taker_fee ?? 0; const defaultRoutingBudget = 0.001; - const btc_now = order.satoshis_now / 100000000; - const rate = order.amount ? order.amount / btc_now : order.max_amount / btc_now; + const btcNow = order.satoshis_now / 100000000; + const rate = order.amount != null ? order.amount / btcNow : order.max_amount / btcNow; const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); const satoshis = computeSats({ amount, @@ -77,9 +77,9 @@ const TakeButton = ({ setSatoshis(satoshisNow()); }, [order.satoshis_now, takeAmount, info]); - const currencyCode: string = order.currency == 1000 ? 'Sats' : currencies[`${order.currency}`]; + const currencyCode: string = order.currency === 1000 ? 'Sats' : currencies[`${order.currency}`]; - const InactiveMakerDialog = function () { + const InactiveMakerDialog = function (): JSX.Element { return ( ): void { + if (e.target.value !== '' && e.target.value != null) { setTakeAmount(`${parseFloat(e.target.value)}`); } else { setTakeAmount(e.target.value); @@ -141,18 +149,18 @@ const TakeButton = ({ }; const amountHelperText = useMemo(() => { - const amount = order.currency == 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); - if (amount < Number(order.min_amount) && takeAmount != '') { + const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); + if (amount < Number(order.min_amount) && takeAmount !== '') { return t('Too low'); - } else if (amount > Number(order.max_amount) && takeAmount != '') { + } else if (amount > Number(order.max_amount) && takeAmount !== '') { return t('Too high'); } else { return null; } }, [order, takeAmount]); - const onTakeOrderClicked = function () { - if (order.maker_status == 'Inactive') { + const onTakeOrderClicked = function (): void { + if (order.maker_status === 'Inactive') { setOpen({ inactiveMaker: true, confirmation: false }); } else { setOpen({ inactiveMaker: false, confirmation: true }); @@ -160,16 +168,16 @@ const TakeButton = ({ }; const invalidTakeAmount = useMemo(() => { - const amount = order.currency == 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); + const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); return ( amount < Number(order.min_amount) || amount > Number(order.max_amount) || - takeAmount == '' || + takeAmount === '' || takeAmount == null ); }, [takeAmount, order]); - const takeOrderButton = function () { + const takeOrderButton = function (): JSX.Element { if (order.has_range) { return ( - {satoshis != '0' && satoshis != '' && !invalidTakeAmount ? ( + {satoshis !== '0' && satoshis !== '' && !invalidTakeAmount ? ( {order.type === 1 @@ -296,33 +304,36 @@ const TakeButton = ({ } }; - const takeOrder = function () { + const takeOrder = function (): void { setLoadingTake(true); apiClient .post( baseUrl, - '/api/order/?order_id=' + order.id, + `/api/order/?order_id=${String(order.id)}`, { action: 'take', - amount: order.currency == 1000 ? takeAmount / 100000000 : takeAmount, + amount: order.currency === 1000 ? takeAmount / 100000000 : takeAmount, }, { tokenSHA256: robot.tokenSHA256 }, ) .then((data) => { setLoadingTake(false); - if (data.bad_request) { + if (data?.bad_request !== undefined) { setBadRequest(data.bad_request); } else { setOrder(data); setBadRequest(''); } + }) + .catch(() => { + setBadRequest('Request error'); }); }; return ( - {badRequest != '' ? ( + {badRequest !== '' ? ( {t(badRequest)} diff --git a/frontend/src/components/OrderDetails/index.tsx b/frontend/src/components/OrderDetails/index.tsx index cf396d82e..5d42d2672 100644 --- a/frontend/src/components/OrderDetails/index.tsx +++ b/frontend/src/components/OrderDetails/index.tsx @@ -63,11 +63,11 @@ const OrderDetails = ({ const amountString = useMemo(() => { // precision to 8 decimal if currency is BTC otherwise 4 decimals - if (order.currency == 1000) { + if (order.currency === 1000) { return ( amountToString( order.amount * 100000000, - order.amount ? false : order.has_range, + order.amount > 0 ? false : order.has_range, order.min_amount * 100000000, order.max_amount * 100000000, ) + ' Sats' @@ -76,7 +76,7 @@ const OrderDetails = ({ return ( amountToString( order.amount, - order.amount ? false : order.has_range, + order.amount > 0 ? false : order.has_range, order.min_amount, order.max_amount, ) + ` ${currencyCode}` @@ -91,7 +91,7 @@ const OrderDetails = ({ minutes, seconds, completed, - }: CountdownRenderProps) { + }: CountdownRenderProps): JSX.Element { if (completed) { // Render a completed state return {t('The order has expired')}; @@ -117,18 +117,26 @@ const OrderDetails = ({ } }; - const timerRenderer = function (seconds: number) { + const timerRenderer = function (seconds: number): JSX.Element { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds - hours * 3600) / 60); return ( - {hours > 0 ? hours + 'h' : ''} {minutes > 0 ? zeroPad(minutes) + 'm' : ''}{' '} + {hours > 0 ? `${hours}h` : ''} {minutes > 0 ? `${zeroPad(minutes)}m` : ''}{' '} ); }; // Countdown Renderer callback with condition - const countdownPenaltyRenderer = function ({ minutes, seconds, completed }) { + const countdownPenaltyRenderer = ({ + minutes, + seconds, + completed, + }: { + minutes: number; + seconds: number; + completed: boolean; + }): JSX.Element => { if (completed) { // Render a completed state return {t('Penalty lifted, good to go!')}; @@ -150,14 +158,14 @@ const OrderDetails = ({ let receive: string = ''; let sats: string = ''; - const isBuyer = (order.type == 0 && order.is_maker) || (order.type == 1 && !order.is_maker); + const isBuyer = (order.type === 0 && order.is_maker) || (order.type === 1 && !order.is_maker); const tradeFee = order.is_maker ? info?.maker_fee ?? 0 : info?.taker_fee ?? 0; const defaultRoutingBudget = 0.001; const btc_now = order.satoshis_now / 100000000; - const rate = order.amount ? order.amount / btc_now : order.max_amount / btc_now; + const rate = order.amount > 0 ? order.amount / btc_now : Number(order.max_amount) / btc_now; if (isBuyer) { - if (order.amount) { + if (order.amount > 0) { sats = computeSats({ amount: order.amount, fee: -tradeFee, @@ -177,7 +185,7 @@ const OrderDetails = ({ routingBudget: defaultRoutingBudget, rate, }); - sats = `${min}-${max}`; + sats = `${String(min)}-${String(max)}`; } send = t('You send via {{method}} {{amount}}', { amount: amountString, @@ -188,7 +196,7 @@ const OrderDetails = ({ amount: sats, }); } else { - if (order.amount) { + if (order.amount > 0) { sats = computeSats({ amount: order.amount, fee: tradeFee, @@ -205,7 +213,7 @@ const OrderDetails = ({ fee: tradeFee, rate, }); - sats = `${min}-${max}`; + sats = `${String(min)}-${String(max)}`; } send = t('You send via Lightning {{amount}} Sats (Approx)', { amount: sats }); receive = t('You receive via {{method}} {{amount}}', { @@ -233,9 +241,9 @@ const OrderDetails = ({ @@ -246,9 +254,9 @@ const OrderDetails = ({ @@ -256,7 +264,7 @@ const OrderDetails = ({ 0 ? 'Amount' : 'Amount Range'} /> } secondary={ - order.currency == 1000 ? t('Swap destination') : t('Accepted payment methods') + order.currency === 1000 ? t('Swap destination') : t('Accepted payment methods') } /> @@ -372,13 +380,13 @@ const OrderDetails = ({ /> ) : null} - {!order.price_now && order.is_explicit ? ( + {order.price_now === undefined && order.is_explicit ? ( ) : null} - {!order.price_now && !order.is_explicit ? ( + {order.price_now === undefined && !order.is_explicit ? ( ) : null} diff --git a/frontend/src/components/PaymentMethods/StringAsIcons.tsx b/frontend/src/components/PaymentMethods/StringAsIcons.tsx index 975d8133e..2fcf5592b 100644 --- a/frontend/src/components/PaymentMethods/StringAsIcons.tsx +++ b/frontend/src/components/PaymentMethods/StringAsIcons.tsx @@ -19,11 +19,11 @@ const StringAsIcons: React.FC = ({ othersText, verbose, size, text = '' }: Props const parsedText = useMemo(() => { const rows = []; - let custom_methods = text; + let customMethods = text; // Adds icons for each PaymentMethod that matches methods.forEach((method, i) => { if (text.includes(method.name)) { - custom_methods = custom_methods.replace(method.name, ''); + customMethods = customMethods.replace(method.name, ''); rows.push( 0) { + if (charsLeft.length > 0) { rows.push(
{' '} - {custom_methods} + {customMethods}
); diff --git a/frontend/src/components/RobotAvatar/index.tsx b/frontend/src/components/RobotAvatar/index.tsx index a91e2acfe..0ec55bca9 100644 --- a/frontend/src/components/RobotAvatar/index.tsx +++ b/frontend/src/components/RobotAvatar/index.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import SmoothImage from 'react-smooth-image'; -import { Avatar, Badge, Tooltip, useTheme } from '@mui/material'; +import { Avatar, Badge, Tooltip } from '@mui/material'; import { SendReceiveIcon } from '../Icons'; import { apiClient } from '../../services/api'; import placeholder from './placeholder.json'; @@ -51,19 +51,19 @@ const RobotAvatar: React.FC = ({ const path = coordinator ? '/static/federation/' : '/static/assets/avatars/'; const [backgroundData] = useState( - placeholderType == 'generating' ? placeholder.generating : placeholder.loading, + placeholderType === 'generating' ? placeholder.generating : placeholder.loading, ); const backgroundImage = `url(data:${backgroundData.mime};base64,${backgroundData.data})`; - const className = placeholderType == 'loading' ? 'loadingAvatar' : 'generatingAvatar'; + const className = placeholderType === 'loading' ? 'loadingAvatar' : 'generatingAvatar'; useEffect(() => { - if (nickname != undefined) { + if (nickname !== undefined) { if (window.NativeRobosats === undefined) { setAvatarSrc(`${baseUrl}${path}${nickname}${small ? '.small' : ''}.webp`); setNicknameReady(true); } else { setNicknameReady(true); - apiClient + void apiClient .fileImageUrl(baseUrl, `${path}${nickname}${small ? '.small' : ''}.webp`) .then(setAvatarSrc); } @@ -136,7 +136,7 @@ const RobotAvatar: React.FC = ({ const getAvatarWithBadges = useCallback(() => { let component = avatar; - if (statusColor) { + if (statusColor !== undefined) { component = ( {component} @@ -156,7 +156,7 @@ const RobotAvatar: React.FC = ({ ); } - if (tooltip) { + if (tooltip !== undefined) { component = ( {component} diff --git a/frontend/src/components/RobotInfo/index.tsx b/frontend/src/components/RobotInfo/index.tsx index 0d589e537..08bcd745d 100644 --- a/frontend/src/components/RobotInfo/index.tsx +++ b/frontend/src/components/RobotInfo/index.tsx @@ -31,7 +31,7 @@ import { UserNinjaIcon } from '../Icons'; import { getWebln } from '../../utils'; import { apiClient } from '../../services/api'; import { signCleartextMessage } from '../../pgp'; -import { AppContext, UseAppStoreType, origin } from '../../contexts/AppContext'; +import { AppContext, type UseAppStoreType, origin } from '../../contexts/AppContext'; interface Props { robot: Robot; @@ -55,8 +55,8 @@ const RobotInfo: React.FC = ({ robot, coordinator, onClose }: Props) => { const [weblnEnabled, setWeblnEnabled] = useState(false); const [openEnableTelegram, setOpenEnableTelegram] = useState(false); - const handleWebln = async () => { - const webln = await getWebln() + const handleWebln = async (): void => { + void getWebln() .then(() => { setWeblnEnabled(true); }) @@ -64,58 +64,59 @@ const RobotInfo: React.FC = ({ robot, coordinator, onClose }: Props) => { setWeblnEnabled(false); console.log('WebLN not available'); }); - return webln; }; useEffect(() => { handleWebln(); }, []); - const handleWeblnInvoiceClicked = async (e: any) => { + const handleWeblnInvoiceClicked = async (e: MouseEvent): void => { e.preventDefault(); - if (robot.earnedRewards) { + if (robot.earnedRewards > 0) { const webln = await getWebln(); const invoice = webln.makeInvoice(robot.earnedRewards).then(() => { - if (invoice) { + if (invoice != null) { handleSubmitInvoiceClicked(e, invoice.paymentRequest); } }); } }; - const handleSubmitInvoiceClicked = (e: any, rewardInvoice: string) => { + const handleSubmitInvoiceClicked = (e: any, rewardInvoice: string): void => { setBadInvoice(''); setShowRewardsSpinner(true); - signCleartextMessage(rewardInvoice, robot.encPrivKey, robot.token).then((signedInvoice) => { - apiClient - .post( - url, - '/api/reward/', - { - invoice: signedInvoice, - }, - { tokenSHA256: robot.tokenSHA256 }, - ) - .then((data: any) => { - setBadInvoice(data.bad_invoice ?? ''); - setShowRewardsSpinner(false); - setWithdrawn(data.successful_withdrawal); - setOpenClaimRewards(!data.successful_withdrawal); - const newRobot = { - ...robot, - earnedRewards: data.successful_withdrawal ? 0 : robot.earnedRewards, - }; - dispatchFederation({ - type: 'updateRobot', - payload: { shortAlias: coordinator.shortAlias, robot: newRobot }, + void signCleartextMessage(rewardInvoice, robot.encPrivKey, robot.token).then( + (signedInvoice) => { + void apiClient + .post( + url, + '/api/reward/', + { + invoice: signedInvoice, + }, + { tokenSHA256: robot.tokenSHA256 }, + ) + .then((data: any) => { + setBadInvoice(data.bad_invoice ?? ''); + setShowRewardsSpinner(false); + setWithdrawn(data.successful_withdrawal); + setOpenClaimRewards(!(data.successful_withdrawal !== undefined)); + const newRobot = { + ...robot, + earnedRewards: data.successful_withdrawal !== undefined ? 0 : robot.earnedRewards, + }; + dispatchFederation({ + type: 'updateRobot', + payload: { shortAlias: coordinator.shortAlias, robot: newRobot }, + }); }); - }); - }); + }, + ); e.preventDefault(); }; - const setStealthInvoice = (wantsStealth: boolean) => { - apiClient + const setStealthInvoice = (wantsStealth: boolean): void => { + void apiClient .post(url, '/api/stealth/', { wantsStealth }, { tokenSHA256: robot.tokenSHA256 }) .then((data) => { const newRobot = { ...robot, stealthInvoices: data?.wantsStealth }; @@ -133,21 +134,21 @@ const RobotInfo: React.FC = ({ robot, coordinator, onClose }: Props) => { {robot.earnedRewards > 0 && (  {t('Claim Sats!')} )} - {robot.activeOrderId && ( + {robot.activeOrderId > 0 && (  {t('Active order!')} )} - {robot.lastOrderId && !robot.activeOrderId && ( + {robot.lastOrderId > 0 && robot.activeOrderId === undefined && (  {t('finished order')} )} - {robot.activeOrderId ? ( + {robot.activeOrderId > 0 ? ( { - navigate(`/order/${robot.activeOrderId}`); + navigate(`/order/${String(robot.activeOrderId)}`); onClose(); }} > @@ -161,10 +162,10 @@ const RobotInfo: React.FC = ({ robot, coordinator, onClose }: Props) => { secondary={t('Your current order')} /> - ) : robot.lastOrderId ? ( + ) : robot.lastOrderId > 0 ? ( { - navigate(`/order/${robot.lastOrderId}`); + navigate(`/order/${String(robot.lastOrderId)}`); onClose(); }} > @@ -284,8 +285,8 @@ const RobotInfo: React.FC = ({ robot, coordinator, onClose }: Props) => { = ({ robot, coordinator, onClose }: Props) => {