Skip to content

Commit

Permalink
refactor: update import paths for massaToken and constants; introduce…
Browse files Browse the repository at this point in the history
… operationHandler for better operation management
  • Loading branch information
Ben-Rey committed Jan 16, 2025
1 parent 0e68b9c commit 75aecfd
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 148 deletions.
2 changes: 1 addition & 1 deletion src/lib/ConnectMassaWallets/components/BearbyWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MASBalance } from './MASBalance';
import { WalletError } from './WalletError';
import Intl from '../i18n';
import { useAccountStore } from '../store';
import { BEARBY_INSTALL } from '../../massa-react/const';
import { BEARBY_INSTALL } from '../../massa-react/utils/const';

export default function BearbyWallet() {
const { connectedAccount, isFetching } = useAccountStore();
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ConnectMassaWallets/components/MASBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react';
import Intl from '../i18n';
import { useAccountStore } from '../store';
import { FetchingLine } from '../../../components';
import { massaToken } from '../../massa-react/const';
import { massaToken } from '../../massa-react/utils/const';
import { formatAmount } from '../../util/parseAmount';

export function MASBalance() {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ConnectMassaWallets/components/MetamaskWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MASBalance } from './MASBalance';
import { WalletError } from './WalletError';
import Intl from '../i18n';
import { useAccountStore } from '../store';
import { METAMASK_INSTALL } from '../../massa-react/const';
import { METAMASK_INSTALL } from '../../massa-react/utils/const';

export default function MetamaskWallet() {
const { connectedAccount, isFetching } = useAccountStore();
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ConnectMassaWallets/components/StationWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
MASSA_STATION_INSTALL,
MASSA_STATION_STORE,
MASSA_WALLET_CREATE_ACCOUNT,
} from '../../massa-react/const';
} from '../../massa-react/utils/const';
import Intl from '../i18n';
import { useAccountStore } from '../store';

Expand Down
84 changes: 11 additions & 73 deletions src/lib/massa-react/hooks/useHandleOperation.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { useState } from 'react';
import { CHAIN_ID, Operation, OperationStatus } from '@massalabs/massa-web3';
import Intl from '../i18n';
import { toast } from '../../../components';
import { logSmartContractEvents, showToast } from '../utils';
import { CHAIN_ID, Operation } from '@massalabs/massa-web3';
import { ToasterMessage } from './types';
import { ERROR_STATUSES } from './const';
import {
executeOperation as executeOperationUtil,
OperationState,
} from '../utils/operationHandler';

