mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-12-02 20:07:43 -05:00
Update the curator invitation component
This commit is contained in:
parent
8984f2cedc
commit
168cd5a01b
6 changed files with 84 additions and 14 deletions
|
@ -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": "You’ve 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 don’t have curators right now.",
|
"studio.curatorsEmptyCanAdd1": "You don’t 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.",
|
||||||
|
|
|
@ -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));
|
||||||
dispatch(setRoles({invited: false, curator: true}));
|
setTimeout(() => {
|
||||||
|
dispatch(setRoles({invited: false, curator: true}));
|
||||||
|
}, 5 * 1000);
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue