# 5. Component Pages

### Create Signup Page

In the same way with the Login page, we can create a page for the registration.

For the registration, we need to collect the username and the email, and redirect to the Hatters to complete the registration.

Lets create the **SignupPage.js** in the **Signup** feature folder:

```javascript
// src/features/Signup/SignupPage.js
import React, { useState } from 'react';
import { appConfig } from '../../app.config';
import { isEmail, isHatName } from '../../utils/validations';

function SignupPage() {
    const initUser = {
        username: '',
        email: '',
    };

    const [user, setUser] = useState(initUser);
    const [errorMsg, setErrorMsg] = useState('');

    const errorMessages = {
        usernameNotValid: 'Sorry, this username is not valid',
        emailNotRecognised: 'Sorry, email is not valid',
    };

    const navigateToHatters = () => {
        const redirectUrl = `http://${window.location.host}/authentication`;
        const applicationId = appConfig.applicationId;

        window.location.href = `https://hatters.dataswift.io/services/baas/signup?email=${user.email}&hat_name=${user.username}&application_id=${applicationId}&redirect_uri=${redirectUrl}&lang=en`;
    };

    const handleChange = event => {
        const name = event.target.name;
        const value = event.target.value;

        setUser({ ...user, [name]: value });
        setErrorMsg('');
    };

    const handleSubmit = event => {
        event.preventDefault();
        validateSignupDetails();
    };

    const validateSignupDetails = () => {
        let errorMsg = '';

        if (!isHatName(user.username)) {
            errorMsg = errorMessages.usernameNotValid;
        } else if (!isEmail(user.email)) {
            errorMsg = errorMessages.emailNotRecognised;
        } else {
            navigateToHatters();
        }

        if (errorMsg) {
            setErrorMsg(errorMsg);
        }
    };

    return (
        <form onSubmit={e => handleSubmit(e)} className={'flex-column-wrapper flex-content-center flex-align-items-center'}>
            <div className={'flex-spacer-small'} />

            <h3>Create Account</h3>
            <div className={'flex-spacer-small'} />

            <input
                className={` ${errorMsg ? 'input-error-field' : null}`}
                name={'username'}
                type={'text'}
                placeholder="Username"
                autoComplete={'username'}
                value={user.username}
                onChange={e => handleChange(e)}
            />
            <input
                className={` ${errorMsg ? 'input-error-field' : null}`}
                name={'email'}
                type={'text'}
                placeholder="Email"
                autoComplete={'email'}
                value={user.email}
                onChange={e => handleChange(e)}
            />
            {errorMsg && <div className={'input-error-label'}>{errorMsg}</div>}

            <div className={'flex-spacer-large'} />

            <button className={'btn btn-accent'} type={'submit'}>
                Next
            </button>

            <div className={'flex-spacer-small'} />
        </form>
    );
}

export default SignupPage;
```

In the **validations.js** file, include a function to check if the email is valid:

```javascript
// src/utils/validations.js
const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

export const isEmail = email => {
  return EMAIL_REGEX.test(email);
};
```

Include the "/signup" route in the **Routing.js**:

```javascript
// src/app/Routing.js
function Routing() {
    return (
        <Router>
            <Header />
            <Switch>
                <Route exact path="/" component={HomePage} />
                <Route path="/login" component={LoginPage} />
                <Route path="/signup" component={SignupPage} />
                <Route path="/authentication" component={AuthenticationHandler} />
            </Switch>
        </Router>
    );
}

export default Routing;
```

### Create a private Route for the authenticated username

In this case, we need to create a "global" state to keep information for the current authenticated user. With the [Context](https://reactjs.org/docs/context.html) we can create a simple state share across all the components.

We'll need to keep information such as a flag to check if the user is authenticated, the [JWT](https://jwt.io) token, and the username.

```javascript
state = {
    user: {
      isAuthenticated: false,
      token: '',
      hatName: '',
    },
  }
```

Firstly, we have to create the Context object. Create the **AuthContext.js** file in the **context** folder under the **components/** folder:

```
// src/components/context/AuthContext.js
import React from 'react';

const AuthContext = React.createContext();

export default AuthContext;
```

Secondly, create the Context Provider with state and helper function to log in/out. Create the **AuthProvider.js**:

```
// src/components/context/AuthProvider.js
import React, { Component } from 'react';
import AuthContext from './AuthContext';
import { HatTokenValidation } from '@dataswift/hat-js/lib/utils/HatTokenValidation';

export class AuthProvider extends Component {
  state = {
    user: {
      isAuthenticated: false,
      token: '',
      hatName: '',
    },
  };

  render() {
    return (
      <AuthContext.Provider
        value={{
          user: this.state.user,
          logout: () => {
            sessionStorage.removeItem('token');

            this.setState({
              user: {
                isAuthenticated: false,
                token: '',
                hatName: '',
              },
            });
          },
          login: (token, hatName) => {
            if (token && !HatTokenValidation.isEncodedTokenExpired(token)) {
              this.setState({
                user: {
                  isAuthenticated: true,
                  token: token,
                  hatName: hatName,
                },
              });
            }
          },
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}
```

#### Include AuthProvider in the App component

```javascript
// src/app/App.js
import { AuthProvider } from "../components/context/AuthProvider";

function App() {
  return (
      <AuthProvider>
        <div className="app">
          <Routing/>
        </div>
      </AuthProvider>
  );
}
```

#### Check if the user is authenticated

Now, in the Home page, we can check if the user is authenticated and display a protected page. In order to see this private page, they must login first.

HAT-JS offers the option to import the HatTokenValidation class to help decode the token, accessing the [JWT](https://jwt.io)'s properties and check the token expiration time:

```
// src/features/Home/HomePage.js
import React, { useEffect, useContext } from 'react';
import './HomePage.scss';
import { HatTokenValidation } from '@dataswift/hat-js/lib/utils/HatTokenValidation';
import AuthContext from "../../components/context/AuthContext";
function HomePage() {
  const authContext = useContext(AuthContext);

  useEffect(() => {
    const token = sessionStorage.getItem('token');

    if (token) {
      const decodedToken = HatTokenValidation.decodeToken(token);

      // If the token has not expired, log in the user.
      if (!HatTokenValidation.isExpired(decodedToken)) {
        authContext.login(token, decodedToken.iss);
      }
    }
  }, []);

  return (
    <AuthContext.Consumer>
      {context => (
        <>
          <div className="home-wrapper">{context.user.isAuthenticated && <div>Authenticated!</div>}</div>
        </>
      )}
    </AuthContext.Consumer>
  );
}

export default HomePage;
```

#### Add a logout button

In the Header.js we can use the **AuthContext** and display the "Logout" button when the user is authenticated:

```javascript
// src/components/header/Header.js
import React from 'react';
import { Link, NavLink } from 'react-router-dom';
import './Header.scss';
import AuthContext from '../context/AuthContext';

function Header() {
    return (
        <AuthContext.Consumer>
            {context => (
                <>
                    <header className="header">
                        <NavLink exact activeClassName="active" to="/">
                            Home
                        </NavLink>

                        {context.user.isAuthenticated && (
                            <Link to="/login" onClick={() => context.logout()}>
                                Log out
                            </Link>
                        )}

                        {!context.user.isAuthenticated && (
                            <ul>
                                <li>
                                    <NavLink activeClassName="active" to="/login">
                                        Log in
                                    </NavLink>
                                </li>
                                <li>
                                    <NavLink activeClassName="active" to="/signup">
                                        Create account
                                    </NavLink>
                                </li>
                            </ul>
                        )}
                    </header>
                </>
            )}
        </AuthContext.Consumer>
    );
}
export default Header;
```

### Create a protected Home component

The next step is to create the protected Home component. Lets create the **HomePrivate.js** file into the Home feature:

```
// src/features/Home/HomePrivate.js
import React from 'react';

function HomePrivate() {
    return (
        <div className="home-private">
            <div className="container">
                <div className="content">
                    Private content
                </div>
            </div>
        </div>
    );
}

export default HomePrivate;
```

And include this CSS in the **HomePage.scss**:

```
// src/features/Home/HomePage.scss
.
.

.home-private {
    height: 100%;
    width: 100%;

    .container {
        border-radius: 6px;
        padding: 2.4rem;
    }

    .content {
        background: #e9e9e9;
        padding: 2.4rem;
        border-radius: 6px;
    }
}
```

And then, replace the **\Authenticated!\\\</div>** with the component:

```
// src/features/Home/HomePage.js
.
.
import HomePrivate from "./HomePrivate";

function HomePage() {
  .
  .

  return (
    <AuthContext.Consumer>
      {context => (
        <>
          <div className="home-wrapper">{context.user.isAuthenticated && <HomePrivate />}</div>
        </>
      )}
    </AuthContext.Consumer>
  );
}

export default HomePage;
```

### Create Notes component

Create a new folder **Notes** in the **features/** with the **Notes.js** file:

```javascript
// src/features/Notes/Notes.js
import React from 'react';
import './Notes.scss';

function Notes() {

    return (
        <form
            className={'notes-wrapper flex-column-wrapper flex-content-center flex-align-items-center'}
        >
            <div className={'flex-spacer-small'} />
            <h3>Save a note on your HAT</h3>
            <input
                name={'note'}
                type={'text'}
                placeholder="Remember to..."
                autoComplete={'text'}
            />
            <div className={'flex-spacer-small'} />
            <button className={'btn btn-accent'} type={'submit'}>
                Save
            </button>
            <div className={'flex-spacer-small'} />
        </form>
    );
}

export default Notes;
```

And the **Notes.scss**:

```css
// src/features/Notes/Notes.scss
.notes-wrapper {
  input {
    margin-top: 2.5rem;
    margin-bottom: 2.5rem;
  }
}

.note-row-wrapper {
  display: flex;
  flex-direction: row;
  margin-top: 1rem;

  .note-content {
    text-align: left;
    flex: 1 1;
    color: #4a556b;
    font-size: 1.6rem;
  }

  button {
    margin-left: 1rem;
  }
}

.notes-list {
  margin-top: 2.5rem;
  width: 100%;
  max-width: 32rem;
  list-style-type: none;
}
```

Include the Notes component in the **HomePrivate.js**:

```javascript
// src/features/Home/HomePrivate.js
import React from 'react';
import Notes from "../Notes/Notes";

function HomePrivate() {
    return (
        <div className="home-private">
            <div className="container">
                <div className="content">
                    <Notes />
                </div>
            </div>
        </div>
    );
}

export default HomePrivate;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dataswyft.com/build/getting-started/react-pda/5.-component-pages.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
