Skip to content

Instantly share code, notes, and snippets.

@beaucollins
Created January 15, 2019 19:58
Show Gist options
  • Select an option

  • Save beaucollins/bf12010d72252bee6573f66e1ff259d4 to your computer and use it in GitHub Desktop.

Select an option

Save beaucollins/bf12010d72252bee6573f66e1ff259d4 to your computer and use it in GitHub Desktop.
/**
* @flow
* @format
*/
/**
* External dependencies
*/
import { reduce, isEmpty } from 'lodash';
/**
* Internal dependencies
*/
import {
hasMyScheduleModifications,
getMyScheduleModifications,
} from 'state/ui/selectors';
import {
setMyScheduleModifications,
} from 'state/ui/actions';
import {
saveDaySettings,
} from 'state/entities/day-settings/actions';
import {
updateAvailabilityBlocks,
} from 'state/entities/availability-blocks/actions';
/**
* Flow
*/
import type { AppMiddleware, ActionTypes } from 'state';
import type { DaySettings } from 'state/entities/day-settings/reducer';
import type { ScheduleModifications } from 'state/ui/reducers';
/**
* The Schedule Modifications (dirty blocks cache) can have deletion entries for
* blocks that only existed temporarily client-side. These entries end up generating
* events on save that are invalid as the blocks were never persisted before the delete.
*
* This function prevents save output from leaking ephemeral delete data to the
* backend interactions by checking the modifications against previously persisted
* block entities (props.existingAvailabilityBlocksInTimespan) before making the save attempt.
*/
const removeTemporaryBlocksFromSaveOutput = (
modifications: ScheduleModifications,
): ScheduleModifications => {
return {
...modifications,
deleted: modifications.deleted.filter(
// TODO, filter out task blocks
block => block,
),
};
};
/**
* Performs all of the required tasks to save a schedule's set of data
* that currently includes 0-7 day settings and all of the block modifications
*/
const middleware: AppMiddleware = store => next => (action: ActionTypes) => {
switch (action.type) {
case 'UI_MY_SCHEDULE_SAVE': {
// are we going to save the schedule?
return new Promise(resolve => {
const state = store.getState();
const hasModifications = hasMyScheduleModifications(state);
if (!hasModifications) {
resolve();
}
const modifications = getMyScheduleModifications(state);
/**
* Save all daySettings that need to be saved
*/
const pending: Array<Promise<*>> = reduce(
modifications.daySettings,
(tasks, daySettings: DaySettings) => {
// Don't save default day settings.
if (!daySettings.daySettingsId) {
return tasks;
}
return [...tasks, Promise.resolve(store.dispatch(saveDaySettings(daySettings)))];
},
[]
);
/**
* If there are modifications also save them
*/
if (!isEmpty(modifications.updated) || !isEmpty(modifications.deleted)) {
// TODO: de we dispatch or de we use the event store api ourselves somehow?
// this.props.updateAvailabilityBlocks(this.removeTemporaryBlocksFromSaveOutput(modifications));
pending.push(Promise.resolve(store.dispatch(updateAvailabilityBlocks(removeTemporaryBlocksFromSaveOutput(modifications)))));
}
/**
* Wait for all tasks to resolve
*/
Promise.all(pending).then(
() => console.log('hooray'),
error => console.log('oops')
);
/**
* Clear out the modifications
*/
// @todo: switch to this.resetMyScheduleModifications,
// but we have to re-work the way day settings save first
store.dispatch(setMyScheduleModifications({
...modifications,
updated: [],
deleted: [],
}));
});
}
}
return next(action);
};
export default middleware;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment