diff --git a/.github/workflows/pledge-signer-sync/pledge-sync.js b/.github/workflows/pledge-signer-sync/pledge-sync.js index 729d105d44..741b077585 100644 --- a/.github/workflows/pledge-signer-sync/pledge-sync.js +++ b/.github/workflows/pledge-signer-sync/pledge-sync.js @@ -25,7 +25,10 @@ if (!GALXE_ACCESS_TOKEN || !FIRESTORE_USER || !FIRESTORE_PASSWORD) { // Limit sync range to last 4 days ( 2 days from last sync + 2 days from now ) const TARGET_DATE = new Date(Date.now() - 4 * 24 * 60 * 60_000) -const wait = (ms) => new Promise((r) => setTimeout(r, ms)) +const wait = (ms) => + new Promise((r) => { + setTimeout(r, ms) + }) const getAddresses = async () => { const app = initializeApp({ diff --git a/__mocks__/@ethersproject/web.ts b/__mocks__/@ethersproject/web.ts index d257b1391d..91b2238302 100644 --- a/__mocks__/@ethersproject/web.ts +++ b/__mocks__/@ethersproject/web.ts @@ -1,4 +1,5 @@ -// eslint-disable-next-line import/no-extraneous-dependencies +// Fixing this here requires digging into Jest a bit, kicking for now. +// eslint-disable-next-line import/no-import-module-exports import sinon from "sinon" const mock = diff --git a/__mocks__/webextension-polyfill.ts b/__mocks__/webextension-polyfill.ts index 44eca39833..3ead628ac3 100644 --- a/__mocks__/webextension-polyfill.ts +++ b/__mocks__/webextension-polyfill.ts @@ -1,3 +1,5 @@ +// Fixing this here requires digging into Jest a bit, kicking for now. +// eslint-disable-next-line import/no-import-module-exports import { Tabs } from "webextension-polyfill" const browserMock = jest.createMockFromModule< diff --git a/background/main.ts b/background/main.ts index bbad70cf3f..cce9e9e959 100644 --- a/background/main.ts +++ b/background/main.ts @@ -244,7 +244,7 @@ const reduxCache: Middleware = (store) => (next) => (action) => { // Declared out here so ReduxStoreType can be used in Main.store type // declaration. -const initializeStore = (preloadedState = {}, main: Main) => +const initializeStore = (main: Main, preloadedState = {}) => configureStore({ preloadedState, reducer: rootReducer, @@ -506,7 +506,7 @@ export default class Main extends BaseService { }) // Start up the redux store and set it up for proxying. - this.store = initializeStore(savedReduxState, this) + this.store = initializeStore(this, savedReduxState) const queueUpdate = debounce( (lastState, newState, updateFn) => { diff --git a/background/services/chain/serial-fallback-provider.ts b/background/services/chain/serial-fallback-provider.ts index 60e20a1bfc..8f0c5d352a 100644 --- a/background/services/chain/serial-fallback-provider.ts +++ b/background/services/chain/serial-fallback-provider.ts @@ -266,7 +266,7 @@ export default class SerialFallbackProvider extends JsonRpcProvider { private subscriptions: { tag: string param: unknown[] - processFunc: (result: unknown) => void + processFunc: (_: unknown) => void }[] = [] // Information on event subscriptions, which can be restored on non-WebSocket diff --git a/background/services/chain/tests/index.unit.test.ts b/background/services/chain/tests/index.unit.test.ts index 0fcb0f2af6..8aff021c01 100644 --- a/background/services/chain/tests/index.unit.test.ts +++ b/background/services/chain/tests/index.unit.test.ts @@ -148,7 +148,8 @@ describe("Chain Service", () => { it("should get block prices if the NETWORK_POLLING_TIMEOUT has been exceeded", async () => { // Set last activity time to 10 minutes ago const externalized = chainService as unknown as ChainServiceExternalized - externalized.lastUserActivityOnNetwork[ETHEREUM.chainID] = Date.now() - 10 * MINUTE + externalized.lastUserActivityOnNetwork[ETHEREUM.chainID] = + Date.now() - 10 * MINUTE const getBlockPricesStub = sandbox .stub(gas, "default") .callsFake(async () => createBlockPrices()) diff --git a/background/services/provider-bridge/index.ts b/background/services/provider-bridge/index.ts index fadc30696f..fa2737d367 100644 --- a/background/services/provider-bridge/index.ts +++ b/background/services/provider-bridge/index.ts @@ -67,7 +67,7 @@ export type AddChainRequestData = ValidatedAddEthereumChainParameter & { */ export default class ProviderBridgeService extends BaseService { #pendingPermissionsRequests: { - [origin: string]: (value: unknown) => void + [origin: string]: (_: unknown) => void } = {} #pendingAddNetworkRequests: { diff --git a/ui/__mocks__/IntersectionObserver.ts b/ui/__mocks__/IntersectionObserver.ts index f8fa24db9d..50913e7a75 100644 --- a/ui/__mocks__/IntersectionObserver.ts +++ b/ui/__mocks__/IntersectionObserver.ts @@ -1,5 +1,5 @@ export default class IntersectionObserverMock { - callbackMap: Map void> = new Map() + callbackMap: Map void> = new Map() constructor( protected callback: (entry: [Partial]) => void diff --git a/ui/components/AccountsNotificationPanel/AccountsNotificationPanelAccounts.tsx b/ui/components/AccountsNotificationPanel/AccountsNotificationPanelAccounts.tsx index a1fe9bd6f2..e934689307 100644 --- a/ui/components/AccountsNotificationPanel/AccountsNotificationPanelAccounts.tsx +++ b/ui/components/AccountsNotificationPanel/AccountsNotificationPanelAccounts.tsx @@ -304,7 +304,7 @@ type Props = { export default function AccountsNotificationPanelAccounts({ onCurrentAddressChange, -}: Props): ReactElement { +}: Props): ReactElement | null { const { t } = useTranslation() const dispatch = useBackgroundDispatch() const history = useHistory() @@ -362,7 +362,7 @@ export default function AccountsNotificationPanelAccounts({ // If there are no account totals for the given type, skip the section. if (accountTypeTotals === undefined || accountTypeTotals.length <= 0) { - return <> + return null } const accountTotalsByType = accountTypeTotals.reduce( diff --git a/ui/components/AccountsNotificationPanel/AccountsNotificationPanelNotifications.tsx b/ui/components/AccountsNotificationPanel/AccountsNotificationPanelNotifications.tsx index 2afa57318c..e9de3ee5c8 100644 --- a/ui/components/AccountsNotificationPanel/AccountsNotificationPanelNotifications.tsx +++ b/ui/components/AccountsNotificationPanel/AccountsNotificationPanelNotifications.tsx @@ -2,6 +2,9 @@ import React, { ReactElement } from "react" import AccountsNotificationPanelNotificationItem from "./AccountsNotificationPanelNotificationItem" import SharedButton from "../Shared/SharedButton" +// This file is currently still a stub, so using sample data. +/* eslint-disable react/no-array-index-key */ + export default function AccountsNotificationPanelNotifications(): ReactElement { return ( <> diff --git a/ui/components/Onboarding/OnboardingOpenClaimFlowBanner.tsx b/ui/components/Onboarding/OnboardingOpenClaimFlowBanner.tsx index 55f761abf5..de1201775e 100644 --- a/ui/components/Onboarding/OnboardingOpenClaimFlowBanner.tsx +++ b/ui/components/Onboarding/OnboardingOpenClaimFlowBanner.tsx @@ -238,7 +238,7 @@ function IneligibleCTAContent({ ) } -export default function OnboardingOpenClaimFlowBanner(): ReactElement { +export default function OnboardingOpenClaimFlowBanner(): ReactElement | null { const claimAmount = useBackgroundSelector(selectEligibility).toString() const isClaimLoading = useBackgroundSelector(selectEligibilityLoading) @@ -266,7 +266,7 @@ export default function OnboardingOpenClaimFlowBanner(): ReactElement { ((!hasSomethingToClaim || isClaimLoading) && addresHasNothingToClaimClosed.split(";").includes(currentAddress)) ) - return <> + return null if (isClaimLoading) return ( diff --git a/ui/components/Shared/SharedDropDown.tsx b/ui/components/Shared/SharedDropDown.tsx index db85702a3e..52ebabde7a 100644 --- a/ui/components/Shared/SharedDropDown.tsx +++ b/ui/components/Shared/SharedDropDown.tsx @@ -1,4 +1,10 @@ -import React, { ReactElement, useRef, useState } from "react" +import React, { + ReactElement, + useCallback, + useMemo, + useRef, + useState, +} from "react" import { useTranslation } from "react-i18next" import { useOnClickOutside } from "../../hooks" import AccountitemOptionLabel from "../AccountItem/AccountItemOptionLabel" @@ -39,11 +45,19 @@ type ContentProps = { function DropdownContainer({ children }: DropdownContainerProps): ReactElement { const [isOpen, setIsOpen] = useState(false) + const dropdownToggle = useCallback( + (value?: boolean) => + setIsOpen(value ?? ((existingValue) => !existingValue)), + [setIsOpen] + ) - const contextValue: DropdownContextValue = { - isOpen, - toggle: (value) => setIsOpen(value ?? ((p) => !p)), - } + const contextValue: DropdownContextValue = useMemo( + () => ({ + isOpen, + toggle: dropdownToggle, + }), + [isOpen, dropdownToggle] + ) return ( diff --git a/ui/components/Shared/SharedSkeletonLoader.tsx b/ui/components/Shared/SharedSkeletonLoader.tsx index 09b75ec31d..413ab97c9e 100644 --- a/ui/components/Shared/SharedSkeletonLoader.tsx +++ b/ui/components/Shared/SharedSkeletonLoader.tsx @@ -8,11 +8,14 @@ export default function SharedSkeletonLoader(props: { children?: ReactNode isLoaded?: boolean customStyles?: string -}): ReactElement | ReactNode { +}): ReactElement { const { width, height, borderRadius, isLoaded, customStyles, children } = props - if (isLoaded) return children + // Want to return a ReactElement to make this maximally easy to integrate, + // whereas children can be a ReactNode; Fragment will let us achieve that. + // eslint-disable-next-line react/jsx-no-useless-fragment + if (isLoaded) return <>{children} return (
diff --git a/ui/components/Signing/SignatureDetails/TransactionSignatureDetails/TransactionSignatureDetailsPanelSwitcher.tsx b/ui/components/Signing/SignatureDetails/TransactionSignatureDetails/TransactionSignatureDetailsPanelSwitcher.tsx index daa99e4c28..67ea3b54f5 100644 --- a/ui/components/Signing/SignatureDetails/TransactionSignatureDetails/TransactionSignatureDetailsPanelSwitcher.tsx +++ b/ui/components/Signing/SignatureDetails/TransactionSignatureDetails/TransactionSignatureDetailsPanelSwitcher.tsx @@ -8,7 +8,7 @@ export default function TransactionDataPanelSwitcher({ transactionRequest, }: { transactionRequest: EnrichedEVMTransactionRequest -}): ReactElement { +}): ReactElement | null { const switchablePanels = useSwitchablePanels([ { name: "Details", @@ -24,5 +24,5 @@ export default function TransactionDataPanelSwitcher({ }, ]) - return <>{switchablePanels} + return switchablePanels } diff --git a/ui/hooks/index.ts b/ui/hooks/index.ts index 89adacc594..9741d960d8 100644 --- a/ui/hooks/index.ts +++ b/ui/hooks/index.ts @@ -1,6 +1,6 @@ import { isAllowedQueryParamPage } from "@tallyho/provider-bridge-shared" -import { useState, useEffect, ReactElement, ReactNode } from "react" +import React, { useState, useEffect, ReactElement } from "react" import { getAllAddresses } from "@tallyho/tally-background/redux-slices/selectors/accountsSelectors" import SharedPanelSwitcher from "../components/Shared/SharedPanelSwitcher" import { useBackgroundSelector } from "./redux-hooks" @@ -41,7 +41,7 @@ type PanelDescriptor = { * interchange between several screens exclusively from each other. * * The underlying component is a `SharedPanelSwitcher`, and the hook returns - * the switcher element and current panel being displayed as siblings for + * the switcher element and current panel being displayed as a fragment for * adding to a JSX component. * * @example @@ -65,20 +65,24 @@ type PanelDescriptor = { * }, * ]) - * return <>{switchablePanels} + * return switchablePanels * ``` */ -export function useSwitchablePanels(panels: PanelDescriptor[]): ReactNode { +export function useSwitchablePanels( + panels: PanelDescriptor[] +): ReactElement | null { const [panelNumber, setPanelNumber] = useState(0) - return [ - SharedPanelSwitcher({ - setPanelNumber, - panelNumber, - panelNames: panels.map(({ name }) => name), - }), - panels[panelNumber].panelElement(), - ] + return React.Fragment({ + children: [ + SharedPanelSwitcher({ + setPanelNumber, + panelNumber, + panelNames: panels.map(({ name }) => name), + }), + panels[panelNumber].panelElement(), + ], + }) } export function useIsOnboarding(): boolean { diff --git a/ui/pages/Earn/DepositCard.tsx b/ui/pages/Earn/DepositCard.tsx index fca9d74c84..1acd4b5ee4 100644 --- a/ui/pages/Earn/DepositCard.tsx +++ b/ui/pages/Earn/DepositCard.tsx @@ -18,14 +18,14 @@ export const getDisplayAPR = ( } return `${data.low} - ${data.high}` } - return data.totalAPR + return data.totalAPR ?? "" } export default function EarnDepositedCard({ vault, }: { vault: AvailableVault -}): ReactElement { +}): ReactElement | null { const { vaultAddress, icons, userDeposited, asset } = vault const userDepositedAmount = fromFixedPointNumber( { diff --git a/ui/pages/EarnDeposit.tsx b/ui/pages/EarnDeposit.tsx index 706ee5002d..e4ee2bd86f 100644 --- a/ui/pages/EarnDeposit.tsx +++ b/ui/pages/EarnDeposit.tsx @@ -46,7 +46,7 @@ import { AccordionPoolInfoContent, } from "./Earn/AccordionPoolInfo" -export default function EarnDeposit(): ReactElement { +export default function EarnDeposit(): ReactElement | null { const storedInput = useBackgroundSelector(selectEarnInputAmount) const account = useBackgroundSelector(selectCurrentAccount) const accountBalances = useBackgroundSelector(selectCurrentAccountBalances) diff --git a/ui/pages/Popup.tsx b/ui/pages/Popup.tsx index 00cc9d8508..662482b45f 100644 --- a/ui/pages/Popup.tsx +++ b/ui/pages/Popup.tsx @@ -212,17 +212,15 @@ export function Main(): ReactElement { .hide { opacity: 0; } - `} - - {isDappPopup && ( - - )} + `} + `} + ) } diff --git a/ui/routes/routes.tsx b/ui/routes/routes.tsx index 75bbc7711d..47c34956ae 100644 --- a/ui/routes/routes.tsx +++ b/ui/routes/routes.tsx @@ -30,7 +30,7 @@ type PageList = { // Tricky to handle all props components are // accepting here. // eslint-disable-next-line @typescript-eslint/no-explicit-any - Component: (...args: any[]) => ReactElement + Component: (...args: any[]) => ReactElement | null hasTabBar: boolean hasTopBar: boolean persistOnClose: boolean