Skip to content

Instantly share code, notes, and snippets.

@amogower
Last active September 16, 2019 09:06
Show Gist options
  • Save amogower/55369c660b36cbd1d46fa7dcd739d384 to your computer and use it in GitHub Desktop.
Save amogower/55369c660b36cbd1d46fa7dcd739d384 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const singleBetMachine = Machine({
id: 'singleBet',
initial: 'initial',
context: {
stake: '',
},
states: {
initial: {},
},
});
const multipleBetMachine = Machine({
id: 'multipleBet',
initial: 'initial',
context: {
stake: '',
},
states: {
initial: {},
},
});
const betslipMachine = Machine({
id: 'ocBetslip',
initial: 'hidden',
context: {
bookie: null,
bookieList: [],
errors: {
global: [],
multiple: [],
single: [],
total: 0,
},
freeBets: [],
multiples: [],
market: {},
receiptNo: '',
selectedBets: [
{ betId: '1' },
{ betId: '2' },
],
singles: [],
totalStake: 0,
totalReturns: 0,
userSelectedBookie: false,
},
states: {
hidden: {
id: 'hidden',
on: {
ADD_BET: {
actions: 'addBet',
target: 'visible',
},
SHOW_BETSLIP: {
target: 'visible',
},
},
},
visible: {
id: 'visible',
initial: 'initializing',
on: {
HIDE_BETSLIP: {
actions: 'hideBetslip',
target: 'hidden',
},
},
states: {
initializing: {
on: {
'': [
{
cond: 'hasNoBets',
target: 'empty',
},
{
target: 'fetchingBetData',
},
]
},
},
empty: {
on: {
ADD_BET: {
actions: 'addBet',
target: 'fetchingBetData',
},
},
},
fetchingBetData: {
invoke: {
src: 'fetchBetData',
onDone: {
actions: 'addBets',
target: 'initialized',
},
onError: {
target: 'error.global',
},
},
},
initialized: {
// entry: assign({
// multiples: (ctx) => ctx.multiples.map(multiple => ({
// ...multiple,
// ref: spawn(multipleBetMachine.withContext(multiple))
// })),
// singles: (ctx) => ctx.singles.map(single => ({
// ...single,
// ref: spawn(singleBetMachine.withContext(single))
// })),
// }),
on: {
'': [
{
cond: 'noBookieSelected',
target: 'bookieList',
},
{
target: 'betslip',
}
],
},
},
betslip: {
on: {
ADD_BET: {
actions: 'addBet',
target: 'fetchingBetData',
},
CHANGE_STAKE: {
actions: 'setStake',
},
OPEN_BOOKIE_LIST: {
target: 'bookieList',
},
PLACE_BETSLIP: [
{
cond: 'hasInsufficientFunds',
target: 'error.global',
},
{
target: 'placingBetslip',
},
],
REMOVE_BET: {
actions: 'removeBet',
},
TOGGLE_EACH_WAY: {
actions: 'toggleEachWay',
},
},
},
bookieList: {
on: {
CLOSE_BOOKIE_LIST: {
target: 'initialized',
},
SELECT_BOOKIE: {
actions: 'selectBookie',
target: 'initialized',
},
},
},
placingBetslip: {
invoke: {
src: 'placeBetslip',
onDone: {
actions: 'cacheReceiptNo',
target: 'receipt',
},
onError: [
{
cond: 'isNotSingleError',
target: 'error.single',
},
{
cond: 'isNotMultipleError',
target: 'error.multiple',
},
{
target: 'error.global',
},
],
},
},
error: {
initial: 'global',
states: {
global: {
on: {
CLOSE_MODAL: {
target: '#visible.betslip',
},
},
},
multiple: {
on: {
CHANGE_STAKE: {
actions: 'setStake',
target: '#visible.betslip',
},
},
},
single: {
on: {
CHANGE_STAKE: {
actions: 'setStake',
target: '#visible.betslip',
},
},
},
},
},
receipt: {
on: {
DONE: {
target: 'done',
},
REUSE_SELECTIONS: {
target: 'betslip',
},
},
},
done: {
type: 'final',
},
},
},
},
onDone: {
actions: 'hideBetslip',
},
}, {
actions: {
addBets: assign({
multiples: (ctx, evt) => evt.data.multiples,
singles: (ctx, evt) => evt.data.singles,
}),
cacheReceiptNo: assign({
receiptNo: (ctx, evt) => evt.receiptNo,
}),
hideBetslip: assign({
betslipVisible: false,
}),
removeBet: assign({
selectedBets: (ctx, evt) => ctx.selectedBets.filter((bet) => bet.betId !== evt.betId),
singles: (ctx, evt) => ctx.singles.filter((single) => single.betId !== evt.betId),
}),
selectBookie: assign({
bookie: (ctx, evt) => evt.bookie,
userSelectedBookie: (ctx, evt) => !!evt.bookie,
}),
setStake: assign({
singles: (ctx, evt) => ctx.singles.map((single) => {
if (single.betId !== evt.betId) return single;
return Object.assign({}, single, {
stake: evt.value,
});
}),
}),
showBetslip: assign({
betslipVisible: true,
}),
toggleEachWay: assign((ctx, evt) => {
let key = 'singles';
let attrCheck = 'betId';
if (evt.betType !== 'Single') {
key = 'multiples';
attrCheck = 'betType';
}
return {
[key]: ctx[key].map((bet) => {
if (bet[attrCheck] !== evt[attrCheck]) return bet;
return Object.assign({}, bet, {
eachWay: !ctx.eachWay,
});
}),
};
}),
},
guards: {
hasInsufficientFunds: (ctx, evt) => {
if (!ctx.bookie) return false;
const hasFunds =
Number(ctx.bookie.balance) >= Number(ctx.totalStake) ||
ctx.singles[0].freeBet;
return !hasFunds;
},
hasNoBets: (ctx) => !ctx.selectedBets.length,
noBookieSelected: (ctx) => !ctx.bookie && !ctx.userSelectedBookie,
isNotSingleError: () => false,
isNotMultipleError: () => false,
},
services: {
fetchBetData: () => new Promise((resolve) => {
setTimeout(() => {
resolve({
multiples: [],
singles: [
{ betId: '1', eachWay: false },
{ betId: '2', eachWay: true },
],
});
}, 1500);
}),
getCachedBets: () => new Promise((resolve) => {
setTimeout(() => {
resolve([1, 2]);
}, 1500);
}),
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment