Skip to content

Instantly share code, notes, and snippets.

@boertel
Last active June 3, 2020 21:40
Show Gist options
  • Save boertel/966b9b5e77ed0316af0f7e42f5d082c0 to your computer and use it in GitHub Desktop.
Save boertel/966b9b5e77ed0316af0f7e42f5d082c0 to your computer and use it in GitHub Desktop.
Machine to handle service requests status changes: https://xstate.js.org/viz/?gist=966b9b5e77ed0316af0f7e42f5d082c0
const initial = undefined
const context = undefined
const machine = Machine(
{
id: 'service-request',
initial: initial || 'REQUESTED',
context: {
hasPayment: true,
hasApproval: true,
name: '<service name>',
partyName: '<guest name>',
propertyName: '<property name>',
paymentLink: '<link to checkout>',
approvalLink: '<approval link>',
custom: {
approve: '<custom approved message>',
decline: '<custom declined message>',
},
quantity: 1,
toGuest: undefined,
toPm: undefined,
...(context || {}),
},
states: {
REQUESTED: {
on: {
request: [
{ target: 'PAYMENT_CHECKOUT_PENDING', cond: 'hasPayment' },
{ target: 'APPROVAL_PENDING', cond: 'hasApproval', actions: 'serviceRequested' },
{ target: 'PM_APPROVED', cond: 'hasNoApproval', actions: 'approve' },
],
},
},
PAYMENT_CHECKOUT_PENDING: {
invoke: {
src: 'createPaymentCheckout',
onDone: {
target: 'PAYMENT_PENDING',
actions: 'serviceRequested',
},
onError: {
target: 'PAYMENT_FAILED',
actions: 'fail',
},
},
},
PAYMENT_PENDING: {
on: {
authorizePayment: [
{ target: 'APPROVAL_PENDING', cond: 'hasApproval', actions: 'serviceRequested' },
{ target: 'PAYMENT_CAPTURED' },
],
},
},
PAYMENT_CAPTURED: {
invoke: {
src: 'capturePayment',
onDone: {
target: 'PM_APPROVED',
actions: 'approve',
},
onError: {
target: 'PAYMENT_FAILED',
actions: 'fail',
},
},
},
PAYMENT_CANCELED: {
invoke: {
id: 'cancelPaymentAuthorization',
src: 'cancelPaymentAuthorization',
onDone: {
target: 'PM_DECLINED',
actions: 'decline',
},
onError: {
target: 'PAYMENT_FAILED',
actions: 'fail',
},
},
},
APPROVAL_PENDING: {
on: {
approve: [
{ target: 'PAYMENT_CAPTURED', cond: 'hasPayment', actions: 'reset' },
{ target: 'PM_APPROVED', actions: 'approve' },
],
decline: [
{ target: 'PAYMENT_CANCELED', cond: 'hasPayment', actions: 'reset' },
{ target: 'PM_DECLINED', actions: 'decline' },
],
},
},
PAYMENT_FAILED: {
type: 'final',
},
FAILED: {
type: 'final',
},
PM_APPROVED: {
type: 'final',
},
PM_DECLINED: {
type: 'final',
},
},
},
{
guards: {
hasApproval: ({ hasApproval }) => hasApproval,
hasNoApproval: ({ hasApproval }) => !hasApproval,
hasPayment: ({ hasPayment }) => hasPayment,
},
services: {
createPaymentCheckout: () => {
return Promise.resolve()
},
capturePayment: () => {
return Promise.resolve()
},
cancelPaymentAuthorization: () => {
return Promise.resolve()
},
},
actions: {
reset: assign({
toGuest: undefined,
toPm: undefined,
}),
serviceRequested: assign({
toGuest: ({ name, hasPayment, hasApproval, paymentLink }, evt) => {
if (hasPayment && (evt.type === 'request' || evt.type === 'authorizePayment')) {
return undefined
}
let message = [`We've received your service request for ${name}`]
if (hasPayment) {
message.push(`, please visit the following link to enter your payment information: ${paymentLink}`)
} else if (hasApproval) {
message.push(` and will provide you with a confirmation message shortly.`)
}
return message.join('')
},
toPm: ({ name, propertyName, hasApproval, hasPayment, approvalLink, partyName }, evt) => {
if (hasPayment && (evt.type === 'request' || evt.type === 'done.invoke.createPaymentCheckout')) {
return undefined
}
let message = [
`You've received a ${name} request${partyName ? ` from ${partyName}` : ''} at ${propertyName}.`,
]
if (hasApproval) {
message.push(` Respond here: ${approvalLink}`)
}
return message.join('')
},
}),
approve: assign({
toGuest: ({ name, hasPayment, custom }) => {
let message = [`[Approved] Your request for ${name} has been approved`]
if (hasPayment) {
message.push(' and your payment has been collected')
}
if (custom.approve) {
message.push(`. ${custom.approve}`)
} else {
message.push('.')
}
return message.join('')
},
toPm: ({ name, hasApproval, hasPayment, propertyName }) => {
if (hasApproval) {
return undefined
}
let message = [`You've received a ${name} request at ${propertyName}`]
if (hasPayment) {
message.push(` and payment has been captured`)
}
message.push('.')
return message.join('')
},
}),
decline: assign({
toGuest: ({ name, hasPayment, custom }) => {
let message = [`[Declined] Your request for ${name} has been declined`]
if (hasPayment) {
message.push(' and your payment authorization has been cancelled')
}
if (custom.decline) {
message.push(`. ${custom.decline}`)
} else {
message.push('.')
}
return message.join('')
},
toPm: () => undefined,
}),
fail: assign({
toGuest: ({ name }) => {
let message = [`Your request for ${name} failed`]
return message.join('')
},
toPm: ({ name, propertyName }) => {
let message = [`A request for ${name} at ${propertyName} failed`]
return message.join('')
},
}),
},
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment