Step by Step: Build a Membership Website with Amplify, Stripe, and Next.js
Tags: builtwithamplify, builtwithappsync, nextjs, stripe
Published: 2023-03-25 22:29:44

## Content of Table: 

1. [Introduce]()
2. [Create a Copy of the Design Project]()
3. [Create an Amplify Project]()
4. [Setup a Next.js Project]()
5. [Pull Components from Amplify]()
6. [Bind Data to the Components]()
7. [Build the Website Pages]()
8. [Create a Checkout Flow]()
9. [Create User Accounts]()
10. [Authenticate the Customers]()
11. [Conclusion]()

## 1. Create a Copy of the Design Project

#### **Objectives**

In this lab, you will learn how to:

+ Kick off a design project using the Amplify template
+ Theme the design to your taste

**Creating the Project Design**

We need to make a copy of this [design file](https://www.figma.com/community/file/1166264876424501672) to get started. The design was created by cloning the official AWS Amplify UI template and adding a different theme.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4izgcdqqtez3jodq7tj.png)

We can see the design was created, you can zoom to show clearly :


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k6l26lqvwysrcvnds97j.png)

Even though we’ll use the customized design file for this project, let’s also see how to use the official UI library for future projects.

1.So, in [the Figma community](https://www.figma.com/community), search for **AWS Amplify UI Kit** and open the kit maintained by the AWS Amplify Team.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cl8p2korka2vovpov1ep.png)

2.Choose figma name ``AWS Amplify UI Kit`` of **AWS Amplify**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21m9p4ayim9ef4yhx63q.png)

3.Click the ``Get a copy`` button to create a copy of the AWS Amplify UI project into our Figma account.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s42gxnud60pjgk4cargk.png)

The AWS Amplify project contains the following pages:

+ **A readme**: describes the UI project.

+ **Primitives**: like buttons and form controls that make up the component.

+ **My Components**: these are reusable components composed of primitives that we can drop on our website.

+ **Examples**: this page shows how to use the components.

**Editing the Project design theme**

We can change the default theme of the official UI template; to do that, we need to install the AWS Amplify theme editor from the Figma community page.

1.Let's search ``Amplify theme``for the AWS Amplify and open it, click the **plugin** tab and click **try it out** it.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/loq4o77bb8d3407rn9fq.png)

2.Click ``Primitives`` and Press the command + / keyboard keys to bring up the Figma command palette back to the Figma project. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w2fnip1e7houvx42vuhx.png)

3.Let's click ``Component`` for the AWS theme editor and open it, navigate to the components tab and search for ``button.primary``. And set up the color (you can choose like picture). Then click **Save**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5cr6wrxyf2s4h0j40vb.png)

4.When save, we should see that we updated the color of the button on the primitives' page.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3u2zaz87ut86hp2gqpv.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ooydmsfrq8dm4w4uibk.png)

**Note**

+ Amplify recommends that we don't change the primitives directly; the components' artboards are locked to prevent accidentally changing the Components.

+ The primitives have a one-to-one mapping with the AWS Amplify React UI library, which we'll use when pulling the component into our react project. Changing the primitives will make it fall out of sync with the React UI library.

+ Amplify will always give us an object containing the themes we are using. We can then pass it to the React UI library to customize it.

On the components page, you should see that all button colors have been updated accordingly, the same thing on the example page


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mddydy8t7lbx087e21ls.png)

**The Design We'll Use**

Instead of Official Amplify UI Kit in this project, we'll use an already [customized one](https://www.figma.com/file/jTMpPiejnjoLihTv663mxa/Membership-Website-for-Amplify-Learn?node-id=1330%3A11587) that suits our membership website. The following is what was edited:

1. **On the Primitives page** - the button color was changed to orange and the background color to dark blue, etc.
2. **The Components page** - utilizes the customized theme and creates the following components:

+ The Hero component.

+ The testimony component.

+ The story component

+ The Nav Component and the Footer component.

3. **On the Examples page** - a complete website was built using the components. The website includes a landing page and a paywall-protected page.

**What's Next?**

