diff --git a/package.json b/package.json
index b9fc2280..699323b5 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"query-string": "^6.13.1",
"react": "^16.11.0",
"react-background-slider": "^1.2.0",
- "react-cropper": "^1.3.0",
+ "react-cropper": "2.1.7",
"react-dom": "^16.11.0",
"react-images-upload": "^1.2.7",
"react-photo-gallery": "^8.0.0",
diff --git a/src/Components/Upload/ImageCropper/index.jsx b/src/Components/Upload/ImageCropper/index.jsx
new file mode 100644
index 00000000..9fc4f1bd
--- /dev/null
+++ b/src/Components/Upload/ImageCropper/index.jsx
@@ -0,0 +1,111 @@
+import React, { useRef, useState, useEffect, useCallback } from 'react';
+import { useSelector } from 'react-redux';
+import PropTypes from 'prop-types';
+
+import NoStyleButton from 'Components/Form/NoStyleButton';
+
+import Cropper from 'react-cropper';
+import 'cropperjs/dist/cropper.css';
+
+function ImageCropper(props) {
+ const { imgHandler } = props;
+ const cropperRef = useRef(null);
+ const user = useSelector((state) => state.authReducer.user);
+
+ const [pictureImg, setPictureImg] = useState(null);
+ const [pictureImgUrl, setPictureImgUrl] = useState(null);
+
+ const handlePictureImg = async (e) => {
+ if (e.target.files[0] !== undefined) {
+ setPictureImg(e.target.files[0]);
+ setPictureImgUrl(URL.createObjectURL(e.target.files[0]));
+ }
+ };
+
+ const handlePostUpload = useCallback(async () => {
+ if (user && cropperRef.current) {
+ const imgElement = cropperRef.current;
+ const { cropper } = imgElement;
+ if (pictureImg && cropper) {
+ const { name } = pictureImg;
+ const canvas = cropper.getCroppedCanvas();
+ if (canvas) {
+ canvas.toBlob(
+ async (croppedImg) => {
+ const image = new FormData();
+ image.append('img', croppedImg, name);
+ imgHandler(image);
+ },
+ undefined,
+ 1,
+ );
+ }
+ } else {
+ // TO DO :: notify uploading image !
+ }
+ } else {
+ // TO DO :: implement login modal !
+ }
+ }, [imgHandler, user, pictureImg]);
+
+ const removePicture = () => {
+ setPictureImg(null);
+ setPictureImgUrl(null);
+ };
+
+ useEffect(() => {
+ handlePostUpload();
+ }, [pictureImg, handlePostUpload]);
+
+ return (
+ <>
+
+
+
+ {pictureImg && (
+ <>
+
+
+ X
+
+ >
+ )}
+ {!pictureImg && (
+
+
+
+
+
+ )}
+
+
+
+ >
+ );
+}
+
+ImageCropper.propTypes = {
+ imgHandler: PropTypes.func.isRequired,
+};
+
+export default ImageCropper;
diff --git a/src/Components/Upload/ImageCropper/index.scss b/src/Components/Upload/ImageCropper/index.scss
new file mode 100644
index 00000000..c3b6047e
--- /dev/null
+++ b/src/Components/Upload/ImageCropper/index.scss
@@ -0,0 +1,81 @@
+/*
+ ImageCropper Component Styling
+*/
+
+.imageCropper {
+ width: 100%;
+ height: 100%;
+ border-radius: 18px;
+ button:focus {
+ outline: none;
+ }
+ &__creator {
+ margin-bottom: 1rem;
+ height: 100%;
+ &-previewPic {
+ height: 100%;
+ position: relative;
+ display: flex;
+ margin: auto;
+ border: 2px dotted #ccd0d5;
+ background-color: rgba(255, 244, 201, 0.3);
+
+ &__remove {
+ margin: 0.5rem;
+ z-index: 1;
+ position: absolute;
+ top: 0;
+ left: 0;
+ color: $main-color;
+ font-weight: bolder;
+ font-size: 1.5rem;
+ }
+
+ &__empty {
+ position: relative;
+ width: 100%;
+ background-color: $background-color;
+ opacity: 50%;
+ &-uploadPic {
+ z-index: 1;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+
+ label {
+ margin: 0;
+ cursor: pointer;
+ font-family: 'GothamRound';
+ color: $main-color;
+
+ &:hover {
+ animation: buttonHover 0.3s ease;
+ animation-fill-mode: forwards;
+ border-radius: 18px;
+ padding: 1rem;
+ background-color: $main-color;
+ color: white;
+ }
+ }
+ }
+ }
+
+ .cropper {
+ margin: auto;
+ max-width: 80%;
+ max-height: 100%;
+ }
+ }
+ }
+}
+
+@keyframes buttonHover {
+ 0% {
+ transform: scale(1);
+ }
+
+ 100% {
+ transform: scale(1.3);
+ }
+}
diff --git a/src/Components/Upload/UploadPost/index.jsx b/src/Components/Upload/UploadPost/index.jsx
index 87375fe2..71c78edb 100644
--- a/src/Components/Upload/UploadPost/index.jsx
+++ b/src/Components/Upload/UploadPost/index.jsx
@@ -5,16 +5,15 @@ import * as PostAction from 'Redux/post';
import PropTypes from 'prop-types';
-import Cropper from 'react-cropper';
-import 'cropperjs/dist/cropper.css';
-import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
-
import RoundLoader from 'Components/Loader/Round';
+import NoStyleButton from 'Components/Form/NoStyleButton';
+import ImageCropper from 'Components/Upload/ImageCropper';
import plusButton from 'Assets/images/plus.svg';
+import { Modal } from 'reactstrap';
+import TextField from '@material-ui/core/TextField';
+
const defaultProps = {
user: null,
token: null,
@@ -48,54 +47,40 @@ class Upload extends Component {
constructor(props) {
super(props);
this.state = {
- pictureImg: null,
- pictureImgUrl: null,
- content: '',
+ imageFormData: null,
+ title: '',
+ description: '',
modal: false,
};
}
- handlePictureImg = async (e) => {
- if (e.target.files[0] !== undefined) {
- await new Promise((accept) =>
- this.setState({ pictureImg: e.target.files[0] }, accept),
- );
- const { pictureImg } = this.state;
- this.setState({
- pictureImgUrl: URL.createObjectURL(pictureImg),
- });
- }
+ handlePictureWithCropper = (imageFormData) => {
+ this.setState({
+ imageFormData,
+ });
+ };
+
+ handleTitle = (e) => {
+ this.setState({ title: e.target.value });
};
- handleContent = (e) => {
- this.setState({ content: e.target.value });
+ handleDescription = (e) => {
+ this.setState({ description: e.target.value });
};
handlePostUpload = async () => {
const { user, uploadPost, token } = this.props;
- const { pictureImgUrl, pictureImg, content } = this.state;
+ const { imageFormData, title, description } = this.state;
if (user) {
- if (pictureImgUrl) {
- this.cropper.getCroppedCanvas({ imageSmoothingQuality: 'high' }).toBlob(
- async (croppedImg) => {
- const image = new FormData();
- const params = new URLSearchParams();
- image.append('img', croppedImg, pictureImg.name);
- params.append('title', content);
- params.append('user_id', user.id);
- params.append('description', content);
- params.append('category_id', 5);
- params.append('is_public', true);
- const postUpload = await uploadPost(image, params, token);
- if (postUpload) window.location.reload();
- // TO DO :: notify failed to upload image
- },
- undefined,
- 1,
- );
- } else {
- // TO DO :: notify uploading image !
- }
+ const params = new URLSearchParams();
+
+ params.append('title', title);
+ params.append('user_id', user.id);
+ params.append('description', description);
+ params.append('category_id', 5);
+ params.append('is_public', true);
+ const postUpload = await uploadPost(imageFormData, params, token);
+ if (postUpload) window.location.reload();
} else {
// TO DO :: implement login modal !
}
@@ -107,84 +92,66 @@ class Upload extends Component {
};
render() {
- const { content, modal, pictureImgUrl } = this.state;
+ const { content, modal } = this.state;
const { isUploading } = this.props;
return (
<>
{isUploading && }
-
-
-
- Upload Your Masterpiece!
-
-
-
-
-
-
+ <>
+
+
+
+
+
+ Share Your Masterpiece with Blecther.
+
+
+ This will be automatically uploaded to my feed and displayed
+ to Blecther home.
- {pictureImgUrl && (
-
- {
- this.cropper = cropper;
- }}
- // Cropper.js options
- center
- />
+
+
+
+
+
+ Brief Introduction about Your Masterpiece
- )}
-
+
+
-
-
-
-
-
-
+
+ >
>
);
}
diff --git a/src/Components/Upload/UploadPost/index.scss b/src/Components/Upload/UploadPost/index.scss
index 6ac37c91..8b75db89 100644
--- a/src/Components/Upload/UploadPost/index.scss
+++ b/src/Components/Upload/UploadPost/index.scss
@@ -2,69 +2,92 @@
Upload Post Component Styling
*/
-.postUpload {
- width: 500px;
- button:focus {
- outline: none;
- }
+.uploadPost {
+ background-color: white;
+ z-index: 1005;
+ width: 70%;
+ height: 70%;
+ position: fixed;
+ transform: translate(-50%, -50%);
+ top: 50%;
+ left: 50%;
+ border-radius: 18px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ overflow: hidden;
+ &__header {
+ width: 100%;
+ height: 15%;
+ display: flex;
+ flex-flow: column wrap;
+ align-items: center;
+ justify-content: center;
+ background-color: $background-color;
+ &__title {
+ color: $main-color;
+ font-size: 1.9rem;
+ }
- .backBtn {
- width: 35px;
- cursor: pointer;
+ &__sub {
+ font-family: 'AppleSDGothicNeo';
+ }
}
- &__creator {
- &-uploadPic {
- width: 80%;
- margin: auto;
- margin-bottom: 5px;
-
- label {
- width: 100%;
- margin: 0;
- cursor: pointer;
- }
+ &__content {
+ width: 90%;
+ height: 50%;
+ flex-direction: column;
+ justify-content: space-around;
+ align-items: center;
+ &__image {
+ height: 100%;
}
+ }
+
+ &__footer {
+ width: 100%;
+ margin-bottom: 3%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ align-items: center;
- &-previewPic {
+ &__input {
+ width: 40%;
+ height: 40%;
display: flex;
flex-direction: column;
- align-items: center;
justify-content: center;
- width: 80%;
- min-height: 300px;
- margin: auto;
- border: 2px dotted #ccd0d5;
- border-radius: 4px;
- margin-bottom: 20px;
-
- .cropper {
- width: 100%;
- max-height: 300px;
+ & input {
+ width: max-content;
}
- }
- &-content {
- width: 80%;
- margin: auto;
+ &__text {
+ text-align: center;
+ color: $main-color;
+ font-size: 1.3rem;
+ }
}
- }
-
- &__sketcher {
- &-uploadPic {
+ &__buttons {
+ width: fit-content;
+ height: 100%;
display: flex;
-
- div {
- width: 50%;
- border: 1px solid #ccd0d5;
- border-radius: 4px;
+ flex-direction: column;
+ justify-content: space-around;
+ & .noStyleButton {
+ height: fit-content;
+ padding: 1rem 4rem;
+ border-radius: 26px;
+ border: 2px solid $main-color;
text-align: center;
+
+ &:hover {
+ color: white;
+ background-color: $main-color;
+ }
}
}
}
-
- &__upload {
- margin-top: 20px;
- text-align: center;
- }
}
diff --git a/src/index.scss b/src/index.scss
index 88d16b2c..1a2dbe5b 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -22,6 +22,7 @@
@import 'Components/Sign/SignUpContainer';
@import 'Components/Sign/SignInModal';
@import 'Components/Upload/UploadPost';
+@import 'Components/Upload/ImageCropper';
@import 'Components/Search/';
@import 'Components/Post/Post';
@import 'Components/Post/PostList';
diff --git a/yarn.lock b/yarn.lock
index 76d96c98..d1c58534 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2307,11 +2307,6 @@ babel-code-frame@^6.22.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
-babel-core@7.0.0-bridge.0:
- version "7.0.0-bridge.0"
- resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
- integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==
-
babel-eslint@10.1.0, babel-eslint@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@@ -3421,10 +3416,10 @@ create-react-context@^0.3.0:
gud "^1.0.0"
warning "^4.0.3"
-cropperjs@^1.5.5:
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.7.tgz#b65019725bae1c6285e881fb661b2141fa57025b"
- integrity sha512-sGj+G/ofKh+f6A4BtXLJwtcKJgMUsXYVUubfTo9grERiDGXncttefmue/fyQFvn8wfdyoD1KhDRYLfjkJFl0yw==
+cropperjs@^1.5.11:
+ version "1.5.11"
+ resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.11.tgz#502ae6d8ca098b124de6813601cca70015879fc0"
+ integrity sha512-SJUeBBhtNBnnn+UrLKluhFRIXLJn7XFPv8QN1j49X5t+BIMwkgvDev541f96bmu8Xe0TgCx3gON22KmY/VddaA==
cropperjs@^1.5.9:
version "1.5.9"
@@ -9335,14 +9330,12 @@ react-background-slider@^1.2.0:
css-vendor "^1.2.1"
prop-types "^15.7.2"
-react-cropper@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/react-cropper/-/react-cropper-1.3.0.tgz#7de0c09a440d62f72c0df5f104d4ad7598cc3bf0"
- integrity sha512-A14BUmeOD84ulNp/eChHOBuChVYatPodhc43wZzO9ZSFoM2Ta8O9P+ZXURyseF/R8v32a6YyMVcBUShj7XqcbA==
+react-cropper@2.1.7:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/react-cropper/-/react-cropper-2.1.7.tgz#f9f8127b9516fecc44f918dd331107bfc32adfaf"
+ integrity sha512-dGp2l2wSh4KubWx3PQZIP27fV4shPYjIvm972IqJZdzi/fpDsB6s3GKEH54mk0gy18+80d3WnlgAP2xJ/o8+yw==
dependencies:
- babel-core "7.0.0-bridge.0"
- cropperjs "^1.5.5"
- prop-types "^15.5.8"
+ cropperjs "^1.5.11"
react-dev-utils@^10.2.1:
version "10.2.1"