mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 17:45:52 -05:00
Include modifying the studio image
This commit is contained in:
parent
647575e4a8
commit
430f67c0e1
4 changed files with 106 additions and 3 deletions
|
@ -10,13 +10,15 @@
|
||||||
const keyMirror = require('keymirror');
|
const keyMirror = require('keymirror');
|
||||||
const api = require('../lib/api');
|
const api = require('../lib/api');
|
||||||
const {selectUsername} = require('./session');
|
const {selectUsername} = require('./session');
|
||||||
const {selectStudioId} = require('./studio');
|
const {selectStudioId, selectStudioImage} = require('./studio');
|
||||||
|
|
||||||
const Errors = keyMirror({
|
const Errors = keyMirror({
|
||||||
NETWORK: null,
|
NETWORK: null,
|
||||||
SERVER: null,
|
SERVER: null,
|
||||||
INAPPROPRIATE: null,
|
INAPPROPRIATE: null,
|
||||||
PERMISSION: null,
|
PERMISSION: null,
|
||||||
|
THUMBNAIL_TOO_LARGE: null,
|
||||||
|
THUMBNAIL_MISSING: null,
|
||||||
UNHANDLED: null
|
UNHANDLED: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,6 +82,8 @@ const selectIsMutatingFollowing = state => state.studioMutations.isMutating.foll
|
||||||
const selectTitleMutationError = state => state.studioMutations.mutationErrors.title;
|
const selectTitleMutationError = state => state.studioMutations.mutationErrors.title;
|
||||||
const selectDescriptionMutationError = state => state.studioMutations.mutationErrors.description;
|
const selectDescriptionMutationError = state => state.studioMutations.mutationErrors.description;
|
||||||
const selectFollowingMutationError = state => state.studioMutations.mutationErrors.following;
|
const selectFollowingMutationError = state => state.studioMutations.mutationErrors.following;
|
||||||
|
const selectIsMutatingImage = state => state.studioMutations.isMutating.image;
|
||||||
|
const selectImageMutationError = state => state.studioMutations.mutationErrors.image;
|
||||||
|
|
||||||
// Thunks
|
// Thunks
|
||||||
/**
|
/**
|
||||||
|
@ -97,6 +101,8 @@ const normalizeError = (err, body, res) => {
|
||||||
try {
|
try {
|
||||||
if (body.errors.length > 0) {
|
if (body.errors.length > 0) {
|
||||||
if (body.errors[0] === 'inappropriate-generic') return Errors.INAPPROPRIATE;
|
if (body.errors[0] === 'inappropriate-generic') return Errors.INAPPROPRIATE;
|
||||||
|
if (body.errors[0] === 'thumbnail-too-large') return Errors.THUMBNAIL_TOO_LARGE;
|
||||||
|
if (body.errors[0] === 'thumbnail-missing') return Errors.THUMBNAIL_MISSING;
|
||||||
return Errors.UNHANDLED;
|
return Errors.UNHANDLED;
|
||||||
}
|
}
|
||||||
} catch (_) { /* No body.errors[], continue */ }
|
} catch (_) { /* No body.errors[], continue */ }
|
||||||
|
@ -154,6 +160,26 @@ const mutateFollowingStudio = shouldFollow => ((dispatch, getState) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mutateStudioImage = input => ((dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
const studioId = selectStudioId(state);
|
||||||
|
const currentImage = selectStudioImage(state);
|
||||||
|
dispatch(startMutation('image'));
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', input.files[0]);
|
||||||
|
api({
|
||||||
|
host: '',
|
||||||
|
uri: `/site-api/galleries/all/${studioId}/`,
|
||||||
|
method: 'POST',
|
||||||
|
withCredentials: true,
|
||||||
|
useCsrf: true,
|
||||||
|
body: formData
|
||||||
|
}, (err, body, res) => {
|
||||||
|
const error = normalizeError(err, body, res);
|
||||||
|
dispatch(completeMutation('image', error ? currentImage : body.thumbnail_url, error));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getInitialState,
|
getInitialState,
|
||||||
studioMutationsReducer,
|
studioMutationsReducer,
|
||||||
|
@ -163,6 +189,7 @@ module.exports = {
|
||||||
mutateStudioTitle,
|
mutateStudioTitle,
|
||||||
mutateStudioDescription,
|
mutateStudioDescription,
|
||||||
mutateFollowingStudio,
|
mutateFollowingStudio,
|
||||||
|
mutateStudioImage,
|
||||||
|
|
||||||
// Selectors
|
// Selectors
|
||||||
selectIsMutatingTitle,
|
selectIsMutatingTitle,
|
||||||
|
@ -170,5 +197,7 @@ module.exports = {
|
||||||
selectIsMutatingFollowing,
|
selectIsMutatingFollowing,
|
||||||
selectTitleMutationError,
|
selectTitleMutationError,
|
||||||
selectDescriptionMutationError,
|
selectDescriptionMutationError,
|
||||||
selectFollowingMutationError
|
selectFollowingMutationError,
|
||||||
|
selectIsMutatingImage,
|
||||||
|
selectImageMutationError
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ const getInitialState = () => ({
|
||||||
description: '',
|
description: '',
|
||||||
openToAll: false,
|
openToAll: false,
|
||||||
commentingAllowed: false,
|
commentingAllowed: false,
|
||||||
thumbnail: '',
|
image: '',
|
||||||
followers: 0,
|
followers: 0,
|
||||||
owner: null,
|
owner: null,
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ const setRoles = roles => ({
|
||||||
const selectStudioId = state => state.studio.id;
|
const selectStudioId = state => state.studio.id;
|
||||||
const selectStudioTitle = state => state.studio.title;
|
const selectStudioTitle = state => state.studio.title;
|
||||||
const selectStudioDescription = state => state.studio.description;
|
const selectStudioDescription = state => state.studio.description;
|
||||||
|
const selectStudioImage = state => state.studio.image;
|
||||||
const selectIsLoadingInfo = state => state.studio.infoStatus === Status.FETCHING;
|
const selectIsLoadingInfo = state => state.studio.infoStatus === Status.FETCHING;
|
||||||
const selectIsFollowing = state => state.studio.following;
|
const selectIsFollowing = state => state.studio.following;
|
||||||
const selectIsLoadingRoles = state => state.studio.rolesStatus === Status.FETCHING;
|
const selectIsLoadingRoles = state => state.studio.rolesStatus === Status.FETCHING;
|
||||||
|
@ -103,6 +104,7 @@ const getInfo = () => ((dispatch, getState) => {
|
||||||
dispatch(setInfo({
|
dispatch(setInfo({
|
||||||
title: body.title,
|
title: body.title,
|
||||||
description: body.description,
|
description: body.description,
|
||||||
|
image: body.image,
|
||||||
openToAll: body.open_to_all,
|
openToAll: body.open_to_all,
|
||||||
commentingAllowed: body.commenting_allowed,
|
commentingAllowed: body.commenting_allowed,
|
||||||
updated: new Date(body.history.modified),
|
updated: new Date(body.history.modified),
|
||||||
|
@ -150,6 +152,7 @@ module.exports = {
|
||||||
selectStudioId,
|
selectStudioId,
|
||||||
selectStudioTitle,
|
selectStudioTitle,
|
||||||
selectStudioDescription,
|
selectStudioDescription,
|
||||||
|
selectStudioImage,
|
||||||
selectIsLoadingInfo,
|
selectIsLoadingInfo,
|
||||||
selectIsLoadingRoles,
|
selectIsLoadingRoles,
|
||||||
selectIsFollowing
|
selectIsFollowing
|
||||||
|
|
69
src/views/studio/studio-image.jsx
Normal file
69
src/views/studio/studio-image.jsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* eslint-disable react/jsx-no-bind */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
|
import {selectStudioImage, selectIsLoadingInfo} from '../../redux/studio';
|
||||||
|
import {selectCanEditInfo} from '../../redux/studio-permissions';
|
||||||
|
import {
|
||||||
|
mutateStudioImage, selectIsMutatingImage, selectImageMutationError
|
||||||
|
} from '../../redux/studio-mutations';
|
||||||
|
import Spinner from '../../components/spinner/spinner.jsx';
|
||||||
|
|
||||||
|
const StudioImage = ({
|
||||||
|
imageError, isLoading, isMutating, image, canEditInfo, handleUpdate
|
||||||
|
}) => (
|
||||||
|
<div>
|
||||||
|
<h3>Image</h3>
|
||||||
|
{isLoading ? (
|
||||||
|
<h4>Loading...</h4>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<div style={{width: '200px', height: '150px', border: '1px solid green'}}>
|
||||||
|
{isMutating ?
|
||||||
|
<Spinner color="blue" /> :
|
||||||
|
<img
|
||||||
|
style={{objectFit: 'contain'}}
|
||||||
|
src={image}
|
||||||
|
/>}
|
||||||
|
</div>
|
||||||
|
{canEditInfo &&
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
disabled={isMutating}
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
onChange={e => {
|
||||||
|
handleUpdate(e.target);
|
||||||
|
e.target.value = '';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{imageError && <div>Error mutating image: {imageError}</div>}
|
||||||
|
</label>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
StudioImage.propTypes = {
|
||||||
|
imageError: PropTypes.string,
|
||||||
|
canEditInfo: PropTypes.bool,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
isMutating: PropTypes.bool,
|
||||||
|
image: PropTypes.string,
|
||||||
|
handleUpdate: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
state => ({
|
||||||
|
image: selectStudioImage(state),
|
||||||
|
canEditInfo: selectCanEditInfo(state),
|
||||||
|
isLoading: selectIsLoadingInfo(state),
|
||||||
|
isMutating: selectIsMutatingImage(state),
|
||||||
|
imageError: selectImageMutationError(state)
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
handleUpdate: mutateStudioImage
|
||||||
|
}
|
||||||
|
)(StudioImage);
|
|
@ -5,6 +5,7 @@ import Debug from './debug.jsx';
|
||||||
import StudioDescription from './studio-description.jsx';
|
import StudioDescription from './studio-description.jsx';
|
||||||
import StudioFollow from './studio-follow.jsx';
|
import StudioFollow from './studio-follow.jsx';
|
||||||
import StudioTitle from './studio-title.jsx';
|
import StudioTitle from './studio-title.jsx';
|
||||||
|
import StudioImage from './studio-image.jsx';
|
||||||
|
|
||||||
import {selectIsLoggedIn} from '../../redux/session';
|
import {selectIsLoggedIn} from '../../redux/session';
|
||||||
import {getInfo, getRoles} from '../../redux/studio';
|
import {getInfo, getRoles} from '../../redux/studio';
|
||||||
|
@ -26,6 +27,7 @@ const StudioInfo = ({
|
||||||
<StudioTitle />
|
<StudioTitle />
|
||||||
<StudioDescription />
|
<StudioDescription />
|
||||||
<StudioFollow />
|
<StudioFollow />
|
||||||
|
<StudioImage />
|
||||||
<Debug
|
<Debug
|
||||||
label="Studio Info"
|
label="Studio Info"
|
||||||
data={studio}
|
data={studio}
|
||||||
|
|
Loading…
Reference in a new issue