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

@@ -1,15 +1,15 @@
asset-manifest.json,1553884046206,ab1a2f7317faa41861e422ef229575fe3ecbb17d1c2f975e88efb9d78e511376
asset-manifest.json,1554736332025,df5343ebe8ed04ae9e0eb3b32e838f56c18dfaf98ffca952c101cd9d712b1608
index.html,1554736332025,a6f9531c2850d3e7f5eb795a03b2a2a4414e302e81a92545416344c89e644a64
manifest.json,1553879304430,52afe5ad7170b2b50e3ac04262420481b529c8c3009d93599bd41e3c44367f78
index.html,1553884046205,42891bf67643a2a8a638791bf6c4ee99e205be5c3b1c63c7ad1ba18706eb45c8
precache-manifest.d45de78050e7934587aed923200cf920.js,1553884046206,af20162c7c52cc330fba328fa78d181cd2e9295171b003d9360eb1c9970e9eb4
service-worker.js,1553884046205,fc351de1a559cf9b70e3022b895c738f94d83d8ccac4992c75e89ef7bb881248
static/css/main.1a707a0f.chunk.css,1553884046207,31f97c61456faf692f2920be106bc1ee08170c1e86a531eb225b32acfb8359ce
reactfavicon.ico,1553876850033,b72f7455f00e4e58792d2bca892abb068e2213838c0316d6b7a0d6d16acd1955
static/css/main.1a707a0f.chunk.css.map,1553884046251,28865d6e3616355a7fbb38dfc7ed97029ed4b5c5e5c61afbe5d433204e76f9ff
static/js/runtime~main.a8a9905a.js,1553884046254,e1af5f94fdd13901b2e433d0d7607e27c01458151c35b1fe4b7feda2a32b7aa9
service-worker.js,1554736332025,77a2d280be8aa608763f3e7ce0d5e3c9d5a0a8fca4d0a2f585e4197785170a90
static/css/main.1a707a0f.chunk.css.map,1554736332065,28865d6e3616355a7fbb38dfc7ed97029ed4b5c5e5c61afbe5d433204e76f9ff
precache-manifest.9a4f81b9fa21bd7215c42e286df1195f.js,1554736332025,3879fcf815575e6ec42ee5ba6c0de64a533475f4bad65088aa85885aa94694d8
static/css/main.1a707a0f.chunk.css,1554736332026,31f97c61456faf692f2920be106bc1ee08170c1e86a531eb225b32acfb8359ce
favicon.ico,1553876855791,229055d54fe1f70f3d835e9d723ea2fef78f2af82ed7ce45efa2f4623c1c1131
static/js/runtime~main.a8a9905a.js.map,1553884046250,c337bf8b58896da637a6e50ab8cfc779eb1ec42c55f8ec429030a03454a549db
static/js/main.4752fead.chunk.js,1553884046253,31c047c091eb527f5bade96d426368d9e05689355d6d9ce29d5539621024cb58
static/js/main.4752fead.chunk.js.map,1553884046254,f9eb4c273c0fcfd32f6ff8113afb509584adaf92667564c6e4ecc30023740cb4
static/js/2.ad8c616b.chunk.js,1553884046253,e9ea391f6951d55e960b05d0353cf46c42a39af282058927141d20876cd5640e
static/js/2.ad8c616b.chunk.js.map,1553884046252,6896a6400a6836fc179167478961bf4c211614d2afcf220caf6c80afd11e8967
static/js/main.66ce8d8f.chunk.js,1554736332068,668635c6cccab3a4ad7c8d03121baa8553aad7f93ea2945f2d9dc7d3a0fccda3
static/js/runtime~main.a8a9905a.js,1554736332036,e1af5f94fdd13901b2e433d0d7607e27c01458151c35b1fe4b7feda2a32b7aa9
static/js/runtime~main.a8a9905a.js.map,1554736332065,c337bf8b58896da637a6e50ab8cfc779eb1ec42c55f8ec429030a03454a549db
static/js/main.66ce8d8f.chunk.js.map,1554736332064,620038709bdf8ee7c0fc8ad271d61ead41ebcaff4f82652fe19eb65c4dbe998c
static/js/2.45d1e149.chunk.js,1554736332065,3b8f973757d4cc2ee88c12af9a97a786c0233909ee6f72d903157257572cccfe
static/js/2.45d1e149.chunk.js.map,1554736332067,5642dc89fcfbc41772fcb04c680e26db61d946042f08eb73c2fd838b1f7ff262

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