Let's Build A Currency Exchange Part II
Tags: react, graphql, apollo, javascript
Published: 2019-08-19 11:38:04

---
title: Let's Build A Currency Exchange Part II
published: true
description: React Hooks | GraphQL | Apollo | Node.js
tags: react, graphql, apollo, javascript
cover_image: https://store-images.s-microsoft.com/image/apps.43630.14323591455066440.4fa2d451-8a1f-44fd-a536-5fda778060ee.5ad45e3a-3125-4acf-8a9f-8c6dc46f060e?mode=scale&q=90&h=1080&w=1920
---

In this half of the tutorial we'll focus on the frontend. The code for this project is on my [GitHub](https://github.com/marlonanthony/forex). You can find the first half of this article [here](https://dev.to/marlonanthony/let-s-build-a-currency-exchange-part-i-52g1). We'll store the code for our frontend in a folder named `client`. Create `client` at the root level, cd into this folder and run the following command in the terminal:

```javascript
npx create-react-app .
```

We use `npx` so that we don't have to install create-react-app globally. Run the following command in your terminal and let's get our dependencies:

```jsx
npm i @apollo/react-hooks apollo-cache-inmemory apollo-client apollo-link-http graphql-tag react-chartjs-2 chart.js react-router-dom
```

With our dependencies in tow, let's do a little spring cleaning. Delete `logo.svg`, `serviceWorker.js`, `App.test.js` and `App.css`. Now remove their imports (and all those weird semicolons galavanting about) from `index.js` and `App.js`. Afterwards, adjust `index.js` such that it resembles the below code:

```jsx
// index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import { ApolloClient } from 'apollo-client'
import { ApolloProvider } from '@apollo/react-hooks'
import { InMemoryCache } from 'apollo-cache-inmemory' 
import { HttpLink } from 'apollo-link-http'

import App from './App'
import './index.css'

const cache = new InMemoryCache() 
const client = new ApolloClient({
  cache,
  link: new HttpLink({
    uri: 'http://localhost:4000/graphql',
    credentials: 'include' 
  })
})

ReactDOM.render(
  <ApolloProvider client={client}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ApolloProvider>, document.getElementById('root')
)
```

