--index.js
--constants.js
--components
--App.js
--CreateLink.js
--Header.js
--Link.js
--LinkList.js
--Login.js
----------------------------------
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './styles/index.css'
import App from './components/App'
import registerServiceWorker from './registerServiceWorker'
import { ApolloProvider } from 'react-apollo'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { BrowserRouter } from 'react-router-dom'
import { setContext } from 'apollo-link-context'
import { AUTH_TOKEN } from './constants'
const httpLink = createHttpLink({
uri: 'http://localhost:4000'
})
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem(AUTH_TOKEN)
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ''
}
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
})
ReactDOM.render(
<BrowserRouter>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</BrowserRouter>,
document.getElementById('root')
)
registerServiceWorker()
----------------------------------------------------
constants.js
export const AUTH_TOKEN = 'auth-token'
---------------------------------------------------------
App.js
import React, { Component } from 'react';
import '../styles/App.css';
import LinkList from './LinkList'
import CreateLink from './CreateLink'
import Header from './Header'
import { Switch, Route } from 'react-router-dom'
import Login from './Login'
class App extends Component {
render() {
return (
<div className="center w85">
<Header />
<div className="ph3 pv1 background-gray">
<Switch>
<Route exact path="/" component={LinkList} />
<Route exact path="/create" component={CreateLink} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</div>
);
}
}
export default App;
-------------------------------------------------------
createLinks.js
import React, { Component } from 'react'
import { Mutation } from 'react-apollo'
import gql from 'graphql-tag'
const POST_MUTATION = gql`
mutation PostMutation($description: String!, $url: String!) {
post(description: $description, url: $url) {
id
createdAt
url
description
}
}
`
class CreateLink extends Component {
state = {
description: '',
url: '',
}
render() {
const { description, url } = this.state
return (
<div>
<div className="flex flex-column mt3">
<input
className="mb2"
value={description}
onChange={e => this.setState({ description: e.target.value })}
type="text"
placeholder="A description for the link"
/>
<input
className="mb2"
value={url}
onChange={e => this.setState({ url: e.target.value })}
type="text"
placeholder="The URL for the link"
/>
</div>
<Mutation mutation={POST_MUTATION} variables={{ description, url }}
onCompleted={() => this.props.history.push('/')}>
{postMutation => <button onClick={postMutation}>Submit</button>}
</Mutation>
</div>
)
}
}
export default CreateLink
----------------------------------------
Header.js
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { withRouter } from 'react-router'
import { AUTH_TOKEN } from '../constants'
class Header extends Component {
render() {
const authToken = localStorage.getItem(AUTH_TOKEN)
return (
<div className="flex pa1 justify-between nowrap orange">
<div className="flex flex-fixed black">
<div className="fw7 mr1">Hacker News</div>
<Link to="/" className="ml1 no-underline black">
new
</Link>
<div className="ml1">|</div>
<Link to="/create" className="ml1 no-underline black">
submit
</Link>
</div>
<div className="flex flex-fixed">
{authToken ? (
<div
className="ml1 pointer black"
onClick={() => {
localStorage.removeItem(AUTH_TOKEN)
this.props.history.push(`/`)
}}
>
logout
</div>
) : (
<Link to="/login" className="ml1 no-underline black">
login
</Link>
)}
</div>
</div>
)
}
}
export default withRouter(Header)
----------------------------------------------
link.js
import React, { Component } from 'react'
class Link extends Component {
render() {
return (
<div>
<div>
{this.props.link.description} ({this.props.link.url})
</div>
</div>
)
}
}
export default Link
--------------------------------------
linklist.js
import React, { Component } from 'react'
import Link from './Link'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
const FEED_QUERY = gql`
{
feed {
links {
id
createdAt
url
description
}
}
}
`
class LinkList extends Component {
render() {
return (
<Query query={FEED_QUERY}>
{({ loading, error, data }) => {
if (loading) return <div>Fetching</div>
if (error) return <div>Error</div>
const linksToRender = data.feed.links
return (
<div>
{linksToRender.map(link => <Link key={link.id} link={link} />)}
</div>
)
}}
</Query>
)
}
}
export default LinkList
----------------------------------------
login.js
import React, { Component } from 'react'
import { AUTH_TOKEN } from '../constants'
import { Mutation } from 'react-apollo'
import gql from 'graphql-tag'
const SIGNUP_MUTATION = gql`
mutation SignupMutation($email: String!, $password: String!, $name: String!) {
signup(email: $email, password: $password, name: $name) {
token
}
}
`
const LOGIN_MUTATION = gql`
mutation LoginMutation($email: String!, $password: String!) {
login(email: $email, password: $password) {
token
}
}
`
class Login extends Component {
state = {
login: true, // switch between Login and SignUp
email: '',
password: '',
name: '',
}
render() {
const { login, email, password, name } = this.state
return (
<div>
<h4 className="mv3">{login ? 'Login' : 'Sign Up'}</h4>
<div className="flex flex-column">
{!login && (
<input
value={name}
onChange={e => this.setState({ name: e.target.value })}
type="text"
placeholder="Your name"
/>
)}
<input
value={email}
onChange={e => this.setState({ email: e.target.value })}
type="text"
placeholder="Your email address"
/>
<input
value={password}
onChange={e => this.setState({ password: e.target.value })}
type="password"
placeholder="Choose a safe password"
/>
</div>
<div className="flex mt3">
<Mutation
mutation={login ? LOGIN_MUTATION : SIGNUP_MUTATION}
variables={{ email, password, name }}
onCompleted={data => this._confirm(data)}
>
{mutation => (
<div className="pointer mr2 button" onClick={mutation}>
{login ? 'login' : 'create account'}
</div>
)}
</Mutation>
<div
className="pointer button"
onClick={() => this.setState({ login: !login })}
>
{login
? 'need to create an account?'
: 'already have an account?'}
</div>
</div>
</div>
)
}
_confirm = async data => {
const { token } = this.state.login ? data.login : data.signup
this._saveUserData(token)
this.props.history.push(`/`)
}
_saveUserData = token => {
localStorage.setItem(AUTH_TOKEN, token)
}
}
export default Login
----------------------------------
No comments:
Post a Comment