From 49999e8acb43e8f1132e9d4b19f3ac3cad00ed46 Mon Sep 17 00:00:00 2001 From: srgooglo Date: Mon, 6 Jun 2022 16:09:54 +0200 Subject: [PATCH] rewrite component & support additions uploads --- .../app/src/components/PostCreator/index.jsx | 242 +++++++++++++----- .../app/src/components/PostCreator/index.less | 232 +++++++++++++++-- 2 files changed, 379 insertions(+), 95 deletions(-) diff --git a/packages/app/src/components/PostCreator/index.jsx b/packages/app/src/components/PostCreator/index.jsx index 679e3a05..3a5e7c79 100644 --- a/packages/app/src/components/PostCreator/index.jsx +++ b/packages/app/src/components/PostCreator/index.jsx @@ -3,96 +3,196 @@ import * as antd from "antd" import { Icons } from "components/Icons" import { User } from "models" import classnames from "classnames" +import { PostAdditions } from "components/PostCard" import "./index.less" +// TODO: Fetch `maxMessageLength` value from server API const maxMessageLength = 512 -const PostCreatorInput = (props) => { - const [value, setValue] = React.useState("") +export default (props) => { + const api = window.app.request - const canPublish = () => { - return value.length !== 0 && value.length < maxMessageLength - } + const [loading, setLoading] = React.useState(false) + const [uploaderVisible, setUploaderVisible] = React.useState(false) + const [focused, setFocused] = React.useState(false) - const onChange = (e) => { - setValue(e.target.value) - } + const [userData, setUserData] = React.useState(null) + const [postData, setPostData] = React.useState({ + message: "", + additions: [] + }) - const handleSubmit = () => { - if (canPublish()) { - if (typeof props.onSubmit === "function") { - props.onSubmit(value) - } - - setValue("") - } - } - - return
-
- -
- -
- : } - /> -
-
-} - -export default class PostCreator extends React.Component { - state = { - loading: false, - } - api = window.app.request - - componentDidMount = async () => { - const userData = await User.data() - - this.setState({ - userData + const updatePostData = (update) => { + setPostData({ + ...postData, + ...update }) } - onSubmit = async (value) => { - await this.setState({ loading: true }) + const cleanPostData = () => { + setPostData({ + message: "", + additions: [] + }) + } - const result = this.api.put.post({ - message: value, - }).catch(error => { + const submit = () => { + setLoading(true) + + const response = api.put.post({ ...postData }).catch(error => { console.error(error) antd.message.error(error) return false }) - this.setState({ loading: false }) + setLoading(false) + + if (response) { + cleanPostData() + } } - render() { - return
- -
+ const onUploadFile = async (req) => { + // get file data + const file = req.file + + // append to form data + const formData = new FormData() + formData.append("files", file) + + setLoading(true) + + // send request + const request = await api.post.upload(formData, undefined).catch((error) => { + console.error(error) + antd.message.error(error) + + req.onError(error) + + return false + }) + + setLoading(false) + + if (request) { + return req.onSuccess(request) + } } + + const canPublish = () => { + const messageLengthValid = postData.message.length !== 0 && postData.message.length < maxMessageLength + + return Boolean(messageLengthValid) + } + + const onDraggerChange = (change) => { + console.log(change) + + switch (change.file.status) { + case "done": { + let additions = postData.additions ?? [] + + additions.push(...change.file.response) + + return updatePostData({ additions }) + } + + default: { + break + } + } + } + + const onChangeMessageInput = (event) => { + console.log(event.target.value) + + updatePostData({ + message: event.target.value + }) + } + + const toggleUploader = (to) => { + setUploaderVisible(to ?? !uploaderVisible) + } + + const toggleFocus = (to) => { + setFocused(to ?? !focused) + } + + React.useEffect(() => { + User.data().then(user => { + setUserData(user) + }) + }, []) + + return
{ + e.preventDefault() + toggleUploader(true) + }} + onDragLeave={(e) => { + e.preventDefault() + toggleUploader(false) + }} + onMouseEnter={() => { + toggleFocus(true) + }} + onMouseLeave={() => { + toggleFocus(false) + }} + > +
+
+ +
+ +
+ : } + /> +
+
+ + {postData.additions.length > 0 && } + +
+
+ { + toggleUploader() + }} + icon={} + /> +
+
+ +
+ +

Click or drag file to this area to upload

+
+
+
} \ No newline at end of file diff --git a/packages/app/src/components/PostCreator/index.less b/packages/app/src/components/PostCreator/index.less index 9a5439fe..dbd506ac 100644 --- a/packages/app/src/components/PostCreator/index.less +++ b/packages/app/src/components/PostCreator/index.less @@ -1,15 +1,199 @@ .postCreator { - width : 100%; - padding : 15px; + display: flex; + flex-direction: column; + + width: 100%; + padding: 15px; background-color: var(--background-color-accent); - max-width : 600px; + max-width: 600px; border-radius: 7px; + .additions { + margin: 10px 0; + width: 100%; + height: 28vh; + + .slick-slider { + .slick-prev { + display: inline !important; + color: #ffffff; + + z-index: 100; + + top: 0; + left: 0; + + height: 100%; + width: 5vw; + + opacity: 0; + + transition: all 150ms ease-in-out; + + &:hover { + opacity: 0.6; + width: 7vw; + } + + &:active { + transform: scale(0.5); + } + } + + .slick-next { + display: inline !important; + color: #ffffff; + + z-index: 100; + + top: 0; + right: 0; + + height: 100%; + width: 5vw; + + opacity: 0; + + transition: all 150ms ease-in-out; + + &:hover { + opacity: 0.6; + width: 7vw; + } + + &:active { + transform: scale(0.5); + } + } + } + + .slick-track { + display: flex; + align-items: center; + } + + .slick-slide { + height: 100%; + + div { + height: 100%; + } + } + + .slick-list { + border-radius: 8px; + } + + .ant-carousel, + .slick-slider, + .slick-list, + .slick-track { + height: 100%; + } + + .addition { + width: 100%; + height: 100%; + + // fixtures for media content + img { + width: 100%; + height: 100%; + + user-select: none; + -webkit-user-drag: none; + + object-fit: cover; + } + + video { + width: 100%; + height: 100%; + + user-select: none; + -webkit-user-drag: none; + + object-fit: cover; + } + + audio { + width: 100%; + height: 100%; + + user-select: none; + -webkit-user-drag: none; + } + + >div { + height: 100%; + } + } + } + + .actions { + display: inline-flex; + flex-direction: row; + justify-content: flex-start; + + height: 40px; + + overflow: hidden; + + transition: all 150ms ease-in-out; + + >div { + margin-left: 10px; + font-size: 1rem; + + svg { + margin: 0 !important; + } + } + + &.hided { + height: 0; + } + } + + .uploader { + display: flex; + flex-direction: row; + justify-content: flex-start; + + height: 5vh; + width: 100%; + + overflow: hidden; + + transition: all 150ms ease-in-out; + + >div { + margin-left: 10px; + font-size: 1rem; + + svg { + margin: 0 !important; + } + } + + &.hided { + height: 0; + } + + span { + width: 100%; + } + + .ant-upload { + width: 100%; + } + } + .textInput { - display : flex; - width : 100%; - transition : height 150ms ease-in-out; + display: flex; + width: 100%; + transition: height 150ms ease-in-out; background-color: var(--background-color-accent); svg { @@ -17,14 +201,14 @@ } .avatar { - width : fit-content; + width: fit-content; height: 45px; display: flex; img { - width : 45px; - height : 45px; + width: 45px; + height: 45px; border-radius: 12px; } } @@ -35,7 +219,7 @@ .textArea { border-radius: 8px !important; - transition : all 150ms ease-in-out !important; + transition: all 150ms ease-in-out !important; &.active { background-color: var(--background-color-primary); @@ -43,27 +227,27 @@ } .ant-btn-primary { - z-index : 10; - position : relative; - border-radius : 0 10px 10px 0; - height : 100%; + z-index: 10; + position: relative; + border-radius: 0 10px 10px 0; + height: 100%; vertical-align: bottom; - border : none; - box-shadow : none; + border: none; + box-shadow: none; } .ant-input { background-color: var(--background-color-accent); - z-index : 10; - position : relative; - border-color : transparent !important; - box-shadow : none; + z-index: 10; + position: relative; + border-color: transparent !important; + box-shadow: none; border-radius: 3px 0 0; - height : 100%; - padding : 5px 10px; - transition : height 150ms linear; - width : 100%; + height: 100%; + padding: 5px 10px; + transition: height 150ms linear; + width: 100%; } .ant-btn-primary[disabled] {