diff --git a/src/store/actions/WalletManagerActions.ts b/src/store/actions/WalletManagerActions.ts index 0f764a4..884bec0 100644 --- a/src/store/actions/WalletManagerActions.ts +++ b/src/store/actions/WalletManagerActions.ts @@ -8,7 +8,7 @@ export interface LoginPayload { password: string }; export const login = createAction(constants.LOGIN, - (password: string): LoginPayload => ({ password }))(); + (password): LoginPayload => ({ password }))(); export interface SetMasterPasswordPayload { salt: string; @@ -16,5 +16,5 @@ password: string; }; export const setMasterPassword = createAction(constants.SET_MASTER_PASSWORD, - (salt: string, tester: string, password: string): SetMasterPasswordPayload => + (salt, tester, password): SetMasterPasswordPayload => ({ salt, tester, password }))(); diff --git a/src/store/actions/WalletsActions.ts b/src/store/actions/WalletsActions.ts index 4bf14f7..e816ef4 100644 --- a/src/store/actions/WalletsActions.ts +++ b/src/store/actions/WalletsActions.ts @@ -4,7 +4,24 @@ import * as constants from "../constants"; import { WalletMap } from "@reducers/WalletsReducer"; +import { Wallet, WalletSyncable, WalletUpdatable } from "@/src/wallets/Wallet"; export interface LoadWalletsPayload { wallets: WalletMap }; export const loadWallets = createAction(constants.LOAD_WALLETS, - (wallets: WalletMap): LoadWalletsPayload => ({ wallets }))(); + (wallets): LoadWalletsPayload => ({ wallets }))(); + +export interface AddWalletPayload { wallet: Wallet }; +export const addWallet = createAction(constants.ADD_WALLET, + (wallet): AddWalletPayload => ({ wallet }))(); + +export interface RemoveWalletPayload { id: string }; +export const removeWallet = createAction(constants.REMOVE_WALLET, + (id): RemoveWalletPayload => ({ id }))(); + +export interface UpdateWalletPayload { id: string, wallet: WalletUpdatable }; +export const updateWallet = createAction(constants.UPDATE_WALLET, + (id, wallet): UpdateWalletPayload => ({ id, wallet }))(); + +export interface SyncWalletPayload { id: string, wallet: WalletSyncable }; +export const syncWallet = createAction(constants.SYNC_WALLET, + (id, wallet): SyncWalletPayload => ({ id, wallet }))(); diff --git a/src/store/constants.ts b/src/store/constants.ts index 94331e2..5f07608 100644 --- a/src/store/constants.ts +++ b/src/store/constants.ts @@ -12,6 +12,5 @@ export const LOAD_WALLETS = "LOAD_WALLETS"; export const ADD_WALLET = "ADD_WALLET"; export const REMOVE_WALLET = "REMOVE_WALLET"; -export const RENAME_WALLET = "RENAME_WALLET"; +export const UPDATE_WALLET = "UPDATE_WALLET"; export const SYNC_WALLET = "SYNC_WALLET"; -export const UPDATE_WALLET_BALANCE = "UPDATE_WALLET_BALANCE" diff --git a/src/store/reducers/WalletsReducer.ts b/src/store/reducers/WalletsReducer.ts index 182b28f..73d6934 100644 --- a/src/store/reducers/WalletsReducer.ts +++ b/src/store/reducers/WalletsReducer.ts @@ -1,4 +1,4 @@ -import { loadWallets } from "@actions/WalletsActions"; +import { addWallet, loadWallets, removeWallet, syncWallet, updateWallet } from "@actions/WalletsActions"; import { createReducer, ActionType } from "typesafe-actions"; import { Wallet } from "../../wallets/Wallet"; @@ -12,10 +12,45 @@ wallets: {} }; -export const WalletsReducer = createReducer(initialState) - .handleAction(loadWallets, (state: State, action: ActionType) => ({ +function assignNewWalletProperties(state: State, id: string, partialWallet: Partial) { + // Fetch the old wallet and assign the new properties + const { [id]: wallet } = state.wallets; + const newWallet = { ...wallet, ...partialWallet }; + return { + ...state, wallets: { ...state.wallets, - ...action.payload.wallets + [id]: newWallet } - })); + }; +} + +export const WalletsReducer = createReducer(initialState) + // Load wallets + .handleAction(loadWallets, (state: State, { payload }: ActionType) => ({ + ...state, + wallets: { + ...state.wallets, + ...payload.wallets + } + })) + // Add wallet + .handleAction(addWallet, (state: State, { payload }: ActionType) => ({ + ...state, + wallets: { + ...state.wallets, + [payload.wallet.id]: payload.wallet + } + })) + // Remove wallet + .handleAction(removeWallet, (state: State, { payload }: ActionType) => { + // Get the wallets without the one we want to remove + const { [payload.id]: removed, ...wallets } = state.wallets; + return { ...state, wallets }; + }) + // Update wallet + .handleAction(updateWallet, (state: State, { payload }: ActionType) => + assignNewWalletProperties(state, payload.id, payload.wallet)) + // Sync wallet + .handleAction(syncWallet, (state: State, { payload }: ActionType) => + assignNewWalletProperties(state, payload.id, payload.wallet)); diff --git a/src/wallets/Wallet.ts b/src/wallets/Wallet.ts index 466c92a..533ab4b 100644 --- a/src/wallets/Wallet.ts +++ b/src/wallets/Wallet.ts @@ -30,6 +30,14 @@ firstSeen?: DateString; } +/** Properties of Wallet that are allowed to be updated. */ +export type WalletUpdatableKeys = "label" | "category" | "password" | "username" | "format" | "address"; +export type WalletUpdatable = Pick; + +/** Properties of Wallet that are allowed to be synced. */ +export type WalletSyncableKeys = "balance" | "names" | "firstSeen"; +export type WalletSyncable = Pick; + export async function decryptWallet(id: string, data: AESEncryptedString, masterPassword: string): Promise { try { // Attempt to decrypt and deserialize the wallet data @@ -63,13 +71,6 @@ return enc; } -declare global { - interface Window { - encryptWallet: typeof encryptWallet - } -} -window.encryptWallet = encryptWallet; - /** Get the local storage key for a given wallet. */ export function getWalletKey(wallet: Wallet): string { return `wallet2-${wallet.id}`; @@ -98,3 +99,11 @@ dispatch(actions.loadWallets(walletMap)); } + +// TODO: temporary exposure of methods for testing +declare global { + interface Window { + encryptWallet: typeof encryptWallet + } +} +window.encryptWallet = encryptWallet;