mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-02 04:49:05 +00:00
major: event block redesign
This commit is contained in:
@@ -2,13 +2,13 @@ import { IconButton } from '@chakra-ui/button';
|
|||||||
import { FiMinus } from 'react-icons/fi';
|
import { FiMinus } from 'react-icons/fi';
|
||||||
|
|
||||||
export default function DeleteIconBtn(props) {
|
export default function DeleteIconBtn(props) {
|
||||||
const { clickhandler, ...rest } = props;
|
const { actionHandler, ...rest } = props;
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
size={props.size || 'xs'}
|
size={props.size || 'xs'}
|
||||||
icon={<FiMinus />}
|
icon={<FiMinus />}
|
||||||
colorScheme='red'
|
colorScheme='red'
|
||||||
onClick={clickhandler}
|
onClick={() => actionHandler('delete')}
|
||||||
_focus={{ boxShadow: 'none' }}
|
_focus={{ boxShadow: 'none' }}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { IconButton } from '@chakra-ui/button';
|
||||||
|
import { FiTrash2 } from 'react-icons/fi';
|
||||||
|
|
||||||
|
export default function TrashIconBtn(props) {
|
||||||
|
const { clickhandler, ...rest } = props;
|
||||||
|
return (
|
||||||
|
<IconButton
|
||||||
|
size={props.size || 'xs'}
|
||||||
|
icon={<FiTrash2 />}
|
||||||
|
colorScheme='red'
|
||||||
|
onClick={clickhandler}
|
||||||
|
_focus={{ boxShadow: 'none' }}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,14 +2,16 @@ import { IconButton } from '@chakra-ui/button';
|
|||||||
import { FiSun } from 'react-icons/fi';
|
import { FiSun } from 'react-icons/fi';
|
||||||
|
|
||||||
export default function VisibleIconBtn(props) {
|
export default function VisibleIconBtn(props) {
|
||||||
const { clickhandler, active, ...rest } = props;
|
const { actionHandler, active, ...rest } = props;
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
size={props.size || 'xs'}
|
size={props.size || 'xs'}
|
||||||
icon={<FiSun />}
|
icon={<FiSun />}
|
||||||
colorScheme='blue'
|
colorScheme='blue'
|
||||||
variant={active ? 'solid' : 'outline'}
|
variant={active ? 'solid' : 'outline'}
|
||||||
onClick={clickhandler}
|
onClick={() =>
|
||||||
|
actionHandler('update', { field: 'isPublic', value: !active })
|
||||||
|
}
|
||||||
_focus={{ boxShadow: 'none' }}
|
_focus={{ boxShadow: 'none' }}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import EditableTimer from '../../input/EditableTimer';
|
|||||||
import { showWarningToast } from '../../helpers/toastManager';
|
import { showWarningToast } from '../../helpers/toastManager';
|
||||||
|
|
||||||
export default function EventTimes(props) {
|
export default function EventTimes(props) {
|
||||||
const { updateValues, delay, timeStart, timeEnd } = props;
|
const { actionHandler, delay, timeStart, timeEnd } = props;
|
||||||
|
|
||||||
const handleValidate = (entry, v) => {
|
const handleValidate = (entry, v) => {
|
||||||
// we dont inforce validation here
|
// we dont inforce validation here
|
||||||
@@ -26,14 +26,14 @@ export default function EventTimes(props) {
|
|||||||
<EditableTimer
|
<EditableTimer
|
||||||
name='timeStart'
|
name='timeStart'
|
||||||
validate={handleValidate}
|
validate={handleValidate}
|
||||||
updateValues={updateValues}
|
actionHandler={actionHandler}
|
||||||
time={timeStart}
|
time={timeStart}
|
||||||
delay={delay}
|
delay={delay}
|
||||||
/>
|
/>
|
||||||
<EditableTimer
|
<EditableTimer
|
||||||
name='timeEnd'
|
name='timeEnd'
|
||||||
validate={handleValidate}
|
validate={handleValidate}
|
||||||
updateValues={updateValues}
|
actionHandler={actionHandler}
|
||||||
time={timeEnd}
|
time={timeEnd}
|
||||||
delay={delay}
|
delay={delay}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import EditableTimer from '../../input/EditableTimer';
|
||||||
|
import { showWarningToast } from '../../helpers/toastManager';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { millisToMinutes, stringFromMillis } from '../../dateConfig';
|
||||||
|
|
||||||
|
const label = {
|
||||||
|
fontSize: '0.75em',
|
||||||
|
color: '#aaa',
|
||||||
|
};
|
||||||
|
|
||||||
|
const TimesDelayed = (props) => {
|
||||||
|
const { handleValidate, actionHandler, delay, timeStart, timeEnd } = props;
|
||||||
|
|
||||||
|
const scheduledStart = stringFromMillis(timeStart, false);
|
||||||
|
|
||||||
|
const scheduledEnd = stringFromMillis(timeEnd, false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span style={label}>
|
||||||
|
Start <span>{scheduledStart}</span>
|
||||||
|
</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='timeStart'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeStart}
|
||||||
|
delay={delay}
|
||||||
|
/>
|
||||||
|
<span style={label}>
|
||||||
|
End <span>{scheduledEnd}</span>
|
||||||
|
</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='timeEnd'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeEnd}
|
||||||
|
delay={delay}
|
||||||
|
/>
|
||||||
|
<span style={label}>Duration</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='duration'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeEnd - timeStart}
|
||||||
|
delay={0}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Times = (props) => {
|
||||||
|
const { handleValidate, actionHandler, timeStart, timeEnd, duration } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span style={label}>Start</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='timeStart'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeStart}
|
||||||
|
delay={0}
|
||||||
|
/>
|
||||||
|
<span style={label}>End</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='timeEnd'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeEnd}
|
||||||
|
delay={0}
|
||||||
|
/>
|
||||||
|
<span style={label}>Duration (min)</span>
|
||||||
|
<EditableTimer
|
||||||
|
name='durationOverride'
|
||||||
|
validate={handleValidate}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
time={timeEnd - timeStart}
|
||||||
|
delay={0}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function EventTimesVertical(props) {
|
||||||
|
const { delay, timeStart, timeEnd } = props;
|
||||||
|
const [duration, setDuration] = useState(
|
||||||
|
millisToMinutes(timeEnd - timeStart) || 0
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
setDuration(millisToMinutes(timeEnd - timeStart));
|
||||||
|
}, [timeStart, timeEnd]);
|
||||||
|
|
||||||
|
const handleValidate = (entry, v) => {
|
||||||
|
// we dont enforce validation here
|
||||||
|
|
||||||
|
if (v == null || timeStart == null || timeEnd == null) return true;
|
||||||
|
if (timeStart === 0) return true;
|
||||||
|
|
||||||
|
let validate = { value: true, catch: '' };
|
||||||
|
if (entry === 'timeStart' && v > timeEnd)
|
||||||
|
validate.catch = 'Start time later than end time';
|
||||||
|
else if (entry === 'timeEnd' && v < timeStart)
|
||||||
|
validate.catch = 'End time earlier than start time';
|
||||||
|
|
||||||
|
if (validate.catch !== '')
|
||||||
|
showWarningToast('Time Input Warning', validate.catch);
|
||||||
|
return validate.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (delay != null) & (delay > 0) ? (
|
||||||
|
<TimesDelayed
|
||||||
|
handleValidate={handleValidate}
|
||||||
|
actionHandler={props.actionHandler}
|
||||||
|
delay={delay}
|
||||||
|
timeStart={timeStart}
|
||||||
|
timeEnd={timeEnd}
|
||||||
|
duration={duration}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Times
|
||||||
|
handleValidate={handleValidate}
|
||||||
|
actionHandler={props.actionHandler}
|
||||||
|
timeStart={timeStart}
|
||||||
|
timeEnd={timeEnd}
|
||||||
|
duration={duration}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,11 +8,12 @@ export const stringFromMillis = (
|
|||||||
delim = ':',
|
delim = ':',
|
||||||
ifNull = '...'
|
ifNull = '...'
|
||||||
) => {
|
) => {
|
||||||
if (ms === null) return ifNull;
|
if (ms === null || isNaN(ms)) return ifNull;
|
||||||
const showWith0 = (value) => (value < 10 ? `0${value}` : value);
|
const showWith0 = (value) => (value < 10 ? `0${value}` : value);
|
||||||
const hours = showWith0(Math.floor(((ms / (1000 * 60 * 60)) % 60) % 24));
|
const hours = showWith0(Math.floor(((ms / (1000 * 60 * 60)) % 60) % 24));
|
||||||
const minutes = showWith0(Math.floor((ms / (1000 * 60)) % 60));
|
const minutes = showWith0(Math.floor((ms / (1000 * 60)) % 60));
|
||||||
const seconds = showWith0(Math.floor((ms / 1000) % 60));
|
const seconds = showWith0(Math.floor((ms / 1000) % 60));
|
||||||
|
|
||||||
return showSeconds
|
return showSeconds
|
||||||
? `${
|
? `${
|
||||||
parseInt(hours) ? `${hours}${delim}` : `00${delim}`
|
parseInt(hours) ? `${hours}${delim}` : `00${delim}`
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const inputProps = {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TimeInput(props) {
|
export default function DelayInput(props) {
|
||||||
const [value, setValue] = useState(props.value);
|
const [value, setValue] = useState(props.value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -29,9 +29,10 @@ export default function TimeInput(props) {
|
|||||||
if (val === props.value) return;
|
if (val === props.value) return;
|
||||||
if (val === '') setValue(0);
|
if (val === '') setValue(0);
|
||||||
if (val >= 0 && val <= 60) {
|
if (val >= 0 && val <= 60) {
|
||||||
props.submitHandler(val);
|
// convert to ms and updates
|
||||||
|
props.actionHandler('update', { field: 'duration', value: val * 60000 });
|
||||||
} else {
|
} else {
|
||||||
setValue(60);
|
props.actionHandler('update', { field: 'duration', value: 3600000 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { millisToMinutes } from '../dateConfig';
|
|
||||||
import style from '../../features/editors/list/Block.module.css';
|
|
||||||
|
|
||||||
export default function DelayValue(props) {
|
|
||||||
const { delay } = props;
|
|
||||||
const delayed = delay > 0;
|
|
||||||
return (
|
|
||||||
<div className={style.delayValue}>
|
|
||||||
{delayed && <span>{`+ ${millisToMinutes(delay)}`}</span>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ import style from './EditableText.module.css';
|
|||||||
|
|
||||||
export default function EditableText(props) {
|
export default function EditableText(props) {
|
||||||
const { label, defaultValue, placeholder, submitHandler } = props;
|
const { label, defaultValue, placeholder, submitHandler } = props;
|
||||||
const [text, setText] = useState('');
|
const [text, setText] = useState(defaultValue || '');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (defaultValue == null) setText('');
|
if (defaultValue == null) setText('');
|
||||||
@@ -19,14 +19,11 @@ export default function EditableText(props) {
|
|||||||
|
|
||||||
const handleChange = (val) => {
|
const handleChange = (val) => {
|
||||||
if (val.length < 40) setText(val);
|
if (val.length < 40) setText(val);
|
||||||
console.log(val.length);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.block}>
|
<div className={style.block}>
|
||||||
<span className={props.underlined ? style.titleUnderlined : style.title}>
|
<span className={style.title}>{label}</span>
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
<Editable
|
<Editable
|
||||||
onChange={(v) => handleChange(v)}
|
onChange={(v) => handleChange(v)}
|
||||||
onSubmit={(v) => handleSubmit(v)}
|
onSubmit={(v) => handleSubmit(v)}
|
||||||
@@ -34,8 +31,11 @@ export default function EditableText(props) {
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className={style.inline}
|
className={style.inline}
|
||||||
>
|
>
|
||||||
<EditablePreview />
|
<EditablePreview
|
||||||
<EditableInput />
|
color={text === '' ? '#666' : 'inherit'}
|
||||||
|
maxWidth='20em'
|
||||||
|
/>
|
||||||
|
<EditableInput overflowX='hidden' maxWidth='20em' />
|
||||||
</Editable>
|
</Editable>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,24 +1,16 @@
|
|||||||
.title,
|
.title {
|
||||||
.titleUnderlined {
|
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
font-size: 0.8em;
|
font-size: 0.75em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 6em;
|
width: 6em;
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titleUnderlined {
|
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: 'block';
|
display: 'block';
|
||||||
overflow: hidden;
|
overflow-x: hidden;
|
||||||
max-width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline {
|
.inline {
|
||||||
display: inline;
|
display: inline;
|
||||||
width: max-content;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { showErrorToast } from '../helpers/toastManager';
|
|||||||
import style from './EditableTimer.module.css';
|
import style from './EditableTimer.module.css';
|
||||||
|
|
||||||
export default function EditableTimer(props) {
|
export default function EditableTimer(props) {
|
||||||
const { name, updateValues, time, delay, validate } = props;
|
const { name, actionHandler, time, delay, validate } = props;
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
|
|
||||||
// prepare time fields
|
// prepare time fields
|
||||||
@@ -46,7 +46,7 @@ export default function EditableTimer(props) {
|
|||||||
if (!validate(name, millis)) return false;
|
if (!validate(name, millis)) return false;
|
||||||
|
|
||||||
// update entry
|
// update entry
|
||||||
updateValues(name, millis);
|
actionHandler('update', { field: name, value: millis });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -56,19 +56,17 @@ export default function EditableTimer(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.time}>
|
<Editable
|
||||||
<Editable
|
onFocus={() => showOriginal}
|
||||||
onFocus={() => showOriginal()}
|
onEdit={() => showOriginal}
|
||||||
onEdit={() => showOriginal}
|
onChange={(v) => setValue(v)}
|
||||||
onChange={(v) => setValue(v)}
|
onSubmit={(v) => validateValue(v)}
|
||||||
onSubmit={(v) => validateValue(v)}
|
value={value}
|
||||||
value={value}
|
placeholder='--:--'
|
||||||
placeholder='--:--'
|
className={delay > 0 ? style.delayedEditable : style.editable}
|
||||||
className={delay > 0 ? style.delayedEditable : style.editable}
|
>
|
||||||
>
|
<EditablePreview />
|
||||||
<EditablePreview />
|
<EditableInput type='time' min='00:00' max='23:59' />
|
||||||
<EditableInput type='time' min='00:00' max='23:59' />
|
</Editable>
|
||||||
</Editable>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
.time {
|
.editable,
|
||||||
|
.delayedEditable {
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
width: 5em;
|
width: 5em;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
|
||||||
|
|
||||||
.editable,
|
|
||||||
.delayedEditable {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.delayedEditable {
|
.delayedEditable {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export default function MessageControl() {
|
|||||||
</Editable>
|
</Editable>
|
||||||
<VisibleIconBtn
|
<VisibleIconBtn
|
||||||
active={pres.visible || undefined}
|
active={pres.visible || undefined}
|
||||||
clickhandler={() => messageControl('toggle-pres-visible')}
|
actionHandler={() => messageControl('toggle-pres-visible')}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,7 +114,7 @@ export default function MessageControl() {
|
|||||||
</Editable>
|
</Editable>
|
||||||
<VisibleIconBtn
|
<VisibleIconBtn
|
||||||
active={publ.visible || undefined}
|
active={publ.visible || undefined}
|
||||||
clickhandler={() => messageControl('toggle-publ-visible')}
|
actionHandler={() => messageControl('toggle-publ-visible')}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,7 +135,7 @@ export default function MessageControl() {
|
|||||||
|
|
||||||
<VisibleIconBtn
|
<VisibleIconBtn
|
||||||
active={lower.visible || undefined}
|
active={lower.visible || undefined}
|
||||||
clickhandler={() => messageControl('toggle-lower-visible')}
|
actionHandler={() => messageControl('toggle-lower-visible')}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { IconButton } from '@chakra-ui/button';
|
|||||||
import { FiZap, FiPlus, FiMinusCircle, FiClock } from 'react-icons/fi';
|
import { FiZap, FiPlus, FiMinusCircle, FiClock } from 'react-icons/fi';
|
||||||
|
|
||||||
export default function ActionButtons(props) {
|
export default function ActionButtons(props) {
|
||||||
const { showAdd, showDelay, showBlock } = props;
|
const { showAdd, showDelay, showBlock, actionHandler } = props;
|
||||||
|
|
||||||
const menuStyle = {
|
const menuStyle = {
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
@@ -25,7 +25,7 @@ export default function ActionButtons(props) {
|
|||||||
<MenuList style={menuStyle}>
|
<MenuList style={menuStyle}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={<FiPlus />}
|
icon={<FiPlus />}
|
||||||
onClick={props.addHandler}
|
onClick={() => actionHandler('event')}
|
||||||
isDisabled={!showAdd}
|
isDisabled={!showAdd}
|
||||||
>
|
>
|
||||||
Event next
|
Event next
|
||||||
@@ -33,14 +33,14 @@ export default function ActionButtons(props) {
|
|||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={<FiClock />}
|
icon={<FiClock />}
|
||||||
onClick={props.delayHandler}
|
onClick={() => actionHandler('delay')}
|
||||||
isDisabled={!showDelay}
|
isDisabled={!showDelay}
|
||||||
>
|
>
|
||||||
Delay next
|
Delay next
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={<FiMinusCircle />}
|
icon={<FiMinusCircle />}
|
||||||
onClick={props.blockHandler}
|
onClick={() => actionHandler('block')}
|
||||||
isDisabled={!showBlock}
|
isDisabled={!showBlock}
|
||||||
>
|
>
|
||||||
Block next
|
Block next
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
/* ============= COMMON ============= */
|
|
||||||
|
|
||||||
.eventRow,
|
|
||||||
.eventRowActive,
|
|
||||||
.block,
|
|
||||||
.delay {
|
|
||||||
position: relative;
|
|
||||||
margin: 0.2em 0;
|
|
||||||
padding: 0.2em 0.5em;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 15px;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.block,
|
|
||||||
.delay {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
gap: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actionOverlay {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
padding-top: 0.2em;
|
|
||||||
gap: 0.5em;
|
|
||||||
align-content: center;
|
|
||||||
align-self: flex-start;
|
|
||||||
|
|
||||||
opacity: 0.8;
|
|
||||||
transition: linear 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eventRow:hover > .actionOverlay,
|
|
||||||
.eventRowActive:hover > .actionOverlay,
|
|
||||||
.block:hover > .actionOverlay,
|
|
||||||
.delay:hover > .actionOverlay {
|
|
||||||
opacity: 1;
|
|
||||||
transition: linear 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NA */
|
|
||||||
.actionOverlay:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
/* ============= EVENT ITEM ============= */
|
|
||||||
|
|
||||||
.eventRow,
|
|
||||||
.eventRowActive {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 2em 2em auto auto 1fr auto;
|
|
||||||
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
align-items: baseline;
|
|
||||||
gap: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eventRow {
|
|
||||||
background-color: rgba(255, 255, 255, 0.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eventRowActive {
|
|
||||||
background-color: rgba(255, 255, 255, 0.36);
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
#00000000 10%,
|
|
||||||
#4bffab10 89%,
|
|
||||||
#227c52aa 90%,
|
|
||||||
#4bffabcc 100%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag {
|
|
||||||
color: rgba(255, 255, 255, 0.37);
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicators {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-self: flex-start;
|
|
||||||
font-size: 0.75em;
|
|
||||||
overflow: hidden;
|
|
||||||
min-width: 0;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next,
|
|
||||||
.nextDisabled {
|
|
||||||
width: max-content;
|
|
||||||
padding: 0 0.2em;
|
|
||||||
color: #4bffab;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nextDisabled {
|
|
||||||
opacity: 0.05;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delayValue {
|
|
||||||
color: #d69e2eaa;
|
|
||||||
padding: 0 0.2em;
|
|
||||||
text-align: center;
|
|
||||||
align-self: flex-start;
|
|
||||||
width: max-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next:after,
|
|
||||||
.delayValue:after {
|
|
||||||
content: '\200b';
|
|
||||||
}
|
|
||||||
|
|
||||||
.titleContainer,
|
|
||||||
.detailedContainer {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowDetailed {
|
|
||||||
display: inline-flex;
|
|
||||||
position: relative;
|
|
||||||
align-self: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titleContainer,
|
|
||||||
.detailedContainer {
|
|
||||||
width: 90%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more {
|
|
||||||
position: absolute;
|
|
||||||
right: 0.25em;
|
|
||||||
top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============= BLOCK BLOCK ============= */
|
|
||||||
.block {
|
|
||||||
background-color: #805ad5;
|
|
||||||
background: linear-gradient(
|
|
||||||
0deg,
|
|
||||||
rgba(107, 70, 193, 0.4) 0%,
|
|
||||||
rgba(128, 90, 213, 0.4) 20%,
|
|
||||||
rgba(107, 70, 193, 0.15) 21%
|
|
||||||
);
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 2em auto;
|
|
||||||
align-content: center;
|
|
||||||
align-items: baseline;
|
|
||||||
gap: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block > .drag {
|
|
||||||
justify-self: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block > .actionOverlay {
|
|
||||||
justify-self: end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============= DELAY BLOCK ============= */
|
|
||||||
.delay {
|
|
||||||
background-color: #ecc94b;
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
rgba(214, 158, 46, 0.4) 0%,
|
|
||||||
rgba(236, 201, 75, 0.4) 20%,
|
|
||||||
rgba(214, 158, 46, 0.07) 21%
|
|
||||||
);
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 2em 1fr auto;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
align-items: baseline;
|
|
||||||
gap: 0.5em;
|
|
||||||
}
|
|
||||||
@@ -2,20 +2,10 @@ import { Draggable } from 'react-beautiful-dnd';
|
|||||||
import { FiMoreVertical } from 'react-icons/fi';
|
import { FiMoreVertical } from 'react-icons/fi';
|
||||||
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
import ActionButtons from './ActionButtons';
|
import ActionButtons from './ActionButtons';
|
||||||
import style from './Block.module.css';
|
import style from './BlockBlock.module.css';
|
||||||
|
|
||||||
export default function BlockBlock(props) {
|
export default function BlockBlock(props) {
|
||||||
const { eventsHandler, index, data } = props;
|
const { index, data, actionHandler } = props;
|
||||||
|
|
||||||
const addHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'event', order: index + 1 });
|
|
||||||
};
|
|
||||||
const deleteHandler = () => {
|
|
||||||
eventsHandler('delete', data.id);
|
|
||||||
};
|
|
||||||
const delayHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'delay', order: index + 1 });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable key={data.id} draggableId={data.id} index={index}>
|
<Draggable key={data.id} draggableId={data.id} index={index}>
|
||||||
@@ -29,13 +19,8 @@ export default function BlockBlock(props) {
|
|||||||
<FiMoreVertical />
|
<FiMoreVertical />
|
||||||
</span>
|
</span>
|
||||||
<div className={style.actionOverlay}>
|
<div className={style.actionOverlay}>
|
||||||
<DeleteIconBtn clickhandler={deleteHandler} />
|
<DeleteIconBtn actionHandler={actionHandler} />
|
||||||
<ActionButtons
|
<ActionButtons showAdd showDelay actionHandler={actionHandler} />
|
||||||
showAdd
|
|
||||||
addHandler={addHandler}
|
|
||||||
showDelay
|
|
||||||
delayHandler={delayHandler}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/* ============= COMMON ============= */
|
||||||
|
|
||||||
|
.block {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2em auto;
|
||||||
|
align-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
background-color: #805ad5;
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(107, 70, 193, 0.4) 0%,
|
||||||
|
rgba(128, 90, 213, 0.4) 20%,
|
||||||
|
rgba(107, 70, 193, 0.15) 21%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================ DRAG ================ */
|
||||||
|
.drag {
|
||||||
|
color: rgba(255, 255, 255, 0.67);
|
||||||
|
align-self: center;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============== ACTION ================ */
|
||||||
|
.actionOverlay {
|
||||||
|
display: flex;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: center;
|
||||||
|
align-self: flex-start;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
gap: 0.5em;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block:hover > .actionOverlay {
|
||||||
|
opacity: 1;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NA */
|
||||||
|
.actionOverlay:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
@@ -1,27 +1,14 @@
|
|||||||
import { Draggable } from 'react-beautiful-dnd';
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
import { FiMoreVertical } from 'react-icons/fi';
|
import { FiMoreVertical } from 'react-icons/fi';
|
||||||
import { millisToMinutes } from '../../../common/dateConfig';
|
import { millisToMinutes } from '../../../common/dateConfig';
|
||||||
import TimeInput from '../../../common/input/TimeInput';
|
|
||||||
import style from './Block.module.css';
|
|
||||||
import ActionButtons from './ActionButtons';
|
import ActionButtons from './ActionButtons';
|
||||||
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
import ApplyIconBtn from '../../../common/components/buttons/ApplyIconBtn';
|
import ApplyIconBtn from '../../../common/components/buttons/ApplyIconBtn';
|
||||||
|
import DelayInput from '../../../common/input/DelayInput';
|
||||||
|
import style from './DelayBlock.module.css';
|
||||||
|
|
||||||
export default function DelayBlock(props) {
|
export default function DelayBlock(props) {
|
||||||
const { data, eventsHandler, index } = props;
|
const { eventsHandler, data, index, actionHandler } = props;
|
||||||
|
|
||||||
const addHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'event', order: index + 1 });
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitHandler = (value) => {
|
|
||||||
// convert to ms and patch
|
|
||||||
eventsHandler('patch', { id: data.id, duration: value * 1000 * 60 });
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteHandler = () => {
|
|
||||||
eventsHandler('delete', data.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyDelayHandler = () => {
|
const applyDelayHandler = () => {
|
||||||
eventsHandler('applyDelay', { id: data.id, duration: data.duration });
|
eventsHandler('applyDelay', { id: data.id, duration: data.duration });
|
||||||
@@ -29,6 +16,7 @@ export default function DelayBlock(props) {
|
|||||||
|
|
||||||
let delayValue =
|
let delayValue =
|
||||||
data.duration != null ? millisToMinutes(data.duration) : undefined;
|
data.duration != null ? millisToMinutes(data.duration) : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable key={data.id} draggableId={data.id} index={index}>
|
<Draggable key={data.id} draggableId={data.id} index={index}>
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
@@ -40,11 +28,15 @@ export default function DelayBlock(props) {
|
|||||||
<span className={style.drag} {...provided.dragHandleProps}>
|
<span className={style.drag} {...provided.dragHandleProps}>
|
||||||
<FiMoreVertical />
|
<FiMoreVertical />
|
||||||
</span>
|
</span>
|
||||||
<TimeInput value={delayValue} submitHandler={submitHandler} />
|
<DelayInput
|
||||||
|
className={style.input}
|
||||||
|
value={delayValue}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
/>
|
||||||
<div className={style.actionOverlay}>
|
<div className={style.actionOverlay}>
|
||||||
<ApplyIconBtn clickhandler={applyDelayHandler} />
|
<ApplyIconBtn clickhandler={applyDelayHandler} />
|
||||||
<DeleteIconBtn clickhandler={deleteHandler} />
|
<DeleteIconBtn actionHandler={actionHandler} />
|
||||||
<ActionButtons showAdd addHandler={addHandler} />
|
<ActionButtons showAdd actionHandler={actionHandler} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/* ============= COMMON ============= */
|
||||||
|
|
||||||
|
.delay {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2em 1fr auto;
|
||||||
|
grid-template-areas: 'drag inpt btns';
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
background-color: #ecc94b;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(214, 158, 46, 0.4) 0%,
|
||||||
|
rgba(236, 201, 75, 0.4) 20%,
|
||||||
|
rgba(214, 158, 46, 0.07) 21%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================ DRAG ================ */
|
||||||
|
|
||||||
|
.drag {
|
||||||
|
grid-area: drag;
|
||||||
|
color: rgba(255, 255, 255, 0.67);
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============== INPUT ================ */
|
||||||
|
|
||||||
|
.input {
|
||||||
|
grid-area: inpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============== ACTION ================ */
|
||||||
|
|
||||||
|
.actionOverlay {
|
||||||
|
grid-area: btns;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: center;
|
||||||
|
align-self: flex-start;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
gap: 0.5em;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay:hover > .actionOverlay {
|
||||||
|
opacity: 1;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NA */
|
||||||
|
.actionOverlay:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
import { FiChevronDown, FiChevronUp, FiMoreVertical } from 'react-icons/fi';
|
||||||
|
import { memo, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { showErrorToast } from '../../../common/helpers/toastManager';
|
||||||
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
|
import EventTimes from '../../../common/components/eventTimes/EventTimes';
|
||||||
|
// import common from './Block.module.css';
|
||||||
|
import style from './EventBlock.module.css';
|
||||||
|
import EditableText from '../../../common/input/EditableText';
|
||||||
|
import DelayValue from '../../../common/input/DelayValue';
|
||||||
|
import ActionButtons from './ActionButtons';
|
||||||
|
import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn';
|
||||||
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
|
|
||||||
|
const areEqual = (prevProps, nextProps) => {
|
||||||
|
return (
|
||||||
|
prevProps.data.revision === nextProps.data.revision &&
|
||||||
|
prevProps.selected === nextProps.selected &&
|
||||||
|
prevProps.next === nextProps.next &&
|
||||||
|
prevProps.index === nextProps.index &&
|
||||||
|
prevProps.delay === nextProps.delay
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const EventBlock = (props) => {
|
||||||
|
const { data, selected, next, delay, index, eventsHandler } = props;
|
||||||
|
|
||||||
|
const [more, setMore] = useState(true);
|
||||||
|
const [visible, setVisible] = useState(data.isPublic || false);
|
||||||
|
|
||||||
|
// Set visibility indicator
|
||||||
|
useEffect(() => {
|
||||||
|
setVisible(data.isPublic);
|
||||||
|
}, [data.isPublic]);
|
||||||
|
|
||||||
|
// Create / delete new events
|
||||||
|
const actionHandler = (action) => {
|
||||||
|
switch (action) {
|
||||||
|
case 'event':
|
||||||
|
eventsHandler('add', { type: 'event', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'delay':
|
||||||
|
eventsHandler('add', { type: 'delay', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'block':
|
||||||
|
eventsHandler('add', { type: 'block', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
eventsHandler('delete', data.id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update data in fields
|
||||||
|
const updateValues = (field, value) => {
|
||||||
|
// validate field
|
||||||
|
if (field in data) {
|
||||||
|
// create object with new field
|
||||||
|
const newData = { id: data.id, [field]: value };
|
||||||
|
|
||||||
|
// request update in parent
|
||||||
|
eventsHandler('patch', newData);
|
||||||
|
} else {
|
||||||
|
showErrorToast('Field Error: ' + field);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTitleSubmit = (v) => {
|
||||||
|
updateValues('title', v);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubtitleSubmit = (v) => {
|
||||||
|
updateValues('subtitle', v);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePresenterSubmit = (v) => {
|
||||||
|
updateValues('presenter', v);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNoteSubmit = (v) => {
|
||||||
|
updateValues('note', v);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleVisibleToggle = useCallback(() => {
|
||||||
|
const viz = !data.isPublic || !visible;
|
||||||
|
updateValues('isPublic', viz);
|
||||||
|
}, [data.isPublic, visible, updateValues]);
|
||||||
|
|
||||||
|
// TODO: inside useEffect()
|
||||||
|
const isSelected = selected ? style.active : '';
|
||||||
|
const isExpanded = more ? style.expanded : style.collapsed;
|
||||||
|
const classSelect = ` ${style.event} ${isExpanded} ${isSelected}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Draggable key={data.id} draggableId={data.id} index={index}>
|
||||||
|
{(provided) => (
|
||||||
|
<div
|
||||||
|
className={classSelect}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
ref={provided.innerRef}
|
||||||
|
>
|
||||||
|
<span className={style.drag} {...provided.dragHandleProps}>
|
||||||
|
<FiMoreVertical />
|
||||||
|
</span>
|
||||||
|
<div className={style.indicators}>
|
||||||
|
<div className={next ? style.next : style.nextDisabled}>Next</div>
|
||||||
|
<DelayValue delay={delay} />
|
||||||
|
</div>
|
||||||
|
<EventTimes
|
||||||
|
updateValues={updateValues}
|
||||||
|
timeStart={data.timeStart}
|
||||||
|
timeEnd={data.timeEnd}
|
||||||
|
delay={delay}
|
||||||
|
className={style.time}
|
||||||
|
/>
|
||||||
|
{more && <div className={style.start}>Start Time</div>}
|
||||||
|
{more && <div className={style.end}>End Time</div>}
|
||||||
|
{more && <div className={style.duration}>Duration</div>}
|
||||||
|
|
||||||
|
<div className={style.rowDetailed}>
|
||||||
|
{more ? (
|
||||||
|
<div className={style.titleContainer}>
|
||||||
|
<EditableText
|
||||||
|
label='Title'
|
||||||
|
defaultValue={data.title}
|
||||||
|
placeholder='Add Title'
|
||||||
|
submitHandler={handleTitleSubmit}
|
||||||
|
underlined
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='Presenter'
|
||||||
|
defaultValue={data.presenter}
|
||||||
|
placeholder='Add Presenter name'
|
||||||
|
submitHandler={handlePresenterSubmit}
|
||||||
|
underlined
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='Subtitle'
|
||||||
|
defaultValue={data.subtitle}
|
||||||
|
placeholder='Add Subtitle'
|
||||||
|
submitHandler={handleSubtitleSubmit}
|
||||||
|
underlined
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='note'
|
||||||
|
defaultValue={data.note}
|
||||||
|
placeholder='Add note'
|
||||||
|
submitHandler={handleNoteSubmit}
|
||||||
|
underlined
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={style.titleContainer}>
|
||||||
|
<EditableText
|
||||||
|
label='Title'
|
||||||
|
defaultValue={data.title}
|
||||||
|
placeholder='Add Title'
|
||||||
|
submitHandler={handleTitleSubmit}
|
||||||
|
isTight
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={style.more} onClick={() => setMore(!more)}>
|
||||||
|
{more ? <FiChevronUp /> : <FiChevronDown />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={style.actionOverlay}>
|
||||||
|
<VisibleIconBtn
|
||||||
|
clickhandler={handleVisibleToggle}
|
||||||
|
active={visible}
|
||||||
|
/>
|
||||||
|
<DeleteIconBtn actionHandler={actionHandler} />
|
||||||
|
<ActionButtons
|
||||||
|
showAdd
|
||||||
|
showDelay
|
||||||
|
showBlock
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(EventBlock, areEqual);
|
||||||
|
// export default EventBlock;
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
|
import Icon from '@chakra-ui/icon';
|
||||||
import { FiChevronDown, FiChevronUp, FiMoreVertical } from 'react-icons/fi';
|
import { FiChevronDown, FiChevronUp, FiMoreVertical } from 'react-icons/fi';
|
||||||
import { memo, useEffect, useState } from 'react';
|
import { memo, useState } from 'react';
|
||||||
import { showErrorToast } from '../../../common/helpers/toastManager';
|
|
||||||
import { Draggable } from 'react-beautiful-dnd';
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
import EventTimes from '../../../common/components/eventTimes/EventTimes';
|
import EventTimes from '../../../common/components/eventTimes/EventTimes';
|
||||||
import style from './Block.module.css';
|
import EventTimesVertical from '../../../common/components/eventTimes/EventTimesVertical';
|
||||||
import EditableText from '../../../common/input/EditableText';
|
import EditableText from '../../../common/input/EditableText';
|
||||||
import DelayValue from '../../../common/input/DelayValue';
|
|
||||||
import ActionButtons from './ActionButtons';
|
import ActionButtons from './ActionButtons';
|
||||||
import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn';
|
import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn';
|
||||||
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
|
import { millisToMinutes } from '../../../common/dateConfig';
|
||||||
|
import style from './EventBlock.module.css';
|
||||||
|
|
||||||
const areEqual = (prevProps, nextProps) => {
|
const areEqual = (prevProps, nextProps) => {
|
||||||
return (
|
return (
|
||||||
@@ -20,147 +21,181 @@ const areEqual = (prevProps, nextProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ExpandedBlock = (props) => {
|
||||||
|
const { provided, data, next, delay, delayValue, actionHandler } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={style.drag} {...provided.dragHandleProps}>
|
||||||
|
<FiMoreVertical />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className={style.indicators}>
|
||||||
|
<span className={next ? style.next : style.nextDisabled}>Next</span>
|
||||||
|
{delayValue != null && (
|
||||||
|
<span className={style.delayValue}>+ {delayValue}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={style.timeExpanded}>
|
||||||
|
<EventTimesVertical
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
timeStart={data.timeStart}
|
||||||
|
timeEnd={data.timeEnd}
|
||||||
|
delay={delay}
|
||||||
|
className={style.time}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={style.titleContainer}>
|
||||||
|
<EditableText
|
||||||
|
label='Title'
|
||||||
|
defaultValue={data.title}
|
||||||
|
placeholder='Add Title'
|
||||||
|
submitHandler={(v) =>
|
||||||
|
actionHandler('update', { field: 'title', value: v })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='Presenter'
|
||||||
|
defaultValue={data.presenter}
|
||||||
|
placeholder='Add Presenter name'
|
||||||
|
submitHandler={(v) =>
|
||||||
|
actionHandler('update', { field: 'presenter', value: v })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='Subtitle'
|
||||||
|
defaultValue={data.subtitle}
|
||||||
|
placeholder='Add Subtitle'
|
||||||
|
submitHandler={(v) =>
|
||||||
|
actionHandler('update', { field: 'subtitle', value: v })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EditableText
|
||||||
|
label='Note'
|
||||||
|
defaultValue={data.note}
|
||||||
|
placeholder='Add Note'
|
||||||
|
submitHandler={(v) =>
|
||||||
|
actionHandler('update', { field: 'note', value: v })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Icon
|
||||||
|
className={style.more}
|
||||||
|
as={FiChevronUp}
|
||||||
|
marginTop='0.2em'
|
||||||
|
gridArea='more'
|
||||||
|
onClick={() => props.setExpanded(false)}
|
||||||
|
/>
|
||||||
|
<div className={style.actionOverlay}>
|
||||||
|
<VisibleIconBtn actionHandler={actionHandler} active={data.isPublic} />
|
||||||
|
<ActionButtons
|
||||||
|
showAdd
|
||||||
|
showDelay
|
||||||
|
showBlock
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
/>
|
||||||
|
<DeleteIconBtn actionHandler={actionHandler} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CollapsedBlock = (props) => {
|
||||||
|
const { provided, data, next, delay, delayValue, actionHandler } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={style.drag} {...provided.dragHandleProps}>
|
||||||
|
<FiMoreVertical />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className={style.indicators}>
|
||||||
|
<span className={next ? style.next : style.nextDisabled}>Next</span>
|
||||||
|
{delayValue != null && (
|
||||||
|
<span className={style.delayValue}>+ {delayValue}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<EventTimes
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
timeStart={data.timeStart}
|
||||||
|
timeEnd={data.timeEnd}
|
||||||
|
delay={delay}
|
||||||
|
className={style.time}
|
||||||
|
/>
|
||||||
|
<div className={style.titleContainer}>
|
||||||
|
<EditableText
|
||||||
|
label='Title'
|
||||||
|
defaultValue={data.title}
|
||||||
|
placeholder='Add Title'
|
||||||
|
submitHandler={(v) =>
|
||||||
|
actionHandler('update', { field: 'title', value: v })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Icon
|
||||||
|
className={style.more}
|
||||||
|
as={FiChevronDown}
|
||||||
|
marginTop='0.2em'
|
||||||
|
gridArea='more'
|
||||||
|
onClick={() => props.setExpanded(true)}
|
||||||
|
/>
|
||||||
|
<div className={style.actionOverlay}>
|
||||||
|
<VisibleIconBtn actionHandler={actionHandler} active={data.isPublic} />
|
||||||
|
<ActionButtons
|
||||||
|
showAdd
|
||||||
|
showDelay
|
||||||
|
showBlock
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const EventBlock = (props) => {
|
const EventBlock = (props) => {
|
||||||
const { data, selected, next, delay, index, eventsHandler } = props;
|
const { data, selected, delay, index, actionHandler } = props;
|
||||||
|
|
||||||
const [more, setMore] = useState(true);
|
const [expanded, setExpanded] = useState(true);
|
||||||
const [visible, setVisible] = useState(data.isPublic || false);
|
|
||||||
|
|
||||||
// Set visibility indicator
|
// TODO: should this go inside useEffect()
|
||||||
useEffect(() => {
|
// Would I then need to add this to state?
|
||||||
setVisible(data.isPublic);
|
const isSelected = selected ? style.active : '';
|
||||||
}, [data.isPublic]);
|
const isExpanded = expanded ? style.expanded : style.collapsed;
|
||||||
|
const classSelect = `${style.event} ${isExpanded} ${isSelected}`;
|
||||||
|
|
||||||
const updateValues = (field, value) => {
|
// Calculate delay in min
|
||||||
// validate field
|
const delayValue = delay > 0 ? millisToMinutes(delay) : null;
|
||||||
if (field in data) {
|
|
||||||
// create object with new field
|
|
||||||
const newData = { id: data.id, [field]: value };
|
|
||||||
|
|
||||||
// request update in parent
|
|
||||||
eventsHandler('patch', newData);
|
|
||||||
} else {
|
|
||||||
showErrorToast('Field Error: ' + field);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const addHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'event', order: index + 1 });
|
|
||||||
};
|
|
||||||
const delayHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'delay', order: index + 1 });
|
|
||||||
};
|
|
||||||
const blockHandler = () => {
|
|
||||||
eventsHandler('add', { type: 'block', order: index + 1 });
|
|
||||||
};
|
|
||||||
const deleteHandler = () => {
|
|
||||||
eventsHandler('delete', data.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTitleSubmit = (v) => {
|
|
||||||
updateValues('title', v);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubtitleSubmit = (v) => {
|
|
||||||
updateValues('subtitle', v);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePresenterSubmit = (v) => {
|
|
||||||
updateValues('presenter', v);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNoteSubmit = (v) => {
|
|
||||||
updateValues('note', v);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVisibleToggle = () => {
|
|
||||||
let viz = !data.isPublic || !visible;
|
|
||||||
updateValues('isPublic', viz);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable key={data.id} draggableId={data.id} index={index}>
|
<Draggable key={data.id} draggableId={data.id} index={index}>
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<div
|
<div
|
||||||
className={selected ? style.eventRowActive : style.eventRow}
|
className={classSelect}
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
>
|
>
|
||||||
<span className={style.drag} {...provided.dragHandleProps}>
|
{expanded ? (
|
||||||
<FiMoreVertical />
|
<ExpandedBlock
|
||||||
</span>
|
provided={provided}
|
||||||
<div className={style.indicators}>
|
data={data}
|
||||||
<div className={next ? style.next : style.nextDisabled}>Next</div>
|
next={props.next}
|
||||||
<DelayValue delay={delay} />
|
delay={delay}
|
||||||
</div>
|
delayValue={delayValue}
|
||||||
<EventTimes
|
actionHandler={actionHandler}
|
||||||
updateValues={updateValues}
|
setExpanded={setExpanded}
|
||||||
timeStart={data.timeStart}
|
|
||||||
timeEnd={data.timeEnd}
|
|
||||||
delay={delay}
|
|
||||||
/>
|
|
||||||
<div className={style.rowDetailed}>
|
|
||||||
{more ? (
|
|
||||||
<div className={style.detailedContainer}>
|
|
||||||
<EditableText
|
|
||||||
label='Title'
|
|
||||||
defaultValue={data.title}
|
|
||||||
placeholder='Add Title'
|
|
||||||
submitHandler={handleTitleSubmit}
|
|
||||||
underlined
|
|
||||||
/>
|
|
||||||
<EditableText
|
|
||||||
label='Presenter'
|
|
||||||
defaultValue={data.presenter}
|
|
||||||
placeholder='Add Presenter name'
|
|
||||||
submitHandler={handlePresenterSubmit}
|
|
||||||
underlined
|
|
||||||
/>
|
|
||||||
<EditableText
|
|
||||||
label='Subtitle'
|
|
||||||
defaultValue={data.subtitle}
|
|
||||||
placeholder='Add Subtitle'
|
|
||||||
submitHandler={handleSubtitleSubmit}
|
|
||||||
underlined
|
|
||||||
/>
|
|
||||||
<EditableText
|
|
||||||
label='note'
|
|
||||||
defaultValue={data.note}
|
|
||||||
placeholder='Add note'
|
|
||||||
submitHandler={handleNoteSubmit}
|
|
||||||
underlined
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className={style.titleContainer}>
|
|
||||||
<EditableText
|
|
||||||
label='Title'
|
|
||||||
defaultValue={data.title}
|
|
||||||
placeholder='Add Title'
|
|
||||||
submitHandler={handleTitleSubmit}
|
|
||||||
isTight
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className={style.more} onClick={() => setMore(!more)}>
|
|
||||||
{more ? <FiChevronUp /> : <FiChevronDown />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={style.actionOverlay}>
|
|
||||||
<VisibleIconBtn
|
|
||||||
clickhandler={handleVisibleToggle}
|
|
||||||
active={visible}
|
|
||||||
/>
|
/>
|
||||||
<DeleteIconBtn clickhandler={deleteHandler} />
|
) : (
|
||||||
<ActionButtons
|
<CollapsedBlock
|
||||||
showAdd
|
provided={provided}
|
||||||
addHandler={addHandler}
|
data={data}
|
||||||
showDelay
|
next={props.next}
|
||||||
delayHandler={delayHandler}
|
delay={delay}
|
||||||
showBlock
|
delayValue={delayValue}
|
||||||
blockHandler={blockHandler}
|
actionHandler={actionHandler}
|
||||||
|
setExpanded={setExpanded}
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
@@ -168,4 +203,3 @@ const EventBlock = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(EventBlock, areEqual);
|
export default memo(EventBlock, areEqual);
|
||||||
// export default EventBlock;
|
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
/* ============= COMMON ============= */
|
||||||
|
.event {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
background-color: rgba(255, 255, 255, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.36);
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
#00000000 10%,
|
||||||
|
#4bffab10 97%,
|
||||||
|
#227c52aa 98%,
|
||||||
|
#4bffabcc 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
grid-template-columns: 2em 2em auto auto 1fr auto 3.7em;
|
||||||
|
grid-template-areas: 'drag indi time time text more btns';
|
||||||
|
justify-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded {
|
||||||
|
grid-template-columns: 2em 2em 2em auto 1fr auto 3.7em;
|
||||||
|
grid-template-rows: repeat(4, 1fr);
|
||||||
|
grid-template-areas:
|
||||||
|
'drag indi time time text more btns'
|
||||||
|
'.... indi time time text .... btns'
|
||||||
|
'.... indi time time text .... btns'
|
||||||
|
'.... indi time time text .... btns';
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================ DRAG ================ */
|
||||||
|
|
||||||
|
.drag {
|
||||||
|
grid-area: drag;
|
||||||
|
color: rgba(255, 255, 255, 0.67);
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= INDICATORS ============= */
|
||||||
|
.indicators {
|
||||||
|
grid-area: indi;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-self: flex-start;
|
||||||
|
font-size: 0.75em;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next,
|
||||||
|
.nextDisabled {
|
||||||
|
width: max-content;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
color: #4bffab;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nextDisabled {
|
||||||
|
opacity: 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delayValue {
|
||||||
|
color: #d69e2eaa;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
text-align: center;
|
||||||
|
align-self: flex-start;
|
||||||
|
width: max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next:after,
|
||||||
|
.delayValue:after {
|
||||||
|
content: '\200b';
|
||||||
|
}
|
||||||
|
/* =============== TIMES ================ */
|
||||||
|
|
||||||
|
.time {
|
||||||
|
grid-area: time;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start {
|
||||||
|
grid-area: star;
|
||||||
|
}
|
||||||
|
|
||||||
|
.end {
|
||||||
|
grid-area: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duration {
|
||||||
|
grid-area: dura;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeExpanded {
|
||||||
|
grid-area: time;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-items: flex-start;
|
||||||
|
|
||||||
|
background-color: rgba(255, 255, 255, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0 0.5em 0.5em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 0.75em;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculatedTime {
|
||||||
|
grid-area: time;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============== TITLES =============== */
|
||||||
|
|
||||||
|
.titleContainer {
|
||||||
|
grid-area: text;
|
||||||
|
display: inline-flex;
|
||||||
|
position: relative;
|
||||||
|
align-self: flex-start;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
background-color: rgba(255, 255, 255, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* ================ MORE ================ */
|
||||||
|
|
||||||
|
.more {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
/* ============== ACTION ================ */
|
||||||
|
|
||||||
|
.actionOverlay {
|
||||||
|
grid-area: btns;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: center;
|
||||||
|
align-self: flex-start;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
gap: 0.5em;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded > .actionOverlay {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event:hover > .actionOverlay {
|
||||||
|
opacity: 1;
|
||||||
|
transition: linear 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NA */
|
||||||
|
.actionOverlay:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import DelayBlock from './DelayBlock';
|
import DelayBlock from './DelayBlock';
|
||||||
import BlockBlock from './BlockBlock';
|
import BlockBlock from './BlockBlock';
|
||||||
import EventBlock from './EventBlock';
|
import EventBlock from './EventBlock';
|
||||||
|
import { showErrorToast } from '../../../common/helpers/toastManager';
|
||||||
|
|
||||||
export default function EventListItem(props) {
|
export default function EventListItem(props) {
|
||||||
const {
|
const {
|
||||||
@@ -14,6 +15,46 @@ export default function EventListItem(props) {
|
|||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
// Create / delete new events
|
||||||
|
const actionHandler = (action, payload) => {
|
||||||
|
switch (action) {
|
||||||
|
case 'event':
|
||||||
|
eventsHandler('add', { type: 'event', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'delay':
|
||||||
|
eventsHandler('add', { type: 'delay', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'block':
|
||||||
|
eventsHandler('add', { type: 'block', order: index + 1 });
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
eventsHandler('delete', data.id);
|
||||||
|
break;
|
||||||
|
case 'update':
|
||||||
|
// Handles and filters update requests
|
||||||
|
const { field, value } = payload;
|
||||||
|
if (field === 'durationOverride') {
|
||||||
|
// duration defines timeEnd
|
||||||
|
let end = (data.timeStart += value);
|
||||||
|
const newData = { id: data.id, timeEnd: end };
|
||||||
|
|
||||||
|
// request update in parent
|
||||||
|
eventsHandler('patch', newData);
|
||||||
|
} else if (field in data) {
|
||||||
|
// create object with new field
|
||||||
|
const newData = { id: data.id, [field]: value };
|
||||||
|
|
||||||
|
// request update in parent
|
||||||
|
eventsHandler('patch', newData);
|
||||||
|
} else {
|
||||||
|
showErrorToast('Field Error: ' + field);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'event':
|
case 'event':
|
||||||
return (
|
return (
|
||||||
@@ -22,17 +63,22 @@ export default function EventListItem(props) {
|
|||||||
data={data}
|
data={data}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
next={next}
|
next={next}
|
||||||
eventsHandler={eventsHandler}
|
actionHandler={actionHandler}
|
||||||
delay={delay}
|
delay={delay}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'block':
|
case 'block':
|
||||||
return (
|
return (
|
||||||
<BlockBlock index={index} data={data} eventsHandler={eventsHandler} />
|
<BlockBlock index={index} data={data} actionHandler={actionHandler} />
|
||||||
);
|
);
|
||||||
case 'delay':
|
case 'delay':
|
||||||
return (
|
return (
|
||||||
<DelayBlock index={index} data={data} eventsHandler={eventsHandler} />
|
<DelayBlock
|
||||||
|
index={index}
|
||||||
|
data={data}
|
||||||
|
eventsHandler={eventsHandler}
|
||||||
|
actionHandler={actionHandler}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user