Skip to content

Instantly share code, notes, and snippets.

@the-main-thing
Last active April 3, 2020 08:02
Show Gist options
  • Save the-main-thing/7f318c1752ebd65e34ae1fa3ddce4b20 to your computer and use it in GitHub Desktop.
Save the-main-thing/7f318c1752ebd65e34ae1fa3ddce4b20 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// 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