Post widget
This commit is contained in:
@@ -20,3 +20,4 @@ Table:
|
|||||||
| 16.07.2023 | Login and register page | 20 |
|
| 16.07.2023 | Login and register page | 20 |
|
||||||
| 16.07.2023 | Fix mock schema and move mock injections out of index.js | 1 |
|
| 16.07.2023 | Fix mock schema and move mock injections out of index.js | 1 |
|
||||||
| 18.07.2023 | Home page and navigate to login/register page if not logged in | 20 |
|
| 18.07.2023 | Home page and navigate to login/register page if not logged in | 20 |
|
||||||
|
| 19.07.2023 | Post widget | 10 |
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Box, useMediaQuery } from "@mui/material";
|
|||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import Navbar from "scenes/navbar";
|
import Navbar from "scenes/navbar";
|
||||||
import UserWidget from "scenes/widgets/UserWidget";
|
import UserWidget from "scenes/widgets/UserWidget";
|
||||||
|
import PostWidget from "scenes/widgets/PostWidget";
|
||||||
|
|
||||||
const HomePage = () => {
|
const HomePage = () => {
|
||||||
const isNotMobile = useMediaQuery("(min-width: 1000px)");
|
const isNotMobile = useMediaQuery("(min-width: 1000px)");
|
||||||
@@ -23,7 +24,9 @@ const HomePage = () => {
|
|||||||
<Box
|
<Box
|
||||||
flexBasis={isNotMobile ? "42%" : undefined}
|
flexBasis={isNotMobile ? "42%" : undefined}
|
||||||
mt={isNotMobile ? undefined : "2rem"}
|
mt={isNotMobile ? undefined : "2rem"}
|
||||||
></Box>
|
>
|
||||||
|
<PostWidget profilePicturePath={profilePicturePath} />
|
||||||
|
</Box>
|
||||||
{isNotMobile && <Box flexBasis="26%"></Box>}
|
{isNotMobile && <Box flexBasis="26%"></Box>}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
179
client/src/scenes/widgets/PostWidget.jsx
Normal file
179
client/src/scenes/widgets/PostWidget.jsx
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import {
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
AttachFileOutlined,
|
||||||
|
GifBoxOutlined,
|
||||||
|
ImageOutlined,
|
||||||
|
MicOutlined,
|
||||||
|
MoreHorizOutlined,
|
||||||
|
} from "@mui/icons-material";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Divider,
|
||||||
|
Typography,
|
||||||
|
InputBase,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
useTheme,
|
||||||
|
useMediaQuery,
|
||||||
|
} from "@mui/material";
|
||||||
|
import Dropzone from "react-dropzone";
|
||||||
|
import FlexBetween from "components/FlexBetween";
|
||||||
|
import WidgetWrapper from "components/WidgetWrapper";
|
||||||
|
import ProfilePhoto from "components/ProfilePhoto";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { setPosts } from "state";
|
||||||
|
|
||||||
|
const PostWidget = ({ profilePicturePath }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [isImageDropzoneOpen, setIsImageDropzoneOpen] = useState(false);
|
||||||
|
const [image, setImage] = useState(null);
|
||||||
|
const [post, setPost] = useState("");
|
||||||
|
const { palette } = useTheme();
|
||||||
|
const { _id } = useSelector((state) => state.user);
|
||||||
|
const token = useSelector((state) => state.token);
|
||||||
|
const isNotMobile = useMediaQuery("(min-width: 1000px)");
|
||||||
|
const mediumMain = palette.neutral.mediumMain;
|
||||||
|
const medium = palette.neutral.medium;
|
||||||
|
|
||||||
|
const handlePost = async () => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("userId", _id);
|
||||||
|
formData.append("content", post);
|
||||||
|
if (image) {
|
||||||
|
formData.append("contentPicture", image);
|
||||||
|
formData.append("contentPicturePath", image.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`http://localhost:3001/posts`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
const posts = await response.json();
|
||||||
|
dispatch(setPosts({ posts }));
|
||||||
|
setImage(null);
|
||||||
|
setPost("");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WidgetWrapper>
|
||||||
|
<FlexBetween gap="1.5rem">
|
||||||
|
<ProfilePhoto image={profilePicturePath} />
|
||||||
|
<InputBase
|
||||||
|
placeholder="What's on your mind?"
|
||||||
|
onChange={(e) => setPost(e.target.value)}
|
||||||
|
value={post}
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: palette.neutral.light,
|
||||||
|
borderRadius: "2rem",
|
||||||
|
padding: "1rem 2rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FlexBetween>
|
||||||
|
{isImageDropzoneOpen && (
|
||||||
|
<Box
|
||||||
|
borderRadius="5px"
|
||||||
|
border={`1px solid ${medium}`}
|
||||||
|
mt="1rem"
|
||||||
|
p="1rem"
|
||||||
|
>
|
||||||
|
<Dropzone
|
||||||
|
acceptedFiles=".jpg,.jpeg,.png"
|
||||||
|
multiple={false}
|
||||||
|
onDrop={(acceptedFiles) => {
|
||||||
|
setImage(acceptedFiles[0]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ getRootProps, getInputProps }) => (
|
||||||
|
<FlexBetween>
|
||||||
|
<Box
|
||||||
|
{...getRootProps()}
|
||||||
|
border={`2px dashed ${palette.primary.main}`}
|
||||||
|
p="1rem"
|
||||||
|
width="100%"
|
||||||
|
sx={{ "&:hover": { cursor: "pointer" } }}
|
||||||
|
>
|
||||||
|
<input {...getInputProps()} />
|
||||||
|
{!image ? (
|
||||||
|
<p>Add image to post</p>
|
||||||
|
) : (
|
||||||
|
<FlexBetween>
|
||||||
|
<Typography>{image.name}</Typography>
|
||||||
|
<EditOutlined />
|
||||||
|
</FlexBetween>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{image && (
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setImage(null)}
|
||||||
|
sx={{ width: "15%" }}
|
||||||
|
>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</FlexBetween>
|
||||||
|
)}
|
||||||
|
</Dropzone>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<Divider sx={{ margin: "1.25rem 0" }} />
|
||||||
|
<FlexBetween>
|
||||||
|
<FlexBetween
|
||||||
|
gap="0.25rem"
|
||||||
|
onClick={() => setIsImageDropzoneOpen(!isImageDropzoneOpen)}
|
||||||
|
>
|
||||||
|
<ImageOutlined sx={{ color: mediumMain }} />
|
||||||
|
<Typography
|
||||||
|
color={mediumMain}
|
||||||
|
sx={{
|
||||||
|
"&:hover": {
|
||||||
|
cursor: "pointer",
|
||||||
|
color: medium,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Image
|
||||||
|
</Typography>
|
||||||
|
</FlexBetween>
|
||||||
|
{isNotMobile ? (
|
||||||
|
<>
|
||||||
|
<FlexBetween gap="0.25rem">
|
||||||
|
<GifBoxOutlined sx={{ color: mediumMain }} />
|
||||||
|
<Typography color={mediumMain}>Clip</Typography>
|
||||||
|
</FlexBetween>
|
||||||
|
<FlexBetween gap="0.25rem">
|
||||||
|
<AttachFileOutlined sx={{ color: mediumMain }} />
|
||||||
|
<Typography color={mediumMain}>Attachment</Typography>
|
||||||
|
</FlexBetween>
|
||||||
|
<FlexBetween gap="0.25rem">
|
||||||
|
<MicOutlined sx={{ color: mediumMain }} />
|
||||||
|
<Typography color={mediumMain}>Audio</Typography>
|
||||||
|
</FlexBetween>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<FlexBetween gap="0.25rem">
|
||||||
|
<MoreHorizOutlined sx={{ color: mediumMain }} />
|
||||||
|
</FlexBetween>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
disabled={!post}
|
||||||
|
onClick={handlePost}
|
||||||
|
sx={{
|
||||||
|
color: palette.background.alt,
|
||||||
|
backgroundColor: palette.primary.main,
|
||||||
|
borderRadius: "3rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Post
|
||||||
|
</Button>
|
||||||
|
</FlexBetween>
|
||||||
|
</WidgetWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostWidget;
|
||||||
Reference in New Issue
Block a user