Skip to content

Instantly share code, notes, and snippets.

@aaronmcadam
Created October 12, 2022 17:14
Show Gist options
  • Save aaronmcadam/46132df7ae1c99266b5d2ad77b7bc4a9 to your computer and use it in GitHub Desktop.
Save aaronmcadam/46132df7ae1c99266b5d2ad77b7bc4a9 to your computer and use it in GitHub Desktop.
Example of an XState state machine modelling a wizard process
import { createModel } from 'xstate/lib/model';
import { GeneralInfoFormValues } from '../create-project-screen/project-wizard/project-wizard-steps/general-info-panel';
import { ArtistInfoFormValues } from '../create-project-screen/project-wizard/project-wizard-steps/artist-info-panel';
import { PlaylistFormValues } from '../create-project-screen/project-wizard/project-wizard-steps/playlist-panel';
import { SocialMediaLinksFormValues } from '../create-project-screen/project-wizard/project-wizard-steps/social-media-links-panel';
export interface ProjectWizardContext {
currentStepNumber: number;
generalInfo: GeneralInfoFormValues;
artistInfo: ArtistInfoFormValues;
playlist: PlaylistFormValues;
socialMediaLinks: SocialMediaLinksFormValues;
}
export const projectWizardModel = createModel(
{
currentStepNumber: 1,
generalInfo: {},
artistInfo: {},
playlist: {},
} as ProjectWizardContext,
{
events: {
ASSIGN_GENERAL_INFO: (payload: GeneralInfoFormValues) => ({
payload,
}),
ASSIGN_ARTIST_INFO: (payload: ArtistInfoFormValues) => ({
payload,
}),
ASSIGN_PLAYLIST: (payload: PlaylistFormValues) => ({
payload,
}),
ASSIGN_SOCIAL_MEDIA_LINKS: (payload: SocialMediaLinksFormValues) => ({
payload,
}),
CONTINUE: () => ({}),
SKIP: () => ({}),
BACK: () => ({}),
},
}
);
const assignGeneralInfo = projectWizardModel.assign(
{
generalInfo: (context, event) => {
return event.payload;
},
},
'ASSIGN_GENERAL_INFO'
);
const assignArtistInfo = projectWizardModel.assign(
{
artistInfo: (context, event) => {
return event.payload;
},
},
'ASSIGN_ARTIST_INFO'
);
const assignPlaylist = projectWizardModel.assign(
{
playlist: (context, event) => {
return event.payload;
},
},
'ASSIGN_PLAYLIST'
);
const assignSocialMediaLinks = projectWizardModel.assign(
{
socialMediaLinks: (context, event) => {
return event.payload;
},
},
'ASSIGN_SOCIAL_MEDIA_LINKS'
);
const incrementStepNumber = projectWizardModel.assign(
{
currentStepNumber: (context, event) => {
return context.currentStepNumber + 1;
},
},
'CONTINUE'
);
const decrementStepNumber = projectWizardModel.assign(
{
currentStepNumber: (context, event) => {
return context.currentStepNumber - 1;
},
},
'BACK'
);
export const projectWizardMachine = projectWizardModel.createMachine({
id: 'projectWizard',
initial: 'generalInfo',
states: {
generalInfo: {
on: {
ASSIGN_GENERAL_INFO: {
actions: [assignGeneralInfo],
},
CONTINUE: {
target: 'artistInfo',
actions: [incrementStepNumber],
},
},
},
artistInfo: {
on: {
ASSIGN_ARTIST_INFO: {
actions: [assignArtistInfo],
},
CONTINUE: {
target: 'playlist',
actions: [incrementStepNumber],
},
BACK: {
target: 'generalInfo',
actions: [decrementStepNumber],
},
},
},
playlist: {
on: {
ASSIGN_PLAYLIST: {
actions: [assignPlaylist],
},
CONTINUE: {
target: 'socialMediaLinks',
actions: [incrementStepNumber],
},
BACK: {
target: 'artistInfo',
actions: [decrementStepNumber],
},
},
},
socialMediaLinks: {
on: {
ASSIGN_SOCIAL_MEDIA_LINKS: {
actions: [assignSocialMediaLinks],
},
CONTINUE: 'wizardCompleted',
SKIP: 'wizardCompleted',
BACK: {
target: 'playlist',
actions: [decrementStepNumber],
},
},
},
wizardCompleted: {
type: 'final',
entry: ['createProject'],
},
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment