Skip to content

Commit 3d208f7

Browse files
committed
Refactoring action buttons.
1 parent cbf8a5e commit 3d208f7

File tree

10 files changed

+169
-220
lines changed

10 files changed

+169
-220
lines changed

src/components/ReferenceSolutions/ReferenceSolutionActions/ReferenceSolutionActions.js

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ import PropTypes from 'prop-types';
33
import { FormattedMessage } from 'react-intl';
44
import { useLocation, useNavigate } from 'react-router-dom';
55

6+
import ActionButtons, { prepareButtonDescriptors } from '../../widgets/ActionButtons';
67
import withLinks from '../../../helpers/withLinks';
78

8-
import ActionButton from './ActionButton';
9-
import ActionDropdown from './ActionDropdown';
10-
119
/**
12-
* Action templates containing basic parameters: label, short (label), icon (name), variant (success if missing),
10+
* Action templates containing basic parameters: label, icon (name), variant (success if missing),
1311
* and confirm (confirm yes/no message for a popover; no confirmation required if missing)
1412
*/
1513
const actionsTemplates = {
@@ -58,7 +56,6 @@ const ReferenceSolutionActions = ({
5856
currentUserId = null,
5957
solution,
6058
visibilityPending = false,
61-
captionAsTooltip = false,
6259
size = undefined,
6360
dropdown = false,
6461
setVisibility = null,
@@ -91,32 +88,16 @@ const ReferenceSolutionActions = ({
9188
};
9289

9390
const pendingIndicators = { visibilityPending };
94-
const actions = knownActions
95-
.filter(a => actionHandlers[a])
96-
.map(a => ({
97-
...actionsTemplates[a],
98-
handler: actionHandlers[a],
99-
pending: pendingIndicators[actionsTemplates[a].pending] || false,
100-
}));
91+
const actions = prepareButtonDescriptors(actionsTemplates, knownActions, actionHandlers, pendingIndicators);
10192

102-
return dropdown ? (
103-
<ActionDropdown id={id} actions={actions} captionAsTooltip={captionAsTooltip} />
104-
) : (
105-
actions.map(action => (
106-
<ActionButton
107-
key={action.icon}
108-
id={id}
109-
variant={action.variant}
110-
icon={action.icon}
111-
label={action.label}
112-
shortLabel={action.short || action.label}
113-
confirm={action.confirm}
114-
pending={action.pending}
115-
captionAsTooltip={captionAsTooltip}
116-
size={size}
117-
onClick={action.handler}
118-
/>
119-
))
93+
return (
94+
<ActionButtons
95+
id={id}
96+
actions={actions}
97+
size={size}
98+
dropdown={dropdown}
99+
dropdownLabel={<FormattedMessage id="generic.update" defaultMessage="Update" />}
100+
/>
120101
);
121102
};
122103

@@ -131,7 +112,6 @@ ReferenceSolutionActions.propTypes = {
131112
}),
132113
visibilityPending: PropTypes.bool,
133114
setVisibility: PropTypes.func,
134-
captionAsTooltip: PropTypes.bool,
135115
size: PropTypes.string,
136116
dropdown: PropTypes.bool,
137117
links: PropTypes.object.isRequired,

src/components/Solutions/SolutionActions/ActionButton.js

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/components/Solutions/SolutionActions/ActionDropdown.js

Lines changed: 0 additions & 78 deletions
This file was deleted.

src/components/Solutions/SolutionActions/SolutionActions.js

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,24 @@ import PropTypes from 'prop-types';
33
import { FormattedMessage } from 'react-intl';
44
import { useLocation, useNavigate } from 'react-router-dom';
55

6+
import ActionButtons, { prepareButtonDescriptors, onlyLabels, onlyTooltips } from '../../widgets/ActionButtons';
67
import withLinks from '../../../helpers/withLinks';
78
import { safeGet } from '../../../helpers/common';
89

9-
import ActionButton from './ActionButton';
10-
import ActionDropdown from './ActionDropdown';
11-
1210
/**
13-
* Action templates containing basic parameters: label, short (label), icon (name), variant (success if missing),
11+
* Action templates containing basic parameters: label, label, tooltip icon (name), variant (success if missing),
1412
* and confirm (confirm yes/no message for a popover; no confirmation required if missing)
1513
*/
1614
const actionsTemplates = {
1715
accept: {
18-
short: <FormattedMessage id="app.solution.actions.accept" defaultMessage="Accept" />,
19-
label: <FormattedMessage id="app.solution.actions.acceptLong" defaultMessage="Accept as Final" />,
16+
label: <FormattedMessage id="app.solution.actions.accept" defaultMessage="Accept" />,
17+
tooltip: <FormattedMessage id="app.solution.actions.acceptLong" defaultMessage="Accept as Final" />,
2018
icon: ['far', 'check-circle'],
2119
pending: 'acceptPending',
2220
},
2321
unaccept: {
24-
short: <FormattedMessage id="app.solution.actions.revokeAccept" defaultMessage="Revoke" />,
25-
label: <FormattedMessage id="app.solution.actions.revokeAcceptLong" defaultMessage="Revoke as Final" />,
22+
label: <FormattedMessage id="app.solution.actions.revokeAccept" defaultMessage="Revoke" />,
23+
tooltip: <FormattedMessage id="app.solution.actions.revokeAcceptLong" defaultMessage="Revoke as Final" />,
2624
icon: ['far', 'circle-xmark'],
2725
variant: 'warning',
2826
pending: 'acceptPending',
@@ -168,32 +166,16 @@ const SolutionActions = ({
168166
};
169167

170168
const pendingIndicators = { acceptPending, updatePending, pointsPending };
171-
const actions = knownActions
172-
.filter(a => actionHandlers[a])
173-
.map(a => ({
174-
...actionsTemplates[a],
175-
handler: actionHandlers[a],
176-
pending: pendingIndicators[actionsTemplates[a].pending] || false,
177-
}));
169+
const actions = prepareButtonDescriptors(actionsTemplates, knownActions, actionHandlers, pendingIndicators);
178170

179-
return dropdown ? (
180-
<ActionDropdown id={id} actions={actions} captionAsTooltip={captionAsTooltip} />
181-
) : (
182-
actions.map(action => (
183-
<ActionButton
184-
key={action.icon}
185-
id={id}
186-
variant={action.variant}
187-
icon={action.icon}
188-
label={action.label}
189-
shortLabel={action.short || action.label}
190-
confirm={action.confirm}
191-
pending={action.pending}
192-
captionAsTooltip={captionAsTooltip}
193-
size={size}
194-
onClick={action.handler}
195-
/>
196-
))
171+
return (
172+
<ActionButtons
173+
id={id}
174+
actions={captionAsTooltip ? onlyTooltips(actions) : onlyLabels(actions)}
175+
size={size}
176+
dropdown={dropdown}
177+
dropdownLabel={captionAsTooltip ? null : <FormattedMessage id="generic.update" defaultMessage="Update" />}
178+
/>
197179
);
198180
};
199181

src/components/forms/ForkExerciseForm/ForkExerciseForm.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ const ForkExerciseForm = ({
9797
{groups => (
9898
<>
9999
<Field
100-
name={'groupId'}
100+
name="groupId"
101101
component={SelectField}
102-
label={''}
102+
label=""
103103
ignoreDirty
104104
addEmptyOption={true}
105105
emptyOptionCaption={formatMessage(messages.emptyOption)}

src/components/forms/RelocateGroupForm/RelocateGroupForm.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const RelocateGroupForm = ({
3939
<Row className="align-items-end">
4040
<Col xs={12} sm>
4141
<Field
42-
name={'groupId'}
42+
name="groupId"
4343
component={SelectField}
4444
label={<FormattedMessage id="app.relocateGroupForm.parentGroup" defaultMessage="Parent Group:" />}
4545
options={groups
Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,41 @@ import Button from '../../widgets/TheButton';
55
import OptionalTooltipWrapper from '../../widgets/OptionalTooltipWrapper';
66
import Icon, { LoadingIcon } from '../../icons';
77

8-
const ActionButton = ({
9-
id,
10-
variant = 'success',
11-
icon,
12-
label,
13-
shortLabel = label,
14-
confirm,
15-
pending,
16-
captionAsTooltip,
17-
size,
18-
onClick,
19-
}) =>
8+
const ActionButton = ({ id, variant = 'success', icon, label, confirm, pending, tooltip = null, size, onClick }) =>
209
confirm ? (
2110
<Button variant={variant} size={size} onClick={onClick} disabled={pending} confirm={confirm} confirmId={id}>
22-
{pending ? <LoadingIcon gapRight={!captionAsTooltip} /> : <Icon icon={icon} gapRight={!captionAsTooltip} />}
23-
{!captionAsTooltip && label}
11+
{pending ? (
12+
<LoadingIcon gapRight={Boolean(label)} />
13+
) : icon && (typeof icon === 'string' || Array.isArray(icon)) ? (
14+
<Icon icon={icon} gapRight={Boolean(label)} />
15+
) : (
16+
icon
17+
)}
18+
{label}
2419
</Button>
2520
) : (
26-
<OptionalTooltipWrapper tooltip={label} hide={!captionAsTooltip}>
21+
<OptionalTooltipWrapper tooltip={tooltip} hide={!tooltip}>
2722
<Button variant={variant} size={size} onClick={onClick} disabled={pending}>
28-
{pending ? <LoadingIcon gapRight={!captionAsTooltip} /> : <Icon icon={icon} gapRight={!captionAsTooltip} />}
29-
{!captionAsTooltip && shortLabel}
23+
{pending ? (
24+
<LoadingIcon gapRight={Boolean(label)} />
25+
) : icon && (typeof icon === 'string' || Array.isArray(icon)) ? (
26+
<Icon icon={icon} gapRight={Boolean(label)} />
27+
) : (
28+
icon
29+
)}
30+
{label}
3031
</Button>
3132
</OptionalTooltipWrapper>
3233
);
3334

3435
ActionButton.propTypes = {
3536
id: PropTypes.string.isRequired,
3637
variant: PropTypes.string,
37-
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
38-
shortLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
39-
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
38+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
39+
tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
40+
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.element]).isRequired,
4041
confirm: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
4142
pending: PropTypes.bool,
42-
captionAsTooltip: PropTypes.bool,
4343
size: PropTypes.string,
4444
onClick: PropTypes.func.isRequired,
4545
};

0 commit comments

Comments
 (0)