Skip to content

Commit

Permalink
fix: web dropdown; ledger import improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
siandreev committed Jul 26, 2024
1 parent 90af308 commit 63ed212
Show file tree
Hide file tree
Showing 20 changed files with 423 additions and 163 deletions.
3 changes: 1 addition & 2 deletions apps/desktop/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,7 @@ export const Loader: FC = () => {
tgAuthBotId: REACT_APP_TG_BOT_ID,
stonfiReferralAddress: REACT_APP_STONFI_REFERRAL_ADDRESS
},
defaultWalletVersion:
isV5R1Enabled(config) || devSettings.enableV5 ? WalletVersion.V5R1 : WalletVersion.V4R2
defaultWalletVersion: WalletVersion.V5R1
};

return (
Expand Down
35 changes: 19 additions & 16 deletions apps/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { localizationText } from '@tonkeeper/core/dist/entries/language';
import { Network, getApiConfig } from '@tonkeeper/core/dist/entries/network';
import { WalletState, WalletVersion } from "@tonkeeper/core/dist/entries/wallet";
import { getApiConfig } from '@tonkeeper/core/dist/entries/network';
import { WalletVersion } from "@tonkeeper/core/dist/entries/wallet";
import { InnerBody, useWindowsScroll } from '@tonkeeper/uikit/dist/components/Body';
import { CopyNotification } from '@tonkeeper/uikit/dist/components/CopyNotification';
import { Footer, FooterGlobalStyle } from '@tonkeeper/uikit/dist/components/Footer';
Expand Down Expand Up @@ -38,8 +38,8 @@ import Initialize, { InitializeContainer } from '@tonkeeper/uikit/dist/pages/imp
import { useKeyboardHeight } from '@tonkeeper/uikit/dist/pages/import/hooks';
import { UserThemeProvider } from '@tonkeeper/uikit/dist/providers/UserThemeProvider';
import { useUserFiat } from '@tonkeeper/uikit/dist/state/fiat';
import { isV5R1Enabled, useTonendpoint, useTonenpointConfig } from "@tonkeeper/uikit/dist/state/tonendpoint";
import { useActiveAccountQuery, useAccountsStateQuery } from "@tonkeeper/uikit/dist/state/wallet";
import { useTonendpoint, useTonenpointConfig } from "@tonkeeper/uikit/dist/state/tonendpoint";
import { useActiveAccountQuery, useAccountsStateQuery, useActiveTonNetwork } from "@tonkeeper/uikit/dist/state/wallet";
import { Container, GlobalStyle } from '@tonkeeper/uikit/dist/styles/globalStyle';
import React, { FC, PropsWithChildren, Suspense, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
Expand All @@ -49,6 +49,8 @@ import { BrowserAppSdk } from './libs/appSdk';
import { useAnalytics, useAppHeight, useAppWidth } from './libs/hooks';
import { useUserLanguage } from "@tonkeeper/uikit/dist/state/language";
import { useDevSettings } from "@tonkeeper/uikit/dist/state/dev";
import { ModalsRoot } from "@tonkeeper/uikit/dist/components/ModalsRoot";
import { Account } from "@tonkeeper/core/dist/entries/account";

const ImportRouter = React.lazy(() => import('@tonkeeper/uikit/dist/pages/import'));
const Settings = React.lazy(() => import('@tonkeeper/uikit/dist/pages/settings'));
Expand Down Expand Up @@ -178,8 +180,9 @@ const Wrapper = styled(FullSizeWrapper)<{ standalone: boolean }>`
`;

export const Loader: FC = () => {
const { data: activeWallet, isLoading: activeWalletLoading } = useActiveAccountQuery();
const { data: wallets, isLoading: isWalletsLoading } = useAccountsStateQuery();
const network = useActiveTonNetwork();
const { data: activeAccount, isLoading: activeWalletLoading } = useActiveAccountQuery();
const { data: accounts, isLoading: isWalletsLoading } = useAccountsStateQuery();
const { data: lang, isLoading: isLangLoading } = useUserLanguage();
const { data: fiat } = useUserFiat();
const { data: devSettings } = useDevSettings();
Expand All @@ -194,27 +197,27 @@ export const Loader: FC = () => {
const tonendpoint = useTonendpoint({
targetEnv: TARGET_ENV,
build: sdk.version,
network: activeWallet?.network,
network,
lang
});
const { data: config } = useTonenpointConfig(tonendpoint);

const navigate = useNavigate();
useAppHeight();

const { data: tracker } = useAnalytics(activeWallet || undefined, wallets, sdk.version);
const { data: tracker } = useAnalytics(activeAccount || undefined, accounts, sdk.version);

useEffect(() => {
if (
activeWallet &&
activeAccount &&
lang &&
i18n.language !== localizationText(lang)
) {
i18n.reloadResources([localizationText(lang)]).then(() =>
i18n.changeLanguage(localizationText(lang))
);
}
}, [activeWallet, i18n]);
}, [activeAccount, i18n]);

if (
isWalletsLoading ||
Expand All @@ -228,7 +231,6 @@ export const Loader: FC = () => {
return <Loading />;
}

const network = activeWallet?.network ?? Network.MAINNET;
const context: IAppContext = {
api: getApiConfig(config, network),
fiat,
Expand All @@ -238,7 +240,7 @@ export const Loader: FC = () => {
extension: false,
proFeatures: false,
ios,
defaultWalletVersion: (isV5R1Enabled(config) || devSettings.enableV5) ? WalletVersion.V5R1 : WalletVersion.V4R2
defaultWalletVersion: WalletVersion.V5R1
};

return (
Expand All @@ -248,11 +250,12 @@ export const Loader: FC = () => {
value={() => navigate(AppRoute.home, { replace: true })}
>
<AppContext.Provider value={context}>
<Content activeWallet={activeWallet} lock={lock} standalone={standalone} />
<Content activeAccount={activeAccount} lock={lock} standalone={standalone} />
<CopyNotification hideSimpleCopyNotifications={!standalone} />
<Suspense fallback={<></>}>
<QrScanner />
</Suspense>
<ModalsRoot />
</AppContext.Provider>
</AfterImportAction.Provider>
</OnImportAction.Provider>
Expand All @@ -261,10 +264,10 @@ export const Loader: FC = () => {
};

export const Content: FC<{
activeWallet?: WalletState | null;
activeAccount?: Account | null;
lock: boolean;
standalone: boolean;
}> = ({ activeWallet, lock, standalone }) => {
}> = ({ activeAccount, lock, standalone }) => {
const location = useLocation();
useWindowsScroll();
useAppWidth(standalone);
Expand Down Expand Up @@ -298,7 +301,7 @@ export const Content: FC<{
);
}

if (!activeWallet || location.pathname.startsWith(AppRoute.import)) {
if (!activeAccount || location.pathname.startsWith(AppRoute.import)) {
return (
<FullSizeWrapper standalone={false}>
<Suspense fallback={<Loading />}>
Expand Down
23 changes: 15 additions & 8 deletions apps/web/src/libs/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import { WalletsState, WalletState } from "@tonkeeper/core/dist/entries/wallet";
import { Account } from "@tonkeeper/core/dist/entries/account";
import { throttle } from '@tonkeeper/core/dist/utils/common';
import { Analytics, AnalyticsGroup, toWalletType } from '@tonkeeper/uikit/dist/hooks/analytics';
import { AptabaseWeb } from '@tonkeeper/uikit/dist/hooks/analytics/aptabase-web';
import { Gtag } from '@tonkeeper/uikit/dist/hooks/analytics/gtag';
import { QueryKey } from '@tonkeeper/uikit/dist/libs/queryKey';
import { useEffect } from 'react';
import { useActiveTonNetwork } from "@tonkeeper/uikit/dist/state/wallet";

export const useAppHeight = () => {
useEffect(() => {
Expand Down Expand Up @@ -48,12 +49,13 @@ export const useAppWidth = (standalone: boolean) => {
};

export const useAnalytics = (
activeWallet?: WalletState,
wallets?: WalletsState,
activeAccount?: Account,
accounts?: Account[],
version?: string
) => {
const network = useActiveTonNetwork();
return useQuery<Analytics>(
[QueryKey.analytics],
[QueryKey.analytics, network],
async () => {
const tracker = new AnalyticsGroup(
new AptabaseWeb(
Expand All @@ -64,12 +66,17 @@ export const useAnalytics = (
new Gtag(import.meta.env.VITE_APP_MEASUREMENT_ID)
);

tracker.init('Web', toWalletType(activeWallet),
activeWallet,
wallets,);
tracker.init({
application: 'Web',
walletType: toWalletType(activeAccount?.activeTonWallet),
activeAccount: activeAccount!,
accounts: accounts!,
network
}
);

return tracker;
},
{ enabled: wallets != null && activeWallet !== undefined }
{ enabled: accounts != null && activeAccount !== undefined }
);
};
45 changes: 40 additions & 5 deletions packages/core/src/entries/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface DeprecatedAccountState {
export type AccountId = string;

export interface IAccount {
id: AccountId;
name: string;
emoji: string;

Expand Down Expand Up @@ -51,6 +52,9 @@ export class AccountTonMnemonic extends Clonable implements IAccount {
return this.tonWallets.find(w => w.id === this.activeTonWalletId)!;
}

/**
* @param id ton public key hex string without 0x corresponding to the mnemonic
*/
constructor(
public readonly id: AccountId,
public name: string,
Expand All @@ -75,7 +79,12 @@ export class AccountTonMnemonic extends Clonable implements IAccount {
}

addTonWalletToActiveDerivation(wallet: TonWalletStandard) {
this.tonWallets.push(wallet);
const walletExists = this.tonWallets.findIndex(w => w.id === wallet.id);
if (walletExists === -1) {
this.tonWallets = this.tonWallets.concat(wallet);
} else {
this.tonWallets[walletExists] = wallet;
}
}

removeTonWalletFromActiveDerivation(walletId: WalletId) {
Expand All @@ -90,6 +99,9 @@ export class AccountTonMnemonic extends Clonable implements IAccount {
}

setActiveTonWallet(walletId: WalletId) {
if (this.tonWallets.every(w => w.id !== walletId)) {
throw new Error('Wallet not found');
}
this.activeTonWalletId = walletId;
}
}
Expand All @@ -116,6 +128,9 @@ export class AccountLedger extends Clonable implements IAccount {
)!;
}

/**
* @param id index 0 derivation ton public key hex string without 0x
*/
constructor(
public readonly id: AccountId,
public name: string,
Expand Down Expand Up @@ -143,7 +158,12 @@ export class AccountLedger extends Clonable implements IAccount {
}

addTonWalletToActiveDerivation(wallet: TonWalletStandard) {
this.activeDerivation.tonWallets.push(wallet);
const walletExists = this.activeDerivation.tonWallets.findIndex(w => w.id === wallet.id);
if (walletExists === -1) {
this.activeDerivation.tonWallets = this.activeDerivation.tonWallets.concat(wallet);
} else {
this.activeDerivation.tonWallets[walletExists] = wallet;
}
}

removeTonWalletFromActiveDerivation(walletId: WalletId) {
Expand All @@ -161,8 +181,8 @@ export class AccountLedger extends Clonable implements IAccount {

setActiveTonWallet(walletId: WalletId) {
for (const derivation of this.derivations) {
const index = derivation.tonWallets.findIndex(w => w.id === walletId);
if (index !== -1) {
const walletInDerivation = derivation.tonWallets.some(w => w.id === walletId);
if (walletInDerivation) {
derivation.activeTonWalletId = walletId;
this.activeDerivationIndex = derivation.index;
return;
Expand All @@ -188,6 +208,9 @@ export class AccountKeystone extends Clonable implements IAccount {
return this.tonWallet;
}

/**
* @param id ton public key hex string without 0x
*/
constructor(
public readonly id: AccountId,
public name: string,
Expand Down Expand Up @@ -236,6 +259,9 @@ export class AccountTonOnly extends Clonable implements IAccount {
return this.tonWallets.find(w => w.id === this.activeTonWalletId)!;
}

/**
* @param id ton public key hex string without 0x
*/
constructor(
public readonly id: AccountId,
public name: string,
Expand All @@ -260,7 +286,12 @@ export class AccountTonOnly extends Clonable implements IAccount {
}

addTonWalletToActiveDerivation(wallet: TonWalletStandard) {
this.tonWallets.push(wallet);
const walletExists = this.tonWallets.findIndex(w => w.id === wallet.id);
if (walletExists === -1) {
this.tonWallets = this.tonWallets.concat(wallet);
} else {
this.tonWallets[walletExists] = wallet;
}
}

removeTonWalletFromActiveDerivation(walletId: WalletId) {
Expand All @@ -275,6 +306,10 @@ export class AccountTonOnly extends Clonable implements IAccount {
}

setActiveTonWallet(walletId: WalletId) {
if (this.tonWallets.every(w => w.id !== walletId)) {
throw new Error('Wallet not found');
}

this.activeTonWalletId = walletId;
}
}
Expand Down
25 changes: 22 additions & 3 deletions packages/core/src/service/accountsStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { DeprecatedAccountState } from '../entries/account';
import { AuthState, DeprecatedAuthState } from '../entries/password';
import { assertUnreachable, notNullish } from '../utils/types';
import {
getFallbackAccountEmoji,
getFallbackDerivationItemEmoji,
getFallbackTonStandardWalletEmoji,
getWalletNameAddress
Expand Down Expand Up @@ -69,6 +70,10 @@ export class AccountsStorage {
};

setActiveAccountId = async (activeAccountId: AccountId | null) => {
const accounts = await this.getAccounts();
if (accounts.every(a => a.id !== activeAccountId)) {
throw new Error('Account not found');
}
await this.storage.set(AppKey.ACTIVE_ACCOUNT_ID, activeAccountId);
};

Expand All @@ -78,9 +83,15 @@ export class AccountsStorage {

addAccountsToState = async (accounts: Account[]) => {
const state = await this.getAccounts();
await this.setAccounts(
state.concat(accounts.filter(acc => state.every(a => a.id !== acc.id)))
);
accounts.forEach(account => {
const existingAccIndex = state.findIndex(a => a.id === account.id);
if (existingAccIndex !== -1) {
state[existingAccIndex] = account;
return;
}
state.push(account);
});
await this.setAccounts(state);
};

/**
Expand Down Expand Up @@ -121,6 +132,14 @@ export class AccountsStorage {
await this.setAccounts(state.filter(w => w.id !== id));
};

async getNewAccountNameAndEmoji(accountId: AccountId) {
const existingAccounts = await this.getAccounts();
const existingAccount = existingAccounts.find(a => a.id === accountId);
const name = existingAccount?.name || 'Account ' + (existingAccounts.length + 1);
const emoji = existingAccount?.emoji || getFallbackAccountEmoji(accountId);
return { name, emoji };
}

private migrateToActiveAccountIdState = async (): Promise<WalletId | null> => {
const state = await this.storage.get<DeprecatedAccountState>(AppKey.DEPRECATED_ACCOUNT);
if (!state || !state.activePublicKey) {
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/service/devStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ import { Network } from '../entries/network';
import { AppKey } from '../Keys';

export interface DevSettings {
enableV5: boolean;
tonNetwork: Network;
}

const defaultDevSettings: DevSettings = {
enableV5: false,
tonNetwork: Network.MAINNET
};

Expand Down
Loading

0 comments on commit 63ed212

Please sign in to comment.