Skip to content

Commit

Permalink
chore: WIP LLD split accounts data into accounts+wallet stores
Browse files Browse the repository at this point in the history
  • Loading branch information
gre committed Mar 28, 2024
1 parent fe951dd commit 49580e1
Show file tree
Hide file tree
Showing 33 changed files with 567 additions and 138 deletions.
1 change: 1 addition & 0 deletions apps/ledger-live-desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@ledgerhq/live-network": "workspace:^",
"@ledgerhq/live-nft": "workspace:^",
"@ledgerhq/live-nft-react": "workspace:^",
"@ledgerhq/live-wallet": "workspace:^",
"@ledgerhq/logs": "workspace:^",
"@ledgerhq/react-ui": "workspace:^",
"@ledgerhq/types-cryptoassets": "workspace:^",
Expand Down
21 changes: 13 additions & 8 deletions apps/ledger-live-desktop/src/helpers/accountModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*/
import { createDataModel, DataModel } from "@ledgerhq/live-common/DataModel";
import { fromAccountRaw, toAccountRaw } from "@ledgerhq/live-common/account/index";
import { Account, AccountRaw, Operation } from "@ledgerhq/types-live";
import { Account, AccountRaw, Operation, AccountUserData } from "@ledgerhq/types-live";
import { accountRawToAccountUserData } from "@ledgerhq/live-wallet/store";

