Skip to content

Commit

Permalink
Photo uploader improving (#664)
Browse files Browse the repository at this point in the history
* Add loading indicator for photos for variant form

* Add loader for uploader for CharacteristicItem

* Add upload indicator for ManageStoreMenu

* Add upload indicator for profile
  • Loading branch information
isaldin authored Oct 24, 2018
1 parent 099383f commit f64237b
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 79 deletions.
29 changes: 23 additions & 6 deletions src/components/Upload/UploadWrapper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// @flow

// TODO: отрефакторить таким образом, чтобы hidden input и вызов uploadFile с
// отображением ошибок рулились из этого компонента.
// другими словами, сделать полностью автономным

import React from 'react';
import type { Node } from 'react';
import classNames from 'classnames';
Expand All @@ -11,21 +15,22 @@ import type { IconSizeType } from 'types';
import './UploadWrapper.scss';

type PropsType = {
children: Node,
onUpload: (e: any) => void,
children?: ?Node,
onUpload: (e: SyntheticInputEvent<HTMLInputElement>) => void,
buttonLabel: string,
buttonHeight: number | string,
buttonWidth: number | string,
fullWidth: ?boolean,
fullWidth?: ?boolean,
buttonIconType: ?string,
overPicture: ?string,
noIndents: ?boolean,
overPicture?: ?string,
noIndents?: ?boolean,
id: string,
dataTest: string,
buttonIconSize?: IconSizeType,
disabled: ?boolean,
disabled?: ?boolean,
customUnit?: boolean,
square?: boolean,
loading?: boolean,
};

// TODO: refactor for avoid use style props
Expand All @@ -46,8 +51,14 @@ const UploadWrapper = ({
disabled,
customUnit,
square,
loading,
}: PropsType) => (
<div styleName={classNames('wrapper', { square })}>
{loading && (
<div styleName="uploadIndicator">
<div styleName="spinner" />{' '}
</div>
)}
<div styleName={classNames('uploadContainer', { noIndents })}>
<label
htmlFor={id}
Expand Down Expand Up @@ -104,6 +115,12 @@ UploadWrapper.defaultProps = {
customUnit: false,
square: false,
buttonIconSize: 32,
children: null,
fullWidth: null,
overPicture: null,
noIndents: null,
disabled: null,
loading: false,
};

export default UploadWrapper;
39 changes: 37 additions & 2 deletions src/components/Upload/UploadWrapper.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
@import "../../styles/variables";
@import '../../styles/variables';

.wrapper {
display: flex;
flex-direction: row;
width: 100%;
position: relative;
}

.square {
Expand Down Expand Up @@ -31,6 +32,40 @@
}
}

.uploadIndicator {
background-color: #000;
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.25;
display: flex;
justify-content: center;
align-items: center;
top: 0;
left: 0;

& .spinner {
opacity: 1;
border: 1px solid transparent;
border-top: 1px solid $color_white;
border-radius: 50%;
width: 4rem;
height: 4rem;
animation: spin 2s linear infinite;
z-index: 1;
}
}

@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}

.uploadButton {
position: relative;
height: 100%;
Expand Down Expand Up @@ -109,4 +144,4 @@

.fullWidth {
width: 100%;
}
}
2 changes: 2 additions & 0 deletions src/components/Upload/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
// @flow

export { default as UploadWrapper } from './UploadWrapper';
28 changes: 17 additions & 11 deletions src/components/common/Button/Button.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../../../styles/variables.scss";
@import '../../../styles/variables.scss';

.container {
position: relative;
Expand Down Expand Up @@ -146,7 +146,7 @@
}