In the next lesson, you will learn how to setup an Amplify project.

## 2. Create an Amplify Project


#### **Objectives**

In this lab, you will learn how to:

+ Create an Amplify project

+ Setup authentication

+ Add data model

+ Generate fake data for your model

+ Import the components from Figma

**Creating an Amplify Project**

Log in to the [AWS](https://signin.aws.amazon.com/signin?redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26nc2%3Dh_ct%26src%3Dheader-signin%26state%3DhashArgsFromTB_us-west-2_6e278d73bcc5ae1c&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=PgNDA_jabFgNlsf536dB-Iv28VbObJsEl1xOr_0-4nE&code_challenge_method=SHA-256) console, or create an account [here](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html?nc1=f_ct&src=default). Search for ``AWS Amplify`` from the search bar and select it from the list of services.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cacfl4tcrjtgf4na5i7.png)

Click **Get Start**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ml2rhmhrlhtwraykibor.png)

Next, click on the **Get Start** in item **Build an app**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzalwjpn9edocjn8qkel.png)

Give a name ``membership-website`` to the application and click the **Confirm deployment** button.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avwpey82b5cq8izx0y73.png)

Wait  to setting up


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y395z11oph7n7d466g7c.png)

After the deployment process, click on the **Launch studio** button to launch a staging studio in a new tab.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjl2ats8ygz9j5s3kro5.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqqszqqigmgn2907d3nr.png)

In the Amplify studio, we'll add authentication to the project, model a database and deploy it, add contents to the database, and import UI components from Figma using the UI builder.

**Adding Authentication**

Navigate to the **authentication** tab since we need only signed-in users to access our content. The login mechanism stays the same; then, in configuring the sign-up section, click the password protection setting and make the password as strong or weak as possible.

Uncheck all other checkboxes except the **Include lowercase characters** checkbox and click **Deploy** to deploy the authentication.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vci4reddjbc3d50p7pa.png)

Next click in **Confirm deployment**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t43apusopdzof5svmu7t.png)

This deployment can take a few minutes


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hktmnrckzjfg1tywubnc.png)

If successfully it will show


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r17ugyqet2glxb54tc8x.png)

**Creating Data Model** 

Navigate to the **data** section and create the following data models:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/735sfu8kyu0jvjucnq7y.png)

Testimonial - this will have the id, name, avatar, and testimony fields.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sifk0d283jzarw1rv5ws.png)

Post - this will have the id, title, body, and description fields and also a readTime field with the type of integer.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulfl18386ewtzvdiicqi.png)

After creating the models and adding fields click the **Save and Deploy** button to deploy the database.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gsxmddc6p9v2ehhvsda.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhsgrgcl8oe4r089taf4.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7kbhjc3i21uqviympv3.png)

**Adding Content to the Data Model**

Add this page we will see


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34rz0h6dem13dyajesrp.png)

Navigate to the **content** section, select either the **Testimonial** or the Post table from the select table dropdown, and click on **Auto-generate seed data**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yl93fjf7brj1vny849ep.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2z9tk62nmgxjttdw69jl.png)


For the **Testimonial** table, set rows to 6, add constraints like in the below and click the **Generate data** button:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urncl8nwpm4r1t44heyz.png)

After generating the data, we can then update the avatar fields with desired avatar URLs. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgfu3r3x7gjrfc2wzpqr.png)

Set the rows to 10 for the Post table, add **constraints**, and click the **Generate data** button to seed the table.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x83ez2uttxepza455zna.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h7ezp0d9yvarkdkqizg.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2sinzbf8i7bn2vr1p9a.png)

**Importing UI Components from Figma**

We'll import the customized design from Figma into Amplify Studio, grab the [URL](https://www.figma.com/file/jTMpPiejnjoLihTv663mxa/Membership-Website-for-Amplify-Learn?node-id=1330%3A11587) from Figma, and navigate the **UI Library** tab.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv7ersw6j831lxebul0q.png)

<!-- you could make this into a Figma community file and have them duplicate it! -->

Next, click the **Get Started** button and paste the [Figma design URL](https://www.figma.com/file/jTMpPiejnjoLihTv663mxa/Membership-Website-for-Amplify-Learn?node-id=1330%3A11587) in the input field and click on **Continue**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaktwgcrqmj8lsb9b7xn.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yiff6q0u5j4trxljso1h.png)

After successfully importing the Figma components, click on **Accept all changes**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf98mbg4fa5p6ozda9uc.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3poyl0v6updevgprssbd.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5rm8nnsqjz1kvzf98b0.png)

Next, click on **Accept all** to accept all the imported components.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgxhbsociiuypx8ecb77.png)

Now, we have all the components in the Amplify project the same way they are in Figma.

**What's Next?**

In the next lesson, we'll setup a Next.js project.

## 3. Setup a Next.js Project

#### **Objectives**

In this lab, you will learn how to:

+ Setup a Next.js project

**Setting Up a Next.js Application**

To create a new Next.js application, let's run the following commands in our terminal:

```
npx create-next-app membership-website
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e16wkumekt4bm9wfm2bg.png)

After creating the application, we'll navigate into the project directory with the command below:

```
cd membership-website
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2xhowaqiq9b9fmbbk9s.png)

Next, install the following dependencies:

+ [aws-amplify](https://www.npmjs.com/package/aws-amplify) - to give us access to the amplify SDK

+ [@aws-amplify/ui-react](https://www.npmjs.com/package/@aws-amplify/ui-react) - this dependency has a one-to-one mapping with the primitive's page in our Figma UI design.

+ [@fontsource/inter](https://www.npmjs.com/package/@fontsource/inter) - so we can tweak the fonts of our project.

The command below will install the above dependencies:

```
npm install aws-amplify @aws-amplify/ui-react @fontsource/inter
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdgox2yhi4mpxb9r6vun.png)

A few final steps:

+ Create a `reset.css` file inside the **styles** folder in the root directory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv6pgpbzgddo6kod4q0l.png)

+ Copy the `globals.css` properties and paste it inside the **reset.css** file.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sa0cv1osr12ymy1vza08.png)


+ Delete the styles in the **globals.css** and add a background color of `#091B2A` to the body.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r63xyrnfzpwenrhvttnt.png)


**What's Next?**

In the next lesson, pull all the UI components and data model from Figma into the new Next.js project.

## 4. Pull Components from Amplify

#### **Objectives**

In this lab, you will learn how to:

+ Pull components and model from Amplify

+ Test the components

**Pulling Components from AWS Amplify**

To pull Amplify components down to the Next.js application, we should have the AWS [Command Line Interface](https://docs.amplify.aws/cli/) installed in the local machine and authorized.

Install the AWS CLI with the following command:

```
npm install -g @aws-amplify/cli
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oxatlormcnvymamvgazi.png)

Click on **Local setup instructions**, copy the pull command and run it in the terminal in the Studio.

Next, authorize the Amplify CLI and follow the prompts below to pull the components, the data models, the authentication and other Amplify settings.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y48tlxw0y9qxlm0x2ay7.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b7bzcorzq8akrl19cusp.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ylp896zeornf3p1oj1q4.png)

AWS will add the following folders to the Next.js application.

+ **vscode** - this houses some AWS to VSCode configurations

+ **amplify** - this contains AWS backend configurations.

+ **models** - this houses the model schemas

+ **ui-components** - this is the most important for our project. It includes all of our Figma designs/components.

Next, we'll import Amplify configurations and wrap the Next.js application with it. To do this, update the `_app.js` file with the following snippets:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19fn9smjqby2gp1hc53v.png)

```python
import "../styles/globals.css";
import { Amplify } from "aws-amplify";
import { studioTheme } from "../ui-components";
import { AmplifyProvider } from "@aws-amplify/ui-react";
import "@aws-amplify/ui-react/styles.css";
import "@fontsource/inter";
import "../styles/reset.css";

import awsconfig from "../aws-exports";
Amplify.configure(awsconfig);

function MyApp({ Component, pageProps }) {
  return (
    <AmplifyProvider theme={studioTheme}>
      <Component {...pageProps} />
    </AmplifyProvider>
  );
}
export default MyApp;
```

In the snippets above, we did the following:

+ Imported Amplify from aws-amplify, studioTheme from ui-components, and AmplifyProvider from @aws-amplify/ui-react.

+ Imported awsconfig from "../aws-exports" and used it to configure Amplify.

+ Wrapped the Components with the AmplifyProvider and passed the studioTheme as the theme prop.

We've successfully connected the AWS backend environment with our Next.js application. To test things out, let's import a component from the **ui-components** folder in the `index.js` file like in the below:

```python
import React from "react";
import { Hero } from "../ui-components";
import { View } from "@aws-amplify/ui-react";

function index() {
  return (
    <View>
      <Hero />
    </View>
  );
}
export default index;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9gsz18fho7g60rg6659.png)

Here, we imported the **Hero** component and **View**, like a wrapper **div** that wraps elements.

Next, run the following command to start the development server:

```
npm run dev #to start the dev server
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0zxmd133ps0zsmg6ais.png)

Next.js will start a development environment at [http://localhost:3000](http://localhost:3000/) in the browser; our application would look just like expected:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hktr94hk8lz8sj8ctfyx.png)

**What's Next?**

In the next lesson, you'll learn how to bind data to the components.

## 5. Bind Data to the Components

#### **Objectives**

In this lab, you will learn how to:

+ Bind data to the components

+ Bind events to the components

+ Binding data to Components

To breathe life into the components, we'll be binding data and events to them in the Amplify Studio. We'll start with the **Nav** component.

Click on the **UI Library** tab, click on the **Nav** and click on **configure** button to bind data and events to the **Nav** component.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpff0m3gu04tfsdegxu1.png)

Next, in configure dialog, click on the component's root **(Nav)** and click **Add** prop. We'll create the following top-level props and consume them in the elements with the **Nav** component.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6kb80hwxfp4ucluq3hv.png)

+ **username**: this prop will receive the user names on the website.

+ **authText**: this prop will display the sign-in or sign-out buttons depending on the user authorization.

+ **avatar**: this will handle the user avatar.

+ **handleAuth**: this will handle the authorization event.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jmtbh7p9eztks5m7v29o.png)

In the **Nav** component, we want to hide the username if there's no user, so select the user element and click on the **Set prop** button; beside the child properties.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40riq4tnrinojxkm3yu5.png)

Select a `display` from the list of props, click on the three vertical dots beside it, click on **add conditional** and add conditions like in the below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wh618q0eia5fdkva0cj.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2k1yjz5sibstyek9ze1.png)

For the **avatar** text, select it, click on the **Set text label** button and set the `label` to the avatar, and for the user name, select it and set its label to the username.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdj9czycvfrp6gtzm13h.png)

For the button, select it, click on **Set an onClick action**, select the onClick prop and set its value to `handleAuth`. Also, click on **Set prop**, select `label` prop, and set the value to `authText`.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wt9ku2snxcn6vhvb5qyl.png)

For the **Hero** component, we'll create a top-level prop `handleClick` and set its type to an Event handler. Select the `Button` element and set its `onClick` prop to the `handleClick` we created above.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6254jwp5mv6erg7ew7e.png)

We'll create two top-level props for the **Persuade** component, `handleClick`, and `banner`, then set their types to the Event handler and `String`.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r82nl8do0jv267njh9rl.png)

Next, select the **Button** element, select the `onClick` prop and set it to the `handleClick` we created. Select the `Banner` element, select the `src` prop and set it to the `banner` prop we created.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q41h098sghxzya438phm.png)

For the `Testimony` component, we'll bind data a bit differently; unlike the earlier components, we'll be binding data provisioned in our database to the `Testimony` component.

Click on the `Testimony` Component and click on **configure**, select the Component's root and click on **Add prop**, Create a top-level prop `testimonyModel`, and set its type to `Testimonial` data model. All the elements of the `Testimony` Component will have access to the rows in the Testimonial table.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fl8cmmpiy01vjdmu47hz.png)

Now, let's set the **Testimony** Component elements to different rows of the Testimonial data model.

+ Select the image element, click on **Set prop,** select the **src** prop and set it to **testimonyModel.avatar**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4e4ae9vaz6luunjw1kf.png)

+ Select the **Author** element, click on **Set prop,** select the **label** prop and set it to **testimonyModel.name**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9i0ejsx3085dwlvgha4.png)

+ Select the **Testimony** text element, click on **Set prop,** select the **label** prop and set it to **testimonyModel.testimony**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdzm90pq1t8wmx88k630.png)

Next, click on **Create collection** to generate cards for the total number of records in the Testimonial data table. Change the display to Grid on the collection page and set the column to **three**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bi62rz3tisq6mcio5jzw.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eu1owcm6kde01zzz4mt0.png)

Next, navigate back to UI Library; let's repeat the process for the Story Component just like we did for the Testimony Component.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0w9c5isndthc3yj4z56.png)

Now, select the **Story** Component, click the **configure** button, select the Component's root, and click on **Add prop.** Create a top-level prop **postModel** and set it to the Post data model.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk1kf5bwez2v6s0h7t4n.png)

To bind postModel data to the Story Component elements, we'll select:

+ **Banner** element, set its **src** prop to any static image.(You can choose `https://loremflickr.com/320/240?lock=212` this image)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3j3ksb10j9hy7q7ahlru.png)

+ Click on **Set prop** and set the label prop to **postModel.title** for the title element.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdr94h0swnc8a5zy7mjt.png)

+ **Description** element and set its text label prop to **postModel.description**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w3ds84s6h4826ol4ml2f.png)

+ **ReadTime** element and set its label prop to **postModel.readTime**; also, we'll concatenate a string `mins read`..


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgbw9n5hgxlpipcmjme0.png)

Next, click the **Create collection** button, name the collection `Stories`. In the collection page, set the display to *Grid* and the column to `3`, then add a padding `10px` round the box.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qznfvdcdvbz61k053pq.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9j26tlg322nhfcg1fsl.png)

**What's Next?**

In the next lesson, you'll learn how to build the complete website using the components.


## 6. Build the Website pages

#### **Objectives**

In this lab, you will learn how to:

+ Use the components to build the website

+ Build the Website

First, run the following command to pull the data binding changes we made into the Next.js project.

```
amplify pull
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on5g77faawfhxtwdyort.png)

Next, create a **components** folder; inside it, create a **Layout.js** file with the following snippets:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36u3a5ru9kie951jnwgn.png)

```
//components/Layout.js
import React from "react";
import { View } from "@aws-amplify/ui-react";
import { Nav } from "../ui-components";
function Layout({ children, authText, handleClick, username }) {
  return (
    <View width="1200px" marginLeft="auto" marginRight="auto">
      <Nav
        marginTop={"20px"}
        handleAuth={handleClick}
        authText={authText}
        username={username}
        avatar={username.split("")[0].toUpperCase()}
      />
      {children}
    </View>
  );
}
export default Layout;
```

In the snippets above, we:

+ Imported View from "@aws-amplify/ui-react" and Nav from ui-components.

+ Rendered View as a wrapper div for the Nav component and the children prop.

+ Rendered the Nav component and passed some layout props to it.

Next, modify the index.js file like the below:

```
//pages/index.js
import React from "react";
import { Flex, View } from "@aws-amplify/ui-react";
import { Footer, Hero, Persuade, Testimonies } from "../ui-components";
import Layout from "../components/Layout";
function index() {
  return (
    <Layout handleClick={() => {}} authText="Sign Up" username="none">
      <View marginBottom="135px">
        <Hero handleClick={() => {}} />
      </View>
      <View>
        <Testimonies />
      </View>
      <Flex justifyContent={"center"}>
        <Persuade banner="https://i.imgur.com/MxbD3N4.png" />
      </Flex>
      <View marginTop="50px" marginBottom="50px">
        <Footer />
      </View>
    </Layout>
  );
}
export default index;
```

In the snippets above, we:

+ Imported Flex and View from "@aws-amplify/ui-react" and Hero, Persuade, Testimonies, and Footer components from ui-components.

+ Imported Layout.js from the components directory, rendered it and passed handleClick, authText, and username props.

+ Used View and Flex and rendered our components within the Layout.js wrapper component. Notice that the username component is not visible in the Nav. That is because we passed none as to its value.

Next, let's create a post page where we will render the Stories component; inside the pages directory, create a post.js file with the following snippets:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7axfrqabmmespnpdqze.png)

```
//pages/post.js
import React from "react";
import { Heading, Text, View } from "@aws-amplify/ui-react";
import Layout from "../components/Layout";
import { Footer, Stories } from "../ui-components";
function Post() {
  return (
    <Layout
      handleClick={() => {}}
      authText="Sign Out"
      username={"christian@hotmail.com".split("@")[0]}
    >
      <View marginTop="50px" marginBottom="30px">
        <Heading level={2}>Welcome to our backstage</Heading>
        <Text marginTop="20px">
          Discover stories,thinking, and expertise from writers on any top{" "}
        </Text>
      </View>
      <Stories />
      <View marginTop="50px" marginBottom="50px">
        <Footer />
      </View>
    </Layout>
  );
}
export default Post;
```

In the snippets above, we did the following:

+ Imported Heading and Text components to format our texts and View component to wrap the Text and other components.

+ Imported the Layout.js components, rendered them, and implemented the post page inside it.

If we navigate to /post in the browser, we would see our post page with the stories component in it. To navigate to the post page from the landing page, let's update the **index.js** with the below snippets:

```
//pages/index.js
//other imports here
import { useRouter } from "next/router";
function index() {
  const router = useRouter();
  return (
    <Layout
      handleClick={() => {
        router.push("/post");
      }}
      authText="Sign Up"
      username="none"
    >
      //other components implementations here
    </Layout>
  );
}
export default index;
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/geqkcp48563gnodcfhm5.png)

