Skip to content

Instantly share code, notes, and snippets.

@amogower
Last active February 13, 2020 09:40
Show Gist options
  • Select an option

  • Save amogower/063bbf3c30dc84358e8ce8df6e90e3ef to your computer and use it in GitHub Desktop.

Select an option

Save amogower/063bbf3c30dc84358e8ce8df6e90e3ef to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
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: 'polling',
states: {
polling: {
invoke: {
src: 'buildBetslip',
onError: 'failure',
onDone: 'success',
},
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: '',
username: '',
},
errors: {
global: [],
multiple: [],
single: [],
total: 0,
},
freeBets: [],
multiples: [],
market: {},
receiptNo: '',
selectedBets: {},
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: 'fetchingBookmakerData',
},
]
},
},
empty: {
on: {
ADD_BET: {
actions: 'addBet',
target: 'initializing',
},
},
},
fetchingBookmakerData: {
invoke: {
src: 'fetchBookmakerData',
onDone: {
target: 'fetchingBetData',
},
onError: {
target: 'error.global',
},
}
},
fetchingBetData: {
invoke: {
src: 'fetchSingleBetData',
onDone: {
actions: 'addBets',
target: 'initialized',
},
onError: {
target: 'error.global',
},
},
},
initialized: {
on: {
'': [
{
cond: 'noBookieSelected',
target: 'bookieList',
},
{
target: 'betslip',
},
],
},
},
bookieList: {
on: {
CLOSE_BOOKIE_LIST: {
target: 'initialized',
},
SELECT_BOOKIE: {
actions: 'selectBookie',
target: 'initialized',
},
},
},
betslip: {
id: 'betslip',
initial: 'betting',
states: {
betting: {
initial: 'loggedOut',
states: {
loggedOut: {
on: {
'': [
{
cond: 'bookieLoggedIn',
target: 'loggedIn'
},
],
LOG_IN: {
target: '#login',
},
},
},
loggedIn: {
on: {
'': [
{
cond: 'bookieLoggedOut',
target: 'loggedOut'
},
],
LOG_OUT: {
actions: 'bookmakerLogout',
target: 'loggedOut',
},
},
},
},
on: {
ADD_BET: {
actions: 'addBet',
target: '#visible.fetchingBetData',
},
OPEN_BOOKIE_LIST: {
target: '#visible.bookieList',
},
PLACE_BETSLIP: [
{
cond: 'bookieLoggedOut',
target: '#login',
},
{
cond: 'hasInsufficientFunds',
target: '#visible.error.global',
},
{
target: 'placingBetslip',
},
],
REMOVE_BET: {
actions: 'removeBet',
},
},
},
placingBetslip: {
invoke: {
src: 'placeBetslip',
onDone: {
actions: 'cacheReceiptNo',
target: 'receipt',
},
onError: [
{
target: 'error.global',
},
],
},
},
receipt: {
on: {
DONE: {
target: 'done',
},
REUSE_SELECTIONS: {
target: '#betslip.betting.loggedIn',
},
},
},
done: {
type: 'final',
},
error: {
initial: 'single',
states: {
global: {
on: {
CLOSE_MODAL: {
actions: 'clearGlobalErrors',
target: '#betslip.betting.loggedIn',
},
},
},
},
},
},
},
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: {
target: '#betslip.polling',
},
},
},
loggingIn: {
invoke: {
src: 'bookmakerLogin',
onDone: {
actions: 'bookmakerLoginSuccess',
target: '#betslip.polling',
},
onError: {
target: 'error.global',
},
},
},
error: {
states: {
global: {
on: {
CLOSE_MODAL: {
actions: 'clearGlobalErrors',
target: '#login',
},
},
},
password: {
on: {
CHANGE_PASSWORD: {
actions: 'changePassword',
target: '#login.loginApi',
},
},
},
username: {
on: {
CHANGE_USERNAME: {
actions: 'changeUsername',
target: '#login.loginApi',
},
},
},
},
},
},
},
error: {
initial: 'global',
states: {
global: {
on: {
CLOSE_MODAL: {
actions: 'clearGlobalErrors',
target: '#visible',
},
},
},
},
},
},
},
},
onDone: {
actions: 'hideBetslip',
},
}, {
actions: {
addBet: assign({
selectedBets: (ctx, evt) => ({
...ctx.selectedBets,
['1234']: { betId: '1234' },
}),
}),
addBets: assign({
multiples: (ctx, evt) => evt.data.multiples,
singles: (ctx, evt) => evt.data.singles,
}),
bookmakerLoginSuccess: assign({
bookie: (ctx) => ({
...ctx.bookie,
loggedIn: true,
}),
}),
cacheReceiptNo: assign({
receiptNo: (ctx, evt) => evt.receiptNo,
}),
changePassword: assign({
credentials: (ctx, evt) => ({
...ctx.credentials,
password: evt.target.value,
}),
}),
changeUsername: assign({
credentials: (ctx, evt) => ({
...ctx.credentials,
username: evt.target.value,
}),
}),
clearGlobalError: assign({
errors: (ctx) => ({
...ctx.errors,
global: ctx.errors.global.slice(1, ctx.errors.global.length),
}),
}),
clearMultipleError: assign({
errors: (ctx, evt) => ({
...ctx.errors,
multiple: ctx.errors.single.filter(error => error.id === evt.currentTarget.dataset.betType),
}),
}),
clearSingleErrors: assign({
errors: (ctx, evt) => ({
...ctx.errors,
single: ctx.errors.single.filter(error => error.id === evt.currentTarget.dataset.betId),
}),
}),
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) => {
// return evt.bookie;
return {
bookieCode: 'B3',
loggedIn: false,
};
},
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: {
bookieLoggedIn: (ctx) => ctx.bookie && ctx.bookie.loggedIn,
bookieLoggedOut: (ctx) => !ctx.bookie || (ctx.bookie && !ctx.bookie.loggedIn),
bookieNotOauth: (ctx) => ctx.bookie && ctx.bookie.loginType !== 'oauth',
hasInsufficientFunds: (ctx) => {
if (!ctx.bookie) return false;
const hasFunds =
Number(ctx.bookie.balance) >= Number(ctx.totalStake) ||
ctx.singles[0].freeBet;
return !hasFunds;
},
hasMultipleError: (ctx) => ctx.errors.multiple.length > 0,
hasNoBets: (ctx) => Object.keys(ctx.selectedBets).length === 0,
hasSingleError: (ctx) => ctx.errors.single.length > 0,
noBookieSelected: (ctx) => !ctx.bookie && !ctx.userSelectedBookie,
noPassword: (ctx) => !ctx.credentials.password,
noUsername: (ctx) => !ctx.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