Skip to content

Commit

Permalink
add trending articles to homepage
Browse files Browse the repository at this point in the history
  • Loading branch information
yannicklescure committed Apr 18, 2022
1 parent eb2d0ba commit f371607
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 7 deletions.
2 changes: 1 addition & 1 deletion client/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function App() {
<Navbar />
<Wrapper>
<Routes>
<Route path="*" element={<ErrorPage />} />
<Route path="/" element={<Homepage />} />
<Route path="*" element={<ErrorPage />} />
<Route path="/tag/:tagName" element={<Tag />} />
<Route path="/new-story" element={user._id ? <NewStory /> : <Navigate to="/login" replace />} />
<Route path="/orders-history" element={user._id ? <Orders /> : <Navigate to="/login" replace />} />
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Article/Head.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const StyledDate = styled.div`
color: ${COLORS.secondary};
`;
const Circle = styled.div`
font-size: 4px;
font-size: 3px;
`;
const EditLink = styled(NavLink)`
text-decoration: none;
Expand Down
7 changes: 7 additions & 0 deletions client/src/components/Banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const Banner = () => {
return (
<>Banner</>
)
}

export default Banner;
2 changes: 1 addition & 1 deletion client/src/components/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Navigation = ({ title }) => {
return (
<Wrapper>
<Title>{title}</Title>
<StyledDate>{fullWrittenDate(new Date(), 'en-US')}</StyledDate>
<StyledDate>{fullWrittenDate(new Date().getTime(), 'en-US')}</StyledDate>
</Wrapper>
)
}
Expand Down
123 changes: 123 additions & 0 deletions client/src/components/Trending.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { useEffect, useState } from "react";
import { NavLink } from "react-router-dom";
import styled from "styled-components";
import { COLORS } from "../constants";
import { fullWrittenDate, shortWrittenDate } from "../helpers";
import { FaCircle, FaRegPaperPlane } from "react-icons/fa";
import Loading from "./Loading/Loading";

const Trending = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState([]);

useEffect(() => {
setLoading(true);
fetch(`/api/trending`)
.then((res) => res.json())
.then((response) => {
// console.log(response.data);
setData(response.data);
setLoading(false);
});
// eslint-disable-next-line
}, []);

const stopPropagation = (event) => {
event.stopPropagation();
}

if (loading) return <Loading size="32" />;

return (
<>
<Title>
<div><FaRegPaperPlane /></div>
<div>Trending on {fullWrittenDate(new Date().getTime(), 'en-US')}</div>
</Title>
<Wrapper>
{
data.map((item, index) => (
<Container key={item._id}>
<Indice>0{index + 1}.</Indice>
<SubWrapper>
<StyledLink
to={`/${item.username}/${item.slug}`}
onClick={stopPropagation}
>{ item.title }</StyledLink>
<StyledInfo>
<div>{shortWrittenDate(item.createdAt)}</div>
<Circle><FaCircle /></Circle>
<div>{item.readingTime} min read</div>
</StyledInfo>
</SubWrapper>
</Container>
))
}
</Wrapper>
</>
)
}

const Wrapper = styled.div`
display: flex;
flex-wrap: wrap;
margin: 16px 0 24px 0;
`;
const SubWrapper = styled.div`
display: flex;
flex-direction: column;
`;
const Container = styled.button`
display: flex;
width: 50%;
gap: 16px;
padding: 16px;
align-items: flex-start;
background: none;
outline: none;
border: none;
border-radius: 4px;
text-align: left;
cursor: pointer;
&:hover {
background-color: ${COLORS.light};
}
`;
const Indice = styled.div`
font-size: 32px;
font-weight: bold;
color: ${COLORS.grey};
`;
const StyledLink = styled(NavLink)`
font-size: 16px;
color: ${COLORS.dark};
text-decoration: none;
margin-top: 3px;
&:hover {
color: ${COLORS.black};
}
`;
const StyledInfo = styled.div`
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 14px;
gap: 4px;
color: ${COLORS.secondary};
margin-top: 8px;
`;
const Circle = styled.div`
font-size: 3px;
`;
const Title = styled.div`
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: bold;
margin-top: 24px;
`;

export default Trending;
4 changes: 2 additions & 2 deletions client/src/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// https://stackoverflow.com/questions/30130241/typeerror-date-is-not-a-constructor
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
export const fullWrittenDate = (date, lang = "en-US") => {
return new window.Date(date).toLocaleDateString(lang, {
return new window.Date(parseInt(date)).toLocaleDateString(lang, {
year: "numeric",
month: "long",
weekday: "long",
Expand All @@ -11,7 +11,7 @@ export const fullWrittenDate = (date, lang = "en-US") => {
};

export const shortWrittenDate = (date, lang = "en-US") => {
return new window.Date(date).toLocaleDateString(lang, {
return new window.Date(parseInt(date)).toLocaleDateString(lang, {
year: "numeric",
month: "short",
day: "numeric",
Expand Down
3 changes: 2 additions & 1 deletion client/src/pages/Homepage.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import Navigation from "../components/Navigation";
import Trending from "../components/Trending";

const Homepage = () => {
const title = 'Homepage';

return (
<>
<Navigation title={title} />
<div>Homepage</div>
<Trending />
</>
)
}
Expand Down
60 changes: 59 additions & 1 deletion server/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { v4: uuidv4 } = require("uuid");
const bcrypt = require("bcrypt");
const { MongoClient } = require("mongodb");
const { readingTime } = require("./helpers");
require("dotenv").config();
const { MONGO_URI, DB_NAME } = process.env;

Expand Down Expand Up @@ -487,7 +488,6 @@ const getStory = async (req, res) => {
};

const getStories = async (req, res) => {
const { username } = req.params;
console.log(req.params);
console.log(req.query);

Expand All @@ -512,6 +512,63 @@ const getStories = async (req, res) => {
}
};

const getTrending = async (req, res) => {
console.log(req.params);

const client = new MongoClient(MONGO_URI, option);
try {
console.log('connecting to db');
await client.connect();
console.log('connected to db');
const db = client.db(DB_NAME);
console.log('requesting stories array');
let stories = await db.collection("stories").find({ visibility: 'public' }).project({
title: 1,
slug: 1,
username: 1,
views: 1,
createdAt: 1,
content: 1
}).toArray();
console.log('received stories array');
// console.log(stories);
if (stories) {
const data = stories.map(story => {
const {
_id,
title,
slug,
username,
createdAt,
content
} = story;
const tmp = story;
const time = readingTime(content);
let views = 1;
if (story.views) views = story.views;
return {
_id,
title,
slug,
username,
createdAt,
readingTime: time,
views
};
}).sort((a,b) => b.views - a.views).slice(0, 6);
res.status(200).json({ status: 200, data, message: "success" })
}
else {
res.status(409).json({ status: 404, message: "Items not found" });
}
} catch (err) {
console.log("Error Getting Items", err);
res.status(500).json({ status: 500, message: err });
} finally {
client.close();
}
};

module.exports = {
getUser,
getUsers,
Expand All @@ -524,6 +581,7 @@ module.exports = {
updateStory,
updateStoryViews,
getTagStories,
getTrending,
// updateCart,
// updateBookmarks,
// updateOrdersHistory,
Expand Down
23 changes: 23 additions & 0 deletions server/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// https://gist.github.com/codeguy/6684588?permalink_comment_id=3243980#gistcomment-3243980
const slugify = (text) => {
return text
.toString() // Cast to string (optional)
.normalize("NFKD") // The normalize() using NFKD method returns the Unicode Normalization Form of a given string.
.toLowerCase() // Convert the string to lowercase letters
.trim() // Remove whitespace from both sides of a string (optional)
.replace(/\s+/g, "-") // Replace spaces with -
.replace(/[^\w\-]+/g, "") // Remove all non-word chars
.replace(/\-\-+/g, "-"); // Replace multiple - with single -
};

const readingTime = (text) => {
const contentString = JSON.stringify(text);
const words = contentString.split(" ").length;
const wordsPerMinute = 200;
return Math.ceil(words / wordsPerMinute);
};

module.exports = {
slugify,
readingTime,
}
2 changes: 2 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
updateStory,
updateStoryViews,
getTagStories,
getTrending,
// updateCart,
// updateBookmarks,
// updateOrdersHistory,
Expand Down Expand Up @@ -57,6 +58,7 @@ app.get("/api/users", getUsers)
app.get("/api/users/:username", getUser)
app.get("/api/tag/:tagName", getTagStories)
app.get("/api/stories/:username", getStories)
app.get("/api/trending", getTrending)
app.get("/api/stories/:username/:slug", getStory)
app.put("/api/stories/:username/:slug", updateStory)
app.put("/api/views", updateStoryViews)
Expand Down

0 comments on commit f371607

Please sign in to comment.