Created
January 19, 2021 19:06
-
-
Save amogower/a86ecebaef1e53440d4daa13f2f8fdee to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or 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 singleBetMachine = Machine({ | |
id: 'singleBet', | |
initial: 'default', | |
context: { | |
isEachWay: false, | |
stake: '', | |
}, | |
states: { | |
default: { | |
on: { | |
CHANGE_STAKE: { | |
actions: 'setStake', | |
}, | |
TOGGLE_EACH_WAY: { | |
actions: 'toggleEachWay', | |
}, | |
}, | |
}, | |
error: { | |
on: { | |
CHANGE_STAKE: { | |
actions: 'setStake', | |
target: 'default', | |
}, | |
}, | |
}, | |
}, | |
}); | |
const multipleBetMachine = Machine({ | |
id: 'multipleBet', | |
initial: 'default', | |
context: { | |
isEachWay: false, | |
stake: '', | |
}, | |
states: { | |
default: { | |
on: { | |
CHANGE_STAKE: { | |
actions: 'setStake', | |
}, | |
TOGGLE_EACH_WAY: { | |
actions: 'toggleEachWay', | |
}, | |
}, | |
}, | |
error: { | |
on: { | |
CHANGE_STAKE: { | |
actions: 'setStake', | |
target: 'default', | |
}, | |
}, | |
}, | |
}, | |
}); | |
const pollingMachine = Machine({ | |
initial: 'fetching', | |
states: { | |
fetching: { | |
invoke: { | |
src: 'buildBetslip', | |
onError: 'failure', | |
onDone: { | |
target: 'success', | |
actions: sendParent('BETSLIP_BUILT'), | |
}, | |
}, | |
after: { TIMEOUT: 'fetching' }, | |
}, | |
failure: { | |
after: { | |
INTERVAL: 'fetching', | |
}, | |
}, | |
success: {}, | |
}, | |
}, { | |
delays: { INTERVAL: 5000, TIMEOUT: 10000 } | |
}); | |
const betslipMachine = Machine({ | |
id: 'ocBetslip', | |
initial: 'hidden', | |
context: { | |
bookie: null, | |
bookieList: [], | |
credentials: { | |
password: null, | |
username: null, | |
}, | |
errors: { | |
global: [], | |
multiple: [], | |
single: [], | |
total: 0, | |
}, | |
freeBets: [], | |
multiples: [], | |
market: {}, | |
receiptNo: null, | |
selectedBets: {}, | |
singles: [], | |
totalStake: 10, | |
totalReturns: 0, | |
userSelectedBookie: false, | |
}, | |
states: { | |
hidden: { | |
id: 'hidden', | |
on: { | |
ADD_BET: { | |
actions: 'addBet', | |
target: 'visible', | |
}, | |
SHOW_BETSLIP: { | |
target: 'visible', | |
}, | |
}, | |
}, | |
visible: { | |
id: 'visible', | |
initial: 'betslip', | |
on: { | |
HIDE_BETSLIP: { | |
actions: 'hideBetslip', | |
target: 'hidden', | |
}, | |
}, | |
states: { | |
bookieList: { | |
on: { | |
CLOSE_BOOKIE_LIST: { | |
actions: 'selectBookie', | |
target: '#betslip.initialized', | |
}, | |
SELECT_BOOKIE: { | |
actions: 'selectBookie', | |
target: '#betslip.initialized', | |
}, | |
}, | |
}, | |
betslip: { | |
id: 'betslip', | |
initial: 'initializing', | |
states: { | |
initializing: { | |
on: { | |
'': [ | |
{ | |
cond: 'hasNoBets', | |
target: 'empty', | |
}, | |
{ | |
target: 'fetchingBookmakerData', | |
}, | |
] | |
}, | |
}, | |
empty: { | |
on: { | |
ADD_BET: { | |
actions: 'addBet', | |
target: 'initializing', | |
}, | |
}, | |
}, | |
fetchingBookmakerData: { | |
invoke: { | |
src: 'fetchBookmakerData', | |
onDone: { | |
target: 'fetchingBetData', | |
}, | |
onError: { | |
target: '#error', | |
}, | |
} | |
}, | |
fetchingBetData: { | |
invoke: { | |
src: 'fetchSingleBetData', | |
onDone: { | |
actions: 'addBets', | |
target: 'initialized', | |
}, | |
onError: { | |
target: '#error', | |
}, | |
}, | |
}, | |
initialized: { | |
on: { | |
'': [ | |
{ | |
cond: 'noBookieSelected', | |
target: '#visible.bookieList', | |
}, | |
{ | |
target: 'betting', | |
}, | |
], | |
}, | |
}, | |
betting: { | |
initial: 'loggedOut', | |
states: { | |
loggedOut: { | |
id: 'loggedOut', | |
on: { | |
'': [ | |
{ | |
cond: 'bookieLoggedIn', | |
target: 'loggedIn' | |
}, | |
], | |
LOG_IN: { | |
target: '#login', | |
}, | |
PLACE_BETSLIP: { | |
target: '#betslip.placeBetslip', | |
}, | |
}, | |
}, | |
loggedIn: { | |
id: 'loggedIn', | |
invoke: { | |
id: 'polling', | |
src: pollingMachine, | |
}, | |
on: { | |
'': [ | |
{ | |
cond: 'bookieLoggedOut', | |
target: 'loggedOut' | |
}, | |
], | |
BETSLIP_BUILT: { | |
actions: 'betslipBuilt', | |
}, | |
LOG_OUT: { | |
actions: 'bookmakerLogout', | |
target: 'loggedOut', | |
}, | |
PLACE_BETSLIP: [ | |
{ | |
cond: 'hasInsufficientFunds', | |
target: '#visible.error', | |
}, | |
{ | |
target: '#betslip.placeBetslip', | |
}, | |
], | |
}, | |
}, | |
}, | |
on: { | |
ADD_BET: { | |
actions: 'addBet', | |
target: '#betslip.fetchingBetData', | |
}, | |
OPEN_BOOKIE_LIST: { | |
target: '#visible.bookieList', | |
}, | |
REMOVE_BET: { | |
actions: 'removeBet', | |
target: '#betslip.initializing', | |
}, | |
}, | |
}, | |
placeBetslip: { | |
on: { | |
'': [ | |
{ | |
cond: 'bookieLoggedOut', | |
target: '#login', | |
}, | |
{ | |
cond: 'hasInsufficientFunds', | |
target: '#visible.error', | |
}, | |
{ | |
target: 'placingBetslip', | |
}, | |
], | |
}, | |
}, | |
placingBetslip: { | |
invoke: { | |
src: 'placeBetslip', | |
onDone: { | |
actions: 'cacheReceiptNo', | |
target: 'receipt', | |
}, | |
onError: [ | |
{ | |
target: '#error', | |
}, | |
], | |
}, | |
}, | |
receipt: { | |
on: { | |
DONE: { | |
target: 'done', | |
}, | |
REUSE_SELECTIONS: { | |
target: '#betslip.betting.loggedIn', | |
}, | |
}, | |
}, | |
done: { | |
type: 'final', | |
}, | |
error: { | |
initial: 'single', | |
states: { | |
single: {}, | |
multiple: {}, | |
}, | |
}, | |
hist: { | |
type: 'history', | |
}, | |
}, | |
}, | |
login: { | |
id: 'login', | |
initial: 'loginOauth', | |
states: { | |
loginApi: { | |
on: { | |
'': { | |
cond: 'bookieNotOauth', | |
target: 'loginApi', | |
}, | |
CHANGE_USERNAME: { | |
actions: 'changeUsername', | |
}, | |
CHANGE_PASSWORD: { | |
actions: 'changePassword', | |
}, | |
LOGIN: [ | |
{ | |
cond: 'noUsername', | |
target: 'error.username', | |
}, | |
{ | |
cond: 'noPassword', | |
target: 'error.password', | |
}, | |
{ | |
target: 'loggingIn', | |
}, | |
], | |
}, | |
}, | |
loginOauth: { | |
on: { | |
LOGIN_SUCCESS: { | |
actions: 'bookmakerLoginSuccess', | |
target: '#betslip.hist', | |
}, | |
LOGIN_FAILURE: { | |
target: '#error', | |
}, | |
}, | |
}, | |
loggingIn: { | |
invoke: { | |
src: 'bookmakerLogin', | |
onDone: { | |
actions: 'bookmakerLoginSuccess', | |
target: '#betslip.hist', | |
}, | |
onError: { | |
target: '#error', | |
}, | |
}, | |
}, | |
error: { | |
states: { | |
password: { | |
on: { | |
CHANGE_PASSWORD: { | |
actions: 'changePassword', | |
target: '#login.loginApi', | |
}, | |
}, | |
}, | |
username: { | |
on: { | |
CHANGE_USERNAME: { | |
actions: 'changeUsername', | |
target: '#login.loginApi', | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
error: { | |
id: 'error', | |
on: { | |
CLOSE_MODAL: { | |
actions: 'clearGlobalErrors', | |
target: 'hist', | |
}, | |
}, | |
}, | |
hist: { | |
type: 'history', | |
history: 'deep', | |
}, | |
}, | |
}, | |
}, | |
onDone: { | |
actions: 'hideBetslip', | |
}, | |
}, { | |
actions: { | |
addBet: assign({ | |
bookie: ({ bookie, bookieList }, event) => | |
event.bookie ? bookieList.find(b => b.code === event.bookie) : bookie, | |
selectedBets: ({ selectedBets }, { data }) => ({ | |
...selectedBets, | |
['1234']: { betId: '1234' }, | |
}), | |
userSelectedBookie: ({ userSelectedBookie }, event) => | |
event.bookie ? true : userSelectedBookie, | |
}), | |
addBets: assign({ | |
multiples: ({ multiples }, { data }) => data ? data.multiples : multiples, | |
singles: ({ singles }, { data }) => data ? data.singles : singles, | |
}), | |
betslipBuilt: assign({ | |
freeBets: ({ freeBets }, { data }) => data ? data.ocBetslip.freeBets : freeBets, | |
multiples: ({ multiples }, { data }) => data ? data.ocBetslip.multiples : multiples, | |
singles: ({ singles }, { data }) => data ? data.ocBetslip.singles : singles, | |
}), | |
bookmakerLoginSuccess: assign({ | |
bookie: ({ bookie }) => ({ | |
...bookie, | |
balance: 250, | |
loggedIn: true, | |
}), | |
}), | |
bookmakerLogout: assign({ | |
bookie: () => null, | |
}), | |
cacheReceiptNo: assign({ | |
receiptNo: (_, { receiptNo }) => receiptNo ? receiptNo : null, | |
}), | |
changePassword: assign({ | |
credentials: ({ credentials }, { target }) => ({ | |
...credentials, | |
password: target.value, | |
}), | |
}), | |
changeUsername: assign({ | |
credentials: ({ credentials }, { target }) => ({ | |
...credentials, | |
username: target.value, | |
}), | |
}), | |
clearGlobalError: assign({ | |
errors: ({ errors }) => ({ | |
...errors, | |
global: errors.global.slice(1, errors.global.length), | |
}), | |
}), | |
clearMultipleError: assign({ | |
errors: ({ errors }, { currentTarget }) => ({ | |
...errors, | |
multiple: errors.single.filter(error => error.id === currentTarget.dataset.betType), | |
}), | |
}), | |
clearSingleErrors: assign({ | |
errors: ({ errors }, { currentTarget }) => ({ | |
...errors, | |
single: errors.single.filter(error => error.id === currentTarget.dataset.betId), | |
}), | |
}), | |
hideBetslip: assign({ | |
betslipVisible: false, | |
}), | |
removeBet: assign({ | |
selectedBets: ({ selectedBets }, { betId }) => ({ ...selectedBets, [betId]: undefined }), | |
singles: ({ singles }, { betId }) => singles.filter((single) => single.betId !== betId), | |
}), | |
selectBookie: assign({ | |
bookie: (ctx, { bookie }) => { | |
// return bookie ? bookie : ctx.bookie; | |
return { | |
bookieCode: 'B3', | |
loggedIn: false, | |
}; | |
}, | |
userSelectedBookie: (_, { bookie }) => !!bookie, | |
}), | |
setStake: assign({ | |
singles: ({ singles }, { betId, value }) => singles.map(single => { | |
if (single.betId !== betId) return single; | |
return Object.assign({}, single, { | |
stake: 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: { | |
bookieLoggedIn: ({ bookie }) => bookie && bookie.loggedIn, | |
bookieLoggedOut: ({ bookie }) => !bookie || (bookie && !bookie.loggedIn), | |
bookieNotOauth: ({ bookie }) => bookie && bookie.loginType !== 'oauth', | |
hasFetchedBookies: ({ bookieList }) => bookieList.length > 0, | |
hasInsufficientFunds: ({ bookie, singles, totalStake }) => { | |
if (!bookie) return false; | |
const hasFunds = | |
Number(bookie.balance) >= Number(totalStake) || | |
singles[0].freeBet; | |
return !hasFunds; | |
}, | |
hasMultipleError: ({ errors }) => errors.multiple.length > 0, | |
hasNoBets: ({ selectedBets }) => Object.keys(selectedBets).length === 0, | |
hasSingleError: ({ errors }) => errors.single.length > 0, | |
noBookieSelected: ({ bookie, userSelectedBookie }) => !bookie && !userSelectedBookie, | |
noPassword: ({ credentials }) => !credentials.password, | |
noUsername: ({ credentials }) => !credentials.username, | |
}, | |
services: { | |
buildBetslip: () => new Promise(resolve => { | |
setTimeout(() => { | |
resolve(); | |
}, 1500); | |
}), | |
fetchBookmakerData: () => new Promise(resolve => { | |
setTimeout(() => { | |
resolve({ | |
bookieList: [ | |
{ bookieCode: 'B3' } | |
], | |
}); | |
}, 1500); | |
}), | |
fetchSingleBetData: () => new Promise(resolve => { | |
setTimeout(() => { | |
resolve({ | |
multiples: [], | |
singles: [ | |
{ betId: '2345', eachWay: false }, | |
{ betId: '3456', 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