From 666b788b576ec33f5c6a43168c9392c8bf0adbeb Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sun, 31 Oct 2021 10:26:14 +0530 Subject: [PATCH 01/10] Added localhost proxy for development --- client/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/package.json b/client/package.json index 8e0d816..66bef19 100644 --- a/client/package.json +++ b/client/package.json @@ -50,5 +50,6 @@ "last 1 firefox version", "last 1 safari version" ] - } + }, + "proxy": "http://127.0.0.1:8081/" } From 1f2c3104bbca40e82d86268c810a98bc4a698a63 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sun, 31 Oct 2021 10:34:19 +0530 Subject: [PATCH 02/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6041ac6..08c27bf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ https://blogger-bhaiya.herokuapp.com/doc/ 1. Clone the repository ```sh -$ git clone https://github.com/Rajpra786/Blog-App.git +$ git clone -b development https://github.com/Rajpra786/Blog-App.git ``` 2. Install the dependencies and start the development server From fdc53fda87c3412d91c54d6b94744c0d2c971fe2 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sun, 31 Oct 2021 11:54:47 +0530 Subject: [PATCH 03/10] update heroku url --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08c27bf..d3dee72 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ ## Live Demo -https://blogger-bhaiya.herokuapp.com +https://ok-blogger.herokuapp.com/ ## Swagger Documentation -https://blogger-bhaiya.herokuapp.com/doc/ +https://ok-blogger.herokuapp.com/doc/ ## Run on worlds fasted-server: localhost From 8b87ae5ab370fda46114699057a2466d7ebc7b57 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Mon, 3 Oct 2022 08:11:58 +0530 Subject: [PATCH 04/10] update blog view --- client/package.json | 2 +- client/src/App.js | 2 +- .../Components/MiniBlogCard/MiniBlogCard.js | 118 +++++++++--------- .../Recommendations/Recommendations.js | 41 +++--- client/src/Components/UserCard/UserCard.js | 53 ++++---- client/src/Containers/BlogById/BlogById.js | 2 +- client/src/Containers/BlogById/BlogContent.js | 37 +++--- client/src/Containers/BlogById/BlogHeader.js | 1 + client/src/Containers/BlogById/Poster.js | 1 + client/src/Containers/BlogById/RightPanel.js | 17 +-- swagger_output.json | 11 +- 11 files changed, 146 insertions(+), 139 deletions(-) diff --git a/client/package.json b/client/package.json index 66bef19..81309cd 100644 --- a/client/package.json +++ b/client/package.json @@ -52,4 +52,4 @@ ] }, "proxy": "http://127.0.0.1:8081/" -} +} \ No newline at end of file diff --git a/client/src/App.js b/client/src/App.js index b52eefc..edd67ed 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -45,7 +45,7 @@ class App extends Component { - + diff --git a/client/src/Components/MiniBlogCard/MiniBlogCard.js b/client/src/Components/MiniBlogCard/MiniBlogCard.js index 70df870..0bfc576 100644 --- a/client/src/Components/MiniBlogCard/MiniBlogCard.js +++ b/client/src/Components/MiniBlogCard/MiniBlogCard.js @@ -1,75 +1,73 @@ import * as React from "react"; import { useTheme } from "@mui/material/styles"; import { - Card, - CardContent, - CardHeader, Box, - CardMedia, Typography, + ListItem, + ListItemAvatar, + Avatar, + ListItemText } from "@mui/material"; import { Link, withRouter } from "react-router-dom"; -const cardStyle = { - display: "flex", - width: "23vw", - height: "27vh", - margin: "1vw", - overflow: "hidden", - border: "0.3vh solid #ddd", - borderRadius: "2vh", - "&:hover": { - boxShadow: "0 1vh 2vh 0px rgba(0, 0, 0, 0.4)", - transform: "scale(1.04)", - }, - "&:active": { - transform: "scale(1.01) translateY(0.5vh)", - }, -}; - const MiniBlogCard = (props) => { const theme = useTheme(); return ( - - - - - - {props.title} - - - - {props.author}} - subheader={ - - {props.date} - - } - /> - - - - - + + + + + + {props.author} + + + + } + secondary={ + + + + {props.title} + + + + } + /> + + + + + + + ); }; diff --git a/client/src/Components/Recommendations/Recommendations.js b/client/src/Components/Recommendations/Recommendations.js index df6c472..e7daecc 100644 --- a/client/src/Components/Recommendations/Recommendations.js +++ b/client/src/Components/Recommendations/Recommendations.js @@ -1,4 +1,4 @@ -import { Grid, Typography } from "@mui/material"; +import { Grid, Typography, List, Divider } from "@mui/material"; import React from "react"; import MiniBlogCard from "../MiniBlogCard/MiniBlogCard"; import Get from "../../Requests/Get"; @@ -25,24 +25,29 @@ class Recommendations extends React.Component { render() { return ( - - - Recommendations + + + More from Ok-Blogger - {this.state.blogs.map((blog) => { - return ( - - ); - })} + + {this.state.blogs.map((blog) => { + return ( + + + + + ); + })} + ); } diff --git a/client/src/Components/UserCard/UserCard.js b/client/src/Components/UserCard/UserCard.js index 3029da3..827f632 100644 --- a/client/src/Components/UserCard/UserCard.js +++ b/client/src/Components/UserCard/UserCard.js @@ -1,7 +1,6 @@ import React from "react"; import Get from "../../Requests/Get"; -import { Typography, Avatar, Card, CardContent, Divider } from "@mui/material"; -import { CardBottom } from "./CardBottom"; +import { Typography, Avatar, CardContent, Button, Grid, Paper, Divider } from "@mui/material"; class UserCard extends React.Component { constructor(props) { @@ -41,32 +40,36 @@ class UserCard extends React.Component { render() { return ( - - - - - {this.state.name} - + + + + + + {this.state.name} + - - {this.state.description} - - - - - + + {this.state.description} + + + + + ); } } diff --git a/client/src/Containers/BlogById/BlogById.js b/client/src/Containers/BlogById/BlogById.js index f4f78be..8607942 100644 --- a/client/src/Containers/BlogById/BlogById.js +++ b/client/src/Containers/BlogById/BlogById.js @@ -78,7 +78,7 @@ class BlogById extends React.Component { - + diff --git a/client/src/Containers/BlogById/BlogContent.js b/client/src/Containers/BlogById/BlogContent.js index 83d10d9..767b60f 100644 --- a/client/src/Containers/BlogById/BlogContent.js +++ b/client/src/Containers/BlogById/BlogContent.js @@ -1,23 +1,28 @@ import React from "react"; -import { Paper } from "@mui/material"; +import { Grid, Paper } from "@mui/material"; import { parser } from "./parser"; +import UserCard from "../../Components/UserCard"; export function BlogContent(props) { return ( - - {parser(props.content)} - + + + {parser(props.content)} + + {props.author && } + ); } diff --git a/client/src/Containers/BlogById/BlogHeader.js b/client/src/Containers/BlogById/BlogHeader.js index 5507170..884373f 100644 --- a/client/src/Containers/BlogById/BlogHeader.js +++ b/client/src/Containers/BlogById/BlogHeader.js @@ -6,6 +6,7 @@ import { EditButton } from "../../Components/Buttons/Buttons"; export function BlogHeader(props) { return ( -
- {props.author && } - -
+ +
); } diff --git a/swagger_output.json b/swagger_output.json index 8c80d13..0de37f8 100644 --- a/swagger_output.json +++ b/swagger_output.json @@ -2,14 +2,13 @@ "swagger": "2.0", "info": { "version": "1.0.0", - "title": "Blog API", + "title": "Blogger-Bhaiya backend API", "description": "This is the documentation for backend server API." }, - "host": "localhost:8081", + "host": "blogger-bhaiya.herokuapp.com", "basePath": "/", - "tags": [], "schemes": [ - "http" + "https" ], "securityDefinitions": { "apiKeyAuth": { @@ -44,11 +43,11 @@ "properties": { "email": { "type": "string", - "example": "hello@gmail.com" + "example": "hello2@gmail.com" }, "password": { "type": "string", - "example": "12345678" + "example": "87654321" } }, "required": [ From 8fb34f136a037c693627d17ec363dfa3bf7fcda4 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Tue, 4 Oct 2022 16:04:51 +0530 Subject: [PATCH 05/10] resolve link issue --- .../Components/MiniBlogCard/MiniBlogCard.js | 7 +++-- client/src/Containers/BlogById/BlogById.js | 13 ++++++-- client/src/Containers/BlogById/BlogHeader.js | 30 ++++--------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/client/src/Components/MiniBlogCard/MiniBlogCard.js b/client/src/Components/MiniBlogCard/MiniBlogCard.js index 0bfc576..d7a7f40 100644 --- a/client/src/Components/MiniBlogCard/MiniBlogCard.js +++ b/client/src/Components/MiniBlogCard/MiniBlogCard.js @@ -37,7 +37,7 @@ const MiniBlogCard = (props) => { secondary={ { } /> - { href={"/blogs/" + props.id} > - + diff --git a/client/src/Containers/BlogById/BlogById.js b/client/src/Containers/BlogById/BlogById.js index 8607942..68b8a65 100644 --- a/client/src/Containers/BlogById/BlogById.js +++ b/client/src/Containers/BlogById/BlogById.js @@ -27,8 +27,14 @@ class BlogById extends React.Component { } static contextType = UserContext; - componentDidMount() { - Get("/blogs/" + this.props.match.params.id) + componentWillReceiveProps(nextProps) { + if (nextProps.location.state === 'desiredState' && nextProps.match.params.id != this.props.match.params.id) { + this.updateData(nextProps.match.params.id); + } + } + + updateData(blogId) { + Get("/blogs/" + blogId) .then((res) => { this.setState({ title: res.data.title, @@ -56,6 +62,9 @@ class BlogById extends React.Component { } }); } + componentDidMount() { + this.updateData(this.props.match.params.id); + } render() { const { isAuth, userId } = this.context; diff --git a/client/src/Containers/BlogById/BlogHeader.js b/client/src/Containers/BlogById/BlogHeader.js index 884373f..b26cef2 100644 --- a/client/src/Containers/BlogById/BlogHeader.js +++ b/client/src/Containers/BlogById/BlogHeader.js @@ -1,52 +1,34 @@ import React from "react"; import { Paper, Typography } from "@mui/material"; import AccessTimeIcon from "@mui/icons-material/AccessTime"; -import { EditButton } from "../../Components/Buttons/Buttons"; export function BlogHeader(props) { return ( -
+ align="center" + sx={{ mb: "1vw" }} + > +
{props.title} - {props.isAuth && props.userId === props.author && ( - - )}
By {props.authorName} ⚫ {props.lastUpdated}{" "} {" "} From 02be2adee17dfb03e6734f5db1a8efa7ba5486f4 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Fri, 7 Oct 2022 20:41:08 +0530 Subject: [PATCH 06/10] Update ui --- .../Components/CategoryBar/CategoryCard.js | 52 +++++++++--------- client/src/Components/Login/LoginPage.js | 1 - client/src/Components/NavBar/NavBar.js | 54 +++++++++++++++++++ client/src/Containers/BlogById/BlogById.js | 2 +- client/src/Containers/Home/Home.js | 20 +++---- 5 files changed, 91 insertions(+), 38 deletions(-) diff --git a/client/src/Components/CategoryBar/CategoryCard.js b/client/src/Components/CategoryBar/CategoryCard.js index 84fa48b..23f7dcc 100644 --- a/client/src/Components/CategoryBar/CategoryCard.js +++ b/client/src/Components/CategoryBar/CategoryCard.js @@ -1,61 +1,61 @@ import React from 'react'; -import { useTheme} from '@mui/material/styles'; -import { Card,Typography,Avatar,Grid} from '@mui/material'; -import {Link} from "react-router-dom"; +import { useTheme } from '@mui/material/styles'; +import { Card, Typography, Avatar, Grid } from '@mui/material'; +import { Link } from "react-router-dom"; -const cardStyles =(theme) => ({ - width:'40vh', +const cardStyles = (theme) => ({ + width: '12vw', overflow: 'hidden', position: 'relative', - marginLeft:'2vh', - marginRight:'1vh', - padding:'1vh', + marginLeft: '2vw', + marginRight: '1vw', + padding: '1vw', '&:after': { content: '""', position: 'absolute', - width: '30vh', - height: '30vh', + width: '10vw', + height: '10vw', background: `linear-gradient(210.04deg, ${theme.palette.warning.dark} -50.94%, rgba(144, 202, 249, 0) 83.49%)`, borderRadius: '50%', - top: '-1vh', - right: '-20vh' + top: '-1vw', + right: '-10vw' }, '&:before': { content: '""', position: 'absolute', - width: '30vh', - height: '30vh', + width: '10vw', + height: '10vw', background: `linear-gradient(140.9deg, ${theme.palette.warning.dark} -14.02%, rgba(144, 202, 249, 0) 70.50%)`, borderRadius: '50%', - top: '-20vh', - right: '-15vh' + top: '-20vw', + right: '-15vw' }, - border: '0.3vh solid #ddd', - borderRadius: '2vh', - '&:hover':{ - boxShadow: '0 0 3vh 0px rgba(0, 0, 0, 0.4)', + border: '0.3vw solid #ddd', + borderRadius: '2vw', + '&:hover': { + boxShadow: '0 0 3vw 0px rgba(0, 0, 0, 0.4)', transform: 'scale(1.04)' }, - '&:active':{ - transform: 'scale(1.01) translateY(0.5vh)' + '&:active': { + transform: 'scale(1.01) translateY(0.5vw)' } }); const CategoryCard = props => { const theme = useTheme(); - return + return - {props.icon} + {props.icon} @@ -65,7 +65,7 @@ const CategoryCard = props => { - + } diff --git a/client/src/Components/Login/LoginPage.js b/client/src/Components/Login/LoginPage.js index daceca4..3571899 100644 --- a/client/src/Components/Login/LoginPage.js +++ b/client/src/Components/Login/LoginPage.js @@ -48,7 +48,6 @@ const LoginPage = (props) => { fullWidth sx={{ m: 1, - "& .MuiTextField-root": { margin: theme.spacing(1), }, diff --git a/client/src/Components/NavBar/NavBar.js b/client/src/Components/NavBar/NavBar.js index 7ad0f42..d5abd33 100644 --- a/client/src/Components/NavBar/NavBar.js +++ b/client/src/Components/NavBar/NavBar.js @@ -23,6 +23,51 @@ import { import DrawerWindow from "./DrawerWindow"; import { MenuBar } from "./MenuBar"; +import { styled, alpha } from '@mui/material/styles'; +import InputBase from '@mui/material/InputBase'; +import SearchIcon from '@mui/icons-material/Search'; + +const Search = styled('div')(({ theme }) => ({ + position: 'relative', + borderRadius: theme.shape.borderRadius, + backgroundColor: alpha(theme.palette.common.white, 0.15), + '&:hover': { + backgroundColor: alpha(theme.palette.common.white, 0.25), + }, + marginLeft: 0, + width: '100%', + [theme.breakpoints.up('sm')]: { + marginLeft: theme.spacing(1), + width: 'auto', + }, +})); + +const SearchIconWrapper = styled('div')(({ theme }) => ({ + padding: theme.spacing(0, 2), + height: '100%', + position: 'absolute', + pointerEvents: 'none', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +})); + +const StyledInputBase = styled(InputBase)(({ theme }) => ({ + color: 'inherit', + '& .MuiInputBase-input': { + padding: theme.spacing(1, 1, 1, 0), + // vertical padding + font size from searchIcon + paddingLeft: `calc(1em + ${theme.spacing(4)})`, + transition: theme.transitions.create('width'), + width: '100%', + [theme.breakpoints.up('sm')]: { + width: '12ch', + '&:focus': { + width: '20ch', + }, + }, + }, +})); const drawerWidth = 240; const NavBar = (props) => { @@ -88,6 +133,15 @@ const NavBar = (props) => { + + + + + +
{ - const data = [1,2]; + const data = [1, 2]; return (
- - - - {Categories.map((value,index)=>{ - if(index % 2 === 0){ + {/* + */} + + {Categories.map((value, index) => { + if (index % 2 === 0) { return ; } - else + else return ; })} - +
From 8574284f2104907da2e78897e8a500b844dc35d1 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sat, 8 Oct 2022 10:07:52 +0530 Subject: [PATCH 07/10] update routes and create new routes --- controllers/appControllers/getPost.js | 70 +++++++++++++++++++ .../commentControllers/commentRoutes.js | 12 ---- controllers/userControllers/userRoutes.js | 20 ------ endpoints.js | 12 ---- index.js | 10 +-- middleware/isAuth.js | 13 ++++ middleware/isAuther.js | 0 routes/appRoutes.js | 9 +++ .../blogControllers => routes}/blogRoutes.js | 12 ++-- routes/commentRoutes.js | 12 ++++ routes/endpoints.js | 13 ++++ routes/userRoutes.js | 20 ++++++ swagger.js | 2 +- swagger_output.json | 30 ++++++++ 14 files changed, 179 insertions(+), 56 deletions(-) create mode 100644 controllers/appControllers/getPost.js delete mode 100644 controllers/commentControllers/commentRoutes.js delete mode 100644 controllers/userControllers/userRoutes.js delete mode 100644 endpoints.js create mode 100644 middleware/isAuth.js delete mode 100644 middleware/isAuther.js create mode 100644 routes/appRoutes.js rename {controllers/blogControllers => routes}/blogRoutes.js (51%) create mode 100644 routes/commentRoutes.js create mode 100644 routes/endpoints.js create mode 100644 routes/userRoutes.js diff --git a/controllers/appControllers/getPost.js b/controllers/appControllers/getPost.js new file mode 100644 index 0000000..c5ba415 --- /dev/null +++ b/controllers/appControllers/getPost.js @@ -0,0 +1,70 @@ +const { Blog } = require("../../models/blog"); +const { Comments } = require("../../models/comments"); +const { User } = require("../../models/user"); + + +async function getBlogDetails(blogId, result) { + await Blog + .findById(blogId) + .populate({ + path: "author", + select: "name email description github twitter website avatar blogs", + populate: { + path: "blogs", + select: "title description image readTime tags", + options: { + limit: 3, + sort: { createdAt: -1 }, + } + } + }). + then(data => { + let dataNew = JSON.parse(JSON.stringify(data)); + let { author, ...blogData } = dataNew; + let { blogs, ...AuthorData } = author; + + result.fromAuthor = blogs; + result.author = AuthorData; + result.blog = blogData; + }).catch(err => { + console.log(JSON.stringify(err, Object.getOwnPropertyNames(err), 4)); + result.blog = null; + throw err; + // TODO : log error here + }); +} + +module.exports = async (req, res) => { + /* + #swagger.tags = ['App'] + #swagger.summary = 'Get Post By Id' + #swagger.description = 'Endpoint get a blog and its related components by blogId. It provides Blog details, its author details, recommandation, related posts' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + */ + + // Blog, Author, Releted posts, More from Author, Top from ok-blogger + + const result = {}; + + const listPromise = []; + // Get blog and author details + listPromise.push(getBlogDetails(req.params.id, result)); + + // Get top from ok-blogger + + await Promise.all(listPromise).then(data => { + return res.status(200).json({ + success: true, + message: "Request completed", + data: result, + }); + }).catch(err => { + return res.status(503).json({ + success: false, + message: "blog not found!", + }); + }) +}; diff --git a/controllers/commentControllers/commentRoutes.js b/controllers/commentControllers/commentRoutes.js deleted file mode 100644 index 1fdd0dd..0000000 --- a/controllers/commentControllers/commentRoutes.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require("express"); -const router = express.Router(); -const auth = require("../../middleware/auth"); -const addComment = require("./addComment"); -const updateComment = require("./updateComment"); -const getComments = require("./getComments"); - -router.get("/:commentBoxId", getComments); -router.post("/:commentBoxId/new", auth, addComment); -router.put("/:commentBoxId/:commentId", auth, updateComment); - -module.exports = router; diff --git a/controllers/userControllers/userRoutes.js b/controllers/userControllers/userRoutes.js deleted file mode 100644 index f5f4ed3..0000000 --- a/controllers/userControllers/userRoutes.js +++ /dev/null @@ -1,20 +0,0 @@ -var router = require("express").Router(); -const auth = require("../../middleware/auth"); -const login = require("./login"); -const getMyProfile = require("./getMyProfile"); -const getPublicProfile = require("./getPublicProfile"); -const logout = require("./logout"); -const register = require("./register"); -const updateProfile = require("./updateProfile"); - -//session -router.post("/session", login); -router.delete("/session", logout); - -//for users -router.post("/new", register); -router.get("/my", auth, getMyProfile); -router.get("/:id", getPublicProfile); -router.put("/:id", auth, updateProfile); - -module.exports = router; diff --git a/endpoints.js b/endpoints.js deleted file mode 100644 index 625cfa1..0000000 --- a/endpoints.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require("express"); -const userRoutes = require("./controllers/userControllers/userRoutes"); -const blogRoutes = require("./controllers/blogControllers/blogRoutes"); -const commentRoutes = require("./controllers/commentControllers/commentRoutes"); - -const router = express.Router(); - -router.use("/api/users/", userRoutes); -router.use("/api/blogs/", blogRoutes); -router.use("/api/comments/", commentRoutes); - -module.exports = router; diff --git a/index.js b/index.js index 8ff374b..d0c3b7a 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ const expressSession = require("express-session"); const morgan = require("morgan"); const path = require("path"); -const endpoints = require("./endpoints"); +const endpoints = require("./routes/endpoints"); const swaggerUi = require("swagger-ui-express"); const swaggerFile = require("./swagger_output.json"); @@ -67,10 +67,10 @@ var options = { app.use(endpoints); app.use("/doc", swaggerUi.serve, swaggerUi.setup(swaggerFile, options)); -app.use(express.static(path.join(__dirname, "client/build"))); -app.get("*", (req, res) => { - res.sendFile(path.join(__dirname + "/client/build/index.html")); -}); +// app.use(express.static(path.join(__dirname, "client/build"))); +// app.get("*", (req, res) => { +// res.sendFile(path.join(__dirname + "/client/build/index.html")); +// }); // Start Server app.listen(PORT, () => { diff --git a/middleware/isAuth.js b/middleware/isAuth.js new file mode 100644 index 0000000..0c057dc --- /dev/null +++ b/middleware/isAuth.js @@ -0,0 +1,13 @@ +const { User } = require('../models/user'); +require("dotenv").config(); + +module.exports = (req, res, next) => { + //parse the token + // let token = req.headers.cookies.replace("authToken=","").replace("%22","").replace("%22",""); + + User.findById(req.session.userId, (err, user) => { + if (err) throw err; + req.user = user; + next(); + }); +} \ No newline at end of file diff --git a/middleware/isAuther.js b/middleware/isAuther.js deleted file mode 100644 index e69de29..0000000 diff --git a/routes/appRoutes.js b/routes/appRoutes.js new file mode 100644 index 0000000..cc8f29c --- /dev/null +++ b/routes/appRoutes.js @@ -0,0 +1,9 @@ +var router = require("express").Router(); +const isAuth = require("../middleware/isAuth"); +const getPost = require("../controllers/appControllers/getPost"); + +// Get /api/app/:id Get all for a given blog id + +router.get("/:id", isAuth, getPost); + +module.exports = router; diff --git a/controllers/blogControllers/blogRoutes.js b/routes/blogRoutes.js similarity index 51% rename from controllers/blogControllers/blogRoutes.js rename to routes/blogRoutes.js index 252b5f4..4a867f0 100644 --- a/controllers/blogControllers/blogRoutes.js +++ b/routes/blogRoutes.js @@ -1,10 +1,10 @@ var router = require("express").Router(); -const auth = require("../../middleware/auth"); -const createBlog = require("./createBlog"); -const getBlogById = require("./getBlogById"); -const getBlogs = require("./getBlogs"); -const updateBlog = require("./updateBlog"); -const getUploadUrl = require("./getUploadUrl"); +const auth = require("../middleware/auth"); +const createBlog = require("../controllers/blogControllers/createBlog"); +const getBlogById = require("../controllers/blogControllers/getBlogById"); +const getBlogs = require("../controllers/blogControllers/getBlogs"); +const updateBlog = require("../controllers/blogControllers/updateBlog"); +const getUploadUrl = require("../controllers/blogControllers/getUploadUrl"); // POST /api/blogs/new (Auth) Create a new blog // PUT /api/blogs/:id (Auth) Update a blog diff --git a/routes/commentRoutes.js b/routes/commentRoutes.js new file mode 100644 index 0000000..62bb482 --- /dev/null +++ b/routes/commentRoutes.js @@ -0,0 +1,12 @@ +const express = require("express"); +const router = express.Router(); +const auth = require("../middleware/auth"); +const addComment = require("../controllers/commentControllers/addComment"); +const updateComment = require("../controllers/commentControllers/updateComment"); +const getComments = require("../controllers/commentControllers/getComments"); + +router.get("/:commentBoxId", getComments); +router.post("/:commentBoxId/new", auth, addComment); +router.put("/:commentBoxId/:commentId", auth, updateComment); + +module.exports = router; diff --git a/routes/endpoints.js b/routes/endpoints.js new file mode 100644 index 0000000..4c3f033 --- /dev/null +++ b/routes/endpoints.js @@ -0,0 +1,13 @@ +const express = require("express"); +const userRoutes = require("./userRoutes"); +const blogRoutes = require("./blogRoutes"); +const commentRoutes = require("./commentRoutes"); +const appRoutes = require("./appRoutes"); + +const router = express.Router(); + +router.use("/api/users/", userRoutes); +router.use("/api/blogs/", blogRoutes); +router.use("/api/comments/", commentRoutes); +router.use("/api/app/", appRoutes) +module.exports = router; diff --git a/routes/userRoutes.js b/routes/userRoutes.js new file mode 100644 index 0000000..c3e3632 --- /dev/null +++ b/routes/userRoutes.js @@ -0,0 +1,20 @@ +var router = require("express").Router(); +const auth = require("../middleware/auth"); +const login = require("../controllers/userControllers/login"); +const getMyProfile = require("../controllers/userControllers/getMyProfile"); +const getPublicProfile = require("../controllers/userControllers/getPublicProfile"); +const logout = require("../controllers/userControllers/logout"); +const register = require("../controllers/userControllers/register"); +const updateProfile = require("../controllers/userControllers/updateProfile"); + +//session +router.post("/session", login); +router.delete("/session", logout); + +//for users +router.post("/new", register); +router.get("/my", auth, getMyProfile); +router.get("/:id", getPublicProfile); +router.put("/:id", auth, updateProfile); + +module.exports = router; diff --git a/swagger.js b/swagger.js index f96d306..10aa1cc 100644 --- a/swagger.js +++ b/swagger.js @@ -56,7 +56,7 @@ const doc = { }; const outputFile = "./swagger_output.json"; -const endpointsFiles = ["./endpoints.js"]; +const endpointsFiles = ["./routes/endpoints.js"]; swaggerAutogen(outputFile, endpointsFiles, doc); // swaggerAutogen(outputFile, endpointsFiles, doc).then(() => { diff --git a/swagger_output.json b/swagger_output.json index 0de37f8..3ad05dd 100644 --- a/swagger_output.json +++ b/swagger_output.json @@ -577,6 +577,36 @@ } ] } + }, + "/api/app/{id}": { + "get": { + "tags": [ + "App" + ], + "summary": "Get Post By Id", + "description": "Endpoint get a blog and its related components by blogId. It provides Blog details, its author details, recommandation, related posts", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "503": { + "description": "Service Unavailable" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } } }, "definitions": { From 3056c82e8026199f3c8bf430b0b017bf283562b6 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sat, 8 Oct 2022 18:21:22 +0530 Subject: [PATCH 08/10] Add stats segment --- controllers/appControllers/getHome.js | 15 +++++++++++ controllers/appControllers/getPost.js | 39 +++++++++++++++++++++++---- models/blog.js | 4 +++ models/stats.js | 37 +++++++++++++++++++++++++ package.json | 8 +++--- 5 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 controllers/appControllers/getHome.js create mode 100644 models/stats.js diff --git a/controllers/appControllers/getHome.js b/controllers/appControllers/getHome.js new file mode 100644 index 0000000..4d38e7e --- /dev/null +++ b/controllers/appControllers/getHome.js @@ -0,0 +1,15 @@ +const { Blog } = require("../../models/blog"); +const { Comments } = require("../../models/comments"); +const { User } = require("../../models/user"); +const { Stats } = require("../../models/stats"); + + +module.exports = async (req, res) => { + //1. top 10 of ok-blogger + //2. latest 10 of ok-blogger + //3. category wise, for each 4 + // top 10 tags + // Should we implement infinite scrolling + + +} \ No newline at end of file diff --git a/controllers/appControllers/getPost.js b/controllers/appControllers/getPost.js index c5ba415..4b23702 100644 --- a/controllers/appControllers/getPost.js +++ b/controllers/appControllers/getPost.js @@ -1,8 +1,29 @@ const { Blog } = require("../../models/blog"); -const { Comments } = require("../../models/comments"); -const { User } = require("../../models/user"); +// async function transform() { +// await Blog.find().then(async blogs => { +// for (let blog of blogs) { +// if (blog._id.toString() !== "6159fde88150df0056cf2df6") { +// let stat = new Stats({ +// blogId: blog._id +// }) +// await stat.save(async (err, cmt) => { +// blog.stats = cmt._id; +// await blog.save().then(blog => { +// console.log("added to ", blog._id); +// }) +// }) +// } +// else { +// console.log("Hello ", blog._id); +// } +// } +// }).catch(err => { +// console.log(err); +// }) +// } +// how to populate multiple ref objects in mongodb? async function getBlogDetails(blogId, result) { await Blog .findById(blogId) @@ -11,14 +32,22 @@ async function getBlogDetails(blogId, result) { select: "name email description github twitter website avatar blogs", populate: { path: "blogs", - select: "title description image readTime tags", + select: "title description image readTime tags stats", options: { limit: 3, sort: { createdAt: -1 }, + }, + populate: { + path: "stats", + select: "approvals reads views likes" } } - }). - then(data => { + }) + .populate({ + path: "stats", + select: "approvals reads views likes" + }) + .then(data => { let dataNew = JSON.parse(JSON.stringify(data)); let { author, ...blogData } = dataNew; let { blogs, ...AuthorData } = author; diff --git a/models/blog.js b/models/blog.js index 769982c..790ffa7 100644 --- a/models/blog.js +++ b/models/blog.js @@ -36,6 +36,10 @@ const blogSchema = mongoose.Schema( type: mongoose.Schema.Types.ObjectId, ref: "Comments", }, + stats: { + type: mongoose.Schema.Types.ObjectId, + ref: "Stats", + }, tags: [ { type: String, diff --git a/models/stats.js b/models/stats.js new file mode 100644 index 0000000..f0485c9 --- /dev/null +++ b/models/stats.js @@ -0,0 +1,37 @@ +const mongoose = require("mongoose"); + +require("dotenv").config(); + +const statsSchema = mongoose.Schema( + { + blogId: { + type: mongoose.Schema.Types.ObjectId, + ref: "Blog", + required: [true, "Stats should be associated with blogId"], + }, + likedBy: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }], + verfiedBy: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }], + approvals: { + type: Number, + default: 0, + }, + reads: { + type: Number, + default: 0, + }, + views: { + type: Number, + default: 0, + }, + likes: { + type: Number, + default: 0, + } + }, + { + timestamps: true, + } +); + +const Stats = mongoose.model("Stats", statsSchema); +module.exports = { Stats }; diff --git a/package.json b/package.json index 196aa4a..a7e6f92 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dotenv": "^10.0.0", "express": "^4.17.1", "express-session": "^1.17.2", - "mongoose": "^5.11.13", + "mongoose": "^5.13.15", "morgan": "^1.10.0", "multer": "^1.4.3", "multer-s3": "^2.9.1", @@ -38,7 +38,5 @@ "@types/cookie": "^0.4.0", "swagger-autogen": "^2.11.2" }, - "devDependencies": { - - } -} + "devDependencies": {} +} \ No newline at end of file From 87539ea21165e7e81405a560245458b6db92a3c4 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Sun, 9 Oct 2022 22:50:55 +0530 Subject: [PATCH 09/10] update nav bar home and query for infinite scrolling --- client/src/App.css | 23 +++ client/src/App.js | 1 + client/src/Components/BlogsList/BlogsList.js | 3 +- client/src/Components/Footer/Footer.js | 181 +++++++++++++++++- .../HorizontalBlogCard/HorizontalBlogCard.js | 6 +- client/src/Components/InfoMsg/InfoMsg.js | 58 ++++++ client/src/Components/InfoMsg/InfoMsg.lazy.js | 11 ++ .../src/Components/InfoMsg/InfoMsg.stories.js | 12 ++ client/src/Components/InfoMsg/InfoMsg.test.js | 9 + client/src/Components/NavBar/NavBar.js | 119 +++++++++++- client/src/Components/Tags/Tags.js | 28 +++ client/src/Components/Tags/index.js | 3 + client/src/Containers/BlogById/BlogById.js | 2 +- client/src/Containers/Home/Home.js | 63 +++++- client/src/themes/dark.js | 9 +- client/src/themes/light.js | 9 +- controllers/appControllers/getHome.js | 5 +- controllers/blogControllers/getBlogs.js | 43 +++-- swagger_output.json | 5 + 19 files changed, 534 insertions(+), 56 deletions(-) create mode 100644 client/src/Components/InfoMsg/InfoMsg.js create mode 100644 client/src/Components/InfoMsg/InfoMsg.lazy.js create mode 100644 client/src/Components/InfoMsg/InfoMsg.stories.js create mode 100644 client/src/Components/InfoMsg/InfoMsg.test.js create mode 100644 client/src/Components/Tags/Tags.js create mode 100644 client/src/Components/Tags/index.js diff --git a/client/src/App.css b/client/src/App.css index 74b5e05..6a5ee34 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -32,7 +32,30 @@ from { transform: rotate(0deg); } + to { transform: rotate(360deg); } } + +/* html { + overflow-x: hidden; +} + +html, +body { + color: hsl(240, 11%, 15%); + margin: 0; +} + +*:not(.material-symbols-rounded, h2.MuiTypography-root, .disableFont) { + font-family: "Outfit", sans-serif !important; +} + +.MuiTouchRipple-rippleVisible { + animation-duration: 0.25s !important; +} + +.MuiTouchRipple-child { + filter: opacity(0.4) !important; +} */ \ No newline at end of file diff --git a/client/src/App.js b/client/src/App.js index edd67ed..061af15 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -14,6 +14,7 @@ import ProfileUpdate from "./Containers/ProfileUpdate"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import Footer from "./Components/Footer/Footer"; +//import './App.css' class App extends Component { constructor(props) { diff --git a/client/src/Components/BlogsList/BlogsList.js b/client/src/Components/BlogsList/BlogsList.js index 5465d25..f8e3228 100644 --- a/client/src/Components/BlogsList/BlogsList.js +++ b/client/src/Components/BlogsList/BlogsList.js @@ -119,9 +119,10 @@ class BlogsList extends React.Component { { + return ( + + + + + Smartlist + + + We're a philanthropic nonprofit striving to help everyone{" "} + + ❤️ + + + + + Proudly made in the USA  + + 🇺🇸 + + + + Featured on ProductHunt + + + + Apps + + + Smartlist + + + Smartlist Availability + + + Smartlist Recipe Generator + + + Smartlist Dressing + + + Smartlist Collaborate + + + + + Company + + + Join our team + + + Terms of service + + + Privacy policy + + + Our team + - return( -
- - - © 2021 Rajendra - - -
- ) + + Links + + + Contact us + + + Knowledge base + + + hello@smartlist.tech + + + Official Discord + + + GitHub + +
+ + + Sponsors + + + + InfinitzHost + + + +
+
+ ); }; diff --git a/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js b/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js index 450448b..34f6061 100644 --- a/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js +++ b/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js @@ -10,11 +10,11 @@ const CardStyle = { paddingLeft: "1vw", paddingRight: "1vw", paddingBottom: "0vh", - width: 550, - height: 250, + width: 900, + height: 200, overflow: "hidden", position: "relative", - border: "hidden", + border: "none", borderRadius: "2vh", "&:hover": { boxShadow: "0 1vh 2vh 0px rgba(0, 0, 0, 0.4)", diff --git a/client/src/Components/InfoMsg/InfoMsg.js b/client/src/Components/InfoMsg/InfoMsg.js new file mode 100644 index 0000000..d9f23fd --- /dev/null +++ b/client/src/Components/InfoMsg/InfoMsg.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { + IconButton, + Box, + Collapse, + Alert, + Typography, + Toolbar +} from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; + +const InfoMsg = (props) => { + const [open, setOpen] = React.useState(true); + + return ( + <> + + + { + setOpen(false); + }} + > + +
+ } + severity="info" + sx={{ + background: "linear-gradient(to right, #237A57, #093028)", + width: "100%", + borderRadius: 4, + boxSizing: "border-box", + zIndex: 1 + }} + variant="filled" + > + + {props.msg} + + + + + + ) +}; + +export default InfoMsg; diff --git a/client/src/Components/InfoMsg/InfoMsg.lazy.js b/client/src/Components/InfoMsg/InfoMsg.lazy.js new file mode 100644 index 0000000..501d126 --- /dev/null +++ b/client/src/Components/InfoMsg/InfoMsg.lazy.js @@ -0,0 +1,11 @@ +import React, { lazy, Suspense } from 'react'; + +const LazyInfoMsg = lazy(() => import('./InfoMsg')); + +const InfoMsg = props => ( + + + +); + +export default InfoMsg; diff --git a/client/src/Components/InfoMsg/InfoMsg.stories.js b/client/src/Components/InfoMsg/InfoMsg.stories.js new file mode 100644 index 0000000..8641e83 --- /dev/null +++ b/client/src/Components/InfoMsg/InfoMsg.stories.js @@ -0,0 +1,12 @@ +/* eslint-disable */ +import InfoMsg from './InfoMsg'; + +export default { + title: "InfoMsg", +}; + +export const Default = () => ; + +Default.story = { + name: 'default', +}; diff --git a/client/src/Components/InfoMsg/InfoMsg.test.js b/client/src/Components/InfoMsg/InfoMsg.test.js new file mode 100644 index 0000000..b5a1bb8 --- /dev/null +++ b/client/src/Components/InfoMsg/InfoMsg.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import InfoMsg from './InfoMsg'; + +it('It should mount', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); \ No newline at end of file diff --git a/client/src/Components/NavBar/NavBar.js b/client/src/Components/NavBar/NavBar.js index d5abd33..e972804 100644 --- a/client/src/Components/NavBar/NavBar.js +++ b/client/src/Components/NavBar/NavBar.js @@ -9,6 +9,8 @@ import MenuIcon from "@mui/icons-material/Menu"; import Login from "../Login/Login"; import { Link } from "react-router-dom"; import { UserContext } from "../../Context/UserContext"; +import InfoMsg from "../InfoMsg/InfoMsg"; +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import { AppBar, @@ -19,6 +21,8 @@ import { CssBaseline, Drawer, Modal, + Button, + //Link } from "@mui/material"; import DrawerWindow from "./DrawerWindow"; @@ -70,6 +74,46 @@ const StyledInputBase = styled(InputBase)(({ theme }) => ({ })); const drawerWidth = 240; +const styles = { + button: { textTransform: "none", borderRadius: 4, px: 2 } +}; + +const NavLink = (props) => { + console.log(props.theme) + return ( + + + + ) +} + +const navLinks = [ + { + link: "/our-team", + name: "Our Team" + }, + { + link: "/write", + name: "Write" + } +] + const NavBar = (props) => { const { window } = props; const [mobileOpen, setMobileOpen] = React.useState(false); @@ -116,7 +160,20 @@ const NavBar = (props) => { - + { sx={{ display: { md: "none", xs: "block" } }}> - - + + + Blogger Bhaiya - - + + + + { + navLinks.map((val, index) => { + return + }) + } + + + @@ -142,6 +244,7 @@ const NavBar = (props) => { inputProps={{ 'aria-label': 'search' }} /> +
{ )} - + handleClose={handleClose}> */}
+
- { + const theme = useTheme(); + + return + { + props.tags.map((val, index) => { + return + }) + } + +} + +export default Tags; diff --git a/client/src/Components/Tags/index.js b/client/src/Components/Tags/index.js new file mode 100644 index 0000000..8c9d0a5 --- /dev/null +++ b/client/src/Components/Tags/index.js @@ -0,0 +1,3 @@ +import Tags from './Tags'; + +export default Tags; diff --git a/client/src/Containers/BlogById/BlogById.js b/client/src/Containers/BlogById/BlogById.js index 170ad67..90ad516 100644 --- a/client/src/Containers/BlogById/BlogById.js +++ b/client/src/Containers/BlogById/BlogById.js @@ -70,7 +70,7 @@ class BlogById extends React.Component { const { isAuth, userId } = this.context; return (
- + { const data = [1, 2]; @@ -11,14 +46,36 @@ const Home = props => {
{/* */} - - {Categories.map((value, index) => { + {/* */} + {/* {Categories.map((value, index) => { if (index % 2 === 0) { return ; } else return ; - })} + })} */} + + + 50 + ? value.description.substring(0, 50) + "..." + : value.description + } + avatar={value.author?.avatar} + author={value.author.name} + date={dateFormat(value.updatedAt, "mmmm dS, yyyy")} + readTime={ + value.readTime ? value.readTime + " min" : "2 min" + } + authorUrl={"/profile/" + value.author._id} + poster={value.image} + /> + + +
diff --git a/client/src/themes/dark.js b/client/src/themes/dark.js index 527e817..40b2d1b 100644 --- a/client/src/themes/dark.js +++ b/client/src/themes/dark.js @@ -1,14 +1,15 @@ -import {createTheme } from '@mui/material/styles'; +import { createTheme } from '@mui/material/styles'; const darkTheme = createTheme({ palette: { - mode: 'dark', + mode: 'dark', + navBack: "rgba(28, 25, 27, 0.8)" }, typography: { fontFamily: [ - 'Serif' + 'sans-serif' ].join(','), - } + } }); export default darkTheme; \ No newline at end of file diff --git a/client/src/themes/light.js b/client/src/themes/light.js index 5ea1767..5414c4b 100644 --- a/client/src/themes/light.js +++ b/client/src/themes/light.js @@ -1,14 +1,15 @@ -import {createTheme } from '@mui/material/styles'; +import { createTheme } from '@mui/material/styles'; const lightTheme = createTheme({ palette: { - mode: 'light', + mode: 'light', + navBack: "rgba(250,250,250,.9)" }, typography: { fontFamily: [ - 'Serif' + 'Serif' ].join(','), - } + } }); export default lightTheme; \ No newline at end of file diff --git a/controllers/appControllers/getHome.js b/controllers/appControllers/getHome.js index 4d38e7e..82a4fff 100644 --- a/controllers/appControllers/getHome.js +++ b/controllers/appControllers/getHome.js @@ -7,9 +7,8 @@ const { Stats } = require("../../models/stats"); module.exports = async (req, res) => { //1. top 10 of ok-blogger //2. latest 10 of ok-blogger - //3. category wise, for each 4 - // top 10 tags - // Should we implement infinite scrolling + // list of to 10 categories + // Should we implement infinite scrolling : Yes } \ No newline at end of file diff --git a/controllers/blogControllers/getBlogs.js b/controllers/blogControllers/getBlogs.js index 082f9e3..0d3117e 100644 --- a/controllers/blogControllers/getBlogs.js +++ b/controllers/blogControllers/getBlogs.js @@ -4,36 +4,36 @@ module.exports = async (req, res) => { /* #swagger.tags = ['Blog'] #swagger.summary = 'Get All blogs' - #swagger.description = 'Endpoint to get all blogs based on query parameters' + #swagger.description = 'Endpoint to get all blogs based on query parameters' #swagger.parameters['tag'] = { - in: 'query', - description: 'blog tag', - schema: { + in: 'query', + description: 'blog tag', + schema: { $tag:'science-and-space' - } - } + } + } #swagger.parameters['max count'] = { - in: 'query', - description: 'Maximum number of elements that need to be returned', - schema: { + in: 'query', + description: 'Maximum number of elements that need to be returned', + schema: { $maxcount:3 - } - } + } + } #swagger.parameters['sort'] = { - in: 'query', - description: 'Sort or Not sorted', - schema: { + in: 'query', + description: 'Sort or Not sorted', + schema: { $sort:true - } - } + } + } #swagger.security = [{ - "apiKeyAuth": [] - }] + "apiKeyAuth": [] + }] */ var blogs = []; @@ -44,12 +44,17 @@ module.exports = async (req, res) => { } if (req.query.sort) { - filters.sort = { updatedAt: "asc" }; + filters.sort = { updatedAt: 1 }; } if (req.query.tag) { query.tags = { $in: req.query.tag }; } + + if (req.query.lastDate) { + query.updatedAt = { $gt: new Date(req.query.lastDate) } + } + await Blog.find( query, "author readTime title description image tags updatedAt", diff --git a/swagger_output.json b/swagger_output.json index 3ad05dd..bcbd3bf 100644 --- a/swagger_output.json +++ b/swagger_output.json @@ -297,6 +297,11 @@ "name": "maxcount", "in": "query", "type": "string" + }, + { + "name": "lastDate", + "in": "query", + "type": "string" } ], "responses": { From 99837dc8bd888a4f7b7ada949226e7d0e4950118 Mon Sep 17 00:00:00 2001 From: Rajendra Prajapat Date: Mon, 17 Oct 2022 13:07:39 +0530 Subject: [PATCH 10/10] Improvments --- client/package.json | 5 +- .../Components/ActionButtons/ActionButtons.js | 79 ++++++++++ client/src/Components/ActionButtons/index.js | 3 + client/src/Components/BlogsList/BlogsList.js | 137 +++++++++++------- .../HorizontalBlogCard/HorizontalBlogCard.js | 50 +++---- .../HorizontalBlogCard/UserDetails.js | 4 +- client/src/Components/InfoMsg/InfoMsg.js | 3 +- client/src/Components/NavBar/NavBar.js | 2 - client/src/Components/Tags/Tags.js | 12 +- client/src/Containers/BlogById/BlogById.js | 5 +- client/src/Containers/Home/Home.js | 64 ++------ client/src/Requests/ImageUpload.js | 2 + controllers/blogControllers/getBlogs.js | 4 +- package.json | 12 +- 14 files changed, 221 insertions(+), 161 deletions(-) create mode 100644 client/src/Components/ActionButtons/ActionButtons.js create mode 100644 client/src/Components/ActionButtons/index.js diff --git a/client/package.json b/client/package.json index 81309cd..c3bd17e 100644 --- a/client/package.json +++ b/client/package.json @@ -8,7 +8,6 @@ "@mui/icons-material": "^5.0.0-rc.1", "@mui/lab": "^5.0.0-alpha.48", "@mui/material": "^5.0.0-rc.1", - "react-scripts": "^4.0.3", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", @@ -22,8 +21,10 @@ "react": "^17.0.2", "react-avatar-edit": "^1.1.0", "react-dom": "^17.0.2", + "react-infinite-scroll-component": "^6.1.0", "react-quill": "^2.0.0-beta.4", "react-router-dom": "^5.3.0", + "react-scripts": "^4.0.3", "react-slick": "^0.28.1", "web-vitals": "^1.1.2" }, @@ -52,4 +53,4 @@ ] }, "proxy": "http://127.0.0.1:8081/" -} \ No newline at end of file +} diff --git a/client/src/Components/ActionButtons/ActionButtons.js b/client/src/Components/ActionButtons/ActionButtons.js new file mode 100644 index 0000000..71c8ecc --- /dev/null +++ b/client/src/Components/ActionButtons/ActionButtons.js @@ -0,0 +1,79 @@ +import React from 'react'; +import { useTheme } from "@mui/material/styles"; +import ShareIcon from '@mui/icons-material/Share'; +import CommentIcon from '@mui/icons-material/Comment'; +import Fab from '@mui/material/Fab'; +import { Grid, Box, Tooltip, SpeedDial, SpeedDialAction } from "@mui/material"; + +import { Instagram, Facebook, Twitter, LinkedIn, Link, Grade } from '@mui/icons-material'; + +const socialMediaActions = [ + { icon: , name: 'Instagram' }, + { icon: , name: 'Facebook' }, + { icon: , name: 'Twitter' }, + { icon: , name: 'LinkedIn' }, + { icon: , name: 'Copy Link' }, +]; + +function SocialMediaDial() { + return ( + + } + > + {socialMediaActions.map((action) => ( + + ))} + + + ); +} + +const actions = [ + { + name: "Star", + icon: + }, + { + name: "Comment", + icon: + } +]; + +const ActionButtons = props => { + const theme = useTheme(); + return + { + actions.map(action => { + return + + + {action.icon} + + + + }) + } + + + + + +} + +export default ActionButtons; \ No newline at end of file diff --git a/client/src/Components/ActionButtons/index.js b/client/src/Components/ActionButtons/index.js new file mode 100644 index 0000000..d3cc681 --- /dev/null +++ b/client/src/Components/ActionButtons/index.js @@ -0,0 +1,3 @@ +import ActionButtons from './ActionButtons'; + +export default ActionButtons; diff --git a/client/src/Components/BlogsList/BlogsList.js b/client/src/Components/BlogsList/BlogsList.js index f8e3228..2bbc1fe 100644 --- a/client/src/Components/BlogsList/BlogsList.js +++ b/client/src/Components/BlogsList/BlogsList.js @@ -2,40 +2,57 @@ import React from "react"; import { Paper, Typography, Grid, Box } from "@mui/material"; import dateFormat from "dateformat"; import Get from "../../Requests/Get"; -import VerticalBlogCard from "../VerticalBlogCard/VerticalBlogCard"; import HorizontalBlogCard from "../HorizontalBlogCard/HorizontalBlogCard"; import { getTitle } from "./getTitle"; +import InfiniteScroll from "react-infinite-scroll-component"; class BlogsList extends React.Component { constructor(props) { super(props); this.state = { loaded: false, - maximumBlogs: props.maximumBlogs ? props.maximumBlogs : -1, + stepSize: 5, + hasMore: true, + lastDate: new Date().toISOString(), category: props.category, - blogs: props.maximumBlogs - ? Array.from(Array(props.maximumBlogs).keys()) - : Array.from(Array(10).keys()), + blogs: Array.from(Array(5).keys()), }; } - componentDidMount() { + getBlogs() { + console.log({ "State Details": this.state }); + if (this.state.blogs.length >= 20) { + this.setState({ hasMore: false }); + return; + } let url = this.state.category ? "/blogs/?tag=" + this.state.category : "/blogs/"; - if (this.state.maximumBlogs > 0) { - if (url === "/blogs/") { - url += "?maxcount=" + this.state.maximumBlogs; - } else url += "&maxcount=" + this.state.maximumBlogs; - } + if (url === "/blogs/") { + url += "?maxcount=" + this.state.stepSize; + } else url += "&maxcount=" + this.state.stepSize; + + url += "&lastDate=" + this.state.lastDate; Get(url) .then((res) => { - this.setState({ - blogs: res.blogs, - loaded: true, - }); + if (this.state.loaded) { + this.setState({ + blogs: [...this.state.blogs, ...res.blogs], + loaded: true, + lastDate: res.blogs?.slice(-1)[0]?.updatedAt + }); + + console.log({ "data": res.blogs, "last": res.blogs?.slice(-1), "lastDate": res.blogs?.slice(-1)[0]?.updatedAt }); + } + else { + this.setState({ + blogs: res.blogs, + loaded: true, + }); + } + console.log({ "State: ": this.state }); }) .catch((err) => { console.log("Error in BlogsList.js"); @@ -43,16 +60,17 @@ class BlogsList extends React.Component { }); } + componentDidMount() { + this.getBlogs(); + } + render() { return (
{this.state.category && ( @@ -62,42 +80,53 @@ class BlogsList extends React.Component { {/* vertical cards */} {this.props.type !== "horizontal" && ( - - + + - {!this.state.loaded && - this.state.blogs.map((value, index) => ( - - - - ))} + { this.getBlogs() }} + hasMore={this.state.hasMore} + loader={

Loading...

} + //height={400} + endMessage={ +

+ Yay! You have seen it all +

+ } + > + {!this.state.loaded && + this.state.blogs.map((value, index) => ( + + + + ))} - {this.state.loaded && - this.state.blogs.map((value, index) => ( - - - 50 - ? value.description.substring(0, 50) + "..." - : value.description - } - avatar={value.author?.avatar} - author={value.author.name} - date={dateFormat(value.updatedAt, "mmmm dS, yyyy")} - readTime={ - value.readTime ? value.readTime + " min" : "2 min" - } - userUrl={"/profile/" + value.author._id} - poster={value.image} - /> - - - ))} + {this.state.loaded && + this.state.blogs.map((value, index) => ( +
+ + 50 + ? value.description.substring(0, 50) + "..." + : value.description + } + avatar={value.author?.avatar} + author={value.author.name} + date={dateFormat(value.updatedAt, "mmmm dS, yyyy")} + readTime={ + value.readTime ? value.readTime + " min" : "2 min" + } + authorUrl={"/profile/" + value.author._id} + poster={value.image} + /> + +
+ ))} +
@@ -137,7 +166,7 @@ class BlogsList extends React.Component { : value.description } avatar={value.author?.avatar} - author={value.author.name} + author={value.author?.name} date={dateFormat(value.updatedAt, "mmmm dS, yyyy")} readTime={ value.readTime ? value.readTime + " min" : "2 min" diff --git a/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js b/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js index 34f6061..44bbbb9 100644 --- a/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js +++ b/client/src/Components/HorizontalBlogCard/HorizontalBlogCard.js @@ -10,23 +10,16 @@ const CardStyle = { paddingLeft: "1vw", paddingRight: "1vw", paddingBottom: "0vh", - width: 900, + width: "100%", height: 200, overflow: "hidden", position: "relative", border: "none", + boxShadow: "none", borderRadius: "2vh", - "&:hover": { - boxShadow: "0 1vh 2vh 0px rgba(0, 0, 0, 0.4)", - transform: "scale(1.04)", - }, "&:active": { transform: "scale(1.01) translateY(0.5vh)", - }, - "@media (max-width:780px)": { - width: 370, - height: 180, - }, + } }; const HorizontalBlogCard = (props) => { @@ -37,23 +30,9 @@ const HorizontalBlogCard = (props) => { to={props.url} style={{ textDecoration: "none", color: theme.palette.text.primary }}> - - - - {props.title} + + + {props.title} { style={{ textDecoration: "none", color: theme.palette.text.primary, + bottom: "3px", + position: "absolute" }}> { readTime={props.readTime}> + + {/* + + */} ); diff --git a/client/src/Components/HorizontalBlogCard/UserDetails.js b/client/src/Components/HorizontalBlogCard/UserDetails.js index e411865..3be83e4 100644 --- a/client/src/Components/HorizontalBlogCard/UserDetails.js +++ b/client/src/Components/HorizontalBlogCard/UserDetails.js @@ -14,7 +14,7 @@ export function UserDetails(props) { }}> } - title={props.author} + title={{props.author}} subheader={ - {props.date} + {props.date} { const theme = useTheme(); @@ -11,11 +8,10 @@ const Tags = props => { return { props.tags.map((val, index) => { diff --git a/client/src/Containers/BlogById/BlogById.js b/client/src/Containers/BlogById/BlogById.js index 90ad516..e7dac5e 100644 --- a/client/src/Containers/BlogById/BlogById.js +++ b/client/src/Containers/BlogById/BlogById.js @@ -8,6 +8,7 @@ import { BlogHeader } from "./BlogHeader"; import { Poster } from "./Poster"; import { BlogContent } from "./BlogContent"; import { RightPanel } from "./RightPanel"; +import ActionButtons from "./../../Components/ActionButtons"; class BlogById extends React.Component { constructor(props) { @@ -23,6 +24,7 @@ class BlogById extends React.Component { tags: [], lastUpdated: "", readTime: "", + atBottom: false, }; } static contextType = UserContext; @@ -86,10 +88,11 @@ class BlogById extends React.Component {
- + +
); diff --git a/client/src/Containers/Home/Home.js b/client/src/Containers/Home/Home.js index 7710edd..250b1f4 100644 --- a/client/src/Containers/Home/Home.js +++ b/client/src/Containers/Home/Home.js @@ -1,26 +1,8 @@ import React from 'react'; -// import CategoryBar from '../../Components/CategoryBar'; -// import HomeCarousel from '../../Components/HomeCarousel/HomeCarousel'; import BlogsList from '../../Components/BlogsList/BlogsList'; -import Categories from '../../Categories'; -import EditorsPickBlock from '../../Components/EditorsPick/EditorsPickBlock/EditorsPickBlock'; -import HorizontalBlogCard from '../../Components/HorizontalBlogCard/HorizontalBlogCard'; -import dateFormat from "dateformat"; -import { Box } from '@mui/material'; +import { Box, Grid } from '@mui/material'; import Tags from '../../Components/Tags'; -const value = { - _id: "Hello615c8e19dd6b9300ac9598dc", - title: "Hello I am Here", - description: "Lets see what we are doing here random random random random random@!", - image: "https://mysimpleblog.s3.ap-south-1.amazonaws.com/6ce1eeb768bcd0bb1aa44db74831e296Screenshot%20%2811%29.png", - author: { - name: "Rajendra Prajapat", - _id: 3545646345, - updatedAt: new Date(), - - } -} const tags = [ { name: "Ok bro", link: "/bro" }, { name: "Ok", link: "/bro" }, @@ -41,45 +23,17 @@ const tags = [ ] const Home = props => { - const data = [1, 2]; return (
- {/* - */} - {/* */} - {/* {Categories.map((value, index) => { - if (index % 2 === 0) { - return ; - } - else - return ; - })} */} - - - 50 - ? value.description.substring(0, 50) + "..." - : value.description - } - avatar={value.author?.avatar} - author={value.author.name} - date={dateFormat(value.updatedAt, "mmmm dS, yyyy")} - readTime={ - value.readTime ? value.readTime + " min" : "2 min" - } - authorUrl={"/profile/" + value.author._id} - poster={value.image} - /> - - - - + + + + + + + +
- - ) }; export default Home; diff --git a/client/src/Requests/ImageUpload.js b/client/src/Requests/ImageUpload.js index 3bbb3c0..a3d128c 100644 --- a/client/src/Requests/ImageUpload.js +++ b/client/src/Requests/ImageUpload.js @@ -6,6 +6,8 @@ const ImageUpload = (file) => { reject("File type is not supported!"); } + //compress image + //get url to upload image from s3 fetch("/api/blogs/image/new/" + file.name) .then(res => res.json()) diff --git a/controllers/blogControllers/getBlogs.js b/controllers/blogControllers/getBlogs.js index 0d3117e..27df214 100644 --- a/controllers/blogControllers/getBlogs.js +++ b/controllers/blogControllers/getBlogs.js @@ -44,7 +44,7 @@ module.exports = async (req, res) => { } if (req.query.sort) { - filters.sort = { updatedAt: 1 }; + filters.sort = { updatedAt: -1 }; } if (req.query.tag) { @@ -52,7 +52,7 @@ module.exports = async (req, res) => { } if (req.query.lastDate) { - query.updatedAt = { $gt: new Date(req.query.lastDate) } + query.updatedAt = { $lt: new Date(req.query.lastDate) } } await Blog.find( diff --git a/package.json b/package.json index a7e6f92..2c7f340 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "homepage": "https://github.com/Rajpra786/Blog-App#readme", "dependencies": { + "@types/cookie": "^0.4.0", "aws-sdk": "^2.983.0", "bcrypt": "^5.0.1", "body-parser": "^1.19.0", @@ -34,9 +35,8 @@ "morgan": "^1.10.0", "multer": "^1.4.3", "multer-s3": "^2.9.1", - "swagger-ui-express": "^4.1.6", - "@types/cookie": "^0.4.0", - "swagger-autogen": "^2.11.2" - }, - "devDependencies": {} -} \ No newline at end of file + "nodemon": "^2.0.20", + "swagger-autogen": "^2.11.2", + "swagger-ui-express": "^4.1.6" + } +}