/**
* @memberof models/account
Expand All @@ -15,7 +16,7 @@ export const opRetentionStategy =

const opRetentionFilter = opRetentionStategy(366, 500);

const accountModel: DataModel<AccountRaw, Account> = createDataModel({
const accountModel: DataModel<AccountRaw, [Account, AccountUserData]> = createDataModel({
migrations: [
// 2018-10-10: change of the account id format to include the derivationMode and seedIdentifier in Account
raw => {
Expand Down Expand Up @@ -78,11 +79,15 @@ const accountModel: DataModel<AccountRaw, Account> = createDataModel({
// ^- Each time a modification is brought to the model, add here a migration function here
],

decode: fromAccountRaw,
encode: (account: Account): AccountRaw =>
toAccountRaw({
...account,
operations: account.operations.filter(opRetentionFilter),
}),
decode: (raw: AccountRaw) => [fromAccountRaw(raw), accountRawToAccountUserData(raw)],
encode: ([account, userData]: [Account, AccountUserData]): AccountRaw =>
toAccountRaw(
{
...account,
operations: account.operations.filter(opRetentionFilter),
},
userData,
),
});

export default accountModel;
49 changes: 16 additions & 33 deletions apps/ledger-live-desktop/src/renderer/actions/accounts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dispatch } from "redux";
import { Account, SubAccount } from "@ledgerhq/types-live";
import { Account, AccountUserData } from "@ledgerhq/types-live";
import { AccountComparator } from "@ledgerhq/live-common/account/index";
import { implicitMigration } from "@ledgerhq/live-common/migrations/accounts";
import { getKey } from "~/renderer/storage";
Expand All @@ -9,20 +9,24 @@ export const replaceAccounts = (payload: Account[]) => ({
payload,
});

export const addAccount = (payload: Account) => ({
type: "DB:ADD_ACCOUNT",
payload,
});

export const removeAccount = (payload: Account) => ({
type: "DB:REMOVE_ACCOUNT",
payload,
});

export const setAccounts = (payload: Account[]) => ({
type: "SET_ACCOUNTS",
payload,
});
export const initAccounts = (data: [Account, AccountUserData][]) => {
// FIXME we want to get rid of implicitMigration because consider it outdated now
const accounts = implicitMigration(data.map(data => data[0]));
const accountsUserData = data.map(data => ({ ...data[1], id: data[0].id }));
//////////////////////////////////////////
return {
type: "INIT_ACCOUNTS",
payload: {
accounts,
accountsUserData,
},
};
};

export const reorderAccounts = (comparator: AccountComparator) => (dispatch: Dispatch) =>
dispatch({
Expand All @@ -31,11 +35,8 @@ export const reorderAccounts = (comparator: AccountComparator) => (dispatch: Dis
});

export const fetchAccounts = () => async (dispatch: Dispatch) => {
const accounts = implicitMigration(await getKey("app", "accounts", []));
return dispatch({
type: "SET_ACCOUNTS",
payload: accounts,
});
const data: [Account, AccountUserData][] = await getKey("app", "accounts", []);
return dispatch(initAccounts(data));
};

type UpdateAccountAction = {
Expand All @@ -62,24 +63,6 @@ export const updateAccount: UpdateAccount = payload => ({
},
});

export const toggleStarAction = (id: string, parentId?: string): UpdateAccountAction => {
return {
type: "DB:UPDATE_ACCOUNT",
payload: {
updater: (account: Account) => {
if (parentId && account.subAccounts) {
const subAccounts: SubAccount[] = account.subAccounts.map(sa =>
sa.id === id ? { ...sa, starred: !sa.starred } : sa,
);
return { ...account, subAccounts };
}
return { ...account, starred: !account.starred };
},
accountId: parentId || id,
},
};
};

export const cleanAccountsCache = () => ({ type: "DB:CLEAN_ACCOUNTS_CACHE" });
export const cleanFullNodeDisconnect = () => ({
type: "DB:CLEAN_FULLNODE_DISCONNECT",
Expand Down
7 changes: 7 additions & 0 deletions apps/ledger-live-desktop/src/renderer/actions/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { setAccountStarred } from "@ledgerhq/live-wallet/store";

export const toggleStarAction = (id: string, value: boolean) => {
const action = setAccountStarred(id, value);
action.type = "DB:" + action.type;
return action;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import IconBuy from "~/renderer/icons/Exchange";
import IconSwap from "~/renderer/icons/Swap";
import IconAccountSettings from "~/renderer/icons/AccountSettings";
import ContextMenuItem from "./ContextMenuItem";
import { toggleStarAction } from "~/renderer/actions/accounts";
import { toggleStarAction } from "~/renderer/actions/wallet";
import { useRefreshAccountsOrdering } from "~/renderer/actions/general";
import { swapSelectableCurrenciesSelector } from "~/renderer/reducers/settings";
import { isCurrencySupported } from "~/renderer/screens/exchange/config";
import { setTrackingSource } from "~/renderer/analytics/TrackPage";
import { ContextMenuItemType } from "./ContextMenuWrapper";
import { IconsLegacy } from "@ledgerhq/react-ui";
import { accountStarredSelector } from "~/renderer/reducers/wallet";
import { State } from "~/renderer/reducers";

type Props = {
account: AccountLike;
Expand All @@ -26,6 +28,7 @@ type Props = {
children: React.ReactNode;
withStar?: boolean;
};

export default function AccountContextMenu({
leftClick,
children,
Expand All @@ -38,6 +41,10 @@ export default function AccountContextMenu({
const refreshAccountsOrdering = useRefreshAccountsOrdering();
const swapSelectableCurrencies = useSelector(swapSelectableCurrenciesSelector);

const isStarred = useSelector((state: State) =>
accountStarredSelector(state, { accountId: account.id }),
);

const menuItems = useMemo(() => {
const currency = getAccountCurrency(account);
const mainAccount = getMainAccount(account, parentAccount);
Expand Down Expand Up @@ -124,9 +131,7 @@ export default function AccountContextMenu({
label: "accounts.contextMenu.star",
Icon: IconStar,
callback: () => {
dispatch(
toggleStarAction(account.id, account.type !== "Account" ? account.parentId : undefined),
);
dispatch(toggleStarAction(account.id, !isStarred));
refreshAccountsOrdering();
},
});
Expand Down
18 changes: 8 additions & 10 deletions apps/ledger-live-desktop/src/renderer/components/Stars/Star.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import React, { useCallback } from "react";
import styled, { keyframes } from "styled-components";
import { useSelector, useDispatch } from "react-redux";
import { toggleStarAction } from "~/renderer/actions/accounts";
import { isStarredAccountSelector } from "~/renderer/reducers/accounts";
import { useDispatch, useSelector } from "react-redux";
import { toggleStarAction } from "~/renderer/actions/wallet";
import { rgba } from "~/renderer/styles/helpers";
import starAnim from "~/renderer/images/starAnim.png";
import starAnim2 from "~/renderer/images/starAnim2.png";
import { useRefreshAccountsOrdering } from "~/renderer/actions/general";
import { Transition } from "react-transition-group";
import { track } from "~/renderer/analytics/segment";
import { State } from "~/renderer/reducers";
import { accountStarredSelector } from "~/renderer/reducers/wallet";
type Props = {
accountId: string;
parentId?: string;
yellow?: boolean;
rounded?: boolean;
};
export default function Star({ accountId, parentId, yellow, rounded }: Props) {
export default function Star({ accountId, yellow, rounded }: Props) {
const isAccountStarred = useSelector((state: State) =>
isStarredAccountSelector(state, {
accountId,
}),
accountStarredSelector(state, { accountId }),
);

const dispatch = useDispatch();
const refreshAccountsOrdering = useRefreshAccountsOrdering();
const toggleStar: React.MouseEventHandler<HTMLInputElement> = useCallback(
e => {
track(isAccountStarred ? "Account Unstar" : "Account Star");
e.stopPropagation();
dispatch(toggleStarAction(accountId, parentId));
dispatch(toggleStarAction(accountId, !isAccountStarred));
refreshAccountsOrdering();
},
[isAccountStarred, dispatch, accountId, parentId, refreshAccountsOrdering],
[dispatch, accountId, refreshAccountsOrdering, isAccountStarred],
);
const MaybeButtonWrapper = yellow ? ButtonWrapper : FloatingWrapper;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ class TokenRow extends PureComponent<Props> {
<Balance unit={unit} balance={account.balance} disableRounding={disableRounding} />
<Countervalue account={account} currency={currency} range={range} />
<Delta account={account} range={range} />
<Star
accountId={account.id}
parentId={account.type !== "Account" ? account.parentId : undefined}
/>
<Star accountId={account.id} />
</Row>
);
}
Expand Down
13 changes: 6 additions & 7 deletions apps/ledger-live-desktop/src/renderer/init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from "react";
import Transport from "@ledgerhq/hw-transport";
import { getEnv } from "@ledgerhq/live-env";
import { NotEnoughBalance } from "@ledgerhq/errors";
import { implicitMigration } from "@ledgerhq/live-common/migrations/accounts";
import { log } from "@ledgerhq/logs";
import "../config/configInit";
import { checkLibs } from "@ledgerhq/live-common/sanityChecks";
Expand Down Expand Up @@ -33,7 +32,7 @@ import { setEnvOnAllThreads } from "~/helpers/env";
import dbMiddleware from "~/renderer/middlewares/db";
import createStore from "~/renderer/createStore";
import events from "~/renderer/events";
import { setAccounts } from "~/renderer/actions/accounts";
import { initAccounts } from "~/renderer/actions/accounts";
import { fetchSettings, setDeepLinkUrl } from "~/renderer/actions/settings";
import { lock, setOSDarkMode } from "~/renderer/actions/application";
import {
Expand Down Expand Up @@ -163,13 +162,13 @@ async function init() {
return currency ? hydrateCurrency(currency) : null;
}),
);
let accounts = await getKey("app", "accounts", []);
if (accounts) {
accounts = implicitMigration(accounts);
store.dispatch(setAccounts(accounts));
const accountData = await getKey("app", "accounts", []);
if (accountData) {
const e = initAccounts(accountData);
store.dispatch(e);

// preload currency that's not in accounts list
if (accounts.some(a => a.currency.id !== "ethereum")) {
if (e.payload.accounts.some(a => a.currency.id !== "ethereum")) {
prepareCurrency(getCryptoCurrencyById("ethereum"));
}
} else {
Expand Down
17 changes: 15 additions & 2 deletions apps/ledger-live-desktop/src/renderer/middlewares/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { Middleware } from "redux";
import { setKey } from "~/renderer/storage";
import { postOnboardingSelector } from "@ledgerhq/live-common/postOnboarding/reducer";
import { actionTypePrefix as postOnboardingActionTypePrefix } from "@ledgerhq/live-common/postOnboarding/actions";
import { accountsSelector } from "./../reducers/accounts";

import { settingsExportSelector, areSettingsLoaded } from "./../reducers/settings";
import { State } from "../reducers";
import { Account, AccountUserData } from "@ledgerhq/types-live";
import { accountUserDataExportSelector } from "@ledgerhq/live-wallet/store";
let DB_MIDDLEWARE_ENABLED = true;

// ability to temporary disable the db middleware from outside
Expand All @@ -14,6 +16,17 @@ export const disable = (ms = 1000) => {
setTimeout(() => (DB_MIDDLEWARE_ENABLED = true), ms);
};

function accountsExportSelector(state: State) {
const all: [Account, AccountUserData][] = [];
for (const account of state.accounts) {
const accountUserData = accountUserDataExportSelector(state.wallet, { account });
if (accountUserData) {
all.push([account, accountUserData]);
}
}
return all;
}

const DBMiddleware: Middleware<{}, State> = store => next => action => {
if (DB_MIDDLEWARE_ENABLED && action.type.startsWith("DB:")) {
const [, type] = action.type.split(":");
Expand All @@ -22,7 +35,7 @@ const DBMiddleware: Middleware<{}, State> = store => next => action => {
payload: action.payload,
});
const state = store.getState();
setKey("app", "accounts", accountsSelector(state));
setKey("app", "accounts", accountsExportSelector(state));
// ^ TODO ultimately we'll do same for accounts to drop DB: pattern
} else if (DB_MIDDLEWARE_ENABLED && action.type.startsWith(postOnboardingActionTypePrefix)) {
next(action);
Expand Down
Loading

0 comments on commit 49580e1

Please sign in to comment.