Skip to content

Instantly share code, notes, and snippets.

@dmitryshelomanov
Last active March 12, 2020 08:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmitryshelomanov/d2957f421192aef6a7faf7d23e7cbceb to your computer and use it in GitHub Desktop.
Save dmitryshelomanov/d2957f421192aef6a7faf7d23e7cbceb to your computer and use it in GitHub Desktop.
// @flow
import {
type Store,
type Effect,
type Event,
sample,
guard,
combine,
restore,
forward,
} from "effector"
import { debugDomain } from "@lib/effector-extend"
import type { AuthEmailResultPayload } from "@lib/ws"
import { wsEmailSend } from "@features/auth"
const { createEffect, createEvent, createStore } = debugDomain
export const changeField: Event<string> = createEvent()
export const sendCode: Event<void> = createEvent()
export const resetStores: Event<void> = createEvent()
export const resultForSendCode: Event<[number, string]> = createEvent()
export const $currentField: Store<string> = restore(changeField, "")
export const $previosField: Store<string> = restore(
resultForSendCode.map(([timer, field]) => field),
"",
).reset(resetStores)
export const $isValidField: Store<boolean> = $currentField.map(
(e) => e.trim().length > 0,
)
export const sendCodeFx: Effect<
string,
AuthEmailResultPayload,
> = createEffect().use(wsEmailSend)
export const decrementTimerFx: Effect<void, void> = createEffect().use(() => {
return new Promise((res, rej) => {
const unbind = resetStores.watch(() => {
rej()
unbind()
})
setTimeout(() => {
res()
unbind()
}, 1000)
})
})
export const $expiredTimer: Store<number> = createStore(0)
.on(resultForSendCode, (prev, [timer]) => timer)
.on(decrementTimerFx.done, (timer) => timer - 1)
.reset(resetStores)
export const $expiredTimerIsEmpty: Store<boolean> = $expiredTimer.map(
(t) => t === 0,
)
export const $expiredTimerIsNotEmpty: Store<boolean> = $expiredTimerIsEmpty.map(
(t) => !t,
)
export const $nextAndPrevFieldsAreEquals: Store<boolean> = combine([
$currentField,
$previosField,
]).map(([x, y]) => x === y)
export const $canSedCode: Store<boolean> = combine([
$nextAndPrevFieldsAreEquals,
$expiredTimerIsEmpty,
$isValidField,
]).map(([nextAndPrevFieldsAreEquals, expiredTimerIsEmpty, isValidField]) => {
if (nextAndPrevFieldsAreEquals) {
return isValidField && expiredTimerIsEmpty
}
return isValidField
})
guard({
source: sample($currentField, sendCode),
filter: $canSedCode,
target: sendCodeFx,
})
guard({
source: decrementTimerFx.done.map(() => undefined),
filter: $expiredTimerIsNotEmpty,
target: decrementTimerFx,
})
forward({ from: resultForSendCode.map(() => undefined), to: decrementTimerFx })
guard({
source: sample(
$currentField,
sendCodeFx.done,
(field, { params, result }) => ({
timeout: result.payload.timeout,
areEqual: params === field,
field,
}),
),
filter: ({ areEqual }) => areEqual,
target: resultForSendCode.prepend(({ timeout, field }) => [timeout, field]),
})
forward({ from: sendCodeFx.map(() => undefined), to: resetStores })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment