Skip to content

Commit

Permalink
refactor: enable address options when multiple addresses selected (#934)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahin-hq authored Feb 3, 2025
1 parent 0989d2f commit cb90ef7
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ export const ReceiverItemMobile: React.FC<ReceiverItemMobileProperties> = ({

export const ButtonsCell: React.VFC<ButtonsCellProperties> = ({ wallet, onSend, onSelectOption }) => {
const { t } = useTranslation();
const { primaryOptions, secondaryOptions } = useWalletOptions(wallet);
const { primaryOptions, secondaryOptions } = useWalletOptions([wallet]);

const isRestoring = !wallet.hasBeenFullyRestored();
const isButtonDisabled =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { WalletActions } from "@/domains/wallet/pages/WalletDetails/components/W
import { Skeleton } from "@/app/components/Skeleton";
import { AddressesSidePanel } from "@/domains/wallet/pages/WalletDetails/components/AddressesSidePanel";
import { ViewingAddressInfo } from "./PortfolioHeader.blocks";
import { Tooltip } from "@/app/components/Tooltip";
import { assertWallet } from "@/utils/assertions";
import { usePortfolio } from "@/domains/portfolio/hooks/use-portfolio";
import { useEnvironmentContext } from "@/app/contexts";
Expand Down Expand Up @@ -47,7 +46,8 @@ export const PortfolioHeader = ({
const isRestored = wallet.hasBeenFullyRestored();
const { convert } = useExchangeRate({ exchangeTicker: wallet.exchangeCurrency(), ticker: wallet.currency() });
const { handleImport, handleCreate, handleSelectOption, handleSend } = useWalletActions(...selectedWallets);
const { primaryOptions, secondaryOptions, additionalOptions, registrationOptions } = useWalletOptions(wallet);
const { primaryOptions, secondaryOptions, additionalOptions, registrationOptions } =
useWalletOptions(selectedWallets);

const { persist } = useEnvironmentContext();

Expand Down Expand Up @@ -273,21 +273,13 @@ export const PortfolioHeader = ({
secondaryOptions,
]}
toggleContent={
<Tooltip
content={t("COMMON.SWITCH_TO_SINGLE_VIEW")}
disabled={selectedWallets.length === 1}
<Button
variant="secondary"
size="icon"
className="text-theme-primary-600 dark:hover:bg-theme-dark-navy-700"
>
<span>
<Button
variant="secondary"
size="icon"
className="text-theme-primary-600 dark:hover:bg-theme-dark-navy-700"
disabled={selectedWallets.length > 1}
>
<Icon name="EllipsisVerticalFilled" size="lg" />
</Button>
</span>
</Tooltip>
<Icon name="EllipsisVerticalFilled" size="lg" />
</Button>
}
onSelect={handleSelectOption}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FormStepProperties } from "@/domains/transaction/pages/SendRegistration
import { StepHeader } from "@/app/components/StepHeader";
import { ThemeIcon } from "@/app/components/Icon";
import { TransactionAddresses } from "@/domains/transaction/components/TransactionDetail";
import { assertWallet } from "@/utils/assertions";

const MINIMUM_PARTICIPANTS = 2;

Expand All @@ -20,6 +21,8 @@ export const FormStep = ({ profile, wallet }: FormStepProperties) => {
const { errors, setValue, register, watch } = useFormContext();
const { participants, minParticipants } = watch();

assertWallet(wallet);

const { common, multiSignatureRegistration } = useValidation();

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const StepsComponent = ({ activeTab, wallet, profile }: SendRegistrationComponen
<FormStep wallet={wallet} profile={profile} />
</TabPanel>
<TabPanel tabId={2}>
<ReviewStep wallet={wallet} profile={profile} />
<ReviewStep wallet={wallet!} profile={profile} />
</TabPanel>
</Tabs>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { useTranslation } from "react-i18next";

import { FormField, FormLabel } from "@/app/components/Form";
import { InputDefault } from "@/app/components/Input";
import { useValidation } from "@/app/hooks";
import { useNetworks, useValidation } from "@/app/hooks";
import { FeeField } from "@/domains/transaction/components/FeeField";
import { TransactionAddresses } from "@/domains/transaction/components/TransactionDetail";
import { FormStepProperties } from "@/domains/transaction/pages/SendRegistration/SendRegistration.contracts";
import { StepHeader } from "@/app/components/StepHeader";
import { ThemeIcon } from "@/app/components/Icon";
import { SelectAddress } from "@/domains/profile/components/SelectAddress";

export const FormStep: React.FC<FormStepProperties> = ({ wallet, profile }: FormStepProperties) => {
const { t } = useTranslation();
Expand All @@ -19,12 +19,26 @@ export const FormStep: React.FC<FormStepProperties> = ({ wallet, profile }: Form
const { getValues, register, setValue } = useFormContext();
const validatorPublicKey = getValues("validatorPublicKey");

const network = useMemo(() => wallet.network(), [wallet]);
const [network] = useNetworks({ profile });
const feeTransactionData = useMemo(() => ({ validatorPublicKey }), [validatorPublicKey]);

useEffect(() => {
register("validatorPublicKey", validatorRegistration.validatorPublicKey(wallet));
}, [register, validatorRegistration]);
if (wallet) {
register("validatorPublicKey", validatorRegistration.validatorPublicKey(wallet));
}
}, [register, validatorRegistration, wallet]);

const handleSelectSender = (address: any) => {
setValue("senderAddress", address, { shouldDirty: true, shouldValidate: false });

const newSenderWallet = profile.wallets().findByAddressWithNetwork(address, network.id());
const isFullyRestoredAndSynced =
newSenderWallet?.hasBeenFullyRestored() && newSenderWallet.hasSyncedWithNetwork();

if (!isFullyRestoredAndSynced) {
newSenderWallet?.synchroniser().identity();
}
};

return (
<section data-testid="ValidatorRegistrationForm_form-step">
Expand All @@ -36,9 +50,23 @@ export const FormStep: React.FC<FormStepProperties> = ({ wallet, profile }: Form
}
/>

<div className="-mx-3 mt-6 sm:mx-0 sm:mt-4">
<TransactionAddresses senderAddress={wallet.address()} profile={profile} network={network} />
</div>
<FormField name="senderAddress" className="-mx-3 mt-6 sm:mx-0 sm:mt-4">
<SelectAddress
showWalletAvatar={false}
wallet={
wallet
? {
address: wallet.address(),
network: wallet.network(),
}
: undefined
}
wallets={profile.wallets().values()}
profile={profile}
disabled={profile.wallets().count() === 0}
onChange={handleSelectSender}
/>
</FormField>

<div className="mt-3 space-y-4 sm:mt-4">
<FormField name="validatorPublicKey">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ const component = ({
profile,
}: {
activeTab: number;
wallet: Contracts.IReadWriteWallet;
wallet?: Contracts.IReadWriteWallet;
profile: Contracts.IProfile;
}) => (
<Tabs activeId={activeTab}>
<TabPanel tabId={1}>
<FormStep wallet={wallet} profile={profile} />
</TabPanel>
<TabPanel tabId={2}>
<ReviewStep wallet={wallet} profile={profile} />
<ReviewStep wallet={wallet!} profile={profile} />
</TabPanel>
</Tabs>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface SendRegistrationDetailsOptions {

export interface SendRegistrationComponent {
activeTab: number;
wallet: Contracts.IReadWriteWallet;
wallet?: Contracts.IReadWriteWallet;
profile: Contracts.IProfile;
}

Expand All @@ -27,7 +27,7 @@ export interface SendRegistrationSignOptions {
}

export interface FormStepProperties {
wallet: Contracts.IReadWriteWallet;
wallet?: Contracts.IReadWriteWallet;
profile: Contracts.IProfile;
}

Expand Down
62 changes: 47 additions & 15 deletions src/domains/transaction/pages/SendRegistration/SendRegistration.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Networks } from "@ardenthq/sdk";
import { Contracts, DTO } from "@ardenthq/sdk-profiles";
import React, { useEffect, useLayoutEffect, useState } from "react";
import React, { useEffect, useLayoutEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { useHistory, useParams } from "react-router-dom";

Expand All @@ -11,7 +11,13 @@ import { Page, Section } from "@/app/components/Layout";
import { StepNavigation } from "@/app/components/StepNavigation";
import { TabPanel, Tabs } from "@/app/components/Tabs";
import { StepsProvider, useEnvironmentContext, useLedgerContext } from "@/app/contexts";
import { useActiveProfile, useActiveWallet, useLedgerModelStatus, useValidation } from "@/app/hooks";
import {
useActiveProfile,
useActiveWalletWhenNeeded,
useLedgerModelStatus,
useNetworks,
useValidation,
} from "@/app/hooks";
import { useKeydown } from "@/app/hooks/use-keydown";
import { AuthenticationStep } from "@/domains/transaction/components/AuthenticationStep";
import {
Expand All @@ -23,6 +29,8 @@ import { FeeWarning } from "@/domains/transaction/components/FeeWarning";
import { MultiSignatureRegistrationForm } from "@/domains/transaction/components/MultiSignatureRegistrationForm";
import { useFeeConfirmation, useMultiSignatureRegistration } from "@/domains/transaction/hooks";
import { TransactionSuccessful } from "@/domains/transaction/components/TransactionSuccessful";
import { assertWallet } from "@/utils/assertions";
import { GasLimit, MIN_GAS_PRICE } from "@/domains/transaction/components/FeeField/FeeField";

export const SendRegistration = () => {
const history = useHistory();
Expand All @@ -37,7 +45,6 @@ export const SendRegistration = () => {

const { env } = useEnvironmentContext();
const activeProfile = useActiveProfile();
const activeWallet = useActiveWallet();
const { sendMultiSignature, abortReference } = useMultiSignatureRegistration();
const { common } = useValidation();

Expand All @@ -53,15 +60,36 @@ export const SendRegistration = () => {
const { formState, register, setValue, watch, getValues } = form;
const { isDirty, isSubmitting, isValid } = formState;

const { fee, fees, isLoading } = watch();
const { fee, fees, isLoading, senderAddress } = watch();

const stepCount = registrationForm ? registrationForm.tabSteps + 2 : 1;
const authenticationStep = stepCount - 1;
const isAuthenticationStep = activeTab === authenticationStep;

const activeWalletFromUrl = useActiveWalletWhenNeeded(false);

const [network] = useNetworks({ profile: activeProfile });

const activeWallet = useMemo(() => {
if (senderAddress) {
return activeProfile.wallets().findByAddressWithNetwork(senderAddress, network.id());
}

if (activeWalletFromUrl) {
return activeWalletFromUrl;
}
}, [activeProfile, activeWalletFromUrl, network, senderAddress]);

useEffect(() => {
register("fees");
register("fee", common.fee(activeWallet.balance(), activeWallet.network(), fees));

const walletBalance = activeWallet?.balance() ?? 0;

const type = registrationType === "validatorRegistration" ? "delegateRegistration" : "multiSignature";

register("gasPrice", common.gasPrice(walletBalance, getValues, MIN_GAS_PRICE, activeWallet?.network()));
register("gasLimit", common.gasLimit(walletBalance, getValues, GasLimit[type], activeWallet?.network()));

register("inputFeeSettings");

register("network", { required: true });
Expand All @@ -75,6 +103,10 @@ export const SendRegistration = () => {
useFeeConfirmation(fee, fees);

useEffect(() => {
if (!activeWallet) {
return;
}

setValue("senderAddress", activeWallet.address(), { shouldDirty: true, shouldValidate: true });

const network = env
Expand Down Expand Up @@ -102,7 +134,7 @@ export const SendRegistration = () => {
return;
}

if (isAuthenticationStep && activeWallet.isLedger() && isLedgerModelSupported) {
if (isAuthenticationStep && activeWallet?.isLedger() && isLedgerModelSupported) {
handleSubmit();
}
}, [ledgerDevice]); // eslint-disable-line react-hooks/exhaustive-deps
Expand All @@ -118,6 +150,8 @@ export const SendRegistration = () => {
});

const handleSubmit = async () => {
assertWallet(activeWallet);

try {
const { mnemonic, encryptionPassword, wif, privateKey, secret, participants, minParticipants, fee } =
getValues();
Expand Down Expand Up @@ -171,7 +205,7 @@ export const SendRegistration = () => {
abortReference.current.abort();

if (activeTab === 1) {
return history.push(`/profiles/${activeProfile.id()}/wallets/${activeWallet.id()}`);
return history.push(`/profiles/${activeProfile.id()}/dashboard`);
}

setActiveTab(activeTab - 1);
Expand All @@ -188,14 +222,14 @@ export const SendRegistration = () => {
}

// Skip authentication step
if (isNextStepAuthentication && activeWallet.isLedger() && isLedgerModelSupported) {
if (isNextStepAuthentication && activeWallet?.isLedger() && isLedgerModelSupported) {
handleSubmit();
}

setActiveTab(nextStep);
};

const hideStepNavigation = activeTab === 10 || (isAuthenticationStep && activeWallet.isLedger());
const hideStepNavigation = activeTab === 10 || (isAuthenticationStep && activeWallet?.isLedger());

const isNextDisabled = isDirty ? !isValid || !!isLoading : true;

Expand All @@ -218,9 +252,7 @@ export const SendRegistration = () => {
<Tabs activeId={activeTab}>
<TabPanel tabId={10}>
<ErrorStep
onClose={() =>
history.push(`/profiles/${activeProfile.id()}/wallets/${activeWallet.id()}`)
}
onClose={() => history.push(`/profiles/${activeProfile.id()}/dashboard`)}
isBackDisabled={isSubmitting}
onBack={() => {
setActiveTab(1);
Expand All @@ -239,7 +271,7 @@ export const SendRegistration = () => {

<TabPanel tabId={authenticationStep}>
<AuthenticationStep
wallet={activeWallet}
wallet={activeWallet!}
ledgerIsAwaitingDevice={!hasDeviceAvailable}
ledgerIsAwaitingApp={!isConnected}
ledgerSupportedModels={[Contracts.WalletLedgerModel.NanoX]}
Expand All @@ -248,7 +280,7 @@ export const SendRegistration = () => {
</TabPanel>

<TabPanel tabId={stepCount}>
<TransactionSuccessful transaction={transaction} senderWallet={activeWallet} />
<TransactionSuccessful transaction={transaction} senderWallet={activeWallet!} />
</TabPanel>
</>
)}
Expand All @@ -257,7 +289,7 @@ export const SendRegistration = () => {
<StepNavigation
onBackClick={handleBack}
onBackToWalletClick={() =>
history.push(`/profiles/${activeProfile.id()}/wallets/${activeWallet.id()}`)
history.push(`/profiles/${activeProfile.id()}/dashboard`)
}
onContinueClick={() => handleNext()}
isLoading={isSubmitting || isLoading}
Expand Down
5 changes: 5 additions & 0 deletions src/domains/transaction/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const TransactionRoutes: RouteItem[] = [
exact: true,
path: ProfilePaths.SendRegistration,
},
{
component: SendRegistration,
exact: true,
path: ProfilePaths.SendValidatorRegistrationProfile,
},
{
component: SendValidatorResignation,
exact: true,
Expand Down
6 changes: 6 additions & 0 deletions src/domains/wallet/hooks/use-wallet-actions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ describe("useWalletActions", () => {
});

expect(history.location.pathname).toBe(`/profiles/${profile.id()}/send-transfer`);

act(() => {
current.handleSelectOption({ value: "delegate-registration" } as DropdownOption);
});

expect(history.location.pathname).toBe(`/profiles/${profile.id()}/send-registration/validatorRegistration`);
});

it("should push right urls to history", () => {
Expand Down
Loading

0 comments on commit cb90ef7

Please sign in to comment.