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 api = require('../lib/api');
|
||||
const {selectUsername} = require('./session');
|
||||
const {selectStudioId} = require('./studio');
|
||||
const {selectStudioId, selectStudioImage} = require('./studio');
|
||||
|
||||
const Errors = keyMirror({
|
||||
NETWORK: null,
|
||||
SERVER: null,
|
||||
INAPPROPRIATE: null,
|
||||
PERMISSION: null,
|
||||
THUMBNAIL_TOO_LARGE: null,
|
||||
THUMBNAIL_MISSING: null,
|
||||
UNHANDLED: null
|
||||
});
|
||||
|
||||
|
@ -80,6 +82,8 @@ const selectIsMutatingFollowing = state => state.studioMutations.isMutating.foll
|
|||
const selectTitleMutationError = state => state.studioMutations.mutationErrors.title;
|
||||
const selectDescriptionMutationError = state => state.studioMutations.mutationErrors.description;
|
||||
const selectFollowingMutationError = state => state.studioMutations.mutationErrors.following;
|
||||
const selectIsMutatingImage = state => state.studioMutations.isMutating.image;
|
||||
const selectImageMutationError = state => state.studioMutations.mutationErrors.image;
|
||||
|
||||
// Thunks
|
||||
/**
|
||||
|
@ -97,6 +101,8 @@ const normalizeError = (err, body, res) => {
|
|||
try {
|
||||
if (body.errors.length > 0) {
|
||||
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;
|
||||
}
|
||||
} 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 = {
|
||||
getInitialState,
|
||||
studioMutationsReducer,
|
||||
|
@ -163,6 +189,7 @@ module.exports = {
|
|||
mutateStudioTitle,
|
||||
mutateStudioDescription,
|
||||
mutateFollowingStudio,
|
||||
mutateStudioImage,
|
||||
|
||||
// Selectors
|
||||
selectIsMutatingTitle,
|
||||
|
@ -170,5 +197,7 @@ module.exports = {
|
|||
selectIsMutatingFollowing,
|
||||
selectTitleMutationError,
|
||||
selectDescriptionMutationError,
|
||||
selectFollowingMutationError
|
||||
selectFollowingMutationError,
|
||||
selectIsMutatingImage,
|
||||
selectImageMutationError
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ const getInitialState = () => ({
|
|||
description: '',
|
||||
openToAll: false,
|
||||
commentingAllowed: false,
|
||||
thumbnail: '',
|
||||
image: '',
|
||||
followers: 0,
|
||||
owner: null,
|
||||
|
||||
|
@ -86,6 +86,7 @@ const setRoles = roles => ({
|
|||
const selectStudioId = state => state.studio.id;
|
||||
const selectStudioTitle = state => state.studio.title;
|
||||
const selectStudioDescription = state => state.studio.description;
|
||||
const selectStudioImage = state => state.studio.image;
|
||||
const selectIsLoadingInfo = state => state.studio.infoStatus === Status.FETCHING;
|
||||
const selectIsFollowing = state => state.studio.following;
|
||||
const selectIsLoadingRoles = state => state.studio.rolesStatus === Status.FETCHING;
|
||||
|
@ -103,6 +104,7 @@ const getInfo = () => ((dispatch, getState) => {
|
|||
dispatch(setInfo({
|
||||
title: body.title,
|
||||
description: body.description,
|
||||
image: body.image,
|
||||
openToAll: body.open_to_all,
|
||||
commentingAllowed: body.commenting_allowed,
|
||||
updated: new Date(body.history.modified),
|
||||
|
@ -150,6 +152,7 @@ module.exports = {
|
|||
selectStudioId,
|
||||
selectStudioTitle,
|
||||
selectStudioDescription,
|
||||
selectStudioImage,
|
||||
selectIsLoadingInfo,
|
||||
selectIsLoadingRoles,
|
||||
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 StudioFollow from './studio-follow.jsx';
|
||||
import StudioTitle from './studio-title.jsx';
|
||||
import StudioImage from './studio-image.jsx';
|
||||
|
||||
import {selectIsLoggedIn} from '../../redux/session';
|
||||
import {getInfo, getRoles} from '../../redux/studio';
|
||||
|
@ -26,6 +27,7 @@ const StudioInfo = ({
|
|||
<StudioTitle />
|
||||
<StudioDescription />
|
||||
<StudioFollow />
|
||||
<StudioImage />
|
||||
<Debug
|
||||
label="Studio Info"
|
||||
data={studio}
|
||||
|
|
Loading…
Reference in a new issue