Search refactor #11
15
src/App.css
15
src/App.css
@@ -31,7 +31,7 @@
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.mobile-title {
|
||||
.nav-title-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
.nav-title-desktop {
|
||||
display: inline-flex;
|
||||
color: orchid;
|
||||
padding-left: 1.5rem;
|
||||
@@ -97,7 +97,7 @@
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 12rem;
|
||||
width: 13.5rem;
|
||||
position: fixed;
|
||||
background-color: black;
|
||||
color: white;
|
||||
@@ -234,17 +234,20 @@
|
||||
position: static;
|
||||
}
|
||||
|
||||
.desktop-title {
|
||||
.nav-title-desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-title {
|
||||
.nav-title-mobile {
|
||||
display: inline-flex;
|
||||
color: orchid;
|
||||
padding-left: 1.5rem;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
.nav-searchbar {
|
||||
width: 12rem;
|
||||
right: 12rem;
|
||||
right: 7rem;
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
|
||||
@@ -12,8 +12,8 @@ export default function Navbar() {
|
||||
return (
|
||||
<>
|
||||
<div className="navbar">
|
||||
<h1 className="nav-title desktop-title">Reddit, but it's all cats</h1>
|
||||
<h1 className="nav-title mobile-title">Cat Reddit</h1>
|
||||
<h1 className="nav-title-desktop">Reddit, but it's all cats</h1>
|
||||
<h1 className="nav-title-mobile">Cat Reddit</h1>
|
||||
<SearchBar />
|
||||
<button className="sidebar-button" onClick={handleCollapse}>Sidebar</button>
|
||||
</div>
|
||||
|
||||
@@ -29,11 +29,32 @@ export const fetchComments = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
export const searchByActive = createAsyncThunk(
|
||||
'posts/searchByActive',
|
||||
async(obj) => {
|
||||
const { sub, term } = obj;
|
||||
try {
|
||||
let fulfilledResponse;
|
||||
const myRequest = new Request(`https://www.reddit.com/${sub}/search.json?q=${term}&restrict_sr=1&sr_nsfw=`);
|
||||
let response = await fetch(myRequest);
|
||||
if (response.ok) {
|
||||
let searchData = await response.json();
|
||||
fulfilledResponse = searchData;
|
||||
}
|
||||
return fulfilledResponse;
|
||||
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: {
|
||||
posts: [],
|
||||
activeComments: [],
|
||||
searchResults: [],
|
||||
requestsPending: false,
|
||||
requestDenied: false,
|
||||
},
|
||||
@@ -43,7 +64,7 @@ export const postsSlice = createSlice({
|
||||
},
|
||||
updatePosts(state,action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
}
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(fetchBySub.pending, (state,action) => {
|
||||
@@ -75,12 +96,28 @@ export const postsSlice = createSlice({
|
||||
state.requestDenied = false;
|
||||
state.activeComments.push(action.payload);
|
||||
})
|
||||
|
||||
builder.addCase(searchByActive.pending, (state,action) => {
|
||||
state.requestsPending = true;
|
||||
state.requestDenied = false;
|
||||
})
|
||||
builder.addCase(searchByActive.rejected, (state,action) => {
|
||||
state.requestsPending = false;
|
||||
state.requestDenied = true;
|
||||
})
|
||||
builder.addCase(searchByActive.fulfilled, (state,action) => {
|
||||
state.requestsPending = false;
|
||||
state.requestDenied = false;
|
||||
state.searchResults = action.payload;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
export default postsSlice.reducer;
|
||||
export const selectPosts = state => state.postsSlice.posts;
|
||||
export const isPending = state => state.postsSlice.requestsPending;
|
||||
export const selectSearchResults = state => state.postsSlice.searchResults;
|
||||
export const { filterPosts, updatePosts } = postsSlice.actions;
|
||||
// exports also includes fetchBySub (takes argument of a sub)
|
||||
// exports also includes fetchComments (takes argument of a post permalink)
|
||||
// exports also includes fetchComments (takes argument of a post permalink)
|
||||
// exports also includes searchByActive
|
||||
@@ -62,6 +62,7 @@ export const redditSlice = createSlice({
|
||||
isSelected: true
|
||||
}
|
||||
},
|
||||
formattedActive: []
|
||||
},
|
||||
reducers: {
|
||||
updateSubVisibility(state,action) { // receives a subreddit name as action.payload
|
||||
@@ -69,29 +70,29 @@ export const redditSlice = createSlice({
|
||||
},
|
||||
getActiveSubs(state,action) {
|
||||
let activeSubs = [];
|
||||
let allSubs = state.redditSlice.subreddits;
|
||||
for (let sub in allSubs) {
|
||||
if (sub.isSelected) {
|
||||
activeSubs.push(sub);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
for (let sub in state.subreddits) {
|
||||
sub.isSelected && activeSubs.push(sub.name);
|
||||
}
|
||||
state.formattedActive = activeSubs;
|
||||
},
|
||||
},
|
||||
extraReducers: {},
|
||||
});
|
||||
|
||||
export const selectAllSubs = state => state.redditSlice.subreddits;
|
||||
export const selectActiveSubs = state => {
|
||||
export const selectActive = state => {
|
||||
let subs = [];
|
||||
for (let sub in state.redditSlice.subreddits) {
|
||||
subs.push(sub);
|
||||
}
|
||||
|
||||
let activeSubs = [];
|
||||
for (let it in state.redditSlice.subreddits) {
|
||||
if (it.isSelected) {
|
||||
activeSubs.push(it);
|
||||
} else {
|
||||
continue;
|
||||
for (let each of subs) {
|
||||
if (each.isSelected) {
|
||||
activeSubs.push(each);
|
||||
}
|
||||
}
|
||||
|
||||
return activeSubs;
|
||||
}
|
||||
export const { updateSubVisibility, getActiveSubs } = redditSlice.actions;
|
||||
|
||||
@@ -1,24 +1,53 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { searchByActive, selectSearchResults } from '../posts/postsSlice';
|
||||
import { selectActive, selectAllSubs } from "../reddit/redditSlice";
|
||||
|
||||
export default function SearchBar() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const selectedSubs = useSelector(selectAllSubs);
|
||||
const activeSubs = useSelector(selectActive);
|
||||
|
||||
const [term, setTerm] = useState('');
|
||||
const [results, setResults] = useState(null);
|
||||
const searchData = useSelector(selectSearchResults);
|
||||
|
||||
const handleChange = (e) => {
|
||||
e.preventDefault();
|
||||
setTerm(e.target.value);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (term) {
|
||||
// dispatch an action which filters content by {term}
|
||||
} else {
|
||||
return;
|
||||
const handleSubmit = () => {
|
||||
if (term && activeSubs) {
|
||||
let extracted = [];
|
||||
for (let sub in activeSubs) {
|
||||
extracted.push(sub);
|
||||
}
|
||||
|
||||
console.log(extracted);
|
||||
let mapped = extracted.map((sub) => dispatch(searchByActive({sub, term})));
|
||||
Promise.all([...mapped]).then((data) => setResults(data));
|
||||
}
|
||||
}, [term])
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
if (results && active) {
|
||||
console.log(results);
|
||||
}
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
}
|
||||
}, [results, activeSubs]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<input type="text" className="nav-searchbar" placeholder="Search posts" value={term ? term : ''} onChange={handleChange} />
|
||||
<input type="submit" onClick={handleSubmit}></input>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -20,6 +20,14 @@
|
||||
margin: 0.8rem 0;
|
||||
}
|
||||
|
||||
.individual-sub button {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.individual-sub label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.search-sub-input {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
import React, { useState } from "react";
|
||||
// import { useDispatch } from "react-redux";
|
||||
// import { updateSubVisibility } from "../reddit/redditSlice";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateSubVisibility } from "../reddit/redditSlice";
|
||||
|
||||
export default function SidebarItem({sub}) {
|
||||
const [visible, setVisible] = useState('hide'); // dispatch will be used to dispatch updateSubVisibility on change in state
|
||||
// const dispatch = useDispatch(); // this will likely be within a useEffect hook
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleClick = () => {
|
||||
if (visible === 'hide') {
|
||||
setVisible('show');
|
||||
} else if (visible === 'show') {
|
||||
setVisible('hide');
|
||||
}
|
||||
const handleClick = () => {
|
||||
dispatch(updateSubVisibility(sub));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="individual-sub">
|
||||
{/* <input type="checkbox" id={sub} checked={checked} onChange={handleClick}></input> */}
|
||||
<button id={sub} onClick={handleClick}>{visible}</button>
|
||||
<button id={sub} onClick={handleClick}>toggle</button>
|
||||
<label id={sub}>{sub}</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user