Skip to content

Instantly share code, notes, and snippets.

@socheatsok78
Last active December 24, 2020 03:27
Show Gist options
  • Save socheatsok78/7d4ac655519d66fe14598e31f5034252 to your computer and use it in GitHub Desktop.
Save socheatsok78/7d4ac655519d66fe14598e31f5034252 to your computer and use it in GitHub Desktop.
Payment Machine - XState (Example)

Payment Machine - XState

How-to

  1. Go to https://xstate.js.org/viz/
  2. Copy and paste paymentMachine.js content in to Definition tab in "XState Visualizer"
  3. Click Update on the Definition tab
  4. You're good to go
function random(max) {
return Math.floor(Math.random() * Math.floor(max))
}
const dummyCard = {
name: 'Finch Poland',
number: '4510 6459 8301 6543',
cvc: 359,
expired_at: '03/2021',
type: 'visa'
}
const paymentMachine = Machine({
id: 'payment',
initial: 'method',
context: {
method: '',
package: '',
amount: 0,
status: '',
card: {}
},
states: {
method: {
initial: 'cash',
states: {
cash: {
entry: ['method'],
on: {
SWITCH_CHECK: 'check',
SWITCH_CARD: 'card',
},
},
check: {
entry: ['method'],
on: {
SWITCH_CASH: 'cash',
SWITCH_CARD: 'card',
}
},
card: {
entry: ['method'],
on: {
SWITCH_CASH: 'cash',
SWITCH_CHECK: 'check',
}
},
hist: {
type: 'history'
}
},
on: {
NEXT: 'package.hist',
}
},
package: {
initial: 'standard',
states: {
standard: {
entry: ['amount', 'package'],
on: {
SWITCH_PREMIUM: {
target: 'premium',
// actions: ['amount']
},
SWITCH_SUBSCRIPTION: {
target: 'subscriptions',
// actions: ['amount']
}
},
},
premium: {
entry: ['amount', 'package'],
on: {
SWITCH_STANDARD: {
target: 'standard',
// actions: ['amount']
},
SWITCH_SUBSCRIPTION: {
target: 'subscriptions',
// actions: ['amount']
}
}
},
subscriptions: {
initial: 'monthly',
states: {
monthly: {
entry: ['amount', 'package'],
on: {
SWITCH_YEARLY: {
target: 'yearly',
// actions: ['amount']
},
}
},
yearly: {
entry: ['amount', 'package'],
on: {
SWITCH_MONTHLY: {
target: 'monthly',
// actions: ['amount']
},
}
}
},
on: {
SWITCH_STANDARD: 'standard',
SWITCH_PREMIUM: 'premium',
}
},
hist: {
type: 'history'
}
},
on: {
NEXT: 'review',
PREVIOUS: 'method.hist'
}
},
review: {
on: {
NEXT: {
target: 'payment'
},
PREVIOUS: 'package.hist'
}
},
payment: {
entry: ['payment'],
on: {
NEXT: {
target: 'order'
},
PREVIOUS: 'review'
}
},
order: {
initial: 'pending',
invoke: {
id: 'verifyPayment',
src: (context, event) => (callback, onEvent) => {
const id = setTimeout(() => {
const status = random(2);
if (status > 0) {
callback('SWITCH_COMPLETE');
} else {
callback('SWITCH_INCOMPLETE');
}
}, 2000);
return () => clearTimeout(id);
}
},
states: {
pending: {
on: {
SWITCH_COMPLETE: 'complete',
SWITCH_INCOMPLETE: 'incomplete',
},
meta: {
message: 'Processing payment...'
},
},
complete: {
entry: ['order'],
meta: {
message: 'Payment success!'
}
},
incomplete: {
entry: ['order'],
meta: {
message: 'Unable to proceed payment!'
}
},
},
}
},
}, {
actions: {
method: (context, event) => {
switch (event.type) {
case 'SWITCH_CARD':
context.method = 'card';
break;
case 'SWITCH_CHECK':
context.method = 'check';
break;
case 'SWITCH_CASH':
default:
context.method = 'cash';
break;
}
},
package: (context, event) => {
switch (event.type) {
case 'SWITCH_SUBSCRIPTION':
case 'SWITCH_MONTHLY':
context.package = 'monthly';
break;
case 'SWITCH_YEARLY':
context.package = 'yearly';
break;
case 'SWITCH_PREMIUM':
context.package = 'premium';
break;
case 'SWITCH_STANDARD':
default:
context.package = 'standard';
break;
}
},
amount: (context, event) => {
switch (event.type) {
case "SWITCH_PREMIUM":
context.amount = 30;
break;
case "SWITCH_SUBSCRIPTION":
case "SWITCH_MONTHLY":
context.amount = 150;
break;
case "SWITCH_YEARLY":
context.amount = 300;
break;
case "SWITCH_STANDARD":
default:
context.amount = 15;
break;
}
},
payment(context, event) {
if (context.method == 'card') {
context.card = dummyCard;
}
},
order(context, event) {
switch (event.type) {
case 'SWITCH_COMPLETE':
context.status = 'completed';
break;
case 'SWITCH_INCOMPLETE':
default:
context.status = 'incompleted';
break;
}
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment