Last active
April 3, 2020 08:02
-
-
Save the-main-thing/7f318c1752ebd65e34ae1fa3ddce4b20 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
// export const STATES = { | |
// idle: 'idle', | |
// ['idle.idle']: 'idle.idle', | |
// ['idle.creating']: 'idle.creating', | |
// savingNew: 'savingNew', | |
// savingChange: 'savingChange', | |
// confirmDelete: 'confirmDelete', | |
// ['confirmDelete.idle']: 'confirmDelete.idle', | |
// ['confirmDelete.creating']: 'confirmDelete.creating', | |
// deleting: 'deleting', | |
// ['deleting.idle']: 'deleting.idle', | |
// ['deleting.creating']: 'deleting.creating', | |
// confirmCancelCreation: 'confirmCancelCreation' | |
// }; | |
/** | |
* TODO: update state chart visualization | |
* https://xstate.js.org/viz/?gist=7f318c1752ebd65e34ae1fa3ddce4b20 | |
*/ | |
const workPeriodsSectionMachine = Machine({ | |
id: 'workPeriodsSection', | |
initial: 'idle', | |
context: { | |
workPeriods: {}, | |
currentKey: null, | |
errorMessage: null, | |
invalidInputs: null | |
}, | |
on: { | |
SET_BACKUP: { | |
actions: ['setBackup'] | |
} | |
}, | |
states: { | |
idle: { | |
initial: 'idle', | |
on: { | |
CHANGE: { | |
actions: ['updateWorkPeriodItemValues', 'removeError'] | |
}, | |
NEW_DATA: { | |
target: 'idle', | |
actions: ['updateWorkPeriods', 'removeError'] | |
}, | |
SAVE_CHANGE: { | |
target: '#workPeriodsSection.savingChange', | |
actions: ['setCurrentKey', 'removeError'] | |
}, | |
DELETE: [ | |
{ | |
cond: 'deletingExistingRecord', | |
in: '#workPeriodsSection.idle.idle', | |
target: '#workPeriodsSection.confirmDelete.idle', | |
actions: ['setCurrentKey', 'removeError'] | |
}, | |
{ | |
cond: 'deletingExistingRecord', | |
in: '#workPeriodsSection.idle.creating', | |
target: '#workPeriodsSection.confirmDelete.creating', | |
actions: ['setCurrentKey', 'removeError'] | |
} | |
] | |
}, | |
states: { | |
idle: { | |
on: { | |
CREATE: { | |
target: 'creating', | |
actions: ['addInitialValues', 'removeError'] | |
} | |
} | |
}, | |
creating: { | |
on: { | |
CANCEL: { | |
target: '#workPeriodsSection.confirmCancelCreation' | |
}, | |
SAVE_NEW: { | |
target: '#workPeriodsSection.savingNew', | |
actions: ['setCurrentKey', 'removeError'] | |
} | |
} | |
} | |
} | |
}, | |
savingNew: { | |
invoke: { | |
src: 'saveNew', | |
onDone: { | |
target: 'idle' | |
}, | |
onError: { | |
target: 'idle.creating', | |
actions: ['setError'] | |
} | |
} | |
}, | |
savingChange: { | |
invoke: { | |
src: 'saveNew', | |
onDone: { | |
target: 'idle' | |
}, | |
onError: { | |
target: 'idle.idle', | |
actions: ['setError'] | |
} | |
} | |
}, | |
confirmDelete: { | |
states: { | |
idle: { | |
on: { | |
CONFIRM: { | |
target: 'deleting.idle' | |
}, | |
DENY: { | |
target: '#workPeriodsSection.idle' | |
} | |
} | |
}, | |
creating: { | |
on: { | |
CONFIRM: { | |
target: 'deleting.creating' | |
}, | |
DENY: { | |
target: '#workPeriodsSection.idle.creating' | |
} | |
} | |
}, | |
deleting: { | |
states: { | |
idle: { | |
invoke: { | |
src: 'delete', | |
onDone: { | |
target: '#workPeriodsSection.idle' | |
}, | |
onError: { | |
target: '#workPeriodsSection.idle', | |
actions: ['setError'] | |
} | |
} | |
}, | |
creating: { | |
invoke: { | |
src: 'delete', | |
onDone: { | |
target: '#workPeriodsSection.idle.creating' | |
}, | |
onError: { | |
target: '#workPeriodsSection.idle.creating', | |
actions: ['setError'] | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
confirmCancelCreation: { | |
on: { | |
CONFIRM: { | |
target: 'idle', | |
actions: ['removeInitialValues', 'removeError'] | |
}, | |
DENY: { | |
target: 'idle.creating' | |
} | |
} | |
} | |
} | |
}, { | |
guards: { | |
deletingExistingRecord: (_, event) => event.key !== 'dummy' | |
}, | |
actions: { | |
updateWorkPeriods: assign({ | |
workPeriods: (context, event) => { | |
if (event.type !== 'NEW_DATA') { | |
throw new Error('updateWorkPeriods must be used only withing NEW_DATA event.'); | |
} | |
const changedFields = new Set(); | |
const workPeriods = {}; | |
if (context.workPeriods.dummy) { | |
workPeriods.dummy = { ...context.workPeriods.dummy, changedFields }; | |
} | |
for (const workPeriod of event.workPeriods) { | |
const { key } = workPeriod; | |
workPeriods[key] = { ...workPeriod, changedFields }; | |
} | |
return workPeriods; | |
} | |
}), | |
updateWorkPeriodItemValues: assign((context, event) => { | |
if (event.type !== 'CHANGE') { | |
throw new Error('updateWorkPeriodItemValues must be called with a CHANGE event'); | |
} | |
const { workPeriods } = context; | |
const { type: _, key, ...newWorkPeriod } = event; | |
const { changedFields: currentlyChangedFields, ...currentWorkPeriod } = workPeriods[key]; | |
const changedFields = new Set(currentlyChangedFields); | |
for (const [field, value] of Object.entries(newWorkPeriod)) { | |
const currentValue = currentWorkPeriod[field]; | |
if (value !== currentValue) { | |
changedFields.add(field); | |
} | |
else { | |
changedFields.delete(field); | |
} | |
} | |
const updatedItem = { | |
...currentWorkPeriod, | |
...newWorkPeriod, | |
changedFields | |
}; | |
return { | |
...context, | |
workPeriods: { | |
...workPeriods, | |
[key]: updatedItem | |
} | |
}; | |
}), | |
addInitialValues: assign({ | |
workPeriods: (context, event) => { | |
if (event.type !== 'CREATE') { | |
throw new Error('addInitialValues should be called with a CREATE event.'); | |
} | |
const { workPeriods } = context; | |
const { initialValues } = event; | |
return { | |
...workPeriods, | |
dummy: { | |
...initialValues, | |
changedFields: new Set() | |
} | |
}; | |
} | |
}), | |
removeInitialValues: assign({ | |
workPeriods: (context, event) => { | |
switch (event.type) { | |
case 'CONFIRM': | |
// eslint-disable-next-line no-case-declarations | |
const { workPeriods } = context; | |
// eslint-disable-next-line no-case-declarations | |
const { dummy: _, ...dataToKeep } = workPeriods; | |
return dataToKeep; | |
default: | |
throw new Error('removeInitialValues should be called with a CONFIRM event.'); | |
} | |
} | |
}), | |
setCurrentKey: assign({ | |
currentKey: (_, event) => { | |
switch (event.type) { | |
case 'SAVE_NEW': | |
return 'dummy'; | |
case 'SAVE_CHANGE': | |
case 'DELETE': | |
return event.key; | |
default: | |
throw new Error('Invalid event type for setCurrentKey action.'); | |
} | |
} | |
}), | |
setError: assign({ | |
errorMessage: (_, event) => { | |
const { data } = event; | |
const { errorMessage } = data || {}; | |
return (errorMessage || | |
'Произошла неизвестная ошибка. Сообщите, пожалуйста, разработчику.'); | |
}, | |
invalidInputs: (_, event) => { | |
const { data } = event; | |
const { invalidInputs } = data || {}; | |
return invalidInputs || null; | |
} | |
}), | |
removeError: assign({ | |
errorMessage: (_, __) => null, | |
invalidInputs: (_, __) => null | |
}), | |
setBackup: assign({ | |
backup: (_, event) => { | |
if (event.type === 'SET_BACKUP') { | |
return event.backup; | |
} | |
} | |
}) | |
} | |
// services: { | |
// saveNew: (context) => { | |
// const { currentKey } = context; | |
// if (!currentKey) { | |
// throw new ValidationError('Missing required key for saveNew service.', { | |
// errorMessage: | |
// 'Невозможно сохранить запись. Отсутствует ключ записи. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const itemToCreate = context.workPeriods[currentKey]; | |
// if (!itemToCreate) { | |
// throw new ValidationError(`Cant find item to create with key: ${currentKey}`, { | |
// errorMessage: | |
// 'Невозможно сохранить запись. Не удалось найти запись для создания. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const { backup } = context; | |
// const { key, changedFields, ...dataToSave } = itemToCreate | |
// return workPeriodsResolver.mutation.createWorkPeriod(dataToSave as WorkPeriod, backup); | |
// }, | |
// saveChange: (context) => { | |
// const { currentKey } = context; | |
// if (!currentKey) { | |
// throw new ValidationError('Missing required key for saveChange service.', { | |
// errorMessage: | |
// 'Невозможно сохранить запись. Отсутствует ключ записи. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const itemToUpdate = context.workPeriods[currentKey]; | |
// if (!itemToUpdate) { | |
// throw new ValidationError(`Cant find item to update with key: ${currentKey}`, { | |
// errorMessage: | |
// 'Невозможно сохранить запись. Не удалось найти запись для сохранения. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const { backup } = context; | |
// const { changedFields, ...dataToSave } = itemToUpdate | |
// return workPeriodsResolver.mutation.updateWorkPeriod(dataToSave, backup); | |
// }, | |
// delete: (context) => { | |
// const { currentKey } = context; | |
// if (!currentKey) { | |
// throw new ValidationError('Missing required key for delete service.', { | |
// errorMessage: | |
// 'Невозможно удалить запись. Отсутствует ключ записи. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const itemToDelete = context.workPeriods[currentKey]; | |
// if (!itemToDelete) { | |
// throw new ValidationError(`Cant find item to delete with key: ${currentKey}`, { | |
// errorMessage: | |
// 'Невозможно удалить запись. Не удалось найти запись для удаления. Пожалуйста, сообщите разработчику.' | |
// }); | |
// } | |
// const { backup } = context; | |
// return workPeriodsResolver.mutation.removeWorkPeriod(itemToDelete.key, backup); | |
// } | |
// } | |
}); | |
// const useStateMachine = (backup: string | undefined) => { | |
// const useMachineTuple = useMachine<Context, Event>(workPeriodsSectionMachine); | |
// const [, send] = useMachineTuple; | |
// useEffect(() => { | |
// send('SET_BACKUP', { backup }); | |
// }, [backup]); | |
// return useMachineTuple; | |
// }; | |
// export default useStateMachine; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment