Last active
December 15, 2020 13:42
-
-
Save AndresRodH/0de38302fe9f566c690e45b441490fef to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains 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
// Available variables: | |
// - Machine | |
// - interpret | |
// - assign | |
// - send | |
// - sendParent | |
// - spawn | |
// - raise | |
// - actions | |
// - XState (all XState exports) | |
const TaskStatus = { | |
OPEN: 0, | |
IN_PROGRESS: 1, | |
CLOSED: 2 | |
} | |
const TransitionableState = { | |
TO_DO: 'TO_DO', | |
IN_PROGRESS: 'IN_PROGRESS', | |
COMPLETED: 'COMPLETED', | |
} | |
const testEntity = { | |
// current status of the entity | |
state: TransitionableState.TO_DO, | |
// the real date "this" stated | |
actualStartDate: null, | |
// the real date "this" was closed | |
actualStopDate: null, | |
// in minutes | |
duration: 10, | |
// date that this task/session could be done | |
estimatedDueDate: null, | |
// the actual time in minutes that took to complete this session/task | |
totalTimeToComplete: null, | |
} | |
const testOnTransition = (newState) => console.log(newState) | |
const isOpen = (status) => status === 'open' || status === TaskStatus.OPEN | |
const isInProgress = (status) => status === 'in_progress' || status === TaskStatus.IN_PROGRESS | |
/** | |
* @see https://xstate.js.org/viz/?gist=0de38302fe9f566c690e45b441490fef | |
* Tracks the status of a transitionable entity. This machine: | |
* | |
* 1. Manages the respective timestamps per transition | |
* 2. Calculates estimated due date if there's a duration available | |
* 3. Keeps track of how much time (in minutes) took to transition from open -> inProgress -> closed | |
*/ | |
const transitionableEntityMachine = ({ | |
entity, | |
onTransition, | |
}) => { | |
const { | |
actualStartDate, | |
actualStopDate, | |
estimatedDueDate, | |
duration, | |
totalTimeToComplete, | |
state: currentState, | |
} = entity; | |
return Machine( | |
{ | |
id: 'transitionableEntity', | |
initial: currentState, | |
context: { | |
actualStopDate, | |
actualStartDate, | |
duration, | |
estimatedDueDate, | |
totalTimeToComplete, | |
}, | |
states: { | |
[TransitionableState.TO_DO]: { | |
on: { | |
SET_IN_PROGRESS: { | |
target: TransitionableState.IN_PROGRESS, | |
actions: ['setActualStartDate', 'calculateEstimatedDueDate', 'notifyTransition'], | |
}, | |
SET_COMPLETED: { | |
target: TransitionableState.COMPLETED, | |
actions: ['setActualStopDate', 'notifyTransition'], | |
}, | |
UPDATE_DURATION: { | |
actions: ['setDuration'], | |
}, | |
}, | |
}, | |
[TransitionableState.IN_PROGRESS]: { | |
on: { | |
SET_TO_DO: { | |
target: TransitionableState.TO_DO, | |
actions: ['clearActualStartDate', 'clearEstimatedDueDate', 'notifyTransition'], | |
}, | |
SET_COMPLETED: { | |
target: TransitionableState.COMPLETED, | |
actions: ['setActualStopDate', 'calculateTotalTime', 'notifyTransition'], | |
}, | |
UPDATE_DURATION: { | |
actions: ['setDuration', 'calculateEstimatedDueDate'], | |
}, | |
}, | |
}, | |
[TransitionableState.COMPLETED]: { | |
on: { | |
SET_TO_DO: { | |
target: TransitionableState.TO_DO, | |
actions: [ | |
'clearActualStopDate', | |
'clearActualStartDate', | |
'clearTotalTimeToComplete', | |
'clearEstimatedDueDate', | |
'notifyTransition', | |
], | |
}, | |
SET_IN_PROGRESS: { | |
target: TransitionableState.IN_PROGRESS, | |
actions: [ | |
'setActualStartDate', | |
'clearActualStopDate', | |
'calculateEstimatedDueDate', | |
'clearTotalTimeToComplete', | |
'notifyTransition', | |
], | |
}, | |
}, | |
}, | |
}, | |
}, | |
{ | |
actions: { | |
notifyTransition: (_ctx, event) => | |
onTransition( | |
event.type === 'SET_TO_DO' | |
? TransitionableState.TO_DO | |
: event.type === 'SET_IN_PROGRESS' | |
? TransitionableState.IN_PROGRESS | |
: TransitionableState.COMPLETED | |
), | |
setActualStartDate: assign({ actualStartDate: () => new Date() }), | |
setActualStopDate: assign({ actualStopDate: () => new Date() }), | |
calculateEstimatedDueDate: assign({ | |
estimatedDueDate: (ctx) => | |
ctx.duration && ctx.actualStartDate | |
? new Date(ctx.actualStartDate.getTime() + ctx.duration * 60000) | |
: null, | |
}), | |
clearActualStartDate: assign({ actualStartDate: () => null }), | |
clearActualStopDate: assign({ actualStopDate: () => null }), | |
clearTotalTimeToComplete: assign({ totalTimeToComplete: () => null }), | |
clearEstimatedDueDate: assign({ estimatedDueDate: () => null }), | |
calculateTotalTime: assign({ | |
totalTimeToComplete: (ctx) => | |
// can only be calculated if there's both start and stop dates | |
// and sessions and tasks can be transitioned from open to closed directly | |
ctx.actualStartDate && ctx.actualStopDate | |
? Math.round((ctx.actualStopDate.getTime() - ctx.actualStartDate.getTime()) / 60000) | |
: null, | |
}), | |
setDuration: assign({ | |
duration: (ctx, event) => { | |
let duration = ctx.duration; | |
if (event.type === 'UPDATE_DURATION') duration = event.duration; | |
return duration; | |
}, | |
}), | |
}, | |
} | |
); | |
}; | |
transitionableEntityMachine({ | |
entity: testEntity, | |
onTransition: (state) => {console.log(state)} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment