Subreddit filtering #4

Merged
innocuous-symmetry merged 7 commits from subreddit-filtering into master 2022-01-29 17:42:20 +00:00
7 changed files with 112 additions and 42 deletions

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import { fetchBySub } from "./postsSlice";
import { selectAllSubs } from "../reddit/redditSlice";
import { useSelector, useDispatch } from "react-redux";
import { updatePosts } from "./postsSlice";
import { v4 } from "uuid";
import Post from "./Post";
@@ -28,7 +29,7 @@ export default function Feed() {
if (subArray) {
prepareData();
}
}, [setEndpoints]);
}, [setEndpoints, subs]);
@@ -69,9 +70,21 @@ export default function Feed() {
}
};
extractedPosts = extractedPosts.sort((x,y) => x.created_utc > y.created_utc); // sorts posts by sort time (to do: fix this)
const comparePosts = (a,b) => { // sorting function: compares time posted within each object in array
if (a.data.created_utc > b.data.created_utc) {
return -1;
} else if (a.data.created_utc < b.data.created_utc) {
return 1;
} else {
return 0;
}
}
let newFeed = extractedPosts.map((post) => {
let sortedPosts = extractedPosts.sort(comparePosts); // implements sorting function
console.log(sortedPosts);
let newFeed = sortedPosts.map((post) => {
return (
<Post
title={post.data.title} // each variable passed in as props
@@ -81,10 +94,10 @@ export default function Feed() {
comments={post.data.num_comments}
time={post.data.created_utc}
key={v4()}
media={post.data.post_hint === 'image' && post.url}
media={post.data.post_hint === 'image' && post.data.url}
permalink={post.data.permalink}
selftext={post.data.selftext}
video={post.data.is_video ? post.data.media.reddit_video.fallback_url : null}
video={post.data.is_video ? post.data.media.reddit_video.fallback_url : null} // to do: handle media edge cases, especially video
/>
);
})
@@ -94,13 +107,15 @@ export default function Feed() {
}
mapPosts();
if (isActive) {
mapPosts();
}
return () => {
isActive = false;
}
}, [data, setFeed])
}, [data, setFeed]);
return (
<>

View File

@@ -14,7 +14,7 @@
height: 15rem;
}
a {
.title {
font-size: 2rem;
}
@@ -27,6 +27,7 @@ img, video {
display: inline-flex;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
}
.post-text {

View File

@@ -4,42 +4,61 @@ import './Post.css';
export default function Post({title,author,subreddit,ups,comments,time,key,media,permalink,selftext,video}) {
const limit = 300;
const [body, setBody] = useState(selftext);
const postDate = new Date(time * 1000); // handles conversion from unix timestamp to local time and date strings
const localTime = postDate.toLocaleTimeString();
const localDate = postDate.toLocaleDateString();
// useEffect(() => {
// if (selftext.length === 0) { // in the case that the post body is empty, it does not include an ellipsis on mouseout
// return;
// } else if (selftext.length > limit) {
// setBody(selftext.substring(0,limit) + '...');
// } else {
// return;
// }
// }, [setBody, selftext]);
useEffect(() => {
if (selftext.length === 0) { // in the case that the post body is empty, it does not include an ellipsis on mouseout
return;
} else if (selftext.length > limit) {
setBody(selftext.substring(0,limit) + '...');
} else {
return;
}
}, [setBody, selftext]);
// const handleHover = () => {
// setBody(selftext);
// }
const handleHover = () => {
setBody(selftext);
}
// const handleMouseOut = () => {
// if (selftext.length === 0) { // ...and then doesn't add it in after a mouseover/out
// return;
// }
const handleMouseOut = () => {
if (selftext.length === 0) { // ...and then doesn't add it in after a mouseover/out
return;
}
// setBody(selftext.substring(0,limit) + '...');
// }
setBody(selftext.substring(0,limit) + '...');
}
return (
<>
<div className="post-body">
<a className="title" href={`https://reddit.com${permalink}`}>{title ? title : 'title'}</a>
{media ? <img alt={title} src={media} /> : ''}
{video ? <video controls type="video/mp4" src={video}></video> : ''}
<p className="post-text">{body}</p>
{title ?
<a className="title" href={`https://reddit.com${permalink}`}>{title}</a>
: <p>[untitled]</p>}
{media ? <img alt={title} src={media} /> : ''}
{video ?
<video controls type="video/mp4" src={video}></video>
: ''}
{body ?
<p onMouseOver={handleHover} onMouseOut={handleMouseOut}>{body}</p>
: ''}
<div className="post-metadata">
<p>{subreddit ? 'r/' + subreddit : ''}</p>
<a href={`https://www.reddit.com${permalink}`}>
{subreddit ? 'r/' + subreddit : ''}
</a>
<p className="user">{author ? 'u/' + author : 'u/username'}</p>
<p className="time-posted">posted at {time ? time : '...?'}</p>
<p className="time-posted">posted at {time ? (localTime + ' on ' + localDate) : '...?'}</p>
<p className="num-comments">{comments ? comments : 'no'} comments</p>
</div>
</div>
</>
);

View File

@@ -52,5 +52,4 @@ export const postsSlice = createSlice({
export default postsSlice.reducer;
export const selectPosts = state => state.postsSlice.posts;
export const { filterPosts, updatePosts } = postsSlice.actions;
// exports also includes fetchBySub (takes argument of a sub)
// exports also includes fetchFromAll (takes argument of an array of subs)
// exports also includes fetchBySub (takes argument of a sub)

View File

@@ -64,9 +64,8 @@ export const redditSlice = createSlice({
},
},
reducers: {
updateSubVisibility(state,action) {
// reads state of buttons in Sidebar component to determine whether each is active
// connects with post rendering, filtering out posts belonging to inactive subreddits
updateSubVisibility(state,action) { // receives a subreddit name as action.payload
state.subreddits[action.payload].isSelected = !state.subreddits[action.payload].isSelected;
}
},
extraReducers: {},
@@ -74,4 +73,15 @@ export const redditSlice = createSlice({
export default redditSlice.reducer;
export const selectAllSubs = state => state.redditSlice.subreddits;
export const selectActiveSubs = state => {
let activeSubs = [];
for (let it in state.redditSlice.subreddits) {
if (it.isSelected) {
activeSubs.push(it);
} else {
continue;
}
}
return activeSubs;
}
export const { updateSubVisibility } = redditSlice.actions;

View File

@@ -1,9 +1,11 @@
import React, { useRef, useState } from "react";
import { useSelector } from "react-redux";
import { useSelector, useDispatch } from "react-redux";
import { selectAllSubs } from "../reddit/redditSlice";
import SidebarItem from "./SidebarItem";
import './Sidebar.css';
export default function Sidebar({isCollapsed}) {
const dispatch = useDispatch();
const allSubs = useSelector(selectAllSubs);
let arrayOfSubs = Object.keys(allSubs);
@@ -24,16 +26,17 @@ export default function Sidebar({isCollapsed}) {
}
}
const handleClick = (e) => {
}
return (
<>
<div className={isCollapsed ? 'sidebar-hidden' : 'sidebar'}> {/* Is collapsed is passed from the parent component, and is mutable within the navbar */}
{
subs.map((sub) => { // Maps each sub to its own line within the sidebar, along with a button that toggles its "isSelected" property
return (
<div className="individual-sub">
<button className="toggle-sub-active">X</button> {/* This button will dispatch an action to change the state of this specific subreddit */}
<p>{sub}</p>
</div>
<SidebarItem sub={sub} isChecked={true}/>
)
})
}

View File

@@ -0,0 +1,23 @@
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { updateSubVisibility, selectAllSubs } from "../reddit/redditSlice";
export default function SidebarItem({sub, isChecked}) {
const [checked, setChecked] = useState(isChecked);
const dispatch = useDispatch();
const allSubs = useSelector(selectAllSubs);
const handleClick = () => {
setChecked(!checked);
dispatch(updateSubVisibility(sub));
}
console.log(allSubs);
return (
<div className="individual-sub">
<input type="checkbox" id={sub} htmlFor={sub} checked={checked} onChange={handleClick}></input>
<label htmlFor={sub}>{sub}</label>
</div>
);
}