Files
ontime/client/src/features/editors/list/EventBlock.jsx
T
Carlos Valente 26cb8a5bfc Feat/seconds (#38)
* change directory structure

move test file to __tests__ at the module directory

* test function

Add more tests to ensure the function remains safe

* fix coverage filter

* change directory structure

move to utilities folder

* refract formatDisplay with tst

* test millis

* test millis to seconds

* refract millis functions

* refractor timeStringToMillis

* create utility consts

* style component

* fixed bug with hidezero parameter

* fix issue with cancelling input edit

* style tweak
2021-11-13 22:39:57 +01:00

207 lines
6.3 KiB
React

import Icon from '@chakra-ui/icon';
import { FiChevronUp, FiMoreVertical } from 'react-icons/fi';
import { useMemo } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import EventTimes from 'common/components/eventTimes/EventTimes';
import EventTimesVertical from 'common/components/eventTimes/EventTimesVertical';
import EditableText from 'common/input/EditableText';
import ActionButtons from './ActionButtons';
import PublicIconBtn from 'common/components/buttons/PublicIconBtn';
import DeleteIconBtn from 'common/components/buttons/DeleteIconBtn';
import { millisToMinutes } from 'common/utils/dateConfig';
import style from './EventBlock.module.css';
import { SelectCollapse, HandleCollapse } from 'app/context/collapseAtom';
import { useAtom } from 'jotai';
const ExpandedBlock = (props) => {
const { provided, data, eventIndex, next, delay, delayValue, actionHandler } =
props;
const oscid = data.id.length > 4 ? '...' : data.id;
// if end is before, assume is the day after
const duration =
data.timeStart > data.timeEnd
? data.timeEnd + 86400000 - data.timeStart
: data.timeEnd - data.timeStart;
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}
duration={duration}
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'
style={{ color: '#d69e2e' }}
maxchar={160}
submitHandler={(v) =>
actionHandler('update', { field: 'note', value: v })
}
/>
<span className={style.oscLabel}>
{`/ontime/goto ${eventIndex + 1} << OSC >> /ontime/gotoid ${oscid}`}
</span>
</div>
<div className={style.actionOverlay}>
<PublicIconBtn 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>
<div className={style.actionOverlay}>
<PublicIconBtn actionHandler={actionHandler} active={data.isPublic} />
<ActionButtons
showAdd
showDelay
showBlock
actionHandler={actionHandler}
/>
</div>
</>
);
};
export default function EventBlock(props) {
const { data, selected, delay, index, eventIndex, actionHandler } = props;
const [collapsed] = useAtom(
useMemo(() => SelectCollapse(data.id), [data.id])
);
const [, setCollapsed] = useAtom(HandleCollapse);
// TODO: should this go inside useEffect()
// Would I then need to add this to state?
const isSelected = selected ? style.active : '';
const isCollapsed = collapsed ? style.collapsed : style.expanded;
const classSelect = `${style.event} ${isCollapsed} ${isSelected}`;
// Calculate delay in min
const delayValue = delay > 0 ? millisToMinutes(delay) : null;
const handleCollapse = (isCollapsed) => {
setCollapsed({ [data.id]: isCollapsed });
};
return (
<Draggable key={data.id} draggableId={data.id} index={index}>
{(provided) => (
<div
className={classSelect}
{...provided.draggableProps}
ref={provided.innerRef}
>
<Icon
className={collapsed ? style.moreCollapsed : style.moreExpanded}
as={FiChevronUp}
onClick={() => handleCollapse(!collapsed)}
/>
{collapsed ? (
<CollapsedBlock
provided={provided}
data={data}
next={props.next}
delay={delay}
delayValue={delayValue}
actionHandler={actionHandler}
/>
) : (
<ExpandedBlock
provided={provided}
eventIndex={eventIndex}
data={data}
next={props.next}
delay={delay}
delayValue={delayValue}
actionHandler={actionHandler}
/>
)}
</div>
)}
</Draggable>
);
}