aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2020-10-29 23:53:13 +0300
committereug-vs <eug-vs@keemail.me>2020-10-29 23:54:35 +0300
commit3fef7795681c405322aed6e1c876948ebc2cc932 (patch)
treec961340ae0364e189361ff7032377f41756e79c7
parente086da62473bf542d972aa53e605926f9af796f5 (diff)
downloadwhich-ui-3fef7795681c405322aed6e1c876948ebc2cc932.tar.gz
refactor: separate ImageCropAreaSelect component
-rw-r--r--src/components/AvatarCrop/AvatarCrop.tsx74
-rw-r--r--src/components/ImageCropAreaSelect/ImageCropAreaSelect.tsx55
-rw-r--r--src/components/ModalScreen/ModalScreen.tsx7
-rw-r--r--src/containers/AvatarCropModal/AvatarCropModal.tsx57
-rw-r--r--src/containers/AvatarCropModal/canvasUtils.js (renamed from src/components/AvatarCrop/canvasUtils.js)0
-rw-r--r--src/containers/Profile/ProfileInfo.tsx15
6 files changed, 120 insertions, 88 deletions
diff --git a/src/components/AvatarCrop/AvatarCrop.tsx b/src/components/AvatarCrop/AvatarCrop.tsx
deleted file mode 100644
index ef6d9c8..0000000
--- a/src/components/AvatarCrop/AvatarCrop.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import React, {useCallback, useContext, useState} from 'react';
-import Cropper from 'react-easy-crop';
-import {makeStyles} from '@material-ui/core/styles';
-import SendIcon from "@material-ui/icons/Send";
-import ModalScreen from "../ModalScreen/ModalScreen";
-import { getCroppedImg } from './canvasUtils'
-
-interface PropTypes {
- avatarToCrop: string;
- setAvatarToCrop: (src: string) => void;
- callback: (file: File) => void;
-}
-
-const useStyles = makeStyles(theme => ({
- cropContainer: {
- position: 'relative',
- width: '100%',
- height: '100vh',
- background: '#333',
- [theme.breakpoints.up('sm')]: {
- height: 400,
- },
- }
-}));
-
-const AvatarCrop: React.FC<PropTypes> = ({ avatarToCrop, setAvatarToCrop, callback }) => {
- const classes = useStyles();
- const [crop, setCrop] = useState({x: 0, y: 0});
- const [zoom, setZoom] = useState(1);
- const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
-
- const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
- setCroppedAreaPixels(croppedAreaPixels)
- }, []);
-
- const handleLoadCroppedImage = useCallback(async () => {
- try {
- const croppedImage = await getCroppedImg(avatarToCrop, croppedAreaPixels);
- callback(croppedImage);
- } catch (e) {
- console.error(e)
- }
- }, [avatarToCrop, croppedAreaPixels]);
-
- const handleCloseModal = useCallback( () => {
- setAvatarToCrop('');
- },[]);
-
- return (
- <ModalScreen
- title="Choose area"
- actionIcon={<SendIcon />}
- handleAction={handleLoadCroppedImage}
- isActionDisabled={false}
- handleCloseModal={handleCloseModal}
- >
- <div className={classes.cropContainer}>
- <Cropper
- image={avatarToCrop}
- crop={crop}
- zoom={zoom}
- aspect={1}
- cropShape="round"
- showGrid={false}
- onCropChange={setCrop}
- onCropComplete={onCropComplete}
- onZoomChange={setZoom}
- />
- </div>
- </ModalScreen>
- )
-};
-
-export default AvatarCrop;
diff --git a/src/components/ImageCropAreaSelect/ImageCropAreaSelect.tsx b/src/components/ImageCropAreaSelect/ImageCropAreaSelect.tsx
new file mode 100644
index 0000000..015dd47
--- /dev/null
+++ b/src/components/ImageCropAreaSelect/ImageCropAreaSelect.tsx
@@ -0,0 +1,55 @@
+import React, { useCallback, useState } from 'react';
+import Cropper from 'react-easy-crop';
+import { makeStyles } from '@material-ui/core/styles';
+
+interface Area {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+}
+
+interface PropTypes {
+ image: string;
+ setArea: (area: Area) => void;
+}
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ position: 'relative',
+ width: '100%',
+ height: '100vh',
+ background: '#333',
+ [theme.breakpoints.up('sm')]: {
+ height: 400,
+ }
+ }
+}));
+
+const ImageCropAreaSelect: React.FC<PropTypes> = ({ image, setArea }) => {
+ const classes = useStyles();
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
+ const [zoom, setZoom] = useState(1);
+
+ const onCropComplete = useCallback((areaPercentage: Area, areaPixels: Area): void => {
+ setArea(areaPixels);
+ }, [setArea]);
+
+ return (
+ <div className={classes.root}>
+ <Cropper
+ image={image}
+ crop={crop}
+ zoom={zoom}
+ aspect={1}
+ cropShape="round"
+ showGrid={false}
+ onCropChange={setCrop}
+ onCropComplete={onCropComplete}
+ onZoomChange={setZoom}
+ />
+ </div>
+ )
+};
+
+export default ImageCropAreaSelect;
diff --git a/src/components/ModalScreen/ModalScreen.tsx b/src/components/ModalScreen/ModalScreen.tsx
index 61cf44a..b71c2c8 100644
--- a/src/components/ModalScreen/ModalScreen.tsx
+++ b/src/components/ModalScreen/ModalScreen.tsx
@@ -1,5 +1,4 @@
import React, { useState, useCallback } from 'react';
-import { useHistory } from 'react-router-dom';
import {
AppBar,
Dialog,
@@ -20,7 +19,7 @@ interface PropTypes {
actionIcon?: JSX.Element;
handleAction?: () => void;
isActionDisabled?: boolean;
- handleCloseModal: ()=> void;
+ handleCloseModal?: ()=> void;
}
const useStyles = makeStyles(theme => ({
@@ -48,11 +47,9 @@ const ModalScreen: React.FC<PropTypes> = ({ title, actionIcon, handleAction, isA
const classes = useStyles();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
- const history = useHistory();
-
const handleClose = useCallback(() => setIsOpen(false), [setIsOpen]);
- const onExited = useCallback(handleCloseModal, [history, handleAction]);
+ const onExited = useCallback(() => handleCloseModal && handleCloseModal(), [handleCloseModal]);
const handleClickAction = useCallback(async () => {
if (handleAction) await handleAction();
diff --git a/src/containers/AvatarCropModal/AvatarCropModal.tsx b/src/containers/AvatarCropModal/AvatarCropModal.tsx
new file mode 100644
index 0000000..a24d2b4
--- /dev/null
+++ b/src/containers/AvatarCropModal/AvatarCropModal.tsx
@@ -0,0 +1,57 @@
+import React, { useState } from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import SendIcon from "@material-ui/icons/Send";
+import { getCroppedImg } from './canvasUtils'
+
+import ImageCropAreaSelect from '../../components/ImageCropAreaSelect/ImageCropAreaSelect';
+import ModalScreen from '../../components/ModalScreen/ModalScreen';
+
+interface Area {
+ x: number;
+ y: number;
+ width?: number;
+ height?: number;
+}
+
+interface PropTypes {
+ avatar: string;
+ callback: (file: File) => void;
+}
+
+const useStyles = makeStyles(theme => ({
+ cropContainer: {
+ position: 'relative',
+ width: '100%',
+ height: '100vh',
+ background: '#333',
+ [theme.breakpoints.up('sm')]: {
+ height: 400,
+ },
+ }
+}));
+
+const AvatarCropModal: React.FC<PropTypes> = ({ avatar, callback }) => {
+ const classes = useStyles();
+ const [area, setArea] = useState<Area>({ x: 0, y: 0 });
+
+ const handleAction = async () => getCroppedImg(avatar, area)
+ .then(croppedImage => callback(croppedImage));
+
+ return (
+ <ModalScreen
+ title="Choose area"
+ actionIcon={<SendIcon />}
+ handleAction={handleAction}
+ isActionDisabled={false}
+ >
+ <div className={classes.cropContainer}>
+ <ImageCropAreaSelect
+ image={avatar}
+ setArea={setArea}
+ />
+ </div>
+ </ModalScreen>
+ )
+};
+
+export default AvatarCropModal;
diff --git a/src/components/AvatarCrop/canvasUtils.js b/src/containers/AvatarCropModal/canvasUtils.js
index b01aadc..b01aadc 100644
--- a/src/components/AvatarCrop/canvasUtils.js
+++ b/src/containers/AvatarCropModal/canvasUtils.js
diff --git a/src/containers/Profile/ProfileInfo.tsx b/src/containers/Profile/ProfileInfo.tsx
index b71e6db..4c9f17e 100644
--- a/src/containers/Profile/ProfileInfo.tsx
+++ b/src/containers/Profile/ProfileInfo.tsx
@@ -11,7 +11,7 @@ import Avatar from '../../components/Avatar/Avatar';
import { patch } from '../../requests';
import { useAuth } from '../../hooks/useAuth';
import uploadFileToS3 from '../../utils/uploadFileToS3';
-import AvatarCrop from "../../components/AvatarCrop/AvatarCrop";
+import AvatarCropModal from '../AvatarCropModal/AvatarCropModal';
interface PropTypes {
savedPolls: number;
@@ -112,13 +112,10 @@ const ProfileInfo: React.FC<PropTypes> = ({
const dateSince = useMemo(() => formatDate(userInfo?.createdAt), [userInfo]);
const handleUpdateAvatar = useCallback(async (file: File) => {
- if (user) {
- uploadFileToS3(file, 0.8, setProgress)
- .then(avatarUrl => patch(`/users/${user._id}`, { avatarUrl }))
- .then(response => setUserInfo(response.data))
- .then(() => setProgress(0));
- setAvatarToCrop('');
- }
+ if (user) uploadFileToS3(file, 0.8, setProgress)
+ .then(avatarUrl => patch(`/users/${user._id}`, { avatarUrl }))
+ .then(response => setUserInfo(response.data))
+ .then(() => setProgress(0));
}, [user, setUserInfo]);
const handleCropAvatar = useCallback( async(file: File) => {
@@ -129,7 +126,7 @@ const ProfileInfo: React.FC<PropTypes> = ({
return (
<div className={classes.root}>
{
- avatarToCrop && <AvatarCrop avatarToCrop={avatarToCrop} setAvatarToCrop={setAvatarToCrop} callback={handleUpdateAvatar}/>
+ avatarToCrop && <AvatarCropModal avatar={avatarToCrop} callback={handleUpdateAvatar}/>
}
{
!userInfo