Update the curator invitation component

This commit is contained in:
Paul Kaplan 2021-05-17 11:02:48 -04:00
parent 8984f2cedc
commit 168cd5a01b
6 changed files with 84 additions and 14 deletions

View file

@ -39,7 +39,10 @@
"studio.inviteCuratorsHeader": "Invite Curators", "studio.inviteCuratorsHeader": "Invite Curators",
"studio.inviteCurator": "Invite", "studio.inviteCurator": "Invite",
"studio.inviteCuratorPlaceholder": "Scratch Username", "studio.inviteCuratorPlaceholder": "Scratch Username",
"studio.curatorInvitationAccepted": "Congratulations! You are now a curator of this studio.",
"studio.curatorInvitation": "Youve been invited to become a curator of this studio.",
"studio.curatorAcceptInvite": "Accept Invite", "studio.curatorAcceptInvite": "Accept Invite",
"studio.curatorInvitationError": "Something went wrong, try again later.",
"studio.curatorsEmptyCanAdd1": "You dont have curators right now.", "studio.curatorsEmptyCanAdd1": "You dont have curators right now.",
"studio.curatorsEmptyCanAdd2": "Add some curators to collaborate with!", "studio.curatorsEmptyCanAdd2": "Add some curators to collaborate with!",
"studio.curatorsEmpty1": "This studio has no curators right now.", "studio.curatorsEmpty1": "This studio has no curators right now.",

View file

@ -168,7 +168,9 @@ const acceptInvitation = () => ((dispatch, getState) => new Promise((resolve, re
// Note: this assumes that the user items from the curator endpoint // Note: this assumes that the user items from the curator endpoint
// are the same structure as the single user data returned from /users/:username // are the same structure as the single user data returned from /users/:username
dispatch(curators.actions.create(userBody, true)); dispatch(curators.actions.create(userBody, true));
setTimeout(() => {
dispatch(setRoles({invited: false, curator: true})); dispatch(setRoles({invited: false, curator: true}));
}, 5 * 1000);
return resolve(); return resolve();
}); });
}); });

View file

