feat: search all entries
This commit is contained in:
61
src/App.js
61
src/App.js
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -150,6 +150,7 @@ class Day extends Component {
|
||||
day: Number(day),
|
||||
year: Number(year),
|
||||
month: Number(month),
|
||||
userId: authUser.uid,
|
||||
},
|
||||
{
|
||||
merge: true,
|
||||
|
||||
@@ -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 })
|
||||
|
||||
165
src/components/screens/Search/Search.js
Normal file
165
src/components/screens/Search/Search.js
Normal 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)
|
||||
2
src/components/screens/Search/index.js
Normal file
2
src/components/screens/Search/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import Search from "./Search"
|
||||
export default Search
|
||||
Reference in New Issue
Block a user