Last active
June 3, 2020 21:40
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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