Here, we imported useRouter from "next/router" and created a constant router with the useRouter() function, and then updated the handleClick. When we click on the Sign-Up button on the landing page, we'll be redirected to the post page.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6p1o4wfreqk16ny4lk6p.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hoaaqili7t4j4b7zsiz3.png)

**What's Next?**

In the next lesson, you'll learn how to create a checkout fow with Stripe.

## 7. Create a Checkout Flow

#### **Objectives**

In this lab, you will learn how to:

+ Setup stripe

+ Create a checkout flow

+ Test checkout

**Creating a Checkout flow with Stripe**

First, sign in to [Stripe](https://stripe.com/?utm_campaign=paid_brand-DE_en_Search_Brand_Stripe-866170064&utm_medium=cpc&utm_source=google&ad_content=604263118055&utm_term=stripe&utm_matchtype=e&utm_adposition=&utm_device=c&gclid=CjwKCAiAl9efBhAkEiwA4TorihJI1nGhqcqYy4GLb6pNYU_aaKd3Fgyy4w1TziBqtl-XHhy7TNoYFhoCqqIQAvD_BwE) or create an account [here](https://dashboard.stripe.com/register); click on the Settings icon from the dashboard, click on the **Checkout and Payment Links**, and create a Company name.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imjud5ir5d3a1pdr65h0.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfizj3jpwjl5godw93jn.png)

Next, scroll down and **Enable client-only integration**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjw9z2thh53i6ls72c1r.png)

