Last active
August 25, 2021 20:34
-
-
Save barucAlmaguer/d4e43cbb57498dfc9f66d995c2da0c3d 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 timelineUiMachine = { | |
initial: 'loading_timeline', | |
states: { | |
loading_timeline: { | |
onEntry: ['clearExcelData', 'fetchTimelineData'], | |
on: { | |
SUCCESS: [ | |
{ | |
target: 'viewing_empty_timeline', | |
cond: 'isDataOutOfRange', | |
actions: ['setDbTimelineData', 'setHistoricProgram', 'setPreviousProgramDate', 'setRooms', 'setResourceCatalog'] | |
}, { | |
target: 'viewing_timeline', | |
cond: 'isDataValid', | |
actions: ['setDbTimelineData', 'setHistoricProgram', 'setOptions', 'setExcelData', 'setRooms', 'setResourceCatalog'] | |
}, { | |
target: 'error_loading_timeline' | |
} | |
], | |
FAILURE: { | |
target: 'error_loading_timeline' | |
// actions: ['setError', 'showError'] | |
} | |
} | |
}, | |
error_loading_timeline: { | |
on: { | |
RETRY: 'loading_timeline', | |
DATE_CHANGE: { | |
target: 'loading_timeline', | |
actions: ['setHistoric'] | |
} | |
} | |
}, | |
viewing_timeline: { | |
onEntry: ['calcLocalTimelineData'], | |
on: { | |
DATE_CHANGE: { | |
target: 'loading_timeline', | |
actions: ['setHistoric'] | |
}, | |
PLAN_FINISHED: { | |
target: 'loading_timeline', | |
actions: ['showAlertRefetchPlan'] | |
} | |
} | |
}, | |
viewing_empty_timeline: { | |
on: { | |
DATE_CHANGE: { | |
target: 'loading_timeline', | |
actions: ['setHistoric'] | |
} | |
} | |
} | |
} | |
} | |
const timelineActionsMachine = { | |
initial: 'inactive', | |
states: { | |
inactive: { | |
onEntry: ['clearSelectedItem', 'calcLocalTimelineData'], | |
on: { | |
SHOW_ACTIONS: { target: 'active', actions: ['setSelectedItem'] } | |
} | |
}, | |
active: { | |
onEntry: ['calcLocalTimelineData'], | |
on: { | |
LENGTH_ACTION: { target: 'active', actions: ['lengthAction'] }, | |
BACK_ACTION: { target: 'active', actions: ['backAction'] }, | |
FORWARD_ACTION: { target: 'active', actions: ['fwdAction'] }, | |
UP_ACTION: { target: 'active', actions: ['upAction', 'updateSelectedItemInterval'] }, | |
DOWN_ACTION: { target: 'active', actions: ['downAction', 'updateSelectedItemInterval'] }, | |
APPLY_ACTION: { target: 'submitting', actions: ['submitSelectedItem'] }, | |
CANCEL_ACTION: { target: 'inactive' } | |
} | |
}, | |
submitting: { | |
on: { | |
SUCCESS: { target: 'inactive', actions: ['updateDbTimelineData', 'updateDbItemPlans', 'clearSelectedItem', 'calcLocalTimelineData'] }, | |
FAILURE: { target: 'inactive', actions: ['showError'] } | |
} | |
}, | |
error: {} | |
} | |
} | |
const timelineMachine = Machine({ | |
id: 'timeline', | |
type: 'parallel', | |
context: { | |
dbTimelineData: [], // timeline synced with database | |
timelineData: [], // local timelineData (may be merged / edited in various ways) | |
options: {}, | |
selectedItem: null, | |
originalSelectedItem: null, // allows simple recalculations of operations made to the selected item | |
resourceCatalog: [], | |
selectedResource: null, | |
originalSelectedResource: null, | |
historicDate: new Date(), | |
historicProgram: null, | |
previousProgramDate: null, | |
excelData: [], | |
rooms: [] | |
}, | |
states: { | |
ui: { ...timelineUiMachine }, | |
timelineActions: { ...timelineActionsMachine } | |
} | |
}, { | |
guards: { | |
isDataValid: (ctx, evt) => true, | |
isDataOutOfRange: (ctx, evt) => true | |
}, | |
actions: { | |
setHistoricProgram: assign({ | |
historicProgram: (ctx, evt) => evt.historicProgram | |
}), | |
setPreviousProgramDate: assign({ | |
previousProgramDate: (ctx, evt) => { | |
const initialDate = new Date(evt.timelineData) | |
// strip useless time info (keep only date from moment object) | |
return new Date(initialDate.year(), initialDate.month(), initialDate.date()) | |
} | |
}), | |
setHistoric: assign({ historicDate: (ctx, evt) => (evt.date) }), | |
setDbTimelineData: assign({ dbTimelineData: (ctx, evt) => (evt.timelineData) }), | |
setSelectedItem: assign({ | |
originalSelectedItem: (ctx, evt) => ( | |
(!ctx.selectedItem || ctx.selectedItem.order !== evt.item.order) | |
? { ...evt.item } | |
: null | |
), | |
selectedItem: (ctx, evt) => ( | |
(!ctx.selectedItem || ctx.selectedItem.order !== evt.item.order) | |
? { ...evt.item } | |
: null | |
), | |
selectedResource: (ctx, evt) => ( | |
(!ctx.selectedItem || ctx.selectedItem.order !== evt.item.order) | |
? evt.resource | |
: null | |
), | |
originalSelectedResource: (ctx, evt) => ( | |
(!ctx.selectedItem || ctx.selectedItem.order !== evt.item.order) | |
? evt.resource | |
: null | |
) | |
}), | |
clearSelectedItem: assign({ | |
originalSelectedItem: (ctx, evt) => (null), | |
selectedItem: (ctx, evt) => (null), | |
selectedResource: (ctx, evt) => (null), | |
originalSelectedResource: (ctx, evt) => (null) | |
}), | |
setOptions: assign({ | |
options: (ctx, evt) => { | |
let newOptions = { ...ctx.options, ...evt.options } | |
return newOptions | |
} | |
}), | |
setResourceCatalog: assign({ | |
resourceCatalog: (ctx, evt) => evt.resourceCatalog | |
}), | |
// ! Timeline item actions | |
lengthAction: assign({ | |
selectedItem: (ctx, evt) => { | |
const currentExtension = new Date(ctx.selectedItem.endAt) | |
const newExtension = evt.value | |
const diff = currentExtension - newExtension | |
return ({ | |
...ctx.selectedItem, | |
endAt: new Date(ctx.selectedItem.endAt).toISOString() | |
}) | |
} | |
}), | |
backAction: assign({ | |
selectedItem: (ctx, evt) => ({ | |
...ctx.selectedItem, | |
startAt: new Date(ctx.selectedItem.startAt).toISOString(), | |
endAt: new Date(ctx.selectedItem.endAt).toISOString() | |
}) | |
}), | |
fwdAction: assign({ | |
selectedItem: (ctx, evt) => ({ | |
...ctx.selectedItem, | |
startAt: new Date(ctx.selectedItem.startAt).toISOString(), | |
endAt: new Date(ctx.selectedItem.endAt).toISOString() | |
}) | |
}), | |
upAction: assign({ | |
selectedResource: (ctx, evt) => { | |
// Find SelectedResource index, and move it upward if possible: | |
const resourceIndex = ctx.dbTimelineData.findIndex((res) => res.name === ctx.selectedResource.name) | |
const newResource = resourceIndex > 0 ? ctx.dbTimelineData[resourceIndex - 1] : ctx.selectedResource | |
return newResource | |
} | |
}), | |
downAction: assign({ | |
selectedResource: (ctx, evt) => { | |
// Find SelectedResource index, and move it upward if possible: | |
const resourceIndex = ctx.dbTimelineData.findIndex((res) => res.name === ctx.selectedResource.name) | |
const lastIndex = ctx.dbTimelineData.length - 1 | |
const newResource = resourceIndex < lastIndex ? ctx.dbTimelineData[resourceIndex + 1] : ctx.selectedResource | |
return newResource | |
} | |
}), | |
updateSelectedItemInterval: assign({ | |
selectedItem: (ctx, evt) => ctx.selectedItem // ! Default, no scaling applied (scaling must be defined in component) | |
}), | |
calcLocalTimelineData: assign({ | |
timelineData: (ctx, evt) => { | |
// No item selected, means nothing to map | |
if (!ctx.selectedItem) return ctx.dbTimelineData | |
const path = `${ctx.selectedItem.__type}s` // 'programs' | 'stops' | |
let localTimelineData = { ...ctx.dbTimelineData }; | |
// * 1. remove selected item from original resouce | |
let srcResourceData = localTimelineData.find((res) => res.name === ctx.originalSelectedResource.name) | |
srcResourceData[path].filter((item) => ( | |
ctx.selectedItem.__type === 'stop' | |
? item.id === ctx.selectedItem.id | |
: item.order === ctx.selectedItem.order | |
)) | |
// * 2. re-insert into new location | |
let dstResourceData = localTimelineData.find((res) => res.name === ctx.selectedResource.name) | |
dstResourceData[path].push(ctx.selectedItem) | |
return localTimelineData | |
} | |
}), | |
updateDbTimelineData: assign({ | |
dbTimelineData: (ctx, evt) => cloneDeep(ctx.timelineData) | |
}), | |
updateDbItemPlans: assign({ | |
dbTimelineData: (ctx, evt) => ctx.dbTimelineData.map(res => ( | |
// find updated resource and program, and replace its plans with the updated ones | |
res.name !== ctx.selectedResource.name | |
? res | |
: { | |
...res, | |
programs: res.programs.map(prog => ( | |
prog.order !== ctx.selectedItem.order | |
? prog | |
: { | |
...prog, | |
plans: [...evt.updatedPlans] | |
} | |
)) | |
} | |
)) | |
}), | |
setExcelData: assign({ | |
excelData: (ctx, evt) => evt.excelData | |
}), | |
clearExcelData: assign({ | |
excelData: (ctx, evt) => ([]) | |
}), | |
setRooms: assign({ | |
rooms: (ctx, evt) => evt.rooms | |
}), | |
showError: (ctx, evt) => { | |
let err = evt.error | |
if (Array.isArray(evt.error) && evt.error.length > 0) { | |
err = evt.error[0] | |
} else { | |
err = evt.error | |
} | |
console.log(err) | |
}, | |
showAlertRefetchPlan: (ctx, evt) => { | |
console.log('Obteniendo última planeación...') | |
} | |
} | |
}) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment