feat: search all entries

This commit is contained in:
Kyle Gill
2019-04-12 16:59:29 -06:00
parent 37b633ea82
commit ee6a1a2d2d
9 changed files with 221 additions and 40 deletions

View File

@@ -13,6 +13,7 @@ import Month from "./components/screens/Month"
import Year from "./components/screens/Year"
import User from "./components/screens/User"
import Login from "./components/screens/Login"
import Search from "./components/screens/Search"
import Register from "./components/screens/Register"
import Start from "./components/screens/Start"
import PrivateRoute from "./components/PrivateRoute"
@@ -20,6 +21,9 @@ import PrivateRoute from "./components/PrivateRoute"
import { withAuthentication } from "./components/session"
import { withFirebase } from "./components/firebase"
const FullscreenLayout = styled.div`
background-color: ${props => props.theme.colors.bodyBackground};
`
const RouteLayout = styled.div`
display: flex;
flex-direction: column;
@@ -42,9 +46,9 @@ class App extends Component {
onChangeTheme = () => {
const { selectedTheme } = this.state
const root = document.documentElement
const body = document.body
const newTheme = selectedTheme === "LIGHT" ? "DARK" : "LIGHT"
root.style.setProperty(
body.style.setProperty(
"background-color",
theme[newTheme].colors.bodyBackground
)
@@ -73,31 +77,34 @@ class App extends Component {
return (
<ThemeProvider theme={currentTheme}>
<Router>
<Navbar toggleTheme={this.onChangeTheme} />
<RouteLayout>
<PrivateRoute
authed={authed}
path="/:year(\d+)"
component={Year}
exact
/>
<PrivateRoute
authed={authed}
path="/:year(\d+)/:month(0[1-9]|1[0-2]+)"
component={Month}
exact
/>
<PrivateRoute
authed={authed}
path="/:year(\d+)/:month(0[1-9]|1[0-2]+)/:day(\d+)"
component={Day}
exact
/>
<Route path="/user" component={User} exact />
<Route path="/login" component={Login} exact />
<Route path="/register" component={Register} exact />
<Route path="/" component={Start} exact />
</RouteLayout>
<FullscreenLayout>
<Navbar toggleTheme={this.onChangeTheme} />
<RouteLayout>
<PrivateRoute
authed={authed}
path="/:year(\d+)"
component={Year}
exact
/>
<PrivateRoute
authed={authed}
path="/:year(\d+)/:month(0[1-9]|1[0-2]+)"
component={Month}
exact
/>
<PrivateRoute
authed={authed}
path="/:year(\d+)/:month(0[1-9]|1[0-2]+)/:day(\d+)"
component={Day}
exact
/>
<Route path="/user" component={User} exact />
<Route path="/login" component={Login} exact />
<Route path="/search" component={Search} exact />
<Route path="/register" component={Register} exact />
<Route path="/" component={Start} exact />
</RouteLayout>
</FullscreenLayout>
</Router>
</ThemeProvider>
)

View File

@@ -11,6 +11,7 @@ import {
Edit2,
LogIn,
Moon,
Search,
Sun,
User,
} from "react-feather"
@@ -53,6 +54,7 @@ const Icon = ({ name, tabindex, label, ...rest }) => (
{name === "Edit2" && <Edit2 />}
{name === "LogIn" && <LogIn />}
{name === "Moon" && <Moon />}
{name === "Search" && <Search />}
{name === "Sun" && <Sun />}
{name === "User" && <User />}
</IconBase>

View File

@@ -72,6 +72,9 @@ const Navbar = ({ authUser, theme, toggleTheme }) => (
<Link to={yearUrl()}>
<Icon name="Calendar" />
</Link>
<Link to={"/search"}>
<Icon name="Search" />
</Link>
<Link to={"/user"}>
<Icon name="User" />
</Link>

View File

@@ -12,6 +12,7 @@ export const H1 = styled.h1`
`
export const Input = styled.input`
color: ${props => props.colors.primary};
background-color: ${props => props.colors.headerBackground};
border: none;
border-radius: 5px;

View File