Next, navigate to the **Products** tab and create a product like in the below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfvx67b6dzj7t3y3nnhz.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x281qhftyz19mhht79l7.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s26wnosumi7gjl6rw77a.png)

Save the product and grab the product price id; we’ll use it later to implement the checkout.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klyi7k3uqb1hkuf3zroj.png)

Next, grab the publishable key from the home page and let’s implement the checkout.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7favculjx11twyveofw4.png)

Next, install the Stripe client SDK with the following command:

```
npm install @stripe/stripe-js
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/je1ftfkj7ilaobwpxj7l.png)

Now, let's implement the checkout so that when a user clicks on the **Become a Member** button in the **Hero** Component, we will redirect the user to the Stripe checkout page to subscribe.

Let's update the **index.js** file with the following snippets:

```
//pages/index.js
//other imports here
import { loadStripe } from "@stripe/stripe-js";
function index() {
  // router here

  async function handleClick() {
    const stripe = await loadStripe(
      "pk_test_51L4jXPKdTSV8bg8w0fz0kimSG031Xoc5jeB4gXeGCt8x7mASfkAYLQzmJSdYNTbQtNIdeHUnJin1xprNw3958ump00e9nhhn9v"
    );
    const { error } = await stripe.redirectToCheckout({
      lineItems: [{ price: "price_1L4lEGKdTSV8bg8wWWfunlGh", quantity: 1 }],
      mode: "subscription",
      successUrl: "http://localhost:3000/post",
      cancelUrl: "http://localhost:3000/cancel",
    });
  }
  return (
    <Layout
      //handleClick here
      authText="Sign Up"
      username="none"
    >
      <View marginBottom="135px">
        <Hero handleClick={handleClick} />
      </View>
      //other components here
    </Layout>
  );
}
export default index;
```

In the snippets above, we:

+ Imported loadStripe from "@stripe/stripe-js" and used the publishable key and price to implement the handleClick function.

+ Provided the success and canceled redirect URLs.

+ Passed the handleClick function to the Hero Component.

When users click on the **Become a Member** button, we'll redirect them to the Stripe checkout page.

To test things out, click the button, enter the Stripe test card details, and on successful subscription, we'll be redirected to the post page, as we specified in the handleClick function.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j5z0hh8483zn94mu8n4c.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ff9t8pi0lkeioj0825zr.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bivenr466gq7ye8yjibd.png)

**What's Next?**

In the next lesson, you'll learn how to create accounts for users after they make payment.


## 8. Create User Accounts


#### **Objectives**

In this lab, you will learn how to:

+ Setup a Stripe webhook

+ Create a serverless function for the webhook

+ Create user accounts

**Creating a User Account**

The idea here is when a user subscribes, we'll get the user details from Stripe and create an account for the user. We'll create a webhook that Stripe will call on a successful subscription to achieve this. First, run the following command and follow the prompt.

```
amplify add api
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5a82re84a7yxhcv41uah.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lwfupysiwutuvrx0nlb.png)