// TODO: Need to be refactored with the useWriteSmartContract.tsx
export function useHandleOperation() {
const [state, setState] = useState({
const [state, setState] = useState<OperationState>({
isOpPending: false,
isPending: false,
isSuccess: false,
isError: false,
opId: undefined as string | undefined,
opId: undefined,
});

async function handleOperation(
async function executeOperation(
operation: Operation,
messages: ToasterMessage,
final = false,
): Promise<Operation | undefined> {
): Promise<void> {
const networkInfo = await operation.provider.networkInfos();
const isMainnet = networkInfo.chainId === CHAIN_ID.Mainnet;

Expand All @@ -37,68 +36,7 @@ export function useHandleOperation() {
opId: undefined,
});

try {
setState((prev) => ({ ...prev, opId: operation.id }));

const loadingToastId = showToast(
'loading',
messages.pending,
operation.id,
isMainnet,
);

const finalStatus = final
? await operation.waitFinalExecution()
: await operation.waitSpeculativeExecution();

dismissLoadingToast(loadingToastId);

if (finalStatus === OperationStatus.NotFound) {
handleOperationTimeout(messages.timeout, operation.id);
throw new Error('Operation not found');
} else if (ERROR_STATUSES.includes(finalStatus)) {
logSmartContractEvents(operation.provider, operation.id);
throw new Error(`Operation failed with status: ${finalStatus}`);
} else {
handleOperationSuccess(messages.success, operation.id);
return operation;
}
} catch (error) {
handleOperationError(error, messages.error, state.opId);
} finally {
setState((prev) => ({ ...prev, isOpPending: false, isPending: false }));
}
}

function dismissLoadingToast(toastId?: string): void {
if (toastId) {
toast.dismiss(toastId);
} else {
console.warn('Attempted to dismiss a toast with undefined ID.');
}
}

function handleOperationTimeout(
timeoutMessage?: string,
opId?: string,
): void {
setState((prev) => ({ ...prev, isError: true }));
showToast('error', timeoutMessage || Intl.t('steps.failed-timeout'), opId);
}

function handleOperationSuccess(successMessage: string, opId?: string): void {
setState((prev) => ({ ...prev, isSuccess: true }));
showToast('success', successMessage, opId);
}

function handleOperationError(
error: unknown,
errorMessage: string,
opId?: string,
): void {
console.error('Error during smart contract call:', error);
setState((prev) => ({ ...prev, isError: true }));
showToast('error', errorMessage, opId);
await executeOperationUtil(operation, messages, final, isMainnet, setState);
}

return {
Expand All @@ -107,6 +45,6 @@ export function useHandleOperation() {
isPending: state.isPending,
isSuccess: state.isSuccess,
isError: state.isError,
handleOperation,
executeOperation,
};
}
81 changes: 15 additions & 66 deletions src/lib/massa-react/hooks/useWriteSmartContract.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { useState } from 'react';
import { toast } from '../../../components';
import { logSmartContractEvents, showToast } from '../utils';
import Intl from '../i18n';
import { Operation, OperationStatus, Provider } from '@massalabs/massa-web3';
import { executeOperation } from '../utils/operationHandler';
import { Provider } from '@massalabs/massa-web3';
import { ToasterMessage } from './types';
import { ERROR_STATUSES } from './const';

interface State {
isOpPending: boolean;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
opId?: string;
}

export function useWriteSmartContract(account: Provider, isMainnet = false) {
const [state, setState] = useState({
const [state, setState] = useState<State>({
isOpPending: false,
isPending: false,
isSuccess: false,
isError: false,
opId: undefined as string | undefined,
opId: undefined,
});

async function callSmartContract(
Expand All @@ -23,7 +28,7 @@ export function useWriteSmartContract(account: Provider, isMainnet = false) {
coins = 0n,
fee?: bigint,
final = false,
): Promise<Operation | undefined> {
): Promise<void> {
if (state.isOpPending) {
throw new Error('Operation is already pending');
}
Expand All @@ -46,69 +51,13 @@ export function useWriteSmartContract(account: Provider, isMainnet = false) {
fee,
});

setState((prev) => ({ ...prev, opId: operation.id }));

const loadingToastId = showToast(
'loading',
messages.pending,
operation.id,
isMainnet,
);

const finalStatus = final
? await operation.waitFinalExecution()
: await operation.waitSpeculativeExecution();

dismissLoadingToast(loadingToastId);

if (finalStatus === OperationStatus.NotFound) {
handleOperationTimeout(messages.timeout, operation.id);
throw new Error('Operation not found');
} else if (ERROR_STATUSES.includes(finalStatus)) {
logSmartContractEvents(operation.provider, operation.id);
throw new Error(`Operation failed with status: ${finalStatus}`);
} else {
handleOperationSuccess(messages.success, operation.id);
return operation;
}
await executeOperation(operation, messages, final, isMainnet, setState);
} catch (error) {
handleOperationError(error, messages.error, state.opId);
} finally {
setState((prev) => ({ ...prev, isOpPending: false, isPending: false }));
throw error;
}
}

function dismissLoadingToast(toastId?: string): void {
if (toastId) {
toast.dismiss(toastId);
} else {
console.warn('Attempted to dismiss a toast with undefined ID.');
}
}

function handleOperationTimeout(
timeoutMessage?: string,
opId?: string,
): void {
setState((prev) => ({ ...prev, isError: true }));
showToast('error', timeoutMessage || Intl.t('steps.failed-timeout'), opId);
}

function handleOperationSuccess(successMessage: string, opId?: string): void {
setState((prev) => ({ ...prev, isSuccess: true }));
showToast('success', successMessage, opId);
}

function handleOperationError(
error: unknown,
errorMessage: string,
opId?: string,
): void {
console.error('Error during smart contract call:', error);
setState((prev) => ({ ...prev, isError: true }));
showToast('error', errorMessage, opId);
}

return {
opId: state.opId,
isOpPending: state.isOpPending,
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import {
MASSA_EXPLO_URL,
MASSA_EXPLORER_URL,
} from './const';
import Intl from './i18n';
import { toast, ToastContent } from '../../components';
import Intl from '../i18n';
import { toast, ToastContent } from '../../../components';

import { Operation, Provider, PublicProvider } from '@massalabs/massa-web3';
import { Toast } from 'react-hot-toast';
import { OperationToast } from '../ConnectMassaWallets/components/OperationToast';
import { OperationToast } from '../../ConnectMassaWallets/components/OperationToast';

export async function logSmartContractEvents(
provider: PublicProvider,
Expand Down
99 changes: 99 additions & 0 deletions src/lib/massa-react/utils/operationHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Operation, OperationStatus } from '@massalabs/massa-web3';
import { toast } from '../../../components';
import { ERROR_STATUSES } from '../hooks/const';
import { ToasterMessage } from '../hooks/types';
import { showToast, logSmartContractEvents } from '.';

export type OperationState = {
isOpPending: boolean;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
opId?: string;
};

export async function executeOperation(
operation: Operation,
messages: ToasterMessage,
final: boolean,
isMainnet: boolean | undefined,
setState: React.Dispatch<React.SetStateAction<OperationState>>,
): Promise<void> {
try {
setState((prev) => ({
...prev,
opId: operation.id,
}));

const loadingToastId = showToast(
'loading',
messages.pending,
operation.id,
isMainnet,
);

const finalStatus = final
? await operation.waitFinalExecution()
: await operation.waitSpeculativeExecution();

dismissLoadingToast(loadingToastId);

if (finalStatus === OperationStatus.NotFound) {
handleOperationTimeout(messages.timeout, operation.id, setState);
throw new Error('Operation not found');
} else if (ERROR_STATUSES.includes(finalStatus)) {
logSmartContractEvents(operation.provider, operation.id);
throw new Error(`Operation failed with status: ${finalStatus}`);
} else {
handleOperationSuccess(messages.success, operation.id, setState);
}
} catch (error) {
if (error instanceof Error) {
handleOperationError(error, messages.error, operation.id, setState);
}
throw error;
} finally {
setState((prev) => ({
...prev,
isOpPending: false,
isPending: false,
}));
}
}

function dismissLoadingToast(toastId?: string): void {
if (toastId) {
toast.dismiss(toastId);
} else {
console.warn('Attempted to dismiss a toast with undefined ID.');
}
}

function handleOperationTimeout(
message = '',
opId: string,
setState: React.Dispatch<React.SetStateAction<OperationState>>,
): void {
setState((prev: OperationState) => ({ ...prev, isError: true }));
showToast('error', message, opId);
}

function handleOperationSuccess(
message: string,
opId: string,
setState: React.Dispatch<React.SetStateAction<OperationState>>,
): void {
setState((prev) => ({ ...prev, isSuccess: true }));
showToast('success', message, opId);
}

function handleOperationError(
error: Error,
message: string,
opId: string,
setState: React.Dispatch<React.SetStateAction<OperationState>>,
): void {
console.error(error);
setState((prev) => ({ ...prev, isError: true }));
showToast('error', message, opId);
}
2 changes: 1 addition & 1 deletion src/lib/util/handlePercent.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Mas } from '@massalabs/massa-web3';
import { massaToken } from '../massa-react/const';
import { massaToken } from '../massa-react/utils/const';
import { handlePercent } from './handlePercent';

describe('handlePercent', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/util/handlePercent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { massaToken } from '../massa-react/const';
import { massaToken } from '../massa-react/utils/const';
import { formatAmount } from './parseAmount';

export function handlePercent(
Expand Down

0 comments on commit 75aecfd

Please sign in to comment.