2021-08-05 20:38:24 +03:00
|
|
|
import { MaybeAsync, Message } from '@mtcute/client'
|
2022-06-30 16:32:56 +03:00
|
|
|
|
2021-06-14 19:01:02 +03:00
|
|
|
import { Dispatcher } from './dispatcher'
|
|
|
|
import { UpdateState } from './state'
|
|
|
|
import { filters } from './filters'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action for the wizard scene.
|
|
|
|
*
|
|
|
|
* `Next`: Continue to the next registered step
|
|
|
|
* (or exit, if this is the last step)
|
|
|
|
*
|
|
|
|
* `Stay`: Stay on the same step
|
|
|
|
*
|
|
|
|
* `Exit`: Exit from the wizard scene
|
|
|
|
*
|
|
|
|
* You can also return a `number` to jump to that step
|
|
|
|
*/
|
|
|
|
export enum WizardSceneAction {
|
|
|
|
Next = 'next',
|
|
|
|
Stay = 'stay',
|
2022-06-30 16:32:56 +03:00
|
|
|
Exit = 'exit',
|
2021-06-14 19:01:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
interface WizardInternalState {
|
|
|
|
$step: number
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wizard is a special type of Dispatcher
|
|
|
|
* that can be used to simplify implementing
|
|
|
|
* step-by-step scenes.
|
|
|
|
*/
|
2022-06-30 16:32:56 +03:00
|
|
|
export class WizardScene<
|
|
|
|
State,
|
|
|
|
SceneName extends string = string
|
|
|
|
> extends Dispatcher<State & WizardInternalState, SceneName> {
|
2021-06-14 19:01:02 +03:00
|
|
|
private _steps = 0
|
|
|
|
|
2021-06-24 01:12:20 +03:00
|
|
|
private _defaultState: State & WizardInternalState = {} as any
|
|
|
|
|
2022-06-30 16:32:56 +03:00
|
|
|
setDefaultState(defaultState: State): void {
|
2021-06-24 01:12:20 +03:00
|
|
|
this._defaultState = defaultState as State & WizardInternalState
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:01:02 +03:00
|
|
|
/**
|
|
|
|
* Get the total number of registered steps
|
|
|
|
*/
|
|
|
|
get totalSteps(): number {
|
|
|
|
return this._steps
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a step to the wizard
|
|
|
|
*/
|
2022-06-30 16:32:56 +03:00
|
|
|
addStep(
|
|
|
|
handler: (
|
|
|
|
msg: Message,
|
|
|
|
state: UpdateState<State, SceneName>
|
|
|
|
) => MaybeAsync<WizardSceneAction | number>
|
|
|
|
): void {
|
2021-06-14 19:01:02 +03:00
|
|
|
const step = this._steps++
|
|
|
|
|
2022-06-30 16:32:56 +03:00
|
|
|
const filter = filters.state<WizardInternalState>(
|
|
|
|
(it) => it.$step === step
|
|
|
|
)
|
2021-06-14 19:01:02 +03:00
|
|
|
|
|
|
|
this.onNewMessage(
|
2022-06-30 16:32:56 +03:00
|
|
|
step === 0 ? filters.or(filters.stateEmpty, filter) : filter,
|
2021-06-14 19:01:02 +03:00
|
|
|
async (msg: Message, state) => {
|
|
|
|
const result = await handler(msg, state)
|
|
|
|
|
|
|
|
if (typeof result === 'number') {
|
2021-06-24 01:12:20 +03:00
|
|
|
await state.merge({ $step: result }, this._defaultState)
|
2021-06-14 19:01:02 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case 'next': {
|
|
|
|
const next = step + 1
|
|
|
|
if (next === this._steps) {
|
|
|
|
await state.exit()
|
|
|
|
} else {
|
2022-06-30 16:32:56 +03:00
|
|
|
await state.merge(
|
|
|
|
{ $step: next },
|
|
|
|
this._defaultState
|
|
|
|
)
|
2021-06-14 19:01:02 +03:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case 'exit':
|
|
|
|
await state.exit()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|