Choose the following options to complete the process:

Next, navigate into the **membershipwebsite5dcac801** file we created above with the following command:

```
cd amplify/backend/function/membershipwebsite5dcac801/src
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ouw37x6sbvtxukkpm6bb.png)

Now, install the aws-sdk and Stripe with the command below:

```
npm install aws-sdk stripe
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owb2opt5yrkkk9f4wf3f.png)

Next, navigate into this amplify/backend/function/membershipwebsite5dcac801/src directory and update the **app.js** file with the following snippets:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6bu8mzt58n67q3vtidp.png)

```
const express = require("express");
const bodyParser = require("body-parser");
const awsServerlessExpressMiddleware = require("aws-serverless-express/middleware");
const aws = require("aws-sdk");
// declare a new express app
const app = express();
app.use(
  bodyParser.json({
    verify: function (res, req, buf) {
      req.rawBody = buf.toString();
    },
  })
);
app.use(awsServerlessExpressMiddleware.eventContext());
// Enable CORS for all methods
app.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "*");
  next();
});
const getStripeKey = async () => {
  const { Parameters } = await new aws.SSM()
    .getParameters({
      Names: ["stripe_key"].map((secretName) => process.env[secretName]),
      WithDecryption: true,
    })
    .promise();
  return Parameters[0].Value;
};
  // post method
app.post("/webhook", async function (req, res) {
  const stripeKey = await getStripeKey();
  const stripe = require("stripe")(stripeKey);
  const customer = await stripe.customers.retrieve(
    req.body.data.object.customer
  );
  const userEmail = customer.email;
  const cognito = new aws.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  cognito.adminCreateUser(
    {
      UserPoolId: process.env.AUTH_MEMBERSHIPWEBSITE_USERPOOLID,
      Username: userEmail,
      DesiredDeliveryMediums: ["EMAIL"],
      UserAttributes: [
        {
          Name: "email",
          Value: userEmail,
        },
      ],
      ValidationData: [
        {
          Name: "email",
          Value: userEmail,
        },
      ],
    },
    function (err, data) {
      if (err) {
        console.log(err);
      } else {
        console.log(data);
      }
    }
  );
});
app.listen(3000, function () {
  console.log("App started");
});
module.exports = app;
```

