diff --git a/.eslintrc.json b/.eslintrc.json index d6212d8e..9c7fc59f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -31,6 +31,7 @@ }, "globals": { "SyntheticInputEvent": false, - "SyntheticKeyboardEvent": false + "SyntheticKeyboardEvent": false, + "Generator": false } } diff --git a/common/actions/wallet.js b/common/actions/wallet.js index 656c0ba1..89770418 100644 --- a/common/actions/wallet.js +++ b/common/actions/wallet.js @@ -12,7 +12,11 @@ export type SaveWalletAction = { payload: BaseWallet }; -export type WalletAction = UnlockPrivateKeyAction | SaveWalletAction; +export type InitWalletAction = { + type: 'WALLET_INIT' +}; + +export type WalletAction = UnlockPrivateKeyAction | SaveWalletAction | InitWalletAction; export function unlockPrivateKey(value: PrivateKeyUnlockParams): UnlockPrivateKeyAction { return { @@ -27,3 +31,9 @@ export function saveWallet(value: BaseWallet): SaveWalletAction { payload: value }; } + +export function initWallet(): InitWalletAction { + return { + type: 'WALLET_INIT' + }; +} diff --git a/common/containers/Tabs/SendTransaction/index.jsx b/common/containers/Tabs/SendTransaction/index.jsx index 894b8a2a..f3ecb116 100644 --- a/common/containers/Tabs/SendTransaction/index.jsx +++ b/common/containers/Tabs/SendTransaction/index.jsx @@ -270,7 +270,7 @@ export class SendTransaction extends React.Component { function mapStateToProps(state: AppState) { return { - wallet: state.wallet + wallet: state.wallet.inst }; } diff --git a/common/reducers/wallet.js b/common/reducers/wallet.js index 44bc87ab..d60849d1 100644 --- a/common/reducers/wallet.js +++ b/common/reducers/wallet.js @@ -1,19 +1,35 @@ // @flow -import type { WalletAction, SaveWalletAction } from 'actions/wallet'; +import type { WalletAction, SaveWalletAction, InitWalletAction } from 'actions/wallet'; import BaseWallet from 'libs/wallet/base'; -export type State = ?BaseWallet; +export type State = { + inst: ?BaseWallet, + balance: number, + tokens: { + [string]: number + } +}; -const initialState: State = null; +const initialState: State = { + inst: null, + balance: 0, + tokens: {} +}; function saveWallet(state: State, action: SaveWalletAction): State { - return action.payload; + return { ...state, inst: action.payload }; +} + +function initWallet(state: State): State { + return { ...state, balance: 0, tokens: {} }; } export function wallet(state: State = initialState, action: WalletAction): State { switch (action.type) { case 'WALLET_SAVE': return saveWallet(state, action); + case 'WALLET_INIT': + return initWallet(state); default: return state; } diff --git a/common/sagas/ens.js b/common/sagas/ens.js index 6c9fd571..347f3c9f 100644 --- a/common/sagas/ens.js +++ b/common/sagas/ens.js @@ -1,11 +1,13 @@ // @flow import { takeEvery, call, put, select } from 'redux-saga/effects'; import { delay } from 'redux-saga'; +import type { Effect } from 'redux-saga/effects'; import { cacheEnsAddress } from 'actions/ens'; import type { ResolveEnsNameAction } from 'actions/ens'; import { getEnsAddress } from 'selectors/ens'; -function* resolveEns(action: ResolveEnsNameAction) { +function* resolveEns(action?: ResolveEnsNameAction) { + if (!action) return; const ensName = action.payload; // FIXME Add resolve logic //// _ens.getAddress(scope.addressDrtv.ensAddressField, function(data) { @@ -28,6 +30,6 @@ function* resolveEns(action: ResolveEnsNameAction) { yield put(cacheEnsAddress(ensName, '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8')); } -export default function* notificationsSaga() { +export default function* notificationsSaga(): Generator { yield takeEvery('ENS_RESOLVE', resolveEns); } diff --git a/common/sagas/notifications.js b/common/sagas/notifications.js index b83a82d7..02e89e4f 100644 --- a/common/sagas/notifications.js +++ b/common/sagas/notifications.js @@ -1,10 +1,12 @@ // @flow import { takeEvery, put, call } from 'redux-saga/effects'; import { delay } from 'redux-saga'; +import type { Effect } from 'redux-saga/effects'; import { closeNotification } from 'actions/notifications'; import type { ShowNotificationAction } from 'actions/notifications'; -function* handleNotification(action: ShowNotificationAction) { +function* handleNotification(action?: ShowNotificationAction) { + if (!action) return; const { duration } = action.payload; // show forever if (duration === 0) { @@ -16,6 +18,6 @@ function* handleNotification(action: ShowNotificationAction) { yield put(closeNotification(action.payload)); } -export default function* notificationsSaga() { +export default function* notificationsSaga(): Generator { yield takeEvery('SHOW_NOTIFICATION', handleNotification); } diff --git a/common/sagas/wallet.js b/common/sagas/wallet.js index cda36ef7..0a356630 100644 --- a/common/sagas/wallet.js +++ b/common/sagas/wallet.js @@ -1,14 +1,26 @@ // @flow import { takeEvery, call, put, select } from 'redux-saga/effects'; +import type { Effect } from 'redux-saga/effects'; import { delay } from 'redux-saga'; -import { saveWallet } from 'actions/wallet'; +import { saveWallet, initWallet } from 'actions/wallet'; import type { UnlockPrivateKeyAction } from 'actions/wallet'; import PrivKeyWallet from 'libs/wallet/privkey'; -function* unlockPrivateKey(action: UnlockPrivateKeyAction) { - yield put(saveWallet(new PrivKeyWallet(action.payload))); +function* init() { + yield put(initWallet()); + // const node = select(node); + // yield call(); + // fetch balance, + // fetch tokens + yield delay(100); } -export default function* notificationsSaga() { +function* unlockPrivateKey(action?: UnlockPrivateKeyAction) { + if (!action) return; + yield put(saveWallet(new PrivKeyWallet(action.payload))); + yield call(init); +} + +export default function* notificationsSaga(): Generator { yield takeEvery('WALLET_UNLOCK_PRIVATE_KEY', unlockPrivateKey); } diff --git a/flow-typed/redux-saga_v0.14.x.js b/flow-typed/redux-saga_v0.14.x.js new file mode 100644 index 00000000..3ace3fcb --- /dev/null +++ b/flow-typed/redux-saga_v0.14.x.js @@ -0,0 +1,508 @@ +declare type ReduxSaga$Predicate = (arg: T) => boolean; + +declare interface ReduxSaga$Task { + isRunning(): boolean, + isCancelled(): boolean, + result(): any, + result(): T, + error(): any, + done: Promise, + cancel(): void +} + +declare interface ReduxSaga$Buffer { + isEmpty(): boolean, + put(message: T): void, + take(): T +} + +declare interface ReduxSaga$Channel { + take(cb: (message: T) => void, matcher?: ReduxSaga$Predicate): void, + put(message: T): void, + close(): void +} + +declare module 'redux-saga/effects' { + declare type Predicate = ReduxSaga$Predicate; + declare type Task = ReduxSaga$Task; + declare type Buffer = ReduxSaga$Buffer; + declare type Channel = ReduxSaga$Channel; + declare type Action = { type: $Subtype }; + declare type Pattern = string | Predicate | (string | Predicate)[]; + + declare type Effect = + | TakeEffect + | PutEffect + | RaceEffect + | CallEffect + | CpsEffect + | ForkEffect + | JoinEffect + | CancelEffect + | SelectEffect + | ActionChannelEffect + | CancelledEffect + | FlushEffect; + + // take + declare interface TakeEffectDescriptor { + pattern: Pattern, + channel: Channel, + maybe?: boolean + } + + declare interface TakeEffect { + TAKE: TakeEffectDescriptor + } + + declare var take: { + (pattern: Pattern): TakeEffect, + (channel: Channel): TakeEffect, + maybe: { + (pattern: Pattern): TakeEffect, + (channel: Channel): TakeEffect + } + }; + + declare var takem: void; + + // put + declare interface PutEffectDescriptor { + action: T, + channel: Channel + } + + declare interface PutEffect { + PUT: PutEffectDescriptor + } + + declare var put: { + (action: T): PutEffect, + (channel: Channel, action: T): PutEffect, + resolve: { + (action: T): PutEffect, + (channel: Channel, action: T): PutEffect + }, + sync: void + }; + + // race + declare type RaceEffectDescriptor = { [key: string]: Effect }; + + declare interface RaceEffect { + RACE: RaceEffectDescriptor + } + + declare function race(effects: { [key: string]: Effect }): RaceEffect; + + // call & apply + declare interface CallEffectDescriptor { + context: any, + fn: Function, + args: any[] + } + + declare type Collable0 = () => any; + declare type Collable1 = (a: A) => any; + declare type Collable2 = (a: A, b: B) => any; + declare type Collable3 = (a: A, b: B, c: C) => any; + declare type Collable4 = (a: A, b: B, c: C, d: D) => any; + declare type Collable5 = (a: A, b: B, c: C, d: D, e: E) => any; + declare type CollableR = (...args: mixed[]) => any; + + declare type CallEffectArg = F | [any, F] | { context: any, fn: F }; + + declare interface CallEffect { + CALL: CallEffectDescriptor + } + + declare type CallEffectFactory = { + (fn: CallEffectArg): R, + (fn: CallEffectArg>, a: A): R, + (fn: CallEffectArg>, a: A, b: B): R, + (fn: CallEffectArg>, a: A, b: B, c: C): R, + (fn: CallEffectArg>, a: A, b: B, c: C, d: D): R, + ( + fn: CallEffectArg>, + a: A, + b: B, + c: C, + d: D, + e: E + ): R, + (fn: CallEffectArg, ...args: any[]): R + }; + + declare var call: CallEffectFactory; + + declare var apply: { + (context: any, fn: Collable0): CallEffect, + (context: any, fn: Collable1, args: [A]): CallEffect, + (context: any, fn: Collable2, args: [A, B]): CallEffect, + (context: any, fn: Collable3, args: [A, B, C]): CallEffect, + (context: any, fn: Collable4, args: [A, B, C, D]): CallEffect, + ( + context: any, + fn: Collable5, + args: [A, B, C, D, E] + ): CallEffect, + (context: any, fn: CollableR, args: any[]): CallEffect + }; + + // cps + declare interface CpsEffect { + CPS: CallEffectDescriptor + } + + declare type CpsCallback = (error: any, result: any) => void; + + declare var cps: { + (fn: CallEffectArg>): CpsEffect, + (fn: CallEffectArg>, a: A): CpsEffect, + (fn: CallEffectArg>, a: A, b: B): CpsEffect, + (fn: CallEffectArg>, a: A, b: B, c: C): CpsEffect, + ( + fn: CallEffectArg>, + a: A, + b: B, + c: C, + d: D + ): CpsEffect + }; + + // fork & spawn + declare interface ForkEffectDescriptor extends CallEffectDescriptor { + detached?: boolean + } + + declare interface ForkEffect { + FORK: ForkEffectDescriptor + } + + declare var fork: CallEffectFactory; + declare var spawn: CallEffectFactory; + + // join + declare interface JoinEffect { + JOIN: Task + } + + declare function join(task: Task): JoinEffect; + + // cancel + declare interface CancelEffect { + CANCEL: Task + } + + declare function cancel(task: Task): CancelEffect; + + // select + declare interface SelectEffectDescriptor { + selector(state: any, ...args: any[]): any, + args: any[] + } + + declare interface SelectEffect { + SELECT: SelectEffectDescriptor + } + + declare var select: { + (): SelectEffect, + (selector: Collable1): SelectEffect, + (selector: Collable2, a: A): SelectEffect, + (selector: Collable3, a: A, b: B): SelectEffect, + (selector: Collable4, a: A, b: B, c: C): SelectEffect, + (selector: Collable5, a: A, b: B, c: C, d: D): SelectEffect, + (selector: CollableR, ...rest: any[]): SelectEffect + }; + + // actionChannel + declare interface ActionChannelEffectDescriptor { + pattern: Pattern, + buffer: Buffer + } + + declare interface ActionChannelEffect { + ACTION_CHANNEL: ActionChannelEffectDescriptor + } + + declare function actionChannel( + pattern: Pattern, + buffer?: Buffer + ): ActionChannelEffect; + + // actionChannel + declare interface CancelledEffect { + CANCELLED: {} + } + + declare function cancelled(): CancelledEffect; + + // flush + declare interface FlushEffect { + FLUSH: Channel + } + + declare function flush(channel: Channel): FlushEffect; + + // takeEvery & takeLatest + declare type Workable0 = (action?: A) => any; + declare type Workable1 = (b: B, action?: A) => any; + declare type Workable2 = (b: B, c: C, action?: A) => any; + declare type Workable3 = (b: B, c: C, d: D, action?: A) => any; + declare type Workable4 = (b: B, c: C, d: D, e: E, action?: A) => any; + declare type WorkableR = ( + b: B, + c: C, + d: D, + e: E, + f: F, + ...args: mixed[] + ) => any; + + declare interface TakeHelper { + (pattern: Pattern, worker: Workable0): ForkEffect, + (pattern: Pattern, worker: Workable1, b: B): ForkEffect, + (pattern: Pattern, worker: Workable2, b: B, c: C): ForkEffect, + ( + pattern: Pattern, + worker: Workable3, + b: B, + c: C, + d: D + ): ForkEffect, + ( + pattern: Pattern, + worker: Workable4, + b: B, + c: C, + d: D, + e: E + ): ForkEffect, + ( + pattern: Pattern, + worker: WorkableR, + b: B, + c: C, + d: D, + e: E, + f: F, + ...rest: any[] + ): ForkEffect + } + + declare var takeEvery: TakeHelper; + declare var takeLatest: TakeHelper; + + // throttle + declare var throttle: { + (ms: number, pattern: Pattern, worker: Workable0): ForkEffect, + (ms: number, pattern: Pattern, worker: Workable1, b: B): ForkEffect, + ( + ms: number, + pattern: Pattern, + worker: Workable2, + b: B, + c: C + ): ForkEffect, + ( + ms: number, + pattern: Pattern, + worker: Workable3, + b: B, + c: C, + d: D + ): ForkEffect, + ( + ms: number, + pattern: Pattern, + worker: Workable4, + b: B, + c: C, + d: D, + e: E + ): ForkEffect, + ( + ms: number, + pattern: Pattern, + worker: WorkableR, + b: B, + c: C, + d: D, + e: E, + f: F, + ...rest: any[] + ): ForkEffect + }; +} + +declare module 'redux-saga/utils' { + import type { + Effect, + TakeEffectDescriptor, + PutEffectDescriptor, + RaceEffectDescriptor, + CallEffectDescriptor, + ForkEffectDescriptor, + SelectEffectDescriptor, + ActionChannelEffectDescriptor + } from 'redux-saga/effects'; + + declare type Task = ReduxSaga$Task; + declare type Channel = ReduxSaga$Channel; + declare type Is = ReduxSaga$Predicate<*>; + declare interface Deferred { + resolve(result: R): void, + reject(error: any): void, + promise: Promise + } + declare interface MockTask extends Task { + setRunning(running: boolean): void, + setResult(result: any): void, + setError(error: any): void + } + + declare var TASK: '@@redux-saga/TASK'; + + declare var SAGA_ACTION: '@@redux-saga/SAGA_ACTION'; + + declare function noop(): void; + + declare var is: { + undef: Is, + notUndef: Is, + func: Is, + number: Is, + array: Is, + promise: Is, + iterator: Is, + task: Is, + observable: Is, + buffer: Is, + pattern: Is, + channel: Is, + helper: Is, + stringableFunc: Is + }; + + declare function deferred(props?: T): T & Deferred; + + declare function arrayOfDeffered(length: number): Deferred[]; + + declare function createMockTask(): MockTask; + + declare var asEffect: { + take(effect: Effect): ?TakeEffectDescriptor, + put(effect: Effect): ?PutEffectDescriptor, + race(effect: Effect): ?RaceEffectDescriptor, + call(effect: Effect): ?CallEffectDescriptor, + cps(effect: Effect): ?CallEffectDescriptor, + fork(effect: Effect): ?ForkEffectDescriptor, + join(effect: Effect): ?Task, + cancel(effect: Effect): ?Task, + select(effect: Effect): ?SelectEffectDescriptor, + actionChannel(effect: Effect): ?ActionChannelEffectDescriptor, + cancelled(effect: Effect): ?{}, + flush(effect: Effect): ?Channel + }; + + declare var CHANNEL_END: { + toString(): '@@redux-saga/CHANNEL_END' + }; +} + +declare module 'redux-saga' { + import type { Middleware } from 'redux'; + import type { Effect } from 'redux-saga/effects'; + import typeof * as Effects from 'redux-saga/effects'; + import typeof * as Utils from 'redux-saga/utils'; + + declare export type Predicate = ReduxSaga$Predicate; + declare export type Task = ReduxSaga$Task; + declare export type Buffer = ReduxSaga$Buffer; + declare export type Channel = ReduxSaga$Channel; + + declare export interface SagaMonitor { + effectTriggered(options: { + effectId: number, + parentEffectId: number, + label: string, + root?: boolean, + effect: Effect + }): void, + effectResolved(effectId: number, result: any): void, + effectRejected(effectId: number, err: any): void, + effectCancelled(effectId: number): void, + actionDispatched(action: A): void + } + + declare type Saga0 = () => Generator<*, *, *>; + declare type Saga1 = (a: A) => Generator<*, *, *>; + declare type Saga2 = (a: A, b: B) => Generator<*, *, *>; + declare type Saga3 = (a: A, b: B, c: C) => Generator<*, *, *>; + declare type Saga4 = (a: A, b: B, c: C, d: D) => Generator<*, *, *>; + declare type SagaR = (...args: mixed[]) => Generator<*, *, *>; + + declare export type SagaMiddleware = Middleware & { + run(saga: Saga0): Task, + run(saga: Saga1, a: A): Task, + run(saga: Saga2, a: A, B: B): Task, + run(saga: Saga3, a: A, B: B, c: C): Task, + run(saga: Saga4, a: A, B: B, c: C, d: T4): Task, + run(saga: SagaR, ...args: any[]): Task + }; + + declare export type Emit = (input: T) => void; + + declare export default function createSagaMiddleware(options?: { + sagaMonitor?: SagaMonitor, + emitter: (emit: Emit) => Emit + }): SagaMiddleware<*, *>; + + declare export type Unsubscribe = () => void; + declare export type Subscribe = (cb: (input: T) => void) => Unsubscribe; + declare export type Logger = (level: 'info' | 'warning' | 'error', ...args: Array) => void; + + declare export function runSaga( + saga: Generator<*, *, *>, + io: { + subscribe?: Subscribe, + dispatch?: (input: DA) => any, + getState?: () => S, + sagaMonitor?: SagaMonitor, + logger?: Logger, + onError?: void + } + ): Task; + + declare export var END: { type: '@@redux-saga/CHANNEL_END' }; + + declare export function eventChannel( + subscribe: Subscribe, + buffer?: Buffer, + matcher?: Predicate + ): Channel; + + declare export function channel(buffer?: Buffer): Channel; + + declare export var buffers: { + none(): Buffer, + fixed(limit?: number): Buffer, + dropping(limit?: number): Buffer, + sliding(limit?: number): Buffer, + expanding(limit?: number): Buffer + }; + + // deprecate + declare export var takeEvery: void; + declare export var takeLatest: void; + declare export var throttle: void; + + declare export function delay(ms: number, rest: void): Promise; + declare export function delay(ms: number, val: T): Promise; + + declare export var CANCEL: '@@redux-saga/cancelPromise'; + + declare export var effects: Effects; + declare export var utils: Utils; +}