mirror of
https://github.com/plankanban/planka.git
synced 2025-07-25 16:19:47 +02:00
parent
d627a5660a
commit
22ec8707ac
35 changed files with 179 additions and 161 deletions
|
@ -9,7 +9,7 @@ import { useSteps } from '../../hooks';
|
|||
import BoardMembershipsStep from '../BoardMembershipsStep';
|
||||
import LabelsStep from '../LabelsStep';
|
||||
import DueDateEditStep from '../DueDateEditStep';
|
||||
import TimerEditStep from '../TimerEditStep';
|
||||
import StopwatchEditStep from '../StopwatchEditStep';
|
||||
import CardMoveStep from '../CardMoveStep';
|
||||
import DeleteStep from '../DeleteStep';
|
||||
|
||||
|
@ -19,7 +19,7 @@ const StepTypes = {
|
|||
USERS: 'USERS',
|
||||
LABELS: 'LABELS',
|
||||
EDIT_DUE_DATE: 'EDIT_DUE_DATE',
|
||||
EDIT_TIMER: 'EDIT_TIMER',
|
||||
EDIT_STOPWATCH: 'EDIT_STOPWATCH',
|
||||
MOVE: 'MOVE',
|
||||
DELETE: 'DELETE',
|
||||
};
|
||||
|
@ -68,8 +68,8 @@ const ActionsStep = React.memo(
|
|||
openStep(StepTypes.EDIT_DUE_DATE);
|
||||
}, [openStep]);
|
||||
|
||||
const handleEditTimerClick = useCallback(() => {
|
||||
openStep(StepTypes.EDIT_TIMER);
|
||||
const handleEditStopwatchClick = useCallback(() => {
|
||||
openStep(StepTypes.EDIT_STOPWATCH);
|
||||
}, [openStep]);
|
||||
|
||||
const handleMoveClick = useCallback(() => {
|
||||
|
@ -89,10 +89,10 @@ const ActionsStep = React.memo(
|
|||
[onUpdate],
|
||||
);
|
||||
|
||||
const handleTimerUpdate = useCallback(
|
||||
(timer) => {
|
||||
const handleStopwatchUpdate = useCallback(
|
||||
(stopwatch) => {
|
||||
onUpdate({
|
||||
timer,
|
||||
stopwatch,
|
||||
});
|
||||
},
|
||||
[onUpdate],
|
||||
|
@ -133,11 +133,11 @@ const ActionsStep = React.memo(
|
|||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
case StepTypes.EDIT_TIMER:
|
||||
case StepTypes.EDIT_STOPWATCH:
|
||||
return (
|
||||
<TimerEditStep
|
||||
defaultValue={card.timer}
|
||||
onUpdate={handleTimerUpdate}
|
||||
<StopwatchEditStep
|
||||
defaultValue={card.stopwatch}
|
||||
onUpdate={handleStopwatchUpdate}
|
||||
onBack={handleBack}
|
||||
onClose={onClose}
|
||||
/>
|
||||
|
@ -197,8 +197,8 @@ const ActionsStep = React.memo(
|
|||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditTimerClick}>
|
||||
{t('action.editTimer', {
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditStopwatchClick}>
|
||||
{t('action.editStopwatch', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Link } from 'react-router-dom';
|
|||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { usePopup } from '../../lib/popup';
|
||||
|
||||
import { startTimer, stopTimer } from '../../utils/timer';
|
||||
import { startStopwatch, stopStopwatch } from '../../utils/stopwatch';
|
||||
import Paths from '../../constants/Paths';
|
||||
import Tasks from './Tasks';
|
||||
import NameEdit from './NameEdit';
|
||||
|
@ -14,7 +14,7 @@ import ActionsStep from './ActionsStep';
|
|||
import User from '../User';
|
||||
import Label from '../Label';
|
||||
import DueDate from '../DueDate';
|
||||
import Timer from '../Timer';
|
||||
import Stopwatch from '../Stopwatch';
|
||||
|
||||
import styles from './Card.module.scss';
|
||||
|
||||
|
@ -24,7 +24,7 @@ const Card = React.memo(
|
|||
index,
|
||||
name,
|
||||
dueDate,
|
||||
timer,
|
||||
stopwatch,
|
||||
coverUrl,
|
||||
boardId,
|
||||
listId,
|
||||
|
@ -60,15 +60,15 @@ const Card = React.memo(
|
|||
}
|
||||
}, []);
|
||||
|
||||
const handleToggleTimerClick = useCallback(
|
||||
const handleToggleStopwatchClick = useCallback(
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
onUpdate({
|
||||
timer: timer.startedAt ? stopTimer(timer) : startTimer(timer),
|
||||
stopwatch: stopwatch.startedAt ? stopStopwatch(stopwatch) : startStopwatch(stopwatch),
|
||||
});
|
||||
},
|
||||
[timer, onUpdate],
|
||||
[stopwatch, onUpdate],
|
||||
);
|
||||
|
||||
const handleNameUpdate = useCallback(
|
||||
|
@ -104,7 +104,7 @@ const Card = React.memo(
|
|||
)}
|
||||
<div className={styles.name}>{name}</div>
|
||||
{tasks.length > 0 && <Tasks items={tasks} />}
|
||||
{(dueDate || timer || notificationsTotal > 0) && (
|
||||
{(dueDate || stopwatch || notificationsTotal > 0) && (
|
||||
<span className={styles.attachments}>
|
||||
{notificationsTotal > 0 && (
|
||||
<span
|
||||
|
@ -122,14 +122,14 @@ const Card = React.memo(
|
|||
<DueDate value={dueDate} size="tiny" />
|
||||
</span>
|
||||
)}
|
||||
{timer && (
|
||||
{stopwatch && (
|
||||
<span className={classNames(styles.attachment, styles.attachmentLeft)}>
|
||||
<Timer
|
||||
<Stopwatch
|
||||
as="span"
|
||||
startedAt={timer.startedAt}
|
||||
total={timer.total}
|
||||
startedAt={stopwatch.startedAt}
|
||||
total={stopwatch.total}
|
||||
size="tiny"
|
||||
onClick={canEdit ? handleToggleTimerClick : undefined}
|
||||
onClick={canEdit ? handleToggleStopwatchClick : undefined}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
|
@ -171,7 +171,7 @@ const Card = React.memo(
|
|||
<ActionsPopup
|
||||
card={{
|
||||
dueDate,
|
||||
timer,
|
||||
stopwatch,
|
||||
boardId,
|
||||
listId,
|
||||
projectId,
|
||||
|
@ -219,7 +219,7 @@ Card.propTypes = {
|
|||
index: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
dueDate: PropTypes.instanceOf(Date),
|
||||
timer: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
stopwatch: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
coverUrl: PropTypes.string,
|
||||
boardId: PropTypes.string.isRequired,
|
||||
listId: PropTypes.string.isRequired,
|
||||
|
@ -252,7 +252,7 @@ Card.propTypes = {
|
|||
|
||||
Card.defaultProps = {
|
||||
dueDate: undefined,
|
||||
timer: undefined,
|
||||
stopwatch: undefined,
|
||||
coverUrl: undefined,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Button, Grid, Icon, Modal } from 'semantic-ui-react';
|
|||
import { usePopup } from '../../lib/popup';
|
||||
import { Markdown } from '../../lib/custom-ui';
|
||||
|
||||
import { startTimer, stopTimer } from '../../utils/timer';
|
||||
import { startStopwatch, stopStopwatch } from '../../utils/stopwatch';
|
||||
import NameField from './NameField';
|
||||
import DescriptionEdit from './DescriptionEdit';
|
||||
import Tasks from './Tasks';
|
||||
|
@ -17,11 +17,11 @@ import Activities from './Activities';
|
|||
import User from '../User';
|
||||
import Label from '../Label';
|
||||
import DueDate from '../DueDate';
|
||||
import Timer from '../Timer';
|
||||
import Stopwatch from '../Stopwatch';
|
||||
import BoardMembershipsStep from '../BoardMembershipsStep';
|
||||
import LabelsStep from '../LabelsStep';
|
||||
import DueDateEditStep from '../DueDateEditStep';
|
||||
import TimerEditStep from '../TimerEditStep';
|
||||
import StopwatchEditStep from '../StopwatchEditStep';
|
||||
import CardMoveStep from '../CardMoveStep';
|
||||
import DeleteStep from '../DeleteStep';
|
||||
|
||||
|
@ -32,7 +32,7 @@ const CardModal = React.memo(
|
|||
name,
|
||||
description,
|
||||
dueDate,
|
||||
timer,
|
||||
stopwatch,
|
||||
isSubscribed,
|
||||
isActivitiesFetching,
|
||||
isAllActivitiesFetched,
|
||||
|
@ -83,11 +83,11 @@ const CardModal = React.memo(
|
|||
|
||||
const isGalleryOpened = useRef(false);
|
||||
|
||||
const handleToggleTimerClick = useCallback(() => {
|
||||
const handleToggleStopwatchClick = useCallback(() => {
|
||||
onUpdate({
|
||||
timer: timer.startedAt ? stopTimer(timer) : startTimer(timer),
|
||||
stopwatch: stopwatch.startedAt ? stopStopwatch(stopwatch) : startStopwatch(stopwatch),
|
||||
});
|
||||
}, [timer, onUpdate]);
|
||||
}, [stopwatch, onUpdate]);
|
||||
|
||||
const handleNameUpdate = useCallback(
|
||||
(newName) => {
|
||||
|
@ -116,10 +116,10 @@ const CardModal = React.memo(
|
|||
[onUpdate],
|
||||
);
|
||||
|
||||
const handleTimerUpdate = useCallback(
|
||||
(newTimer) => {
|
||||
const handleStopwatchUpdate = useCallback(
|
||||
(newStopwatch) => {
|
||||
onUpdate({
|
||||
timer: newTimer,
|
||||
stopwatch: newStopwatch,
|
||||
});
|
||||
},
|
||||
[onUpdate],
|
||||
|
@ -160,7 +160,7 @@ const CardModal = React.memo(
|
|||
const BoardMembershipsPopup = usePopup(BoardMembershipsStep);
|
||||
const LabelsPopup = usePopup(LabelsStep);
|
||||
const DueDateEditPopup = usePopup(DueDateEditStep);
|
||||
const TimerEditPopup = usePopup(TimerEditStep);
|
||||
const StopwatchEditPopup = usePopup(StopwatchEditStep);
|
||||
const CardMovePopup = usePopup(CardMoveStep);
|
||||
const DeletePopup = usePopup(DeleteStep);
|
||||
|
||||
|
@ -185,7 +185,7 @@ const CardModal = React.memo(
|
|||
</Grid.Row>
|
||||
<Grid.Row className={styles.modalPadding}>
|
||||
<Grid.Column width={canEdit ? 12 : 16} className={styles.contentPadding}>
|
||||
{(users.length > 0 || labels.length > 0 || dueDate || timer) && (
|
||||
{(users.length > 0 || labels.length > 0 || dueDate || stopwatch) && (
|
||||
<div className={styles.moduleWrapper}>
|
||||
{users.length > 0 && (
|
||||
<div className={styles.attachments}>
|
||||
|
@ -294,30 +294,33 @@ const CardModal = React.memo(
|
|||
</span>
|
||||
</div>
|
||||
)}
|
||||
{timer && (
|
||||
{stopwatch && (
|
||||
<div className={styles.attachments}>
|
||||
<div className={styles.text}>
|
||||
{t('common.timer', {
|
||||
{t('common.stopwatch', {
|
||||
context: 'title',
|
||||
})}
|
||||
</div>
|
||||
<span className={styles.attachment}>
|
||||
{canEdit ? (
|
||||
<TimerEditPopup defaultValue={timer} onUpdate={handleTimerUpdate}>
|
||||
<Timer startedAt={timer.startedAt} total={timer.total} />
|
||||
</TimerEditPopup>
|
||||
<StopwatchEditPopup
|
||||
defaultValue={stopwatch}
|
||||
onUpdate={handleStopwatchUpdate}
|
||||
>
|
||||
<Stopwatch startedAt={stopwatch.startedAt} total={stopwatch.total} />
|
||||
</StopwatchEditPopup>
|
||||
) : (
|
||||
<Timer startedAt={timer.startedAt} total={timer.total} />
|
||||
<Stopwatch startedAt={stopwatch.startedAt} total={stopwatch.total} />
|
||||
)}
|
||||
</span>
|
||||
{canEdit && (
|
||||
<button
|
||||
onClick={handleToggleTimerClick}
|
||||
onClick={handleToggleStopwatchClick}
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon
|
||||
name={timer.startedAt ? 'pause' : 'play'}
|
||||
name={stopwatch.startedAt ? 'pause' : 'play'}
|
||||
size="small"
|
||||
className={styles.addAttachment}
|
||||
/>
|
||||
|
@ -447,12 +450,12 @@ const CardModal = React.memo(
|
|||
})}
|
||||
</Button>
|
||||
</DueDateEditPopup>
|
||||
<TimerEditPopup defaultValue={timer} onUpdate={handleTimerUpdate}>
|
||||
<StopwatchEditPopup defaultValue={stopwatch} onUpdate={handleStopwatchUpdate}>
|
||||
<Button fluid className={styles.actionButton}>
|
||||
<Icon name="clock outline" className={styles.actionIcon} />
|
||||
{t('common.timer')}
|
||||
{t('common.stopwatch')}
|
||||
</Button>
|
||||
</TimerEditPopup>
|
||||
</StopwatchEditPopup>
|
||||
<AttachmentAddPopup onCreate={onAttachmentCreate}>
|
||||
<Button fluid className={styles.actionButton}>
|
||||
<Icon name="attach" className={styles.actionIcon} />
|
||||
|
@ -524,7 +527,7 @@ CardModal.propTypes = {
|
|||
name: PropTypes.string.isRequired,
|
||||
description: PropTypes.string,
|
||||
dueDate: PropTypes.instanceOf(Date),
|
||||
timer: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
stopwatch: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
isSubscribed: PropTypes.bool.isRequired,
|
||||
isActivitiesFetching: PropTypes.bool.isRequired,
|
||||
isAllActivitiesFetched: PropTypes.bool.isRequired,
|
||||
|
@ -577,7 +580,7 @@ CardModal.propTypes = {
|
|||
CardModal.defaultProps = {
|
||||
description: undefined,
|
||||
dueDate: undefined,
|
||||
timer: undefined,
|
||||
stopwatch: undefined,
|
||||
};
|
||||
|
||||
export default CardModal;
|
||||
|
|
|
@ -4,9 +4,9 @@ import PropTypes from 'prop-types';
|
|||
import classNames from 'classnames';
|
||||
import { useForceUpdate, usePrevious } from '../../lib/hooks';
|
||||
|
||||
import { formatTimer } from '../../utils/timer';
|
||||
import { formatStopwatch } from '../../utils/stopwatch';
|
||||
|
||||
import styles from './Timer.module.scss';
|
||||
import styles from './Stopwatch.module.scss';
|
||||
|
||||
const SIZES = {
|
||||
TINY: 'tiny',
|
||||
|
@ -14,7 +14,7 @@ const SIZES = {
|
|||
MEDIUM: 'medium',
|
||||
};
|
||||
|
||||
const Timer = React.memo(({ as, startedAt, total, size, isDisabled, onClick }) => {
|
||||
const Stopwatch = React.memo(({ as, startedAt, total, size, isDisabled, onClick }) => {
|
||||
const prevStartedAt = usePrevious(startedAt);
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
|
@ -56,7 +56,7 @@ const Timer = React.memo(({ as, startedAt, total, size, isDisabled, onClick }) =
|
|||
onClick && styles.wrapperHoverable,
|
||||
)}
|
||||
>
|
||||
{formatTimer({ startedAt, total })}
|
||||
{formatStopwatch({ startedAt, total })}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
@ -71,7 +71,7 @@ const Timer = React.memo(({ as, startedAt, total, size, isDisabled, onClick }) =
|
|||
);
|
||||
});
|
||||
|
||||
Timer.propTypes = {
|
||||
Stopwatch.propTypes = {
|
||||
as: PropTypes.elementType,
|
||||
startedAt: PropTypes.instanceOf(Date),
|
||||
total: PropTypes.number.isRequired, // eslint-disable-line react/no-unused-prop-types
|
||||
|
@ -80,7 +80,7 @@ Timer.propTypes = {
|
|||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
Timer.defaultProps = {
|
||||
Stopwatch.defaultProps = {
|
||||
as: 'button',
|
||||
startedAt: undefined,
|
||||
size: SIZES.MEDIUM,
|
||||
|
@ -88,4 +88,4 @@ Timer.defaultProps = {
|
|||
onClick: undefined,
|
||||
};
|
||||
|
||||
export default Timer;
|
||||
export default Stopwatch;
|
3
client/src/components/Stopwatch/index.js
Normal file
3
client/src/components/Stopwatch/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Stopwatch from './Stopwatch';
|
||||
|
||||
export default Stopwatch;
|
|
@ -7,12 +7,18 @@ import { useToggle } from '../../lib/hooks';
|
|||
import { Input, Popup } from '../../lib/custom-ui';
|
||||
|
||||
import { useForm } from '../../hooks';
|
||||
import { createTimer, getTimerParts, startTimer, stopTimer, updateTimer } from '../../utils/timer';
|
||||
import {
|
||||
createStopwatch,
|
||||
getStopwatchParts,
|
||||
startStopwatch,
|
||||
stopStopwatch,
|
||||
updateStopwatch,
|
||||
} from '../../utils/stopwatch';
|
||||
|
||||
import styles from './TimerEditStep.module.scss';
|
||||
import styles from './StopwatchEditStep.module.scss';
|
||||
|
||||
const createData = (timer) => {
|
||||
if (!timer) {
|
||||
const createData = (stopwatch) => {
|
||||
if (!stopwatch) {
|
||||
return {
|
||||
hours: '0',
|
||||
minutes: '0',
|
||||
|
@ -20,7 +26,7 @@ const createData = (timer) => {
|
|||
};
|
||||
}
|
||||
|
||||
const { hours, minutes, seconds } = getTimerParts(timer);
|
||||
const { hours, minutes, seconds } = getStopwatchParts(stopwatch);
|
||||
|
||||
return {
|
||||
hours: `${hours}`,
|
||||
|
@ -29,7 +35,7 @@ const createData = (timer) => {
|
|||
};
|
||||
};
|
||||
|
||||
const TimerEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) => {
|
||||
const StopwatchEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
const [data, handleFieldChange, setData] = useForm(() => createData(defaultValue));
|
||||
const [isEditing, toggleEditing] = useToggle();
|
||||
|
@ -39,12 +45,12 @@ const TimerEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) =
|
|||
const secondsField = useRef(null);
|
||||
|
||||
const handleStartClick = useCallback(() => {
|
||||
onUpdate(startTimer(defaultValue));
|
||||
onUpdate(startStopwatch(defaultValue));
|
||||
onClose();
|
||||
}, [defaultValue, onUpdate, onClose]);
|
||||
|
||||
const handleStopClick = useCallback(() => {
|
||||
onUpdate(stopTimer(defaultValue));
|
||||
onUpdate(stopStopwatch(defaultValue));
|
||||
}, [defaultValue, onUpdate]);
|
||||
|
||||
const handleClearClick = useCallback(() => {
|
||||
|
@ -83,11 +89,11 @@ const TimerEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) =
|
|||
}
|
||||
|
||||
if (defaultValue) {
|
||||
if (!dequal(parts, getTimerParts(defaultValue))) {
|
||||
onUpdate(updateTimer(defaultValue, parts));
|
||||
if (!dequal(parts, getStopwatchParts(defaultValue))) {
|
||||
onUpdate(updateStopwatch(defaultValue, parts));
|
||||
}
|
||||
} else {
|
||||
onUpdate(createTimer(parts));
|
||||
onUpdate(createStopwatch(parts));
|
||||
}
|
||||
|
||||
onClose();
|
||||
|
@ -102,7 +108,7 @@ const TimerEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) =
|
|||
return (
|
||||
<>
|
||||
<Popup.Header onBack={onBack}>
|
||||
{t('common.editTimer', {
|
||||
{t('common.editStopwatch', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
|
@ -171,16 +177,16 @@ const TimerEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) =
|
|||
);
|
||||
});
|
||||
|
||||
TimerEditStep.propTypes = {
|
||||
StopwatchEditStep.propTypes = {
|
||||
defaultValue: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
onBack: PropTypes.func,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
TimerEditStep.defaultProps = {
|
||||
StopwatchEditStep.defaultProps = {
|
||||
defaultValue: undefined,
|
||||
onBack: undefined,
|
||||
};
|
||||
|
||||
export default TimerEditStep;
|
||||
export default StopwatchEditStep;
|
3
client/src/components/StopwatchEditStep/index.js
Normal file
3
client/src/components/StopwatchEditStep/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import StopwatchEditStep from './StopwatchEditStep';
|
||||
|
||||
export default StopwatchEditStep;
|
|
@ -1,3 +0,0 @@
|
|||
import Timer from './Timer';
|
||||
|
||||
export default Timer;
|
|
@ -1,3 +0,0 @@
|
|||
import TimerEditStep from './TimerEditStep';
|
||||
|
||||
export default TimerEditStep;
|
Loading…
Add table
Add a link
Reference in a new issue