@@ -150,6 +150,7 @@ class Day extends Component {
day: Number(day),
year: Number(year),
month: Number(month),
userId: authUser.uid,
},
{
merge: true,

View File

@@ -69,7 +69,7 @@ class RegisterFormBase extends Component {
email: user.email,
theme: "LIGHT",
})
this.props.history.push("/home")
this.props.history.push("/")
})
.catch(error => {
this.setState({ error })

View File

@@ -0,0 +1,165 @@
import React, { Component } from "react"
import { withRouter, Link } from "react-router-dom"
/** @jsx jsx */
import { jsx, css, keyframes } from "@emotion/core"
import styled from "@emotion/styled"
import { compose } from "recompose"
import { withTheme } from "emotion-theming"
import { BeatLoader } from "react-spinners"
import { Input } from "../../elements"
import { pad } from "../../../utils/date"
import { withFirebase } from "../../firebase"
import { withAuthentication } from "../../session"
const SearchGrid = styled.div`
display: grid;
grid-template-columns: 1fr;
grid-gap: 10px;
`
const SearchLayout = styled.div`
width: 100%;
align-self: center;
margin-top: 20px;
`
const SearchResult = styled.div`
margin-top: 5px;
padding: 20px;
border-radius: 5px;
color: ${props => props.theme.colors.primary};
border: 1px solid;
border-color: ${props => props.theme.colors.quarternary};
&:hover {
cursor: pointer;
border-color: ${props => props.theme.colors.tertiary};
}
`
const fadeKeyFrames = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`
const LoadingSpinner = styled(BeatLoader)`
opacity: 0;
`
class Search extends Component {
state = {
entries: [],
allEntries: [],
searchInput: "",
loading: true,
}
componentDidMount() {
const entries = this.getEntries()
console.log(entries)
}
onChange = event => {
const searchInput = event.target.value
this.setState({ searchInput })
this.filterEntries(searchInput)
}
filterEntries = searchTerm => {
const { allEntries } = this.state
if (searchTerm == "") {
this.setState({ entries: allEntries })
} else {
const filteredEntries = allEntries.filter(entry => {
return entry.text.toLowerCase().includes(searchTerm.toLowerCase())
})
this.setState({ entries: filteredEntries })
}
}
getEntries = async _ => {
const { firebase, authUser } = this.props
const entriesRef = await firebase.db
.collection("entries")
.where("userId", "==", authUser.uid)
.get()
const entries = entriesRef.docs.map(doc => doc.data())
console.log(entries)
// const sortedEntries = entries.sort((a, b) => {
// return (
// new Date(b.year, b.month - 1, b.day) -
// new Date(a.year, a.month - 1, a.day)
// )
// })
// console.log(sortedEntries)
this.setState({ entries, allEntries: entries, loading: false })
}
render() {
const { entries, searchInput, loading } = this.state
const { theme } = this.props
return (
<SearchLayout>
<SearchGrid>
<Input
value={searchInput}
onChange={e => this.onChange(e)}
type="text"
placeholder="Search..."
colors={theme.colors}
/>
{loading ? (
<div style={{ marginTop: 10, margin: "0 auto" }}>
<LoadingSpinner
color={theme.colors.quarternary}
size={10}
margin="4px"
css={css`
animation: ${fadeKeyFrames} 1s ease-in;
`}
/>
</div>
) : (
entries.map((entry, index) => (
<Link
key={index}
to={`${entry.year}/${pad(entry.month)}/${pad(entry.day)}`}
style={{ textDecoration: "none" }}
>
<SearchResult
css={css`
animation: ${fadeKeyFrames} 0.2s ease-in;
`}
>
<div
css={css`
font-style: italic;
color: ${theme.colors.secondary};
margin-bottom: 5px;
`}
>
{entry.day}/{entry.month}/{entry.year}
</div>
<div>
{entry.text.substring(0, 128)}
{entry.text.length >= 128 && "..."}
</div>
</SearchResult>
</Link>
))
)}
</SearchGrid>
</SearchLayout>
)
}
}
export default compose(
withFirebase,
withTheme,
withAuthentication
)(Search)

View File

@@ -0,0 +1,2 @@
import Search from "./Search"
export default Search