First, we handle our imports. Then we create a new instance of `InMemoryCache` and add it to our `ApolloClient` configuration Object. We use `HttpLink` to hit our GraphQL API and just as we did in the [GraphQL Playground](http://localhost:4000/graphql), we add `credentials: 'include'` to ensure that our cookie is sent along with every request. 

Inside of our render function we wrap everything with React Router's `BrowserRouter`. `react-router` describes `BrowserRouter` as, "A router that uses the HTML5 history API to keep your UI in sync with the URL." 

We pass `ApolloProvider` our new instance of `ApolloClient` so that later we can `consume` it (akin to the React `Context` API). As I write this `@apollo/react-hooks` is a nice ripe age of one day old. This is a minified version of `react-apollo` which doesn't offer render prop functionality, but reduces bundle size by 50%!

Open up `App.js` and add the following code:

```jsx
// App.js

import React from 'react'
import { Route } from 'react-router-dom'

import Landing from './pages/Landing'

const App = () => <Route exact path='/' component={ Landing } />

export default App
```

React Router's `Route` component allows us to define a routes `path`, and assign said path a component to be rendered. In our case this component is `Landing`. Create a `pages` folder inside of the `src` folder. Inside `pages` create a new file and name it `Landing.js`. Insert the following code:

```jsx
// Landing.js

import React from 'react'

const Landing = () => <div>Hello world!</div>

export default Landing
```

Once more, we demonstrate our respect for tradition and muster our most majestic, 'Hello world' yet! Nothing quite tucks me in like a well-groomed, "Hello world!" 

Inside the `src` folder, create another folder and name it `graphql`. Inside of this folder create two subfolders: `mutations` and `queries`. Inside of `queries` create a new file and name it `currencyPairInfo.js`.

Add the following code:

```javascript
// currencyPairInfo.js

import gql from 'graphql-tag'

export const CURRENCY_PAIR_INFO = gql`
  query CurrencyPairInfo($fc: String, $tc: String) {
    currencyPairInfo(tc: $tc, fc: $fc) {
      fromCurrency 
      fromCurrencyName
      toCurrency
      toCurrencyName
      exchangeRate
      lastRefreshed
      timeZone
      bidPrice
      askPrice
    }
  }
`
```

First, we import `gql` from `graphql-tag` so that we can define our mutations and queries. Inside of this file we're doing the exact same thing we did in the GraphQL Playground, except we add an additional name (`CurrencyPairInfo`) to our query and further describe the shape of our schema. Finally, we store this query in the constant `CURRENCY_PAIR_INFO`.

Now that we have our query, let's return to Landing.js and use it.

```jsx
// Landing.js

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'

import { CURRENCY_PAIR_INFO } from '../graphql/queries/currencyPairInfo'

const Landing = () => {
  const [ fc, setFc ] = useState('EUR'),
        [ tc, setTc ] = useState('USD'),
        { data, loading, error, refetch } = useQuery(CURRENCY_PAIR_INFO, {
          variables: { fc, tc }
        })

  if(loading) return <p>Loading...</p>
  if(error) return <button onClick={() => refetch()}>Retry</button>

  return data && (
    <section>
      <h3>Currency Exchange</h3>
      <div>
        <select
          value={`${fc}/${tc}`}
          onChange={e => {
            const [ fromCurrency, toCurrency ] = e.target.value.split('/')
            setFc(fromCurrency)
            setTc(toCurrency)
          }}>
          <option>EUR/USD</option>
          <option>JPY/USD</option>
          <option>GBP/USD</option>
          <option>AUD/USD</option>
          <option>USD/CHF</option>
          <option>NZD/USD</option>
          <option>USD/CAD</option>
        </select>
        <button onClick={() => refetch()}>refresh</button>
      </div>
      <div className='landing_pair_data'>
        { data.currencyPairInfo && Object.keys(data.currencyPairInfo).map(val => (
          <div key={val} className='data'>
            <p><span>{val}: </span>{ data.currencyPairInfo[val] }</p>
          </div>
        ))}
      </div>
    </section>
  )
}

export default Landing
```

We import `useQuery` from `@apollo/react-hooks`, the query we wrote in `currencyPairInfo.js` and `useState` from `React`. Instead of using a class component to initialize state via `this.state`, and later using `setState` to update it, we're going to be using the React Hook `useState`. `useState` takes the initial state as an argument and returns the current state and a function to update said state. This state will be used to collect user input. We provide our query this input as `variables` and `useQuery` returns the response.

The most traded pairs of currencies in the world are called the Majors. They constitute the largest share of the foreign exchange market, about 85%, and therefore they exhibit high market liquidity. The Majors are: EUR/USD, USD/JPY, GBP/USD, AUD/USD, USD/CHF, NZD/USD and USD/CAD. These are the currency pairs we'll provide to our users.

We create a `select` list, each `option` providing the variables to our query. These options make up the Majors. Apollo provides a `refetch` function that will reload the given query. We place this function in a button so that `onClick` the user can get up-to-date data. Take heed not to ping the Alpha Vantage API too often. If you send too many request, they'll graciously provide you with a timeout lasting a few seconds. Just enough time to ponder your insolence.

Our data is returned to us via `data.currencyPairInfo`. We map over said data and provide it to the DOM. You'll notice we're rendering `__typename: PairDisplay`. Apollo Client uses `__typename` and `id` fields to handle cache updates. If you query a different currency pair, then query the original pair again, you'll notice that the previous pairs data is instantly available via `apollo-cache-inmemory`.

I can't stare at our data pressed up against the left margin like this. Head into index.css and just add a quick `text-align: center` to the `body`.

With that quick aside, let's clean up `Landing.js`. Create a new folder in `src` and call it `components`. Inside of `components` create a `pairs` folder. Inside of `pairs` create a new file `SelectList.js` and insert the following:

```jsx
// SelectList.js

import React from 'react'

const SelectList = ({ fc, setFc, tc, setTc }) => (
  <select
    value={`${fc}/${tc}`}
    onChange={e => {
      const [ fromCurrency, toCurrency ] = e.target.value.split('/')
      setFc(fromCurrency)
      setTc(toCurrency)
    }}>
    <option>EUR/USD</option>
    <option>JPY/USD</option>
    <option>GBP/USD</option>
    <option>AUD/USD</option>
    <option>USD/CHF</option>
    <option>NZD/USD</option>
    <option>USD/CAD</option>
  </select>
)

export default SelectList
```

Back in Landing.js replace `select` with `SelectList` and pass the necessary props.

```diff

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'

import { CURRENCY_PAIR_INFO } from '../graphql/queries/currencyPairInfo'
+import SelectList from '../components/SelectList'

const Landing = () => {
  const [ fc, setFc ] = useState('EUR'),
        [ tc, setTc ] = useState('USD'),
        { data, loading, error, refetch } = useQuery(CURRENCY_PAIR_INFO, {
          variables: { fc, tc }
        })

  if(loading) return <p>Loading...</p>
  if(error) return <button onClick={() => refetch()}>Retry</button>

  return data && (
    <section>
      <h3>Currency Exchange</h3>
      <div>
+       <SelectList fc={fc} tc={tc} setFc={setFc} setTc={setTc} />
        <button onClick={() => refetch()}>refresh</button>
      </div>
      <div className='landing_pair_data'>
        { data.currencyPairInfo && Object.keys(data.currencyPairInfo).map(val => (
          <div key={val} className='data'>
            <p><span>{val}: </span>{ data.currencyPairInfo[val] }</p>
          </div>
        ))}
      </div>
    </section>
  )
}

export default Landing
```

Much better! Now that we're receiving data from the Aplha Vantage API let's get to navigation. Open up `App.js` and make the following adjustments:

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'

const App = () => (
  <main>
    <div className='navbar'><Navbar /></div>
    <Switch>
      <Route exact path='/' component={ Landing } />
    </Switch>
  </main>
)

export default App
```

We import `Switch` from `react-router-dom` and a file named `Navbar` that we're about to create. The `Switch` component renders the first child (`Route` or `Redirect`) that matches a routes `path` and displays it.

Inside of `components` create a new folder and call it `navbar`. Inside create a new file named `Navbar.js` and insert the following:

```jsx
// Navbar.js

import React from 'react'
import { NavLink } from 'react-router-dom'

import './Navbar.css'

const Navbar = () => (
  <div className='navigation'>
    <header><NavLink exact to='/'>Forex</NavLink></header>
    <ul>
      <li><NavLink exact to="/login">Login</NavLink></li>
      <li><NavLink exact to='/register'>Sign Up</NavLink></li>
      <li>Logout</li>
    </ul>
  </div>
)

export default Navbar
```

This article is not about styling. I wanted to be careful not to pollute the codebase with styled components, making it both time consuming and harder for some to reason about the logic. For this reason, I've decided to use only two CSS files: `index.css` and `Navbar.css`. We'll be using very little CSS — just enough for dark mode. 😎

Inside of the `navbar` folder create `Navbar.css` and insert the below code:

```css
/* Navbar.css */

.navbar { margin-bottom: 55px; }

.navigation {
  position: fixed;
  left: 0;
  top: 0;
  background: var(--secondary-color);
  width: 100vw;
  height: 55px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.navigation header a {
  text-decoration: none;
  color: var(--header-text-color);
  margin-left: 10px;
}
.navigation ul {
  display: flex;
  list-style: none;
  margin-right: 15px;
}

.navigation li {
  margin: 0 15px;
  color: var(--header-text-color);
}
.navigation li:hover {
  cursor: pointer;
  color: var(--main-color);
}

.navigation a {
  text-decoration: none;
  color: var(--header-text-color);
}
.navigation a:hover,
.navigation a:active,
.navigation a.active {
  color: var(--main-color);
}
```

Adjust `index.css` to the following:

```css
/* index.css */

/* Global */

* {
  --main-color: rgb(0,0,0);
  --secondary-color: rgb(55,131,194);
  --text-color: rgba(200,200,200, 0.6);
  --header-text-color: rgb(200,200,200);
}

body {
  font-family: Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  margin: 0;
  background: var(--main-color);
  text-align: center;
  box-sizing: border-box;
}

a { text-decoration: none;  color: rgb(0,0,0); }
section { padding-top: 50px; }
span { color: var(--secondary-color); }
p { color: var(--text-color); font-size: 14px; }
p:hover { color: rgba(200,200,200, 0.4); }
h1,h2, h3, h4 { color: var(--header-text-color); }
button, select { cursor: pointer; }


/* Landing && Pair */

.landing_pair_data {
  margin: 20px 0 20px calc(50% - 170px);
  padding: 20px;
  width: 300px;
  border-radius: 20px;
  box-shadow: 1px 1px 1px 1px var(--secondary-color), 
    -1px -1px 1px 1px var(--secondary-color);
}

.data {
  border-bottom: 1px solid var(--secondary-color);
  width: 280px;
  margin-left: calc(50% - 140px);
  text-align: start;
  text-transform: capitalize;
  padding: 2px 2px 2px 0;
}

.modal {
  position: absolute;
  background: rgb(225,225,225);
  color: var(--main-color);
  width: 280px;
  left: calc(50% - 160px);
  top: 25%;
  padding: 20px;
  animation: modal .5s;
}
.modal p {
  color: var(--main-color);
}

@keyframes modal {
  from { opacity: 0; }
  to { opacity: 1; }
}


/* Account  */

.pair_divs {
  padding: 20; 
  border: 1px solid rgba(255,255,255,0.1); 
  border-radius: 5px;
  width: 400px; 
  margin: 10px auto;
}
.pair_divs p {
  text-align: start;
  padding-left: 20px;
}
.pair_divs:hover {
  border: 1px solid rgba(55,131,194, 0.3);
}


/* Chart  */

.chartData {  
  padding-top: 50px;  
  height: calc(100vh - 105px); 
}
.chartData form input,
.chartData form button {
  margin: 10px;
}


/* Login && Register */

.login input,
.register input {
  padding: 5px; 
  margin: 10px 0px; 
  width: 60%;
  max-width: 400px;
  background: var(--main-color);
  color: var(--header-text-color);
  font-size: 13px;
}

.login form,
.register form {
  display: flex; 
  justify-content: center; 
  flex-direction: column; 
  align-items: center;
}
```

These two files represent the entirety of our CSS. Save your files and take a look at the browser.

![navbar](https://github.com/marlonanthony/currency_exchange/blob/master/images/navbar.png?raw=true)

Now that we have our navbar, let's create a register route. Inside of `graphql/mutations` create a new file named `register.js` and insert the below code:

```javascript
// graphql/mutations/register.js

import gql from 'graphql-tag'

export const REGISTERMUTATION = gql`
  mutation RegisterMutation($email: String!, $password: String!, $name: String!) {
    register(email: $email, password: $password, name: $name)  
  }
`
```

Inside `components`, create a new folder and name it `auth`. Inside of `auth` create a new file and name it `Register.js`. Insert the following: 

```jsx
// components/auth/Register.js

import React, { useState } from 'react'
import { useMutation } from '@apollo/react-hooks'

import { REGISTERMUTATION } from '../../graphql/mutations/register'

export default function Register(props) {
  const [ email, setEmail ] = useState(''),
        [ password, setPassword ] = useState(''),
        [ name, setName ] = useState(''),
        [ register, { error } ] = useMutation(REGISTERMUTATION, {
          variables: { email, password, name }
        })

  return (
    <div className='register'>
      <form onSubmit={ async e => {
        e.preventDefault()
        await register()
        props.history.push('/login')
      }}>
        <h2>Sign Up</h2>
        <input
          required
          name='email'
          type='email'
          value={ email }
          onChange={ e => setEmail(e.target.value) }
          placeholder='Enter your email'
        />
        <input
          required
          type='password'
          value={ password }
          onChange={ e => setPassword(e.target.value) }
          placeholder='Enter your password'
        />
        <input
          required
          type='text'
          value={ name }
          onChange={ e => setName(e.target.value) }
          placeholder='Enter your name'
        />
        { error && <p>{ error.message }</p> }
        <button>SignUp</button>
      </form>
    </div>
  )
}
```

We use a `form` to collect the users data and place it in the components state. `onSubmit`, we pass the state as `variables` to the `register` mutation. Since we're setting the emails input `type` to 'email' and passing the `required` prop, we won't see the error we threw on the backend. We're not comparing passwords so there's no error to be thrown there. The only error we created that will make it to us is 'User already exists.' That's why I'm not checking for individual errors and just displaying the error under all of the inputs.

Open up `App.js`. Import `Register.js` and create the Register components `Route`.

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'
import Register from './components/auth/Register'

const App = () => (
  <main>
    <div className='navbar'><Navbar /></div>
    <Switch>
      <Route exact path='/' component={ Landing } />
      <Route path='/register' component={ Register } />
    </Switch>
  </main>
)

export default App
```

If you navigate to our Register component, you'll be able to register a new user. We can confirm this by checking our [database](https://www.mongodb.com/cloud/atlas).

Inside of `graphql/mutations` create a new file, name it `login.js` and insert the following:

```javascript
// graphql/mutations/login.js

import gql from 'graphql-tag'

export const LOGINMUTATION = gql`
  mutation LoginMutation($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      id
      email
      name
    }
  }
`
```

Inside of `graphql/queries` create a new file named `me.js` and add the following code:

```javascript
// graphql/queries/me.js

import gql from 'graphql-tag'

export const MEQUERY = gql`
  query MeQuery {
    me {
      id
      email 
      name
      bankroll
    }
  }
`
```

Head to the `auth` folder, create a new file and name it `Login.js`. Adjust Login.js such that it resembles the below code:

```jsx
// Login.js

import React, { useState } from 'react'
import { useMutation } from '@apollo/react-hooks'

import { MEQUERY } from '../../graphql/queries/me'
import { LOGINMUTATION } from '../../graphql/mutations/login'

export default function Login(props) {
  const [ email, setEmail ] = useState(''),
        [ password, setPassword ] = useState(''),
        [ login, { error } ] = useMutation(LOGINMUTATION, {
          variables: { email, password },
          update: (cache, { data }) => {
            if(!data || !data.login) return 
            cache.reset()
            cache.writeQuery({
              query: MEQUERY,
              data: { me: data.login }
            })
          }
        })

  return (
    <div className='login'>
      <form onSubmit={ async e => {
        e.preventDefault()
        await login()
        props.history.push('/') 
      }}>
        <h2>Login</h2>
        <input
          required
          name='email'
          type='email'
          value={ email }
          onChange={ e => setEmail(e.target.value) }
          placeholder='Enter your email'
        />
        <input
          required
          type='password'
          value={ password }
          onChange={ e => setPassword(e.target.value) }
          placeholder='Enter your password'
        />
        { error && <p>{ error.message }</p> }
        <button type='submit'>Login</button>
      </form>
    </div>
  )
}
```

`onSubmit` we log the user in and redirect them back to the home page. ApolloClient provides us with an `update` function that we can use to update the cache once a user logs in. Once a user logs in successfully we `update` the cache such that the `me` query represents the current user. 

From the docs:

> The update function is called with the Apollo cache as the first argument. The cache has several utility functions such as cache.readQuery and  cache.writeQuery that allow you to read and write queries to the cache with GraphQL as if it were a server. There are other cache methods, such as  cache.readFragment, cache.writeFragment, and  cache.writeData, which you can learn about in our detailed caching guide if you're curious.

> Note: The update function receives cache rather than client as its first parameter. This cache is typically an instance of InMemoryCache, as supplied to the ApolloClient constructor when the client was created. In case of the update function, when you call cache.writeQuery, the update internally calls broadcastQueries, so queries listening to the changes will update. However, this behavior of broadcasting changes after  cache.writeQuery happens only with the update function. Anywhere else, cache.writeQuery would just write to the cache, and the changes would not be immediately broadcast to the view layer. To avoid this confusion, prefer client.writeQuery when writing to cache.

> The second argument to the update function is an object with a data property containing your mutation result. If you specify an optimistic response, your update function will be called twice: once with your optimistic result, and another time with your actual result. You can use your mutation result to update the cache with cache.writeQuery.

If a user enters an invalid email they will see the HTML error, not ours. If a user enters a valid but incorrect email we throw, 'Email or password is incorrect!' If a user enters an incorrect password, we throw the exact same error, making it harder for a bad actor to decipher which input is incorrect. This being the case, we probably don't want to display the error in the place that it occurs, lest we give away the game.

Open up App.js and make the following adjustments:

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'
import Register from './components/auth/Register'
import Login from './components/auth/Login'

const App = () => (
  <Switch>
    <Route path='/login' component={ Login } />
    <Route path='/' render={() => (
      <main>
        <div className='navbar'><Navbar /></div>
        <Route exact path='/' component={ Landing } />
        <Route path='/register' component={ Register } />
      </main>
    )} />
  </Switch>
)

export default App
```

Since we're clearing the cache before a user logs in, and the navbar utilizes the `me` query for authorization, we're going to place the Login component outside of the navbar. 

We can now login a user and we are persisting the users session id in a cookie. If you open up your DevTools, under the Application folder, and inside the Cookies tab, you'll see our cookie.

It'd probably be best if we weren't simultaneously displaying both Login and Logout in our navbar. Adjust Navbar.js like so:

```jsx
// Navbar.js

import React from 'react'
import { NavLink, Redirect } from 'react-router-dom'
import { useQuery } from '@apollo/react-hooks'

import { MEQUERY } from '../../graphql/queries/me'
import './Navbar.css'

const Navbar = () => {
  const { data, loading, error } = useQuery(MEQUERY)

  if(loading) return <p>Loading....</p>
  if(error) return <Redirect to='/login' />
  if(!data) return <p>This is unfortunate</p>

  return (
    <div className='navigation'>
      <header><NavLink exact to='/'>Forex</NavLink></header>
      { !data.me ? (
        <ul>
          <li><NavLink exact to='/login'>Login</NavLink></li>
          <li><NavLink exact to='/register'>SignUp</NavLink></li>
        </ul> ) 
      : (
        <ul>
          <li>Logout</li>
        </ul>
      )}
    </div>
  )
}

export default Navbar
```

In the case of an error in our `me` query, we `Redirect` the user to login. If a user is returned we display Logout, `else` Login/SignUp. At the moment Logout isn't very useful. We'll start with the mutation. Create a new file named `logout.js` inside of `graphql/mutations` and insert the code below.

```javascript
// graphql/mutations/logout.js

import gql from 'graphql-tag'

export const LOGOUT_MUTATION = gql`
  mutation Logout {
    logout
  }
`
```

Create `Logout.js` inside of `components/auth` and insert the following:

```jsx
// components/auth/Logout.js

import React from 'react' 
import { useMutation } from '@apollo/react-hooks'
import { withRouter } from 'react-router-dom'

import { MEQUERY } from '../../graphql/queries/me'
import { LOGOUT_MUTATION } from '../../graphql/mutations/logout'

const Logout = props => {
  const [logout] = useMutation(LOGOUT_MUTATION, {
    update: cache => {
      cache.writeQuery({
        query: MEQUERY,
        data: { me: null }
      })
      props.history.push('/')
    }
  })
  
  return <div onClick={() => logout()}>Logout</div>
}

export default withRouter(Logout)
```

When a user clicks `Logout` three things happen:

* The `logout` mutation destroys the session on the `req` Object.

* We update the cache such that the `me` query returns `null`.

* We redirect the user to the home page.

If a component isn't rendered by React Router (passed as a `component` prop to a `Route`), then we won't have access to `history.push`. React Router's HOC `withRouter` provides us access to the history Object via props. We utilize `props.history.push('/')` to navigate the user back to the home page. Don't forget to wrap the Logout component with `withRouter` when exporting the file.

Import `Logout.js` into `Navbar.js` and replace `<li><Logout></li>` with our new component. With that adjustment thou shalt logout! 

We can now focus on allowing users to open long/short positions. Open up `Landing.js` and make the following adjustments:

```jsx
// Landing.js

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'

import { MEQUERY } from '../graphql/queries/me'
import { CURRENCY_PAIR_INFO } from '../graphql/queries/currencyPairInfo'
import SelectList from '../components/pairs/SelectList'
import OpenLongPosition from '../components/positions/OpenLongPosition'

const Landing = () => {
  const [ fc, setFc ] = useState('EUR'),
        [ tc, setTc ] = useState('USD'),
        [ askPrice, setAskPrice ] = useState(0),
        [ bidPrice, setBidPrice ] = useState(0),
        [ showModal, setShowModal ] = useState(false),
        user = useQuery(MEQUERY),
        { data, loading, error, refetch } = useQuery(CURRENCY_PAIR_INFO, {
          variables: { fc, tc }
        })

  if(loading) return <p>Loading...</p>
  if(error) return <button onClick={() => refetch()}>Retry</button>
  
  return data && (
    <section>
      <h2>Currency Exchange</h2>
      { user.data.me && <p>Available Balance { user.data.me.bankroll.toLocaleString()}.00</p> }
      <div>
        <SelectList fc={fc} tc={tc} setFc={setFc} setTc={setTc} />
        <button onClick={() => refetch()}>Refresh</button>
        { user.data.me && (
          <OpenLongPosition
            fc={fc}
            tc={tc}
            pairData={data}
            askPrice={askPrice}
            setAskPrice={setAskPrice}
            showModal={showModal}
            setShowModal={setShowModal}
        />)}
        <button>Sell</button>
      </div>
      <div className='landing_pair_data'>
        { data.currencyPairInfo && Object.keys(data.currencyPairInfo).map(val => (
          <div key={val} className='data'>
            <p><span>{val}: </span>{ data.currencyPairInfo[val] }</p>
          </div>
        ))}
      </div>
    </section>
  )
}

export default Landing
```

We import `MEQUERY` and a file we'll need to create called `OpenLongPosition`. We integrate `useState` to store/update the `askPrice`, `bidPrice`, and to toggle a modal. After we have our user, we display their bankroll (available funds). If a user alters the currency pair or refreshes the data, we change the state of `askPrice` and `bidPrice` accordingly. Finally, if a user is found we display a 'Buy' button (`OpenLongPosition`).

Inside of `graphql/mutations` create a new file, name it `openPosition.js`, and add the below code:

```javascript
// openPosition.js

import gql from 'graphql-tag'

export const OPENPOSITION = gql`
  mutation OpenPosition(
    $pair: String!, 
    $lotSize: Int!, 
    $openedAt: Float!, 
    $position: String!
  ) {
    openPosition(
      pair: $pair, 
      lotSize: $lotSize, 
      openedAt: $openedAt, 
      position: $position
    ) {
      success
      message
      pair {
        id
        user
        position
        pair
        lotSize
        openedAt
      }
    }
  }
`
```

In `graphql/queries` create a new file named `getPairs.js` and insert the below code:

```javascript
// graphql/queries/getPairs.js

import gql from 'graphql-tag'

export const GETPAIRS = gql`
  query GetPairs {
    getPairs {
      id
      user
      pair
      lotSize
      openedAt
      closedAt
      pipDif
      profitLoss
      open
      position
      createdAt
      updatedAt
    }
  }
`
```

In `components` create a new folder and name it `positions`. Inside create a new file named `OpenLongPosition.js` and add the following code:

```jsx
// OpenLongPosition.js

import React from 'react'
import { Link } from 'react-router-dom'
import { useMutation } from '@apollo/react-hooks'

import { OPENPOSITION } from '../../graphql/mutations/openPosition'
import { MEQUERY } from '../../graphql/queries/me'
import { GETPAIRS } from '../../graphql/queries/getPairs'

const OpenLongPosition = ({
  fc, 
  tc, 
  pairData,
  askPrice,
  setAskPrice,
  showModal,
  setShowModal
}) => {

  const [ openPosition, { data, loading, error }] = useMutation(OPENPOSITION, {
    variables: {
      pair: `${fc}/${tc}`,
      lotSize: 100000,
      openedAt: askPrice,
      position: 'long'
    },
    update: cache => {
      const user = cache.readQuery({ query: MEQUERY })
      user.me.bankroll -= 100000
      cache.writeQuery({
        query: MEQUERY,
        data: { me: user.me }
      })
    },
    refetchQueries: [{ query: GETPAIRS }]
  })

  if(loading) return <p>Loading...</p>
  if(error) return <p>{ error.message }</p>

  return openPosition && (
    <>
      <button onClick={ async () => {
        await setAskPrice(+pairData.currencyPairInfo.askPrice)
        alert('Are you sure you want to buy?')
        await openPosition()
        setShowModal(true)
      }}>
        Buy
      </button>
      { data && data.openPosition.message && showModal && (
        <div className='modal'>
          <button onClick={() => setShowModal(false)}>x</button>
          <p>{ data.openPosition.message }</p>
          <p>Currency Pair: { data.openPosition.pair.pair }</p>
          <p>Lot Size: { data.openPosition.pair.lotSize.toLocaleString() }.00</p>
          <p>Opened At: { data.openPosition.pair.openedAt }</p>
          <p>Position: { data.openPosition.pair.position }</p>
          <Link to={{ pathname: '/account', state: { data } }}>
            <button>Details</button>
          </Link>
        </div>
      )}
    </>
  )
}

export default OpenLongPosition
```

We pass our mutation the required variables. Once the user clicks the 'Buy' button we'd usually want to display some data and allow them to confirm the purchase. Here we're just using an `alert`. The user is then displayed a modal describing their transaction and a `details` button that will redirect them to a page we still need to create — `Account`. Open up MongoDB Atlas and you'll see the newly created position.

Apollo provides us a number of ways to update the cache after a mutation. We've implemented a few of them in this project. In this component we're utilizing `refetchQueries` to update our pairs. Let's take a look at the docs:

> refetchQueries is the simplest way of updating the cache. With  refetchQueries you can specify one or more queries that you want to run after a mutation is completed in order to refetch the parts of the store that may have been affected by the mutation.

We've seen a few of the options that the Mutation hook accepts. Take a peek at the [docs](https://www.apollographql.com/docs/react/essentials/mutations/) for the full list.

Before we get to creating the `Account` component, let's allow a user to open a `short` position. Open up `components/positions`, create a new file named `OpenShortPosition.js` and add the below code:

```jsx
// components/positions/OpenShortPosition.js

import React from 'react'
import { Link } from 'react-router-dom'
import { useMutation } from '@apollo/react-hooks'

import { OPENPOSITION } from '../../graphql/mutations/openPosition'
import { MEQUERY } from '../../graphql/queries/me'
import { GETPAIRS } from '../../graphql/queries/getPairs'

const OpenShortPosition = ({
  fc,
  tc,
  pairData,
  bidPrice,
  setBidPrice,
  showModal,
  setShowModal
}) => {
  const [ openPosition, { data, loading, error }] = useMutation(OPENPOSITION, {
    variables: {
      pair: `${fc}/${tc}`, 
      lotSize: 100000, 
      openedAt: bidPrice, 
      position: 'short' 
    },
    update: cache => {
      const user = cache.readQuery({ query: MEQUERY })
      user.me.bankroll -= 100000
      cache.writeQuery({
        query: MEQUERY,
        data: { me: user.me }
      })
    },
    refetchQueries: [{ query: GETPAIRS }]
  })

  if(loading) return <p>Loading...</p>
  if(error) return <p>{ error.message }</p>
  
  return openPosition && (
    <>
      <button onClick={ async () => {
        await setBidPrice(+pairData.currencyPairInfo.bidPrice)
        alert('Are you sure you want to sell short?')
        await openPosition()
        setShowModal(true) 
      }}>
        Sell
      </button> 
      { data && data.openPosition.message && showModal && ( 
        <div className='modal'>
          <button onClick={() => setShowModal(false)}>x</button>
          <p>{ data && data.openPosition.message }</p>
          <p>Currency Pair: { data.openPosition.pair.pair }</p>
          <p>Lot Size: { data.openPosition.pair.lotSize.toLocaleString() }.00</p>
          <p>Opened At: { data.openPosition.pair.openedAt }</p>
          <p>Position: { data.openPosition.pair.position }</p>
          <Link to={{ pathname: '/account', state: { data } }}>
            <button>Details</button>
          </Link>
        </div>
      )}
    </>
  )
}

export default OpenShortPosition
```

Here we do the exact same thing we did in `OpenLongPosition` except we pass `bidPrice` instead of `askPrice` and `position: short` instead of `position: long` as arguments.

Back in Landing.js replace the 'Sell' button with our newly created `OpenShortPosition` component.

```jsx
// Landing.js

import OpenShortPosition from '../components/positions/OpenShortPosition'

{ user.data.me && (
  <OpenShortPosition
    fc={fc}
    tc={tc}
    pairData={data}
    bidPrice={bidPrice}
    setBidPrice={setBidPrice}
    showModal={showModal}
    setShowModal={setShowModal}
/>)}
```

With that our users are able to sell short. We still need to create our `Account` component. Let's get to it! In the `pages` folder create `Account.js` and add the below code:

```jsx
// Account.js

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'
import { Link, Redirect } from 'react-router-dom'

import { GETPAIRS } from '../graphql/queries/getPairs'
import { MEQUERY } from '../graphql/queries/me'

const Account = props => {
  const [ open, setOpen ] = useState(true),
        user = useQuery(MEQUERY),
        { data, loading, error } = useQuery(GETPAIRS)

  if(user.error) return <Redirect to='/login' />
  if(!user.data || !user.data.me) return <p>A man has no name.</p>
  if(loading) return <p>Loading...</p>
  if(!data) return <p>Nothing to show!</p>
  if(error) return <p>{ error.message }</p>

  return (
    <section>
      <h2>{ user.me.name }</h2>
      <div>
        <p><span>Available Balance: </span>{ user.me.bankroll.toLocaleString() }.00</p> 
      </div>
      <br />
      { props.location.state &&  (
        <div>
          <h3>New Position</h3>
          <div className='pair_divs'>
            <p><span>Pair: </span>{ props.location.state.data.openPosition.pair.pair }</p>
            <p><span>Lot Size: </span>{ props.location.state.data.openPosition.pair.lotSize.toLocaleString() }.00</p>
            <p><span>Pip Dif: </span>{ props.location.state.data.openPosition.pair.openedAt }</p>
            <p><span>Position: </span>{ props.location.state.data.openPosition.pair.position }</p>
          </div>
        </div>
      )}
      <br />
      <h3>Currency Pairs</h3>
      <button onClick={() => setOpen(true)}>open</button>
      <button onClick={() => setOpen(false)}>closed</button>
      <div>
      { data.getPairs && data.getPairs.map(pair => pair.open && open && (
        <div className='pair_divs' key={pair.id}>
          <Link to={{ pathname: '/pair', state: { pair, me: user.me } }}>
            { pair.pair && <p><span>Currency Pair: </span>{ pair.pair }</p> }
            { pair.lotSize && <p><span>Lot Size: </span>{ pair.lotSize.toLocaleString() }.00</p> }
            { pair.position && <p><span>Position: </span>{ pair.position }</p> }
            { pair.openedAt && <p><span>Opened At: </span>{ pair.openedAt.toFixed(4) }</p> }
            { pair.createdAt && <p><span>Created At: </span>{ new Date(+pair.createdAt).toLocaleString() }</p> }
            { pair.updatedAt && <p><span>Updated At: </span>{ new Date(+pair.updatedAt).toLocaleString() }</p> }
          </Link>
        </div>
      ))}
      { data.getPairs && data.getPairs.map(pair => !pair.open && !open && (
        <div className='pair_divs' key={ pair.id }>
          <div>
            { pair.pair && <p><span>Currency Pair: </span>{ pair.pair }</p> }
            { pair.lotSize && <p><span>Lot Size: </span>{ pair.lotSize.toLocaleString() }.00</p> }
            { pair.position && <p><span>Position: </span>{ pair.position }</p> }
            { pair.openedAt && <p><span>Opened At: </span>{ pair.openedAt.toFixed(4) }</p> }
            { pair.closedAt && <p><span>Closed At: </span>{ pair.closedAt.toFixed(4) }</p> }
            { <p><span>Pip Dif: </span>{ pair.pipDif || 0 }</p> }
            { <p><span>Profit/Loss: </span>{ pair.profitLoss.toFixed(2) || 0 }</p> }
            { pair.createdAt && <p><span>Created At: </span>{ new Date(+pair.createdAt).toLocaleString() }</p> }
            { pair.updatedAt && <p><span>Updated At: </span>{ new Date(+pair.updatedAt).toLocaleString() }</p> }
          </div>
        </div>
      ))}
      </div>
    </section>
  )
}

export default Account
```

React Router's `Link` component allows us to pass state when navigating a user to another view. This is convienient if we wanted to render unique views when coming from certain routes. We use this to display the new position that the user just opened — if any. You could get creative here but we'll keep it simple and just display some data about the new position.

Under the new position (if there is one), we display all of the users positions. Open positions are shown by default, but we provide a button to toggle between open and closed. If the position is open, the user can click on the currency pair. This will navigate them to `/pair` (which we need to create) and provide further options. This component is a bit verbose. We'll refactor in a moment.

Let's import `Account.js` into App.js and create its `Route`.

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'
import Register from './components/auth/Register'
import Login from './components/auth/Login'
import Account from './pages/Account'

const App = () => (
  <Switch>
    <Route path='/login' component={ Login } />
    <Route path='/' render={() => (
      <main>
        <div className='navbar'><Navbar /></div>
        <Route exact path='/' component={ Landing } />
        <Route path='/register' component={ Register } />
        <Route path='/account' component={ Account } />
      </main>
    )} />
  </Switch>
)

export default App
```

We'll also want `Account` to be accessible from the Navbar when a user is logged in. 

```jsx
// Navbar.js

return (
  <ul>
    <li><NavLink to='/account'>Account</NavLink></li>
    <li><Logout /></li>
  </ul>
)
```

When navigating to `/account` from the navbar you'll notice 'New Position' isn't being displayed. Cool! Now let's refactor `Account.js` and add some functionality. Inside of `components/pairs` create a new file named `NewPosition.js`. Cut the following code from `Account.js` and insert it into your newly created file.

```jsx
// components/pairs/NewPosition.js

import React from 'react'

export default function NewPosition({ state }) {
  return (
    <div>
      <h3>New Position</h3>
      <div className='pair_divs' style={{ textAlign: 'center' }}>
        <p><span>Pair: </span>{ state.data.openPosition.pair.pair }</p>
        <p><span>Lot Size: </span>{ state.data.openPosition.pair.lotSize.toLocaleString() }.00</p>
        <p><span>Pip Dif: </span>{ state.data.openPosition.pair.openedAt }</p>
        <p><span>Position: </span>{ state.data.openPosition.pair.position }</p>
      </div>
    </div>
  )
}
```

In the same folder create a new file and name it `Pairs.js`. Cut the following code from `Account.js` and add it to this file.

```jsx
// components/pairs/Pairs.js

import React from 'react'
import { Link } from 'react-router-dom'

const Pairs = ({ data, open, user }) => (
  <div>
    { data.getPairs && data.getPairs.map(pair => pair.open && open && (
      <div className='pair_divs' key={ pair.id }>
        <Link to={{ pathname: '/pair', state: { pair, me: user.data.me } }}>
          { pair.pair && <p><span>Currency Pair: </span>{ pair.pair }</p> }
          { pair.lotSize && <p><span>Lot Size: </span>{ pair.lotSize.toLocaleString() }.00</p> }
          { pair.position && <p><span>Position: </span>{ pair.position }</p> }
          { pair.openedAt && <p><span>Opened At: </span>{ pair.openedAt.toFixed(4) }</p> }
          { pair.createdAt && <p><span>Created At: </span>{ new Date(+pair.createdAt).toLocaleString() }</p> }
          { pair.updatedAt && <p><span>Updated At: </span>{ new Date(+pair.updatedAt).toLocaleString() }</p> }
        </Link>
      </div>
    ))}
    { data.getPairs && data.getPairs.map(pair => !pair.open && !open && (
      <div className='pair_divs' key={ pair.id }>
        <div>
          { pair.pair && <p><span>Currency Pair: </span>{ pair.pair }</p> }
          { pair.lotSize && <p><span>Lot Size: </span>{ pair.lotSize.toLocaleString() }.00</p> }
          { pair.position && <p><span>Position: </span>{ pair.position }</p> }
          { pair.openedAt && <p><span>Opened At: </span>{ pair.openedAt.toFixed(4) }</p> }
          { pair.closedAt && <p><span>Closed At: </span>{ pair.closedAt.toFixed(4) }</p> }
          { <p><span>Pip Dif: </span>{ pair.pipDif || 0 }</p> }
          { <p><span>Profit/Loss: </span>{ pair.profitLoss.toFixed(2) || 0 }</p> }
          { pair.createdAt && <p><span>Created At: </span>{ new Date(+pair.createdAt).toLocaleString() }</p> }
          { pair.updatedAt && <p><span>Updated At: </span>{ new Date(+pair.updatedAt).toLocaleString() }</p> }
        </div>
      </div>
    ))}
  </div>
)

export default Pairs
```

Okay. We should implement an `addFunds` button while we're working on `Account.js`. Create a new file named `addFunds.js` inside of `graphql/mutations` and insert the following:

```javascript
// graphql/mutations/addFunds.js

import gql from 'graphql-tag'

export const ADDFUNDS = gql`
  mutation ($amount: Int!) {
    addFunds(amount: $amount) {
      success
      message
      bankroll
    }
  }
`
```

In the `components/pairs` folder create a new file named `AddFunds.js` and add the below code:

```jsx
// components/pairs/AddFunds.js

import React, { useState } from 'react'
import { useMutation } from '@apollo/react-hooks'

import { ADDFUNDS } from '../../graphql/mutations/addFunds'

export default function AddFunds() {
  const [ showModal, setShowModal ] = useState(false),
        [ addFunds, { data, loading, error } ] = useMutation(ADDFUNDS, {
          variables: { amount: 1000000 }
        })

  if(loading) return <p>Loading...</p>
  if(error) return <p>{ error.message }</p>

  return addFunds && (
    <>
      <button onClick={ async () => {
        alert('Are you sure?')
        await addFunds()
        setShowModal(true)
      }}>Add Funds</button>
      { data && data.addFunds.message && showModal && (
        <div className='modal'>
          <button onClick={() => setShowModal(false)}>x</button>
          <p>{ data.addFunds.message }</p>
        </div>
      )}
    </>
  )
}
```

Usually the user would have some say over how much they deposit. That said, who's making a fuss when we're just out here handing out milli's? 

It's high time we got back to `Account.js`.

```jsx
// Account.js

import React, { useState } from 'react'
import { useQuery } from '@apollo/react-hooks'
import { Redirect } from 'react-router-dom'

import { GETPAIRS } from '../graphql/queries/getPairs'
import { MEQUERY } from '../graphql/queries/me'
import AddFunds from '../components/pairs/AddFunds'
import Pairs from '../components/pairs/Pairs'
import NewPosition from '../components/pairs/NewPosition'

export default function Account(props) {
  const [ open, setOpen ] = useState(true),
        user = useQuery(MEQUERY),
        { data, loading, error } = useQuery(GETPAIRS)

  if(user.error) return <Redirect to='/login' />
  if(!user.data || !user.data.me) return <p>A man has no name.</p>
  if(loading) return <p>Loading...</p>
  if(!data) return (
    <section>
      <h2>{ user.data.me.name }</h2>
      <div>
        <p><span>Available Balance: </span>{ user.data.me.bankroll.toLocaleString() }.00</p>
        <AddFunds />
      </div>
    </section>
  )
  if(error) return <p>{ error.message }</p>
  
  return (
    <section>
      <h2>{ user.data.me.name }</h2>
      <div>
        <p><span>Available Balance: </span>{ user.data.me.bankroll.toLocaleString() }.00</p>
        <AddFunds />
      </div>
      { props.location.state && <NewPosition state={ props.location.state } /> }
      <h3>Currency Pairs</h3>
      <button onClick={() => setOpen(true)}>open</button>
      <button onClick={() => setOpen(false)}>closed</button>
      <Pairs data={ data } open={ open } user={ user } />
    </section>
  )
}
```

First, we handle our imports. Next, we implement `useQuery` to find out about the user. If there's no `getPair` data we just display information about the user and the `AddFunds` button `else` we display all the data.

Our users can now open positions and add money to their account. Let's allow them to close positions. Once again this starts with a mutation. In `graphql/mutations` create `closePosition.js` and add the following:

```javascript
// graphql/mutations/closePosition.js

import gql from 'graphql-tag'

export const CLOSEPOSITION = gql`
  mutation ClosePosition($id: ID!, $closedAt: Float!) {
    closePosition(id: $id, closedAt: $closedAt) {
      success
      message
      pair {
        id
        user
        pair
        lotSize
        position
        openedAt
        closedAt
        pipDif
        profitLoss
        open
        createdAt
        updatedAt
      }
    }
  }
`
```

When a user clicks on an open position, they get navigated to `/pair`. This is where they'll be able to close their positions. In the `pages` folder, create `Pair.js` and adjust it such that it resembles the below code:

```jsx
// Pair.js

import React from 'react'
import { useQuery } from '@apollo/react-hooks'

import { CURRENCY_PAIR_INFO } from '../graphql/queries/currencyPairInfo'
import ClosePosition from '../components/positions/ClosePosition'
import PairDetails from '../components/pairs/PairDetails'

export default function Pair(props) {
  const { createdAt, lotSize, openedAt, pair, position, id } = props.location.state.pair,
        { bankroll, name } = props.location.state.me,
        [ fc, tc ] = pair.split('/'),
        { data, loading, error, refetch } = useQuery(CURRENCY_PAIR_INFO, {
          variables: { fc, tc }
        })

  if(loading) return <p>Loading...</p>
  if(error) return <p>{ error.message }</p>
  
  const { bidPrice, lastRefreshed, askPrice } = data.currencyPairInfo,
        pipDifLong = (bidPrice - openedAt).toFixed(4),
        pipDifShort = (openedAt - askPrice).toFixed(4),
        potentialProfitLoss = position === 'long'
          ? pipDifLong * lotSize
          : pipDifShort * lotSize,
        date = new Date(lastRefreshed + ' UTC')
  
  return data && (
    <section>
      <div className='landing_pair_data'>
        <h3>Pair Details</h3>
        <div>
          <p>{ name } your available balance is { bankroll.toLocaleString() }.00</p> 
          <div>
            <button onClick={() => refetch()}>Refresh</button>
            <ClosePosition 
              id={id} 
              bidPrice={bidPrice} 
              askPrice={askPrice} 
              position={position} 
            />
          </div>
        </div>
        <PairDetails
          pair={pair} 
          lotSize={lotSize}
          openedAt={openedAt}
          position={position}
          createdAt={createdAt}
          askPrice={askPrice}
          bidPrice={bidPrice}
          lastRefreshed={date.toLocaleString()}
          pipDifLong={pipDifLong}
          pipDifShort={pipDifShort}
          potentialProfitLoss={potentialProfitLoss}
        />
      </div>
    </section>
  )
}
```

Once we have our state we pass in the query variables to `currencyPairInfo`. The response provides the data required to complete our `closePosition` mutation. Depending on whether the `position` is long or short, we use either the `askPrice` or `bidPrice` to calculate the difference in price since the initial purchase. This difference in price is what we're calling the pip difference (pipDif). 

As described by [dailyfx.com](https://www.dailyfx.com/forex/education/trading_tips/daily_trading_lesson/2019/01/18/what-is-a-pip.html):

> PIP - which stands for Point in Percentage - is the unit of measure used by forex traders to define the smallest change in value between two currencies. This is usually represented by a single digit move in the fourth decimal place. The pip value is calculated by multiplying one pip(0.0001) by the specific lot/contract size. For standard lots this entails 100,000 units of the base currency and for mini lots, this is 10,000 units. For example, looking at EUR/USD, a one pip movement in a standard contract is equal to $10(0.0001 x 100,000).

Each currency pair has its own relative relationship, so we calculate profit/loss by simply comparing the `openedAt` price to the `closedAt` price. We calculate the `pipDif` by first figuring out if the `position` is long or short. If the position is long we subtract the `openedAt` price from the `bidPrice`. Conversely, if the position is short, we subtract the `askPrice` from the `openedAt` price. This will provide our `pipDif`. Once we have the difference in price, we multiply it by the `lotSize`.

You can see how easily this is calculated once demonstrated visually. For a standard lot (100,000 units) each pip (usually fourth decimal place) movement equates to 10 currency units of profilt/loss.

![pipdif](https://github.com/marlonanthony/currency_exchange/blob/master/images/pipdif.png?raw=true)

For a mini lot (10,000 units) we do the same but every pip movement equates to 1 currency unit profit/loss.

![pipdif minilot](https://github.com/marlonanthony/currency_exchange/blob/master/images/pipdif2.png?raw=true)

It's important to understand that we're not converting one currency to another. We're just betting on which currency will be worth more relative to the other. For clarity, if you wanted to buy (or long) EUR against USD, you'd sell EUR/USD or buy USD/EUR. Conversely, to long USD against the EUR, you'd buy EUR/USD or sell USD/EUR. Rollover (interest) and margin are outside the scope of this tutorial so we'll focus exclusively on the pipDif.

We need to create `ClosePosition` and `PairDetails`. Inside of `components/positions`, create `ClosePosition.js` and add the following:

```jsx
// components/positions/ClosePosition.js

import React, { useState } from 'react'
import { useQuery, useMutation } from '@apollo/react-hooks'
import { Link } from 'react-router-dom'

import { CLOSEPOSITION } from '../../graphql/mutations/closePosition'
import { MEQUERY } from '../../graphql/queries/me'
import { GETPAIRS } from '../../graphql/queries/getPairs'

export default function ClosePosition({ id, bidPrice, askPrice, position }) {
  const [ showModal, setShowModal ] = useState(false),
        { refetch  } = useQuery(MEQUERY),
        [ closePosition, { data, loading, error } ] = useMutation(CLOSEPOSITION, {
          variables: position === 'long'
            ? { id, closedAt: +bidPrice } 
            : { id, closedAt: +askPrice },
          refetchQueries: [{ query: GETPAIRS }]
        })

  if(loading) return <p>Loading...</p>
  if(error) return <p>{ error.message }</p>

  return closePosition && (
    <>
      <button onClick={ async () => {
        alert(`Are you sure you want to close your ${
          position === 'long' ? 'long' : 'short' } position?`) 
        await closePosition()
        setShowModal(true)
        refetch()
      }}>
        { position === 'long' ? 'Sell' : 'Buy' }
      </button> 
      
      { data && data.closePosition.message && showModal && ( 
        <div className='modal'>
          <button onClick={() => setShowModal(false)}>x</button>
          <p>{ data.closePosition.message }</p>
          <Link to='/account'><button>Account</button></Link>
        </div>
      )}
    </>
  )
}
```

All this file is doing is deciphering whether the `position` is long or short and providing the `closePosition` mutation the appropriate variables (pair `id` and `bidPrice/askPrice`). The `closePosition` response message will be displayed via a modal.

We're using the `useQuery` hook to gain access to the `me` queries `refetch` function. We add the `refetch` method to our button such that after the `closePosition` mutation runs, `refetch` will refresh the users data. If we didn't use `refetchQueries` here, after our mutation runs the `open` pairs would be up-to-date, but the `closed` pairs wouldn't be.

In the components folder create `PairDetails.js` and add the code below:

```jsx
// components/PairDetails.js

import React from 'react'

const PairDetails = ({
  pair,
  lotSize,
  openedAt,
  position,
  createdAt,
  askPrice,
  bidPrice,
  lastRefreshed,
  pipDifLong,
  pipDifShort,
  potentialProfitLoss
}) => (
  <div>
    <p><span>Currency Pair: </span>{pair}</p>
    <p><span>Lot Size: </span>{lotSize.toLocaleString()}.00</p>
    <p><span>Opened At: </span>{(+openedAt).toFixed(4)}</p>
    <p><span>Position: </span>{position}</p>
    <p><span>Created At: </span>{new Date(+createdAt).toLocaleString()}</p>
    { position === 'long' 
      ? (
        <>
          <br />
          <p><span>Current Bid Price: </span>{(+bidPrice).toFixed(4)}</p>
          <p><span>Last Refreshed: </span>{lastRefreshed}</p>
          <p><span>Current Pip Difference: </span>{pipDifLong}</p>
          <p><span>Potential PL: </span>
            {potentialProfitLoss.toLocaleString()}.00
          </p>
        </> ) 
      : (
        <>
          <br />
          <p><span>Current Ask Price: </span>{(+askPrice).toFixed(4)}</p>
          <p><span>Last Refreshed: </span>{lastRefreshed}</p>
          <p><span>Current Pip Difference: </span>{pipDifShort}</p>
          <p><span>Potential PL: </span>
            {potentialProfitLoss.toLocaleString()}.00
          </p>
        </>
      )
    }
  </div>
)

export default PairDetails
```

We display the open positions data. We also display the current `askPrice`/`bidPrice` and the `potentialProfitLoss` that closing the position would provide.

Import Pair.js into App.js and create its `Route`.

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'
import Register from './components/auth/Register'
import Login from './components/auth/Login'
import Account from './pages/Account'
import Pair from './pages/Pair'

const App = () => (
  <Switch>
    <Route path='/login' component={ Login } />
    <Route path='/' render={() => (
      <main>
        <div className='navbar'><Navbar /></div>
        <Route exact path='/' component={ Landing } />
        <Route path='/register' component={ Register } />
        <Route path='/account' component={ Account } />
        <Route path='/pair' component={ Pair } />
      </main>
    )} />
  </Switch>
)

export default App
```

If you navigate to /account as a result of opening a new position, you should see the following:

![account](https://github.com/marlonanthony/currency_exchange/blob/master/images/account.png?raw=true)

Click on an open pair and take a good gander at the browser.

![pair details](https://github.com/marlonanthony/currency_exchange/blob/master/images/pair_details.png?raw=true)

And with that a user can close positions. Best we don't just rest on our laurels. Time to implement our chart! We'll start with the query. In `graphql/queries` create a new file and name it `monthlyTimeSeries.js`. Insert the following:

```javascript
// graphql/queries/monthlyTimeSeries.js

import gql from 'graphql-tag' 

export const MONTHLYTIMESERIES = gql`
  query MonthlyTimeSeries($fc: String, $tc: String) {
    monthlyTimeSeries(fc: $fc, tc: $tc) {
      timesArray
      valuesArray
    }
  }
`
```

In the `pages` folder create a new file named `Chart.js` and add the below code:

```jsx
// Chart.js

import React, { useState } from 'react'
import { Line } from 'react-chartjs-2'
import { useQuery } from '@apollo/react-hooks'

import { MONTHLYTIMESERIES } from '../graphql/queries/monthlyTimeSeries'

export default function Chart() {
  const [ fc, setFc ] = useState('EUR'),
        [ tc, setTc ] = useState('USD'), 
        [ fromCurrency, setFromCurrency ] = useState('EUR'), 
        [ toCurrency, setToCurrency ] = useState('USD'),
        { data, error, loading, refetch } = useQuery(MONTHLYTIMESERIES, {
          variables: { fc, tc }
        })

  if(loading) return <p>loading...</p>
  if(error) return <button onClick={() => {
    refetch({ fc: 'EUR', tc: 'USD' })
    window.location.href = '/chart'
  }}>retry</button>
  
  const labels = data && data.monthlyTimeSeries.timesArray,
        chartData = data && data.monthlyTimeSeries.valuesArray
  
  return (
    <div className='chartData'>
      <form onSubmit={e => {
        e.preventDefault()
        setFc(fromCurrency)
        setTc(toCurrency) 
      }}>
        <input 
          name='fromCurrency'
          value={fromCurrency}
          placeholder='From Currency'
          onChange={e => setFromCurrency(e.target.value.toUpperCase())}
        />
        <input 
          name='toCurrency'
          value={toCurrency}
          placeholder='To Currency'
          onChange={e => setToCurrency(e.target.value.toUpperCase())}
        />
        <button>submit</button>
      </form>
      <Line data={{
        labels,
        datasets: [
          {
            label: `${fc}/${tc} Time Series FX (Monthly)`,
            fill: true,
            lineTension: 0.1,
            backgroundColor: 'rgb(55, 131, 194)',
            borderColor: 'white',
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: 'white',
            pointBackgroundColor: '#fff',
            pointBorderWidth: 1,
            pointHoverRadius: 5,
            pointHoverBackgroundColor: 'white',
            pointHoverBorderColor: 'rgba(220,220,220,1)',
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            pointHitRadius: 10,
            data: chartData
          }
        ]
      }} />
    </div>
  )
}
```

We use our `monthlyTimeSeries` query to fetch our chart data. We provide a couple inputs so that the user can choose which currency pair they'd like to investigate. If the user enters an incorrect pair we present them with a refresh button. The `refetch` function accepts arguments to its associated `query`. `onClick` we use this function to display EUR/USD again. We feed the `Line` component that we get curtesy of `react-chartjs-2` the two arrays from our query: `labels` and `chartData`. Finally, we add some styling and return our chart.

We'll need to import `Chart.js` into `App.js` and give it a `path` in `Navbar.js`. Let's start with `App.js`:

```jsx
// App.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'

import Landing from './pages/Landing'
import Navbar from './components/navbar/Navbar'
import Register from './components/auth/Register'
import Login from './components/auth/Login'
import Account from './pages/Account'
import Pair from './pages/Pair'
import Chart from './pages/Chart'

const App = () => (
  <Switch>
    <Route path='/login' component={ Login } />
    <Route path='/' render={() => (
      <main>
        <div className='navbar'><Navbar /></div>
        <Route exact path='/' component={ Landing } />
        <Route path='/register' component={ Register } />
        <Route path='/account' component={ Account } />
        <Route path='/pair' component={ Pair } />
        <Route path='/chart' component={ Chart } />
      </main>
    )} />
  </Switch>
)

export default App
```

Navbar.js:

```jsx
// Navbar.js

import React from 'react'
import { NavLink, Redirect } from 'react-router-dom'
import { useQuery } from '@apollo/react-hooks'

import { MEQUERY } from '../../graphql/queries/me'
import Logout from '../auth/Logout'
import './Navbar.css'

const Navbar = () => {
  const { data, loading, error } = useQuery(MEQUERY)
  
  if(loading) return <p>Loading....</p>
  if(error) return <Redirect to='/login' />
  if(!data) return <p>This is unfortunate</p>

  return (
    <div className='navigation'>
      <header><NavLink exact to='/'>Forex</NavLink></header>
      { !data.me ? (
        <ul>
          <li><NavLink exact to='/login'>Login</NavLink></li>
          <li><NavLink exact to='/register'>SignUp</NavLink></li>
        </ul> ) 
      : (
        <ul>
          <li><NavLink to='/chart'>Chart</NavLink></li>
          <li><NavLink to='/account'>Account</NavLink></li>
          <li><Logout /></li>
        </ul>
      )}
    </div>
  )
}

export default Navbar
```

Once you save your files our app will be complete and should resemble the video below:

[![forex demo](https://img.youtube.com/vi/mbx9sLVk5UQ/0.jpg)](https://youtu.be/mbx9sLVk5UQ)

You'll notice that the chart is fully responsive and not so bad on the old spectacles. 

BEHOLD! We've created a currency exchange and hopefully learned a little something along the way. I know I did. 

___

Reach out: [Twitter](https://twitter.com/marlonanthony10) | [Medium](https://medium.com/@marlonanthony) | [GitHub](https://github.com/marlonanthony)