{events.map((e, index) => {
if (index === 0) {
cumulativeDelay = 0;
@@ -174,24 +171,34 @@ export default function EventList(props) {
previousEnd = thisEnd;
thisEnd = e.timeEnd;
}
-
return (
-
-
+
+ {index === 0 && showQuickEntry && (
+
+ )}
+
+
+
+ {showQuickEntry && (
+
+ )}
);
})}
diff --git a/client/src/features/editors/list/EventListItem.jsx b/client/src/features/editors/list/EventListItem.jsx
index 6f0e0c088..ff88a1a86 100644
--- a/client/src/features/editors/list/EventListItem.jsx
+++ b/client/src/features/editors/list/EventListItem.jsx
@@ -3,6 +3,7 @@ import BlockBlock from '../BlockBlock/BlockBlock';
import EventBlock from '../EventBlock/EventBlock';
import { memo, useContext } from 'react';
import { LoggingContext } from '../../../app/context/LoggingContext';
+import { LocalEventSettingsContext } from '../../../app/context/LocalEventSettingsContext';
const areEqual = (prevProps, nextProps) => {
return (
@@ -29,12 +30,21 @@ const EventListItem = (props) => {
...rest
} = props;
const { emitError } = useContext(LoggingContext);
+ const { starTimeIsLastEnd, defaultPublic } = useContext(LocalEventSettingsContext);
// Create / delete new events
const actionHandler = (action, payload) => {
switch (action) {
case 'event':
- eventsHandler('add', { type: 'event', order: index + 1 });
+ eventsHandler(
+ 'add',
+ {
+ type: 'event',
+ order: index + 1,
+ isPublic: defaultPublic,
+ },
+ { startIsLastEnd: starTimeIsLastEnd ? index : undefined }
+ );
break;
case 'delay':
eventsHandler('add', { type: 'delay', order: index + 1 });
@@ -85,9 +95,7 @@ const EventListItem = (props) => {
/>
);
case 'block':
- return (
-
- );
+ return
;
case 'delay':
return (
{
- queryClient.setQueryData(
- [EVENTS_TABLE, context.newEvent.id],
- context.previousEvent
- );
+ queryClient.setQueryData([EVENTS_TABLE, context.newEvent.id], context.previousEvent);
},
// Mutation finished, failed or successful
// Fetch anyway, just to be sure
@@ -105,10 +96,7 @@ export default function EventListWrapper() {
queryClient.cancelQueries([EVENTS_TABLE, newEvent.id]);
// Snapshot the previous value
- const previousEvent = queryClient.getQueryData([
- EVENTS_TABLE,
- newEvent.id,
- ]);
+ const previousEvent = queryClient.getQueryData([EVENTS_TABLE, newEvent.id]);
// optimistically update object
queryClient.setQueryData([EVENTS_TABLE, newEvent.id], newEvent);
@@ -119,10 +107,7 @@ export default function EventListWrapper() {
// Mutation fails, rollback undos optimist update
onError: (error, newEvent, context) => {
- queryClient.setQueryData(
- [EVENTS_TABLE, context.newEvent.id],
- context.previousEvent
- );
+ queryClient.setQueryData([EVENTS_TABLE, context.newEvent.id], context.previousEvent);
},
// Mutation finished, failed or successful
// Fetch anyway, just to be sure
@@ -237,11 +222,16 @@ export default function EventListWrapper() {
// Events API
const eventsHandler = useCallback(
- async (action, payload) => {
+ async (action, payload, options = undefined) => {
switch (action) {
case 'add':
try {
- await addEvent.mutateAsync(payload);
+ let newEvent = { ...payload };
+ // there is an option to pass an index of an array to use as start time
+ if (options?.startIsLastEnd !== undefined) {
+ newEvent.timeStart = data[options.startIsLastEnd].timeEnd || 0;
+ }
+ await addEvent.mutateAsync(newEvent);
} catch (error) {
emitError(`Error fetching data: ${error.message}`);
}
@@ -326,6 +316,7 @@ export default function EventListWrapper() {
break;
}
},
+ // eslint-disable-next-line react-hooks/exhaustive-deps
[data]
);
diff --git a/client/src/features/editors/list/List.module.scss b/client/src/features/editors/list/List.module.scss
index 417dea6b8..e0655f421 100644
--- a/client/src/features/editors/list/List.module.scss
+++ b/client/src/features/editors/list/List.module.scss
@@ -23,11 +23,11 @@
.cursor {
width: 100%;
background: linear-gradient(
- 180deg,
- #ff7597 2%,
- #0001 3%,
- #0001 97%,
- #ff7597 98%
+ 180deg,
+ #ff7597 2%,
+ #0001 3%,
+ #0001 97%,
+ #ff7597 98%
);
border-radius: 14px;
diff --git a/client/src/features/menu/EventListMenu.jsx b/client/src/features/menu/EventListMenu.jsx
index 54bc4f46d..b25159b64 100644
--- a/client/src/features/menu/EventListMenu.jsx
+++ b/client/src/features/menu/EventListMenu.jsx
@@ -1,16 +1,16 @@
-import { memo, useMemo } from 'react';
+import { memo, useContext } from 'react';
import { Divider } from '@chakra-ui/react';
-import style from './EventListMenu.module.css';
+import { CursorContext } from '../../app/context/CursorContext';
import MenuActionButtons from './MenuActionButtons';
import CollapseBtn from 'common/components/buttons/CollapseBtn';
-import ExpandBtn from 'common/components/buttons/ExpandBtn';
-import { SelectSetting, HandleOptions } from 'app/context/settingsAtom';
-import { useAtom } from 'jotai';
-import LockIconBtn from 'common/components/buttons/LockIconBtn';
+import CursorUpBtn from '../../common/components/buttons/CursorUpBtn';
+import CursorDownBtn from '../../common/components/buttons/CursorDownBtn';
+import CursorLockedBtn from 'common/components/buttons/CursorLockedBtn';
+import style from './EventListMenu.module.css';
const EventListMenu = ({ eventsHandler }) => {
- const [cursorSettings] = useAtom(useMemo(() => SelectSetting('cursor'), []));
- const [, SetOption] = useAtom(HandleOptions);
+ const { isCursorLocked, toggleCursorLocked, moveCursorUp, moveCursorDown } =
+ useContext(CursorContext);
const actionHandler = (action) => {
switch (action) {
@@ -23,12 +23,14 @@ const EventListMenu = ({ eventsHandler }) => {
case 'block':
eventsHandler('add', { type: action, order: 0 });
break;
+ case 'cursorUp':
+ moveCursorUp();
+ break;
+ case 'cursorDown':
+ moveCursorDown();
+ break;
case 'togglelock':
- let newSet = 'locked';
- if (cursorSettings === 'locked') {
- newSet = 'unlocked';
- }
- SetOption({ cursor: newSet });
+ toggleCursorLocked();
break;
case 'deleteall':
eventsHandler('deleteall');
@@ -40,16 +42,14 @@ const EventListMenu = ({ eventsHandler }) => {
return (
-
eventsHandler('collapseall')}
- />
- eventsHandler('expandall')} />
+ eventsHandler('collapseall')} />
- actionHandler('cursorUp')} />
+ actionHandler('cursorDown')} />
+ actionHandler('togglelock')}
- active={cursorSettings === 'locked'}
+ active={isCursorLocked}
/>
diff --git a/client/src/features/modals/AppSettingsModal.jsx b/client/src/features/modals/AppSettingsModal.jsx
index c5ba0130f..bc9e3aac1 100644
--- a/client/src/features/modals/AppSettingsModal.jsx
+++ b/client/src/features/modals/AppSettingsModal.jsx
@@ -1,16 +1,6 @@
import { ModalBody } from '@chakra-ui/modal';
-import {
- FormControl,
- FormLabel,
- Input,
- PinInput,
- PinInputField,
-} from '@chakra-ui/react';
-import {
- getSettings,
- ontimePlaceholderSettings,
- postSettings,
-} from 'app/api/ontimeApi';
+import { Checkbox, FormControl, FormLabel, Input, PinInput, PinInputField } from '@chakra-ui/react';
+import { getSettings, ontimePlaceholderSettings, postSettings } from 'app/api/ontimeApi';
import { useContext, useEffect, useState } from 'react';
import { useFetch } from 'app/hooks/useFetch';
import { APP_SETTINGS } from 'app/api/apiConstants';
@@ -20,6 +10,7 @@ import { IconButton } from '@chakra-ui/button';
import { FiEye } from 'react-icons/fi';
import SubmitContainer from './SubmitContainer';
import { inputProps } from './modalHelper';
+import { LocalEventSettingsContext } from '../../app/context/LocalEventSettingsContext';
export default function AppSettingsModal() {
const { data, status, refetch } = useFetch(APP_SETTINGS, getSettings);
@@ -29,6 +20,19 @@ export default function AppSettingsModal() {
const [submitting, setSubmitting] = useState(false);
const [hidePin, setHidePin] = useState(true);
+ const {
+ showQuickEntry,
+ setShowQuickEntry,
+ starTimeIsLastEnd,
+ setStarTimeIsLastEnd,
+ defaultPublic,
+ setDefaultPublic,
+ } = useContext(LocalEventSettingsContext);
+
+ const [doShowQuickEntry, setDoShowQuickEntry] = useState(showQuickEntry);
+ const [doStarTimeIsLastEnd, setDoStarTimeIsLastEnd] = useState(starTimeIsLastEnd);
+ const [doDefaultPublic, setDoDefaultPublic] = useState(defaultPublic);
+
/**
* Set formdata from server state
*/
@@ -40,6 +44,24 @@ export default function AppSettingsModal() {
});
}, [changed, data]);
+ /**
+ * Set formdata from context
+ */
+ useEffect(() => {
+ if (showQuickEntry == null) return;
+ setDoShowQuickEntry(showQuickEntry);
+ }, [showQuickEntry]);
+
+ useEffect(() => {
+ if (starTimeIsLastEnd == null) return;
+ setDoStarTimeIsLastEnd(starTimeIsLastEnd);
+ }, [starTimeIsLastEnd]);
+
+ useEffect(() => {
+ if (defaultPublic == null) return;
+ setDoDefaultPublic(defaultPublic);
+ }, [defaultPublic]);
+
/**
* Validate and submit data
*/
@@ -47,29 +69,38 @@ export default function AppSettingsModal() {
event.preventDefault();
setSubmitting(true);
+ // set context
+ setShowQuickEntry(doShowQuickEntry);
+ setStarTimeIsLastEnd(doStarTimeIsLastEnd);
+ setDefaultPublic(doDefaultPublic);
+
const f = formData;
- let e = { status: false, message: '' };
- // Validate fields
- if (f.pinCode === '' || f.pinCode == null) {
- e.status = true;
- e.message += 'App pin code removed';
- } else {
- e.status = true;
- e.message += 'App pin code added';
+ // we might not have changed this
+ if (f.pinCode !== data.pinCode) {
+ let e = { status: false, message: '' };
+
+ // Validate fields
+ if (f.pinCode === '' || f.pinCode == null) {
+ e.status = true;
+ e.message += 'App pin code removed';
+ } else {
+ e.status = true;
+ e.message += 'App pin code added';
+ }
+
+ // set fields with error
+ if (!e.status) {
+ emitError(`Invalid Input: ${e.message}`);
+ } else {
+ await postSettings(formData);
+ await refetch();
+ emitWarning(e.message);
+ setChanged(false);
+ }
}
-
- // set fields with error
- if (!e.status) {
- emitError(`Invalid Input: ${e.message}`);
- } else {
- await postSettings(formData);
- await refetch();
- emitWarning(e.message);
- setChanged(false);
- }
-
setSubmitting(false);
+ setChanged(false);
};
/**
@@ -78,6 +109,11 @@ export default function AppSettingsModal() {
const revert = async () => {
setChanged(false);
await refetch();
+
+ // set from context
+ setDoShowQuickEntry(showQuickEntry);
+ setDoStarTimeIsLastEnd(starTimeIsLastEnd);
+ setDoDefaultPublic(defaultPublic);
};
/**
@@ -92,6 +128,13 @@ export default function AppSettingsModal() {
setChanged(true);
};
+ /**
+ * Sets changed flag to true
+ */
+ const handleContextChange = () => {
+ setChanged(true);
+ };
+
const disableModal = status !== 'success';
return (
@@ -157,6 +200,36 @@ export default function AppSettingsModal() {
+
Create Event Default Settings
+
+ {
+ setDoShowQuickEntry(e.target.checked);
+ handleContextChange();
+ }}
+ >
+ Show quick entry on hover
+
+ {
+ setDoStarTimeIsLastEnd(e.target.checked);
+ handleContextChange();
+ }}
+ >
+ Start time is last end
+
+ {
+ setDoDefaultPublic(e.target.checked);
+ handleContextChange();
+ }}
+ >
+ Event default public
+
+