feat: eventsAPI

This commit is contained in:
cv
2021-04-10 11:39:53 +02:00
parent e2561bcd54
commit e62b79f84e
13 changed files with 384 additions and 193 deletions
+8
View File
@@ -0,0 +1,8 @@
import { serverURL } from './apiConstants';
export const eventsURL = serverURL + 'events/';
export const fetchAllEvents = async () => {
const res = await fetch(eventsURL + 'all');
// TODO: Safe json convert
return res.json();
};
+5 -12
View File
@@ -2,9 +2,9 @@ import { IconButton } from '@chakra-ui/button';
import { SettingsIcon } from '@chakra-ui/icons';
import { Grid, GridItem, Heading } from '@chakra-ui/layout';
import { Box } from '@chakra-ui/layout';
import { useContext } from 'react';
import { useEffect, useState } from 'react';
import { EventContext } from '../../app/context/eventContext';
import { useContext, useEffect } from 'react';
import { useQuery } from 'react-query';
import { useState } from 'react';
import { EventListContext } from '../../app/context/eventListContext';
import NumberedText from '../../common/components/text/NumberedText';
import PlaybackControl from '../control/PlaybackControl';
@@ -12,26 +12,22 @@ import MessageForm from '../form/MessageForm';
import PreviewContainer from '../viewers/PreviewContainer';
import styles from './Editor.module.css';
import EventList from './list/EventList';
import EventListWrapper from './list/EventListWrapper';
export default function Editor() {
const [formMode, setFormMode] = useState(null);
const [events] = useContext(EventListContext);
const [webEvents, setWebEvents] = useState(null);
const [event, setEvent] = useContext(EventContext);
const [playback, setPlayback] = useState({
current: null,
next: null,
currentTimer: null,
numEvents: 0,
state: 'pause',
prevState: 'pause',
});
const updatePlayback = (vals) => {
setPlayback({ ...playback, ...vals });
};
console.log('events here', webEvents);
return (
<Grid
templateRows='1fr 1fr 1fr'
@@ -46,10 +42,7 @@ export default function Editor() {
</Heading>
<NumberedText number={1} text={'Manage and select event to run'} />
<div className={styles.content}>
<EventList
events={webEvents}
formMode={formMode}
setFormMode={setFormMode}
<EventListWrapper
selected={playback.current}
updatePlayback={updatePlayback}
/>
+42 -147
View File
@@ -1,160 +1,55 @@
import { useContext, useEffect } from 'react';
import { EventContext } from '../../../app/context/eventContext';
import { EventListContext } from '../../../app/context/eventListContext';
import EventListItem from './EventListItem';
import style from './List.module.css';
import DelayBlock from './DelayBlock';
import BlockBlock from './BlockBlock';
import EventListMenu from '../../menu/EventListMenu';
export default function EventList(props) {
const [events, setEvents] = useContext(EventListContext);
const [event] = useContext(EventContext);
const { events, selected, eventsHandler } = props;
// update number of events
useEffect(() => {
const f = events.filter((e) => e.type === 'event');
props.updatePlayback({ numEvents: f.length });
}, [events]);
const insertItemAt = (item, index) => {
// handle insert at beggining of array
if (index === -1) {
// move all items one element down, starting from new position
events.forEach((e) => {
e.order = e.order + 1;
});
return [item, ...events];
} else {
let before = events.slice(0, index + 1);
let after = events.slice(index + 1);
// move all items one element down, starting from new position
after.forEach((e) => {
e.order = e.order + 1;
});
return [...before, item, ...after];
}
};
const createEvent = (itemIndex = -1) => {
// make an event
// TODO: Replace this with global def somewhere
// TODO: handle random ids better
let newEvent = {
id: Math.random(),
order: itemIndex + 1,
title: '',
subtitle: '',
presenter: '',
timeStart: new Date(),
timeEnd: new Date(),
clockStarted: null,
timerDuration: 0,
type: 'event',
};
// set to state
setEvents(insertItemAt(newEvent, itemIndex));
};
const createDelay = (itemIndex = 0) => {
// make an event
// TODO: Replace this with global def somewhere
// TODO: handle random ids better
let newEvent = {
id: Math.random(),
order: itemIndex + 1,
timerDuration: 0,
type: 'delay',
};
// set to state
setEvents(insertItemAt(newEvent, itemIndex));
};
const createBlock = (itemIndex = 0) => {
// make an event
// TODO: Replace this with global def somewhere
// TODO: handle random ids better
let newEvent = {
id: Math.random(),
order: itemIndex + 1,
type: 'block',
};
// set to state
setEvents(insertItemAt(newEvent, itemIndex));
};
const deleteEvent = (index) => {
// TODO: This feels weird?
let e = events.splice(index, 1);
setEvents([...events]);
};
const replaceAt = (array, index, value) => {
const ret = array.slice(0);
ret[index] = value;
return ret;
};
const updateData = (itemIndex, data) => {
const newEvents = replaceAt(events, itemIndex, data);
setEvents(newEvents);
};
console.log('events in event list', events);
console.log('EventList: events in event list', events);
let cumulativeDelay = 0;
let eventCount = -1;
// Torbjorn: is this very dirty code?
// -- map and cumulative delay thing
// -- should i skip the order value and just use the array as order? (checkout dnd)
return (
<>
<EventListMenu createEvent={createEvent} />
<div className={style.eventContainer}>
{events.map((e, index) => {
if (e.type === 'event') {
eventCount = eventCount + 1;
return (
<EventListItem
key={e.id}
index={index}
data={e}
selected={props.selected === eventCount}
createEvent={createEvent}
deleteEvent={deleteEvent}
createDelay={createDelay}
createBlock={createBlock}
updateData={updateData}
delay={cumulativeDelay}
/>
);
} else if (e.type === 'block') {
cumulativeDelay = 0;
return (
<BlockBlock
key={e.id}
index={index}
createEvent={createEvent}
deleteEvent={deleteEvent}
/>
);
} else if (e.type === 'delay') {
cumulativeDelay = cumulativeDelay + e.timerDuration;
return (
<DelayBlock
key={e.id}
index={index}
data={e}
createEvent={createEvent}
deleteEvent={deleteEvent}
updateData={updateData}
/>
);
}
})}
</div>
</>
<div className={style.eventContainer}>
{events.map((e, index) => {
if (e.type === 'event') {
eventCount = eventCount + 1;
return (
<EventListItem
key={e.id}
index={index}
data={e}
selected={selected === eventCount}
eventsHandler={eventsHandler}
delay={cumulativeDelay}
/>
);
} else if (e.type === 'block') {
cumulativeDelay = 0;
return (
<BlockBlock
key={e.id}
index={index}
data={e}
eventsHandler={eventsHandler}
/>
);
} else if (e.type === 'delay') {
cumulativeDelay = cumulativeDelay + e.timerDuration;
return (
<DelayBlock
key={e.id}
index={index}
data={e}
eventsHandler={eventsHandler}
/>
);
}
})}
</div>
);
}
@@ -0,0 +1,81 @@
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useEffect } from 'react';
import { fetchAllEvents } from '../../../app/api/eventsApi.js';
import EventList from './EventList';
import EventListMenu from '../../menu/EventListMenu.jsx';
import axios from 'axios';
import { showErrorToast } from '../../../common/helpers/toastManager';
import { eventsURL } from '../../../app/api/eventsApi';
import { Skeleton } from '@chakra-ui/skeleton';
import style from './List.module.css';
export default function EventListWrapper() {
const { data, status, isError } = useQuery('events', fetchAllEvents);
const queryClient = useQueryClient();
// TODO: Move to events API?
const addEvent = useMutation((data) => axios.post(eventsURL, data));
const updateEvent = useMutation((data) => axios.put(eventsURL, data));
const deleteEvent = useMutation((eventId) =>
axios.delete(eventsURL + eventId)
);
// Show toasts on errors
useEffect(() => {
if (isError) {
showErrorToast('Error fetching data');
}
}, [isError]);
// Events API
const eventsHandler = async (action, payload) => {
// Torbjorn: is this a good way to do it?
// How do I handle the mutation thing
// https://react-query.tanstack.com/guides/invalidations-from-mutations
// https://react-query.tanstack.com/guides/updates-from-mutation-responses
switch (action) {
case 'add':
try {
const event = await addEvent
.mutateAsync(payload)
.then(queryClient.invalidateQueries('events'));
} catch (error) {
showErrorToast('Error creating event', error.message);
}
break;
case 'update':
try {
const event = await updateEvent
.mutateAsync(payload)
.then(queryClient.invalidateQueries('events'));
} catch (error) {
showErrorToast('Error updating event', error.message);
}
break;
case 'delete':
try {
const event = await deleteEvent
.mutateAsync(payload)
.then(queryClient.invalidateQueries('events'));
} catch (error) {
showErrorToast('Error deleting event', error.message);
}
break;
default:
showErrorToast('Unrecognised request', action);
break;
}
};
return (
<>
<EventListMenu eventsHandler={eventsHandler} />
{status === 'success' ? (
<EventList events={data} eventsHandler={eventsHandler} />
) : (
<div className={style.eventContainer}>
<Skeleton height='50vh' />
</div>
)}
</>
);
}