@ -6,15 +6,42 @@ import classNames from 'classnames';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {acceptInvitation} from './lib/studio-member-actions'; import {acceptInvitation} from './lib/studio-member-actions';
import {selectShowCuratorInvite} from '../../redux/studio-permissions';
const StudioCuratorInvite = ({onSubmit}) => { const StudioCuratorInvite = ({showCuratorInvite, onSubmit}) => {
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState(null); const [accepted, setAccepted] = useState(false);
const [error, setError] = useState(false);
if (!showCuratorInvite) return null;
if (error) {
return (
<div className="studio-invitation studio-info-box studio-info-box-error">
<div className="studio-invitation-msg">
<FormattedMessage id="studio.curatorInvitationError" />
</div>
</div>
);
}
if (accepted) {
return (
<div className="studio-invitation studio-info-box studio-info-box-success">
<div className="studio-invitation-msg">
<FormattedMessage id="studio.curatorInvitationAccepted" />
</div>
</div>
);
}
return ( return (
<div> <div className="studio-invitation studio-info-box">
<div className="studio-invitation-msg">
<FormattedMessage id="studio.curatorInvitation" />
</div>
<button <button
className={classNames('button', { className={classNames('studio-invitation-button button', {
'mod-mutating': submitting 'mod-mutating': submitting
})} })}
disabled={submitting} disabled={submitting}
@ -22,22 +49,28 @@ const StudioCuratorInvite = ({onSubmit}) => {
setSubmitting(true); setSubmitting(true);
setError(null); setError(null);
onSubmit() onSubmit()
.then(() => {
setSubmitting(false);
setAccepted(true);
})
.catch(e => { .catch(e => {
setError(e); setError(e);
setSubmitting(false); setSubmitting(false);
}); });
}} }}
><FormattedMessage id="studio.curatorAcceptInvite" /></button> ><FormattedMessage id="studio.curatorAcceptInvite" /></button>
{error && <div>{error}</div>}
</div> </div>
); );
}; };
StudioCuratorInvite.propTypes = { StudioCuratorInvite.propTypes = {
showCuratorInvite: PropTypes.func,
onSubmit: PropTypes.func onSubmit: PropTypes.func
}; };
const mapStateToProps = () => ({}); const mapStateToProps = state => ({
showCuratorInvite: selectShowCuratorInvite(state)
});
const mapDispatchToProps = ({ const mapDispatchToProps = ({
onSubmit: acceptInvitation onSubmit: acceptInvitation

View file

@ -8,12 +8,11 @@ import {curators} from './lib/redux-modules';
import Debug from './debug.jsx'; import Debug from './debug.jsx';
import {CuratorTile} from './studio-member-tile.jsx'; import {CuratorTile} from './studio-member-tile.jsx';
import CuratorInviter from './studio-curator-inviter.jsx'; import CuratorInviter from './studio-curator-inviter.jsx';
import CuratorInvite from './studio-curator-invite.jsx';
import {loadCurators} from './lib/studio-member-actions'; import {loadCurators} from './lib/studio-member-actions';
import {selectCanInviteCurators, selectShowCuratorInvite} from '../../redux/studio-permissions'; import {selectCanInviteCurators} from '../../redux/studio-permissions';
const StudioCurators = ({ const StudioCurators = ({
canInviteCurators, showCuratorInvite, items, error, loading, moreToLoad, onLoadMore canInviteCurators, items, error, loading, moreToLoad, onLoadMore
}) => { }) => {
useEffect(() => { useEffect(() => {
if (items.length === 0) onLoadMore(); if (items.length === 0) onLoadMore();
@ -24,7 +23,6 @@ const StudioCurators = ({
<h2><FormattedMessage id="studio.curatorsHeader" /></h2> <h2><FormattedMessage id="studio.curatorsHeader" /></h2>
</div> </div>
{canInviteCurators && <CuratorInviter />} {canInviteCurators && <CuratorInviter />}
{showCuratorInvite && <CuratorInvite />}
{error && <Debug {error && <Debug
label="Error" label="Error"
data={error} data={error}
@ -87,7 +85,6 @@ StudioCurators.propTypes = {
}) })
})), })),
canInviteCurators: PropTypes.bool, canInviteCurators: PropTypes.bool,
showCuratorInvite: PropTypes.bool,
loading: PropTypes.bool, loading: PropTypes.bool,
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
moreToLoad: PropTypes.bool, moreToLoad: PropTypes.bool,
@ -97,8 +94,7 @@ StudioCurators.propTypes = {
export default connect( export default connect(
state => ({ state => ({
...curators.selector(state), ...curators.selector(state),
canInviteCurators: selectCanInviteCurators(state), canInviteCurators: selectCanInviteCurators(state)
showCuratorInvite: selectShowCuratorInvite(state)
}), }),
{ {
onLoadMore: loadCurators onLoadMore: loadCurators

View file

@ -22,6 +22,7 @@ import StudioManagers from './studio-managers.jsx';
import StudioCurators from './studio-curators.jsx'; import StudioCurators from './studio-curators.jsx';
import StudioComments from './studio-comments.jsx'; import StudioComments from './studio-comments.jsx';
import StudioActivity from './studio-activity.jsx'; import StudioActivity from './studio-activity.jsx';
import StudioCuratorInvite from './studio-curator-invite.jsx';
import { import {
projects, projects,
@ -53,6 +54,7 @@ const StudioShell = ({studioLoadFailed}) => {
<div> <div>
<Switch> <Switch>
<Route path={`${match.path}/curators`}> <Route path={`${match.path}/curators`}>
<StudioCuratorInvite />
<StudioManagers /> <StudioManagers />
<StudioCurators /> <StudioCurators />
</Route> </Route>

View file

@ -349,6 +349,40 @@ $radius: 8px;
} }
} }
.studio-invitation {
margin-top: 1rem;
padding: 1rem;
box-sizing: border-box;
min-height: 85px; /* So the box doesn't change height after being accepted */
display: flex;
justify-content: space-between;
align-items: center;
@media #{$intermediate-and-smaller} {
flex-direction: column;
.studio-invitation-msg {
margin-top: .5rem;
margin-bottom: 1rem;
}
}
}
.studio-info-box {
border-radius: 4px;
background: $ui-blue-10percent;
border: 1px solid $ui-blue-25percent;
&.studio-info-box-success {
background: #CEF2E8;
border: 1px solid rgba(15, 189, 140, 0.5);
}
&.studio-info-box-error {
background: #FFF0DF;
border: 1px solid $ui-dark-orange;
}
}
/* Modification classes for different interaction states */ /* Modification classes for different interaction states */
.mod-fetching { /* When a field has no content to display yet */ .mod-fetching { /* When a field has no content to display yet */
position: relative; position: relative;