Skip to content

Commit

Permalink
Make @umami/state package platform agnostic (#2329)
Browse files Browse the repository at this point in the history
  • Loading branch information
OKendigelyan authored Jan 21, 2025
1 parent 26ce960 commit 0a3987e
Show file tree
Hide file tree
Showing 22 changed files with 119 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const RestoreLedger = ({
toast({ description: "Account successfully created!", status: "success" });
closeModal();
}, LEDGER_TIMEOUT),
error => {
(error: { name: string; message: any }) => {
if (error.name === "PublicKeyRetrievalError") {
return {
description: "Request rejected. Please unlock your Ledger and open the Tezos app",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const useSignWithBeacon = (

return openWith(<SuccessStep hash={opHash} />);
},
error => ({
(error: { message: any }) => ({
description: `Failed to confirm Beacon operation: ${error.message}`,
})
);
Expand Down
21 changes: 14 additions & 7 deletions apps/desktop/src/providers/UmamiTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { ChakraProvider, ColorModeScript } from "@chakra-ui/react";
import { ChakraProvider, ColorModeScript, useToast } from "@chakra-ui/react";
import { ToastProvider } from "@umami/utils";

import theme from "../style/theme";

export const UmamiTheme = (props: any) => (
<ChakraProvider theme={theme}>
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
{props.children}
</ChakraProvider>
);
export const UmamiTheme = (props: any) => {
const toast = useToast();

return (
<ToastProvider toast={toast}>
<ChakraProvider theme={theme}>
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
{props.children}
</ChakraProvider>
</ToastProvider>
);
};
2 changes: 1 addition & 1 deletion apps/desktop/src/utils/beacon/useHandleBeaconMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const useHandleBeaconMessage = () => {

return openWith(modal, { onClose });
},
error => ({
(error: { message: any }) => ({
description: `Error while processing Beacon request: ${error.message}`,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const useSignWithBeacon = ({

return openWith(<SuccessStep hash={opHash} />);
},
error => ({
(error: { message: any }) => ({
description: `Failed to confirm Beacon operation: ${error.message}`,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const useSignWithWalletConnect = ({
await walletKit.respondSessionRequest({ topic: requestId.topic, response });
return openWith(<SuccessStep hash={opHash} />);
},
error => ({
(error: { message: any }) => ({
description: `Failed to confirm WalletConnect operation: ${error.message}`,
})
);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/beacon/useHandleBeaconMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export const useHandleBeaconMessage = () => {

return openWith(modal, { onClose });
},
error => ({
(error: { message: any }) => ({
description: `Error while processing Beacon request: ${error.message}`,
})
);
Expand Down
30 changes: 15 additions & 15 deletions apps/web/src/providers/UmamiTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ChakraProvider, ColorModeScript } from "@chakra-ui/react";
import { ChakraProvider, ColorModeScript, useToast } from "@chakra-ui/react";
import { Global, css } from "@emotion/react";
import { ToastProvider } from "@umami/utils";
import { type PropsWithChildren } from "react";
import "focus-visible/dist/focus-visible";

Expand All @@ -17,17 +18,16 @@ const GlobalStyles = css`
}
`;

export const UmamiTheme = ({ children }: PropsWithChildren) => (
<ChakraProvider
theme={theme}
toastOptions={{
defaultOptions: {
render: CustomToast,
},
}}
>
<Global styles={GlobalStyles} />
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
{children}
</ChakraProvider>
);
export const UmamiTheme = ({ children }: PropsWithChildren) => {
const toast = useToast({ render: CustomToast });

return (
<ChakraProvider theme={theme}>
<ToastProvider toast={toast}>
<Global styles={GlobalStyles} />
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
{children}
</ToastProvider>
</ChakraProvider>
);
};
5 changes: 5 additions & 0 deletions apps/web/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ jest.doMock("@chakra-ui/react", () => ({
useColorMode: () => ({ colorMode: "light", toggleColorMode: jest.fn() }),
}));

jest.mock("@umami/utils", () => ({
...jest.requireActual("@umami/utils"),
useCustomToast: () => mockToast,
}));

jest.mock("./utils/persistor", () => ({
pause: jest.fn(),
}));
Expand Down
1 change: 1 addition & 0 deletions packages/data-polling/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"@umami/state": "workspace:^",
"@umami/tezos": "workspace:^",
"@umami/tzkt": "workspace:^",
"@umami/test-utils": "workspace:^",
"date-fns": "^4.1.0",
"framer-motion": "^11.15.0",
"lodash": "^4.17.21",
Expand Down
2 changes: 2 additions & 0 deletions packages/data-polling/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { webcrypto } from "crypto";
import { TextDecoder, TextEncoder } from "util";

import { mockToast } from "@umami/state";
import { mockLocalStorage } from "@umami/test-utils";

beforeEach(() => {
Object.defineProperties(global, {
crypto: { value: webcrypto, writable: true },
TextDecoder: { value: TextDecoder, writable: true },
TextEncoder: { value: TextEncoder, writable: true },
localStorage: { value: mockLocalStorage(), writable: true },
});
});

Expand Down
7 changes: 3 additions & 4 deletions packages/data-polling/src/testUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import * as testLib from "@testing-library/react";
import { type UmamiStore, makeStore } from "@umami/state";
import { type PropsWithChildren, act } from "react";
import { Provider } from "react-redux";
import { makeStore, UmamiStore } from "@umami/state";
import { PropsWithChildren, act } from "react";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const customRenderHook = <
Result,
Expand Down
3 changes: 0 additions & 3 deletions packages/state/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
},
"dependencies": {
"@airgap/beacon-wallet": "^4.3.1",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@reduxjs/toolkit": "^2.5.0",
"@reown/walletkit": "^1.0.1",
"@tanstack/react-query": "^5.62.11",
Expand Down
23 changes: 16 additions & 7 deletions packages/state/src/hooks/beacon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
type NetworkType,
Serializer,
} from "@airgap/beacon-wallet";
import { useToast } from "@chakra-ui/react";
import { useQuery } from "@tanstack/react-query";
import { type RawPkh } from "@umami/tezos";
import { useCustomToast } from "@umami/utils";
import { uniq } from "lodash";
import { useDispatch } from "react-redux";

Expand Down Expand Up @@ -102,7 +102,7 @@ export const useRemoveBeaconPeersByAccounts = () => {

export const useAddPeer = () => {
const { refresh } = useBeaconPeers();
const toast = useToast();
const toast = useCustomToast();

return (payload: string) =>
new Serializer()
Expand All @@ -111,11 +111,20 @@ export const useAddPeer = () => {
.then(peer => WalletClient.addPeer(peer as ExtendedPeerInfo))
.then(() => refresh())
.catch(e => {
toast({
description:
"Beacon sync code in the clipboard is invalid. Please copy a beacon sync code from the dApp",
status: "error",
});
const description =
"Beacon sync code in the clipboard is invalid. Please copy a beacon sync code from the dApp";
const type = "error";

toast.show
? toast.show({
type,
text1: description,
})
: toast({
description,
status: type,
});

console.error(e);
});
};
4 changes: 2 additions & 2 deletions packages/state/src/hooks/useAsyncActionHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ describe("useAsyncActionHandler", () => {
view.result.current.handleAsyncActionUnsafe(() => Promise.reject(new Error("test error")))
)
).rejects.toThrow("test error");
expect(mockToast).toHaveBeenCalledTimes(2);
expect(mockToast).toHaveBeenCalledTimes(1);
});

it("Unsafe propagates the error and shows the toast once on first handling", async () => {
Expand All @@ -181,7 +181,7 @@ describe("useAsyncActionHandler", () => {
status: "error",
isClosable: true,
});
expect(mockToast).toHaveBeenCalledTimes(2);
expect(mockToast).toHaveBeenCalledTimes(1);
});

it("Unsafe propagates the error and shows no toast on second handling", async () => {
Expand Down
18 changes: 4 additions & 14 deletions packages/state/src/hooks/useAsyncActionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { type UseToastOptions, useToast } from "@chakra-ui/react";
import { getErrorContext } from "@umami/utils";
import { type ToastOptions, getErrorContext, useCustomToast } from "@umami/utils";
import { useCallback, useRef, useState } from "react";

import { useAppDispatch } from "./useAppDispatch";
import { errorsActions } from "../slices";
import { mockToast } from "../testUtils";

/**
* Hook for gracefully handling async actions.
Expand All @@ -22,13 +20,13 @@ import { mockToast } from "../testUtils";
export const useAsyncActionHandler = () => {
const [isLoading, setIsLoading] = useState(false);
const isLoadingRef = useRef(isLoading);
const toast = useToast();
const toast = useCustomToast();
const dispatch = useAppDispatch();

const handleAsyncActionUnsafe = useCallback(
async <T>(
fn: () => Promise<T>,
toastOptions?: UseToastOptions | ((error: any) => UseToastOptions)
toastOptions?: ToastOptions | ((error: any) => ToastOptions)
): Promise<T | void> => {
if (isLoadingRef.current) {
return;
Expand All @@ -53,14 +51,6 @@ export const useAsyncActionHandler = () => {
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});

// TODO: fix this dirty hack
mockToast({
description: errorContext.description,
status: "error",
isClosable: true,
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});

dispatch(errorsActions.add(errorContext));
}
throw error;
Expand All @@ -76,7 +66,7 @@ export const useAsyncActionHandler = () => {
const handleAsyncAction = useCallback(
async <T>(
fn: () => Promise<T>,
toastOptions?: UseToastOptions | ((error: any) => UseToastOptions)
toastOptions?: ToastOptions | ((error: any) => ToastOptions)
): Promise<T | void> => handleAsyncActionUnsafe(fn, toastOptions).catch(() => {}),
[handleAsyncActionUnsafe]
);
Expand Down
6 changes: 3 additions & 3 deletions packages/state/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Object.defineProperties(global, {
fetch: { value: jest.fn(), writable: true },
});

jest.mock("@chakra-ui/react", () => ({
...jest.requireActual("@chakra-ui/react"),
useToast: () => mockToast,
jest.mock("@umami/utils", () => ({
...jest.requireActual("@umami/utils"),
useCustomToast: () => mockToast,
}));

jest.mock("./beacon/WalletClient", () => ({
Expand Down
13 changes: 6 additions & 7 deletions packages/state/src/testUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import * as testLib from "@testing-library/react";
import { type Account } from "@umami/core";
import { type Multisig } from "@umami/multisig";
import { type RawPkh } from "@umami/tezos";
import { type PropsWithChildren, act } from "react";
import { Provider } from "react-redux";

import { accountsActions, multisigsActions } from "./slices";
import { makeStore, UmamiStore } from "./store";
import * as testLib from "@testing-library/react";
import { type UmamiStore, makeStore } from "./store";

export const addTestAccount = (store: UmamiStore, account: Account | Multisig) => {
if (!("type" in account) || account.type === "multisig") {
Expand All @@ -18,11 +22,6 @@ export const addTestAccounts = (store: UmamiStore, accounts: (Account | Multisig
accounts.forEach(account => addTestAccount(store, account));
};

import { PropsWithChildren, act } from "react";
import { Provider } from "react-redux";
import { RawPkh } from "@umami/tezos";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const customRenderHook = <
Result,
Props,
Expand Down
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./ErrorContext";
export * from "./providers";
27 changes: 27 additions & 0 deletions packages/utils/src/providers/ToastProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type PropsWithChildren, createContext, useContext } from "react";

// TODO: fix this type when we have a better toast implementation
export type ToastOptions = any;

export type Toast = {
show?: (options: ToastOptions) => void;
[key: string]: any;
} & ((options: ToastOptions) => void);

type ToastContextType = {
toast: Toast;
};

const ToastContext = createContext<ToastContextType | undefined>(undefined);

export const useCustomToast = () => {
const toastContext = useContext(ToastContext);
if (!toastContext) {
throw new Error("useCustomToast must be used within a ToastProvider");
}
return toastContext.toast;
};

export const ToastProvider = ({ children, toast }: PropsWithChildren<{ toast: Toast }>) => (
<ToastContext.Provider value={{ toast }}>{children}</ToastContext.Provider>
);
1 change: 1 addition & 0 deletions packages/utils/src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ToastProvider";
Loading

1 comment on commit 0a3987e

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title Lines Statements Branches Functions
apps/desktop Coverage: 83%
83.82% (1788/2133) 79.58% (850/1068) 78.27% (454/580)
apps/web Coverage: 83%
83.82% (1788/2133) 79.58% (850/1068) 78.27% (454/580)
packages/components Coverage: 97%
97.51% (196/201) 95.91% (94/98) 88.13% (52/59)
packages/core Coverage: 81%
82.37% (215/261) 72.51% (95/131) 81.66% (49/60)
packages/crypto Coverage: 100%
100% (43/43) 90.9% (10/11) 100% (7/7)
packages/data-polling Coverage: 96%
94.63% (141/149) 87.5% (21/24) 92.85% (39/42)
packages/multisig Coverage: 98%
98.47% (129/131) 85.71% (18/21) 100% (36/36)
packages/social-auth Coverage: 100%
100% (21/21) 100% (11/11) 100% (3/3)
packages/state Coverage: 85%
84.3% (827/981) 80.5% (190/236) 77.83% (302/388)
packages/tezos Coverage: 89%
88.72% (118/133) 94.59% (35/37) 86.84% (33/38)
packages/tzkt Coverage: 89%
87.32% (62/71) 87.5% (14/16) 80.48% (33/41)

Please sign in to comment.