function buildVibrationPattern(seconds) { return new Array(seconds / 1500) .fill(null) .reduce(prev => [...prev, 0, 1000, 500], []) } const DEFAULT_WAIT_TIME = 30000 const CURRENT_ORDER_STATE = `WAITING_COURIER` const ORDER_STATE = { IN_PROGRESS: `IN_PROGRESS`, WAITING_COURIER: `WAITING_COURIER` } const CURRENT_ORDER_TYPE = `DELIVERY` const ORDER_TYPE = { DELIVERY: `DELIVERY`, HIRED: `HIRED` } Machine( { id: `courier-state-and-jobs`, initial: `initializing`, context: { fetchKey: 1, online: false, offer: { id: null, receivedAt: null } }, states: { initializing: { on: { '': [ { cond: `isOffline`, target: `offline` }, { cond: `isOnline`, target: `online` } ] } }, offline: { entry: `setOffline`, on: { GO_ONLINE: `goOnline` } }, goOnline: { invoke: { id: `goOnline`, src: `goOnline`, onDone: `online`, onError: `offline` } }, goOffline: { invoke: { id: `goOffline`, src: `goOffline`, onDone: `offline`, onError: `offline` } }, online: { entry: `setOnline`, initial: `waiting`, on: { GO_OFFLINE: `goOffline` }, states: { waiting: { on: { ORDER_RECEIVED: { actions: `setOffer`, target: `fetchingOrder` } } }, fetchingOrder: { invoke: { id: `fetchOrder`, src: `fetchOrder`, onDone: [ { cond: `isAssigned`, actions: `incrementFetchKey`, target: `waiting` }, { cond: `doesNotHaveEnoughTimeToAcceptOrder`, target: `waiting` }, { cond: `isDeliveryOrder`, target: `offer` }, { cond: `isHiredOrder`, actions: `incrementFetchKey`, target: `waiting` } ], onError: `waiting` } }, offer: { onDone: `waiting`, initial: `waiting`, states: { waiting: { entry: `vibrate`, exit: `cancelVibration`, on: { ACCEPT_JOB: `accepting`, REJECT_JOB: `rejecting` }, after: { ORDER_DELAY: `rejecting` } }, accepting: { invoke: { id: `acceptOrder`, src: `acceptOrder`, onDone: `done`, onError: [ { target: `done` } ] } }, rejecting: { invoke: { id: `rejectOrder`, src: `rejectOrder`, onDone: `done`, onError: [ { target: `done`, actions: (ctx, event) => { console.log(`ctx: `, ctx) console.log(`event: `, event) } } ] } }, done: { entry: `resetOffer`, type: `final` } } } } } } }, { actions: { setOffline: assign({ online: () => false, }), setOnline: assign({ online: () => true, }), setOfferId: assign({ offer: () => ({ acceptedAt: new Date(), id: 1, receivedAt: new Date(), }), }), resetOffer: assign({ offer: () => ({ acceptedAt: null, id: null, receivedAt: null, }), }), incrementFetchKey: assign({ fetchKey: (ctx) => ctx.fetchKey + 1, }), vibrate: () => { console.log(`vibrate`) }, cancelVibration: () => { console.log(`cancelVibration`) }, }, delays: { ORDER_DELAY: ctx => { if (!ctx.time) { return DEFAULT_WAIT_TIME } return Math.floor(ctx.time + DEFAULT_WAIT_TIME - Date.now()) }, }, guards: { isOffline: ctx => !ctx.online, isOnline: ctx => ctx.online, isAssigned: (ctx, event) => ORDER_STATE.IN_PROGRESS === CURRENT_ORDER_STATE, isDeliveryOrder: (ctx, event) => ORDER_TYPE.DELIVERY === CURRENT_ORDER_TYPE, isHiredOrder: (ctx, event) => ORDER_TYPE.HIRED === CURRENT_ORDER_TYPE, doesNotHaveEnoughTimeToAcceptOrder: ({offer: {receivedAt}}) => { return false } } } )