&.disabled {
opacity: .3;
opacity: 0.3;

&:hover {
color: $color_blue;
Expand All @@ -171,6 +171,15 @@
width: 100%;
}

.isLoading {
background-color: $color_blue_hover;
border: 1px solid $color_blue_hover;

& .spinner {
opacity: 1;
}
}

.spinner {
position: absolute;
opacity: 0;
Expand All @@ -185,16 +194,13 @@
// transition: $transition_all_ease;
}

.isLoading {
background-color: $color_blue_hover;
border: 1px solid $color_blue_hover;

& .spinner {opacity: 1;}
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}

.transparent {
Expand Down
29 changes: 23 additions & 6 deletions src/pages/Manage/Store/ManageStoreMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type PropsType = {
};

type StateType = {
isMainPhotoUploading: boolean,
storeData: ?{
myStore: {
id: string,
Expand Down Expand Up @@ -79,6 +80,7 @@ const MANAGE_STORE_MENU_FRAGMENT = graphql`
class ManageStoreMenu extends Component<PropsType, StateType> {
state = {
storeData: null,
isMainPhotoUploading: false,
};

componentWillMount() {
Expand Down Expand Up @@ -117,18 +119,31 @@ class ManageStoreMenu extends Component<PropsType, StateType> {

disposeUser: () => void;

handleOnUpload = async (e: any) => {
handleOnUpload = (e: SyntheticInputEvent<HTMLInputElement>) => {
e.preventDefault();
const file = e.target.files[0];
const result = await uploadFile(file);
if (!result.url) return;
this.handleLogoUpload(result.url);
this.setState({ isMainPhotoUploading: true });
uploadFile(e.target.files[0])
.then(result => {
if (!result || result.url == null) {
log.error(result);
alert('Error :('); // eslint-disable-line
}
this.handleLogoUpload(result.url || '');
})
.catch(alert)
.finally(() => {
this.setState({ isMainPhotoUploading: false });
});
};

handleLogoUpload = (url: string) => {
const { environment } = this.props;
// $FlowIgnoreMe
const storeId = pathOr(null, ['storeData', 'myStore', 'id'], this.state);
const storeId: ?string = pathOr(
null,
['storeData', 'myStore', 'id'],
this.state,
);

if (!storeId) {
this.props.showAlert({
Expand Down Expand Up @@ -274,6 +289,8 @@ class ManageStoreMenu extends Component<PropsType, StateType> {
myStore ? convertSrc(storeLogo, 'medium') || null : newStoreLogo
}
dataTest="storeImgUploader"
loading={this.state.isMainPhotoUploading}
buttonHeight="100%"
/>
{((myStore && storeLogo) || (!myStore && newStoreLogo)) && (
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import React, { PureComponent } from 'react';
import React, { Component } from 'react';
import {
assoc,
pathOr,
Expand Down Expand Up @@ -34,7 +34,15 @@ type PropsType = {
value: { attrId: number, value: string, metaField?: string },
};

class CharacteristicItem extends PureComponent<PropsType> {
type StateType = {
isPhotoUploading: boolean,
};

class CharacteristicItem extends Component<PropsType, StateType> {
state = {
isPhotoUploading: false,
};

getSelectItems = (
attribute: AttributeType,
): Array<{ id: string, label: string }> => {
Expand Down Expand Up @@ -78,12 +86,22 @@ class CharacteristicItem extends PureComponent<PropsType> {
});
};

handleOnUpload = async (e: any) => {
handleOnUpload = (e: SyntheticInputEvent<HTMLInputElement>) => {
e.preventDefault();
const file = e.target.files[0];
const result = await uploadFile(file);
if (!result.url) return;
this.props.onSelect(assoc('metaField', result.url, this.props.value));

this.setState({ isPhotoUploading: true });
uploadFile(e.target.files[0])
.then(result => {
if (!result || result.url == null) {
log.error(result);
alert('Error :('); // eslint-disable-line
}
this.props.onSelect(assoc('metaField', result.url, this.props.value));
})
.catch(alert)
.finally(() => {
this.setState({ isPhotoUploading: false });
});
};

render() {
Expand Down Expand Up @@ -111,6 +129,8 @@ class CharacteristicItem extends PureComponent<PropsType> {
buttonIconType="upload"
overPicture={convertSrc(characteristicImg, 'small')}
dataTest="productCharacteristicImgUploader"
loading={this.state.isPhotoUploading}
buttonLabel=""
/>
</div>
<div styleName="characteristicSelect">
Expand Down
Loading

0 comments on commit f64237b

Please sign in to comment.