Skip to content

Instantly share code, notes, and snippets.

@flybayer
Created February 6, 2020 04:49
Show Gist options
  • Save flybayer/7d335c34294f9cda5b4784409daeaa4f to your computer and use it in GitHub Desktop.
Save flybayer/7d335c34294f9cda5b4784409daeaa4f to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const checkoutAppMachine = Machine(
{
id: "checkoutApp",
initial: "studentEntry",
strict: true,
context: {
currentStepNumber: 0,
account: {
authenticated: false,
},
customer: {
first_name: "",
last_name: "",
timezone: "",
email: "",
phone: "",
address1: "",
city: "",
state: "",
zip_code: "",
agree_to_terms: false,
},
students: [],
bookings: {
reading: undefined,
math: undefined,
language: undefined,
science: undefined,
screening: undefined,
},
existingOrders: [],
someoneTakingLanguage: false,
someoneTakingScience: false,
editingExistingOrder: undefined,
isScreeningMode: false,
addons: {
resultsConsultation: false,
},
},
states: {
studentEntry: {
type: "atomic",
entry: assign({ currentStepNumber: 0 }),
on: {
CHANGE_STUDENTS: {
actions: assign((context, event) => {
const students = event.value
const someoneTakingLanguage =
students.some(student => student.tests.language) && !context.isScreeningMode
const someoneTakingScience =
students.some(student => student.tests.science) && !context.isScreeningMode
const newBookings = {}
// This ensures bookings are cleared if someone
// selected one of these tests and later remove it
// But only if not joining a group which already has bookings
if (!context.joinGroup) {
if (!someoneTakingLanguage) newBookings.language = undefined
if (!someoneTakingScience) newBookings.science = undefined
}
return {
students,
someoneTakingLanguage,
someoneTakingScience,
bookings: {
...context.bookings,
...newBookings,
},
}
}),
},
CHANGE_ACCOUNT: {
actions: assign((context, event) => {
return {
account: {
...context.account,
...event.value,
},
}
}),
},
CHANGE_CUSTOMER: {
actions: assign((context, event) => {
return {
customer: {
...context.customer,
...event.value,
},
}
}),
},
CHANGE_ORDERS: {
actions: assign((context, event) => {
return {
existingOrders: event.value,
}
}),
},
CHANGE_BOOKINGS: {
actions: assign((context, event) => {
return {
bookings: { ...context.bookings, ...event.bookings },
}
}),
},
EDIT_EXISTING_ORDER: {
actions: assign((context, event) => {
return {
editingExistingOrder: event.value,
isScreeningMode: !!event.value.bookings.screening,
addons: event.value.addons,
}
}),
},
CHANGE_BOOK_GROUP: {
target: "scheduling",
actions: assign((context, event) => {
return { bookGroup: event.value, students: [] }
}),
},
CHANGE_JOIN_GROUP: {
actions: assign((context, event) => {
return { joinGroup: event.value }
}),
},
CHANGE_SCREENING_MODE: {
actions: assign((context, event) => {
return { isScreeningMode: event.value }
}),
},
CHANGE_CONSULTATION_ADDON: {
actions: assign((context, event) => {
return { addons: { ...context.addons, resultsConsultation: event.value } }
}),
},
NEXT: "scheduling",
},
},
scheduling: {
type: "compound",
entry: assign({ currentStepNumber: 1 }),
on: {
CHANGE_BOOKINGS: {
actions: assign({
bookings: (context, event) => ({ ...context.bookings, ...event.bookings }),
}),
},
CHANGE_NEED_LANGUAGE: {
target: ".default",
actions: assign((context, event) => {
return {
someoneTakingLanguage: event.value,
bookings: { ...context.bookings, language: undefined },
}
}),
},
CHANGE_NEED_SCIENCE: {
target: ".default",
actions: assign((context, event) => {
return {
someoneTakingScience: event.value,
bookings: { ...context.bookings, science: undefined },
}
}),
},
NEXT: "checkout",
"SCHEDULE.READING": "scheduling.reading",
"SCHEDULE.MATH": "scheduling.math",
"SCHEDULE.LANGUAGE": "scheduling.language",
"SCHEDULE.SCIENCE": "scheduling.science",
"NAVIGATE.STUDENT_ENTRY": { target: "studentEntry", cond: "notBookingGroup" },
},
initial: "default",
states: {
default: {
on: {
"": [
{ target: "review", cond: "bookingComplete" },
{
target: "screening",
cond: {
type: "needTestAndNeedScheduled",
testName: "screening",
},
},
{
target: "reading",
cond: {
type: "needTestAndNeedScheduled",
testName: "reading",
},
},
{
target: "math",
cond: {
type: "needTestAndNeedScheduled",
testName: "math",
},
},
{
target: "language",
cond: {
type: "needTestAndNeedScheduled",
testName: "language",
},
},
{
target: "science",
cond: {
type: "needTestAndNeedScheduled",
testName: "science",
},
},
],
},
},
screening: {
entry: assign({
bookings: (context, event) =>
context.editingExistingOrder
? context.bookings
: ({
...context.bookings,
screening: undefined,
}),
}),
on: {
NEXT: "review",
},
},
reading: {
entry: assign({
bookings: (context, event) =>
context.editingExistingOrder
? context.bookings
: ({
...context.bookings,
math: undefined,
language: undefined,
science: undefined,
screening: undefined,
}),
}),
on: {
NEXT: [{ target: "review", cond: "bookingComplete" }, { target: "math" }],
},
},
math: {
entry: assign({
bookings: (context, event) =>
context.editingExistingOrder
? context.bookings
: ({
...context.bookings,
language: undefined,
science: undefined,
}),
}),
on: {
NEXT: [
{ target: "review", cond: "bookingComplete" },
{
target: "language",
cond: {
type: "needTest",
testName: "language",
},
},
{
target: "science",
cond: {
type: "needTest",
testName: "science",
},
},
],
},
},
language: {
entry: assign({
bookings: (context, event) =>
context.editingExistingOrder
? context.bookings
: ({
...context.bookings,
science: undefined,
}),
}),
on: {
NEXT: [
{ target: "review", cond: "bookingComplete" },
{
target: "science",
cond: {
type: "needTest",
testName: "science",
},
},
],
},
},
science: {
on: {
NEXT: "review",
},
},
review: {},
},
},
checkout: {
type: "atomic",
entry: assign({ currentStepNumber: 2 }),
on: {
CHANGE_CONSULTATION_ADDON: {
actions: assign((context, event) => {
return { addons: { ...context.addons, resultsConsultation: event.value } }
}),
},
"NAVIGATE.STUDENT_ENTRY": { target: "studentEntry", cond: "notBookingGroup" },
"NAVIGATE.SCHEDULING": "scheduling.review",
SUCCESS: "checkoutSuccess",
},
},
checkoutSuccess: {
type: "final",
},
},
},
{
actions: {},
guards: {
needTest: (context, event, { cond }) => {
switch (cond.testName) {
case "screening":
if (context.isScreeningMode) {
return true
}
return false
case "language":
return context.someoneTakingLanguage
case "science":
return context.someoneTakingScience
default:
return true
}
},
needTestAndNeedScheduled: (context, event, { cond }) => {
let needTest
switch (cond.testName) {
case "screening":
if (context.isScreeningMode) {
needTest = true
}
break
case "language":
needTest = context.someoneTakingLanguage
break
case "science":
needTest = context.someoneTakingScience
break
default:
needTest = true
}
return needTest && !context.bookings[cond.testName]
},
bookingComplete: (context, event) => {
if (context.isScreeningMode && context.bookings.screening) return true
if (!context.bookings.reading) return false
if (!context.bookings.math) return false
if (context.someoneTakingLanguage && !context.bookings.language) return false
if (context.someoneTakingScience && !context.bookings.science) return false
return true
},
isBookingGroup: (context, event) => {
return !!context.bookGroup
},
notBookingGroup: (context, event) => {
return !context.bookGroup
},
isJoiningGroup: (context, event) => {
return !!context.joinGroup
},
},
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment