Skip to content

Instantly share code, notes, and snippets.

@dsebastien
Last active April 3, 2020 23:15
Show Gist options
  • Save dsebastien/e66e863ccc7104ab88db37fdddbdd314 to your computer and use it in GitHub Desktop.
Save dsebastien/e66e863ccc7104ab88db37fdddbdd314 to your computer and use it in GitHub Desktop.
import {Machine, StateSchema} from 'xstate';
// TODO review/improve based on: https://xstate.js.org/docs/guides/typescript.html#using-typescript
/**
* Extended state of the machine (if any)
* Reference: https://xstate.js.org/docs/guides/context.html
*/
// tslint:disable-next-line:no-empty-interface
interface MeetingStateMachineContext {}
/**
* The different states
*/
export enum MeetingState {
DRAFT = "draft",
DELETED = 'deleted',
PLANNED = 'planned',
STARTED = 'started',
CANCELLED = 'cancelled',
ONGOING = 'ongoing',
PAUSED = 'paused',
FINISHED = 'finished',
FROZEN = 'frozen',
}
/**
* Supported event names
*/
export enum MeetingStateMachineEventName {
DELETE = "DELETE",
SEND_INVITES = "SEND_INVITES",
START_WITHOUT_INVITES = "START_WITHOUT_INVITES",
CANCEL = "CANCEL",
PREPARE_START = "PREPARE_START",
START = "START",
PAUSE = "PAUSE",
UNPAUSE = "UNPAUSE",
STOP = "STOP",
FREEZE = "FREEZE",
}
/**
* Supported event types.
* Each can have additional properties if needed
*/
type MeetingStateMachineEvent =
{ type: MeetingStateMachineEventName.DELETE } |
{ type: MeetingStateMachineEventName.SEND_INVITES } |
{ type: MeetingStateMachineEventName.START_WITHOUT_INVITES } |
{ type: MeetingStateMachineEventName.CANCEL } |
{ type: MeetingStateMachineEventName.PREPARE_START } |
{ type: MeetingStateMachineEventName.START } |
{ type: MeetingStateMachineEventName.PAUSE } |
{ type: MeetingStateMachineEventName.UNPAUSE } |
{ type: MeetingStateMachineEventName.STOP } |
{ type: MeetingStateMachineEventName.FREEZE };
// type MeetingStateMachineEvent =
// { type: 'DELETE'} |
// { type: 'SEND_INVITES' } |
// { type: 'START_WITHOUT_INVITES' } |
// { type: 'CANCEL' } |
// { type: 'PREPARE_START' } |
// { type: 'START' } |
// { type: 'PAUSE' } |
// { type: 'UNPAUSE' } |
// { type: 'STOP' } |
// { type: 'FREEZE' };
interface MeetingStateTransitionList extends StateSchema {
on?: {
[key in MeetingStateMachineEventName]: MeetingState;
}
}
interface MeetingStateMachineSchema extends StateSchema<MeetingStateTransitionList> {
states: {
[key in MeetingState]: MeetingStateTransitionList;
},
}
/**
* State machine for meetings
*/
export const meetingStateMachineDefinitionV1 = Machine<MeetingStateMachineContext, MeetingStateMachineSchema, MeetingStateMachineEvent>({
version: "1", // WARNING: MUST be incremented whenever the structure changes
id: 'meetings',
initial: MeetingState.DRAFT,
strict: true,
context: {
},
states: {
[MeetingState.DRAFT]: {
on: {
[MeetingStateMachineEventName.DELETE]: MeetingState.DELETED,
[MeetingStateMachineEventName.SEND_INVITES]: MeetingState.PLANNED,
[MeetingStateMachineEventName.START_WITHOUT_INVITES]: MeetingState.STARTED,
}
},
[MeetingState.DELETED]: {
type: 'final'
},
[MeetingState.PLANNED]: {
on: {
[MeetingStateMachineEventName.CANCEL]: MeetingState.CANCELLED,
[MeetingStateMachineEventName.PREPARE_START]: MeetingState.STARTED // replace PREPARE_START with '' to have an automatic transition
}
},
[MeetingState.CANCELLED]: {
type: 'final'
},
[MeetingState.STARTED]: {
on: {
[MeetingStateMachineEventName.START]: MeetingState.ONGOING,
}
},
[MeetingState.ONGOING]: {
on: {
[MeetingStateMachineEventName.PAUSE]: MeetingState.PAUSED,
[MeetingStateMachineEventName.STOP]: MeetingState.FINISHED,
}
},
[MeetingState.PAUSED]: {
on: {
[MeetingStateMachineEventName.UNPAUSE]: MeetingState.ONGOING,
}
},
[MeetingState.FINISHED]: {
on: {
[MeetingStateMachineEventName.FREEZE]: MeetingState.FROZEN,
}
},
[MeetingState.FROZEN]: {
type: 'final'
}
}
});
const dummyMeetingStateMachine = interpret(meetingStateMachineDefinitionV1)
//.onTransition(state => console.log(state.value))
.start();
//console.log("Initial state: ", meetingStateMachineDefinitionV1.initialState);
const currentState = dummyMeetingStateMachine.state;
console.log("Next (allowed) events: ", currentState.nextEvents);
const canDelete = currentState.nextEvents.includes(MeetingStateMachineEvent.DELETE);
console.log("Can delete? ", canDelete); // true
const eventResult = dummyMeetingStateMachine.send( {type: MeetingStateMachineEvent.DELETE}).changed;
console.log("Delete event accepted?: ", eventResult);
//console.log(dummyMeetingStateMachine.state);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment