Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions newdle/client/src/components/ParticipantGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getNewdleTimeslots,
getNewdleTimezone,
} from '../selectors';
import CheckmarkParenIcon from './answer/CheckmarkParenIcon';
import {NameCell, TableHeader, TableFooter} from './GridCommon';
import styles from './GridCommon.module.scss';

Expand All @@ -27,17 +28,28 @@ function SummaryCell({
const status = participant.answers[timeslot];
const positive = status === 'available';
const negative = status === 'unavailable';
const warning = status === 'ifneedbe';
const statusColors = {available: 'green', ifneedbe: 'yellow', unavailable: 'red'};

let content = null;
if ((!limitedSlots && status) || (limitedSlots && positive)) {
content = (
<Icon
name={status !== 'unavailable' ? 'checkmark' : 'close'}
color={statusColors[status]}
size="large"
/>
);
if (status === 'ifneedbe') {
content = (
<CheckmarkParenIcon
className={`${statusColors[status]} icon`}
size="large"
color="#fbbd08"
/>
);
} else {
content = (
<Icon
name={status !== 'unavailable' ? 'checkmark' : 'close'}
color={statusColors[status]}
size="large"
/>
);
}
} else if (!status && hasAnswered) {
content = (
<Popup
Expand All @@ -60,6 +72,7 @@ function SummaryCell({
<Table.Cell
positive={positive}
negative={!limitedSlots && negative}
warning={!limitedSlots && warning}
key={timeslot}
textAlign="center"
className={className}
Expand Down
31 changes: 17 additions & 14 deletions newdle/client/src/components/ParticipantTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../selectors';
import {serializeDate, toMoment} from '../util/date';
import {useIsMobile} from '../util/hooks';
import CheckmarkParenIcon from './answer/CheckmarkParenIcon';
import AvailabilityRing from './AvailabilityRing';
import styles from './ParticipantTable.module.scss';

Expand All @@ -24,22 +25,24 @@ function formatMeetingTime(startTime, duration) {

function ParticipantNames({participants}) {
const [renderAll, setRenderAll] = useState(false);
const statusColors = {available: 'green', ifneedbe: 'yellow', unavailable: 'red'};

// eslint-disable-next-line react/prop-types
const renderName = ({name, comment, status, id}) => (
<div key={id} className={styles['user-element']}>
<Icon
name={status !== 'unavailable' ? 'checkmark' : 'close'}
color={statusColors[status]}
size="tiny"
circular
inverted
/>
{name}
<p className={styles['comment']}>{comment}</p>
</div>
);
const renderName = ({name, comment, status, id}) => {
const badgeStyle = styles[`status-badge--${status}`];
return (
<div key={id} className={styles['user-element']}>
<span className={`${styles['status-badge']} ${badgeStyle}`}>
{status === 'ifneedbe' ? (
<CheckmarkParenIcon size={12} />
) : (
<Icon name={status === 'unavailable' ? 'close' : 'checkmark'} size="small" fitted />
)}
</span>
{name}
<p className={styles['comment']}>{comment}</p>
</div>
);
};

// allow to exceed max by 1 since the "show +1" button takes the same space
// as actually showing the participant name
Expand Down
36 changes: 36 additions & 0 deletions newdle/client/src/components/ParticipantTable.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,39 @@
color: gray;
flex-basis: 100%;
}

.status-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
border-radius: 50%;
margin-right: 0.4rem;
flex-shrink: 0;
color: #fff;

> :global(.icon) {
margin: 0 !important;
font-size: 0.7rem !important;
line-height: 1 !important;
height: auto !important;
width: auto !important;
}

:global(.checkmark-paren-icon) {
display: block;
}
}

.status-badge--available {
background-color: #21ba45;
}

.status-badge--ifneedbe {
background-color: #fdc500;
}

.status-badge--unavailable {
background-color: #db2828;
}
27 changes: 20 additions & 7 deletions newdle/client/src/components/answer/AnswerGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import {getNewdleParticipants} from '../../selectors';
import {toMoment} from '../../util/date';
import {NameCell, TableHeader, TableFooter} from '../GridCommon';
import CheckmarkParenIcon from './CheckmarkParenIcon';
import styles from '../GridCommon.module.scss';

/**
Expand Down Expand Up @@ -79,6 +80,7 @@ function AnswerCell({
const status = participant.answers[timeslot];
const positive = status === 'available';
const negative = status === 'unavailable';
const warning = status === 'ifneedbe';

let busyPositions = [];
if (!unknown && hasBusyTimes) {
Expand All @@ -90,13 +92,23 @@ function AnswerCell({

let content = null;
if (!limitedSlots && status) {
content = (
<Icon
name={status !== 'unavailable' ? 'checkmark' : 'close'}
color={statusColors[status]}
size="large"
/>
);
if (status === 'ifneedbe') {
content = (
<CheckmarkParenIcon
className={`${statusColors[status]} icon`}
size="large"
color="#fbbd08"
/>
);
} else {
content = (
<Icon
name={status !== 'unavailable' ? 'checkmark' : 'close'}
color={statusColors[status]}
size="large"
/>
);
}
} else if (limitedSlots) {
if (positive) {
content = <Icon name="checkmark" color={statusColors[status]} size="large" />;
Expand Down Expand Up @@ -132,6 +144,7 @@ function AnswerCell({
<Table.Cell
positive={positive}
negative={negative && !limitedSlots}
warning={warning && !limitedSlots}
key={timeslot}
textAlign="center"
selectable={selectable && !taken}
Expand Down
9 changes: 6 additions & 3 deletions newdle/client/src/components/answer/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,22 @@ function groupOverlaps(options, duration) {
function getAnswerProps(slot, answer, limitedSlots) {
if (answer === 'available') {
return {
icon: 'check square outline',
icon: 'check',
label: t`YES`,
action: () => setAnswer(slot, limitedSlots ? 'unavailable' : 'ifneedbe'),
className: styles.available,
};
} else if (answer === 'ifneedbe') {
return {
icon: 'check square outline',
icon: '~',
label: t`IF NEEDED`,
action: () => setAnswer(slot, 'unavailable'),
className: styles.ifneedbe,
};
} else {
return {
icon: 'window close outline',
icon: 'times',
label: t`NO`,
action: () => setAnswer(slot, 'available'),
className: styles.unavailable,
};
Expand Down
65 changes: 65 additions & 0 deletions newdle/client/src/components/answer/CheckmarkParenIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import PropTypes from 'prop-types';

const SIZE_MAP = {
mini: 10,
tiny: 12,
small: 14,
medium: 18,
large: 24,
big: 30,
huge: 40,
massive: 52,
};

export default function CheckmarkParenIcon({
size = 'medium',
color = 'currentColor',
style = {},
className = '',
...rest
}) {
const px = typeof size === 'number' ? size : SIZE_MAP[size] ?? SIZE_MAP.medium;

const sw = 15; // stroke width

return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="-5 0 170 120"
width={px + 2}
height={px}
fill="none"
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
className={`checkmark-paren-icon${className ? ' ' + className : ''}`}
aria-hidden="true"
style={{display: 'inline-block', verticalAlign: 'middle', ...style}}
{...rest}
>
{/* Left parenthesis */}
<path d="M 40 10 C 8 30, 8 90, 40 110" strokeWidth={sw} />

{/* Right parenthesis */}
<path d="M 120 10 C 152 30, 152 90, 120 110" strokeWidth={sw} />

{/* Checkmark */}
<path d="M 44 62 L 68 84 L 116 38" strokeWidth={sw + 1} />
</svg>
);
}

CheckmarkParenIcon.propTypes = {
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
color: PropTypes.string,
style: PropTypes.object,
className: PropTypes.string,
};

CheckmarkParenIcon.defaultProps = {
size: 'medium',
color: 'currentColor',
style: {},
className: '',
};
24 changes: 21 additions & 3 deletions newdle/client/src/components/answer/Option.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import {useDispatch} from 'react-redux';
import PropTypes from 'prop-types';
import {Icon} from 'semantic-ui-react';
import CheckmarkParenIcon from './CheckmarkParenIcon';
import styles from './answer.module.scss';

export default function Option({
Expand All @@ -10,21 +11,36 @@ export default function Option({
icon,
action,
className,
label,
taken,
styles: moreStyles,
}) {
const dispatch = useDispatch();

let iconEl;
if (taken) {
iconEl = <Icon name="ban" />;
} else if (icon === '~') {
iconEl = <CheckmarkParenIcon className={`icon ${styles['icon-ifneedbe']}`} />;
} else if (icon === 'check') {
iconEl = <Icon name={icon} className={styles['icon-check']} />;
} else {
iconEl = <Icon name={icon} />;
}

return (
<div
className={`${styles.option} ${className}`}
onClick={taken ? null : () => dispatch(action())}
style={{...moreStyles, cursor: taken ? 'inherit' : 'pointer'}}
>
<span className={styles.times}>
{startTime} - {endTime}
<span className={styles['time-info']}>
{iconEl}
<span className={styles.times}>
{startTime} - {endTime}
</span>
</span>
<Icon name={!taken ? icon : 'ban'} />
{label && !taken && <span className={styles.label}>{label}</span>}
</div>
);
}
Expand All @@ -35,11 +51,13 @@ Option.propTypes = {
action: PropTypes.func,
className: PropTypes.string,
icon: PropTypes.string.isRequired,
label: PropTypes.string,
styles: PropTypes.object,
taken: PropTypes.bool.isRequired,
};

Option.defaultProps = {
onClick: null,
label: undefined,
styles: {},
};
Loading
Loading