diff --git a/client/src/app/api/eventsApi.js b/client/src/app/api/eventsApi.js index c258cc2b9..ec19409be 100644 --- a/client/src/app/api/eventsApi.js +++ b/client/src/app/api/eventsApi.js @@ -31,9 +31,14 @@ export const requestPatch = async (data) => { }; export const requestReorder = async (data) => { - const reorder = 'reorder'; - console.log('debug got reorder with payload', data); - const res = await axios.patch(eventsURL + '/' + reorder, data); + const action = 'reorder'; + const res = await axios.patch(eventsURL + '/' + action, data); + return res; +}; + +export const requestApplyDelay = async (eventId) => { + const action = 'applydelay'; + const res = await axios.patch(eventsURL + '/' + action + '/' + eventId); return res; }; diff --git a/client/src/common/components/buttons/ApplyIconBtn.jsx b/client/src/common/components/buttons/ApplyIconBtn.jsx new file mode 100644 index 000000000..67a4e2f3a --- /dev/null +++ b/client/src/common/components/buttons/ApplyIconBtn.jsx @@ -0,0 +1,16 @@ +import { IconButton } from '@chakra-ui/button'; +import { FiChevronsDown } from 'react-icons/fi'; + +export default function ApplyIconBtn(props) { + const { clickhandler, ...rest } = props; + return ( + } + colorScheme='orange' + onClick={clickhandler} + _focus={{ boxShadow: 'none' }} + {...rest} + /> + ); +} diff --git a/client/src/features/editors/list/DelayBlock.jsx b/client/src/features/editors/list/DelayBlock.jsx index 960703c6f..4ee8e1ac3 100644 --- a/client/src/features/editors/list/DelayBlock.jsx +++ b/client/src/features/editors/list/DelayBlock.jsx @@ -5,6 +5,7 @@ import TimeInput from '../../../common/input/TimeInput'; import style from './Block.module.css'; import ActionButtons from './ActionButtons'; import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn'; +import ApplyIconBtn from '../../../common/components/buttons/ApplyIconBtn'; export default function DelayBlock(props) { const { data, eventsHandler, index } = props; @@ -22,6 +23,10 @@ export default function DelayBlock(props) { eventsHandler('delete', data.id); }; + const applyDelayHandler = () => { + eventsHandler('applyDelay', { id: data.id, duration: data.duration }); + }; + let delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined; return ( @@ -37,6 +42,7 @@ export default function DelayBlock(props) {
+
diff --git a/client/src/features/editors/list/EventList.jsx b/client/src/features/editors/list/EventList.jsx index 50176d63f..d5d5e2e99 100644 --- a/client/src/features/editors/list/EventList.jsx +++ b/client/src/features/editors/list/EventList.jsx @@ -95,6 +95,9 @@ export default function EventList(props) { // drop outside of area if (!result.destination) return; + // no change + if (result.destination === result.source.index) return; + // Call API eventsHandler('reorder', { index: result.draggableId, diff --git a/client/src/features/editors/list/EventListWrapper.jsx b/client/src/features/editors/list/EventListWrapper.jsx index c75872bc1..af1f6f5ec 100644 --- a/client/src/features/editors/list/EventListWrapper.jsx +++ b/client/src/features/editors/list/EventListWrapper.jsx @@ -8,6 +8,7 @@ import { requestPut, requestDelete, requestReorder, + requestApplyDelay, } from '../../../app/api/eventsApi.js'; import EventList from './EventList'; import EventListMenu from '../../menu/EventListMenu.jsx'; @@ -156,7 +157,14 @@ export default function EventListWrapper() { }, }); - const reorderEvent = useMutation(requestReorder, { + const applyDelay = useMutation(requestApplyDelay, { + // Mutation finished, failed or successful + onSettled: () => { + queryClient.invalidateQueries(eventsNamespace); + }, + }); + + const reorderEvent = useMutation(requestReorder, { // we optimistically update here onMutate: async (data) => { // cancel ongoing queries @@ -241,6 +249,41 @@ export default function EventListWrapper() { } catch (error) { showErrorToast('Error reordering event', error.message); } + break; + case 'applyDelay': + let t = Date.now(); + + // if delay <= 0 delete delay and next block + if (payload.duration <= 0) { + try { + // look for block after + let afterId = false; + let blockAfter = null; + for (const d of data) { + if (d.id === payload.id) afterId = true; + if (afterId && d.type === 'block') { + blockAfter = d.id; + break; + } + } + + // delete delay + await deleteEvent.mutateAsync(payload.id); + // delete block after, if any + if (blockAfter) await deleteEvent.mutateAsync(blockAfter); + } catch (error) { + showErrorToast('Error applying delay', error.message); + } + } else { + console.log('debug applydelay', payload.id); + try { + await applyDelay.mutateAsync(payload.id); + } catch (error) { + showErrorToast('Error applying delay', error.message); + } + } + console.log('debug m apply', Date.now() - t); + break; default: showErrorToast('Unrecognised request', action); diff --git a/server/controllers/eventsController.js b/server/controllers/eventsController.js index ef933eac4..e9ab335c3 100644 --- a/server/controllers/eventsController.js +++ b/server/controllers/eventsController.js @@ -165,15 +165,11 @@ exports.eventsReorder = async (req, res) => { // TODO: Validate event if (!req.body) { res.status(400).send(`No object found in request`); - console.log(`No object found in request`); - return; } const { index, from, to } = req.body; - console.log(req.body); - // get events let events = db.get('events').value(); let idx = events.findIndex((e) => e.id === index, from); @@ -181,7 +177,6 @@ exports.eventsReorder = async (req, res) => { // Check if item is at given index if (idx !== from) { res.status(400).send(`Id not found at index`); - console.log(`Id not found at index`, idx, from); return; } @@ -206,6 +201,71 @@ exports.eventsReorder = async (req, res) => { } }; +// Create controller for PATCH request to '/events/applydelay/:eventId' +// Returns - +exports.eventsApplyDelay = async (req, res) => { + // no valid params + if (!req.params.eventId) { + res.status(400).send(`No id found in request`); + return; + } + + try { + // get events + let events = db.get('events').value(); + + // AUX + let delayIndex = null; + let blockIndex = null; + let delayValue = 0; + + for (const [index, e] of events.entries()) { + if (delayIndex == null) { + // look for delay + if (e.id === req.params.eventId && e.type === 'delay') { + delayValue = e.duration; + delayIndex = index; + } + } + + // apply delay value to all items until block or end + else { + if (e.type === 'event') { + // update times + e.timeStart += delayValue; + e.timeEnd += delayValue; + + // increment revision + e.revision += 1; + } else if (e.type === 'block') { + // save id and stop + blockIndex = index; + break; + } + } + } + + // delete delay + events.splice(delayIndex, 1); + + // delete block + // index would have moved down since we deleted delay + if (blockIndex) events.splice(blockIndex - 1, 1); + + // update events + db.set('events', events).write(); + + // update timer + _updateTimers(); + + res.sendStatus(201); + } catch (error) { + console.log('debug:', error); + + res.status(400).send(error); + } +}; + // Create controller for DELETE request to '/events/:eventId' // Returns - exports.eventsDelete = async (req, res) => { @@ -213,7 +273,6 @@ exports.eventsDelete = async (req, res) => { if (!req.params.eventId) { res.status(400).send(`No id found in request`); return; - console.log('debug: No id found in request'); } try { diff --git a/server/routes/eventsRouter.js b/server/routes/eventsRouter.js index 2f4515afa..a156906cf 100644 --- a/server/routes/eventsRouter.js +++ b/server/routes/eventsRouter.js @@ -22,6 +22,9 @@ router.patch('/', eventsController.eventsPatch); // create route between controller and '/events/reorder' endpoint router.patch('/reorder/', eventsController.eventsReorder); +// create route between controller and '/events/applydelay/:eventId' endpoint +router.patch('/applydelay/:eventId', eventsController.eventsApplyDelay); + // create route between controller and '/events/:eventId' endpoint router.delete('/:eventId', eventsController.eventsDelete);