Most snippets above were generated when we followed the amplify add api command prompts, and we added the following:

+ Imported the aws-sdk using the require function

+ Added the verify option to the bodyParser function and set it to an anonymous function.

+ Implemented the post route and did the following:

    + Created the stripeKey constant and set to the getStripeKey() function.

    + Imported stripe using the Node.js require function and added the stripeKey.

    + Retrieved the customer detail using the stripe instance and set the userEmail to customer email.
      cognito, called the adminCreateUser() function, and created the user.

    + We passed an anonymous function as a second parameter to the route.

When a user subscribes again, we'll get an email with the user email as username and a generated temporal password. Also, if we inspect the Stripe webhook, we will see the user details.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfx6oqer4u5fe3auhvd1.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lzpgy0jebuinuwe342l.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmlwadob71dskza5t04b.png)

If successfully, we will see the email


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w08okgezcvykso5fav4u.png)

**What's Next?**

In the next lesson, you'll learn how to protect the website from unauthorized customers.

## 9. Authenticate the Customers


#### **Objectives**

In this lab, you will learn how to:

+ Create UI for authentication

+ Protect the customer area from unauthorized access

+ Authenticating Users

We want to protect the post page so the only signed users can access it; let's update the **post.js** file with the following snippets:

```
//pages/post.js
//other imports here
import {Authenticator,Flex,Heading,Text,useTheme,View,} from "@aws-amplify/ui-react";
import { Footer, Logo, Stories } from "../ui-components";
function Post() {

const authComponents = {
    Header() {
      const { tokens } = useTheme();
      return (
        <Flex
          justifyContent={"center"}
          direction="column"
          paddingTop={tokens.space.xxxl}
          paddingBottom={tokens.space.xxl}
        >
          <Logo />
        </Flex>
      );
    },
  };

  return (
    <Authenticator components={authComponents} hideSignUp={true}>
      {({ signOut, user }) => (
        <Layout
          handleClick={() => signOut()}
          authText="Sign Out"
          username={user.attributes.email.split("@")[0]}
        >
          // other components here
        </Layout>
      )}
    </Authenticator>
  );
}
export default Post;
``` 

In the snippets above, we:

+ Imported Authenticator, useTheme, and Flex from "@aws-amplify/ui-react" and imported Logo from "ui-components."

+ Created authComponent object, created a Header() function inside it, destructured tokens from the useTheme() function, and used Flex to render the Logo component.

+ Wrapped the Layout with Authenticator and passed authComponent to its components prop.
Passed the signOut function to the Layout handleClick event and updated the username value with the user parameter.

Click **Sign Up**, when the page pops up like this


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dnyx18zi7eo29xfgcqee.png)

Copy **Your temporary password** from your email and change your password


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sibnwjzvke0h4dd7ym2p.png)

When you re-enter the site, you will have to re-verify your information


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/etbw1cq1lew9gbes98d7.png)

Check your email


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fvto00m3ydukd91cg5n1.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z17d3uoff3fz35nvprfd.png)

And you have done the customer authentication part.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0eh4ua24imiq6640tw8i.png)

## 10. Conclusion

In this lab, you learned how to:

+ Theme a design in Figma for your AWS Amplify project
+ Create Amplify projects
+ Convert convert components in Figam to React code
+ Integrate Stripe with your AWS Amplify project
+ Protect your website with authentication

If you're looking to learn more about Amplify, head to our [docs](https://docs.amplify.aws/) and join our [Discord community](https://discord.gg/amplify).