---
# System prepended metadata

title: Rich Web Applications

---

# Rich Web Applications

## Week one

### node package manager (npm)

get the latest **npm** version
```console
npm install -g npm@latest
```

### Next.js

create an app with latest **Next.js** version
```console
npx create-next-app@latest
```

run the Next.js development server
```console
npm run dev
```

## Week two

### Material UI

install **Material UI**
```console
npm install @mui/material @emotion/react @emotion/styled
```

login page code from
https://github.com/mui/material-ui/blob/v5.14.11/docs/data/material/getting-started/templates/sign-in/SignIn.js

fixed the errors by using a client component and installing Material UI Icons

> To use Client Components, you can add the React "use client" directive at the top of a file, above your imports.
> 
> "use client" is used to declare a boundary between a Server and Client Component modules. This means that by defining a "use client" in a file, all other modules imported into it, including child components, are considered part of the client bundle.
https://nextjs.org/docs/app/building-your-application/rendering/client-components
```javascript
"use client"
```

install **Material UI Icons**
```console
npm install @mui/icons-material @mui/material @emotion/styled @emotion/react
```

### Docker

download **Docker Desktop** from
https://www.docker.com/products/docker-desktop/

add `compose.yaml` file to folder
```yaml=
# Use root/example as user/password credentials
version: '3.1'

services:

  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: example
      ME_CONFIG_MONGODB_URL: mongodb://root:example@mongo:27017/
```
create and start containers
```console
docker compose up
```

open Mongo Express
http://localhost:8081/

login credentials:
* username: admin
* password: pass

## Week three

create API routes
```
app/
└── api/                
    └── login/          
        └── route.js    
```

### Data fetching

https://nextjs.org/docs/app/building-your-application/data-fetching

`fetch()`
```javascript
fetch(`http://localhost:3000/api/login?email=${email}&pass=${pass}`);
```

`route.js`
```javascript=
export async function GET(req,res) {
    const email = req.nextUrl.searchParams.get('email');
    const pass = req.nextUrl.searchParams.get('pass');
    return Response.json({ "email": email, "pass": pass })
}
```

### Mongo DB

installing **mongodb**
```console
npm i mongodb
```

## Week four

### Mongo DB

create a database `app`
create a collection `login`

add two datasets to collection

```json
{
    "_id": ObjectId(),
    "username": "sample@test.com",
    "pass": "12345",
    "acctype": "customer"
}
```

```json
{
    "_id": ObjectId(),
    "username": "sample2@test.com",
    "pass": "12345",
    "acctype": "manager"
}
```

### Rerunning compose

add in a port definition in the `compose.yaml` file
The purpose of this is to map the docker mongodb port 27017 to the local machine 27017 so you can connect to it.


```diff=12
+    ports:
+      - 27017:27017
```

change `route.js` file in api/login/ folder to add Mongo DB connection.

```javascript=
export async function GET(req,res) {
    const email = req.nextUrl.searchParams.get('email');
    const pass = req.nextUrl.searchParams.get('pass');
    
    const { MongoClient } = require('mongodb');

    const url = 'mongodb://root:example@localhost:27017/';
    const client = new MongoClient(url);

    const dbName = 'app';

    await client.connect();
    console.log('Connected successfully to server');
    const db = client.db(dbName);
    const collection = db.collection('login');

    const findResult = await collection.find({"username":
    email}).toArray();
    console.log('Found documents =>', findResult);

    let valid = false
    if(findResult.length > 0 ){
        valid = findResult[0].pass == pass;
    } else {
        console.log(`No user with username: ${email} found.`);
    }

    // at the end of the process we need to send something back.
    return Response.json({ "data": valid});
}
```

## Week five

### Customer dashboard to view products

#### Setting up the database

creating a new collection `products`

adding a product to collection

```json
{
    "_id":ObjectId(),
    "pname":"jam doughnut",
    "price":"1 euro"
}
```

#### Creating the dashboard

create a new dashboard page
```
app/
└── dashboard/                
    └── page.js  
```

add code to `page.js` (the following is the final code at the end of week 5)

```javascript
'use client';
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { ThemeProvider } from '@mui/material/styles';
import { createTheme } from '@mui/material/styles';
import { green, purple } from '@mui/material/colors';
import { useState, useEffect } from 'react'
import { withIronSessionApiRoute } from "iron-session/next";
export default function Page() {
    //
    // function for putting items into the shopping cart.
    //
    function putInCart(pname) {
        console.log("putting in cart: " + pname)
        fetch("http://localhost:3000/api/putInCart?pname=" + pname);
    }
    const [data, setData] = useState(null)
    useEffect(() => {
        fetch('http://localhost:3000/api/getProducts')
            .then((res) => res.json())
            .then((data) => {
                setData(data)
            })
    }, [])
    if (!data) return <p>No data</p>
    const theme = createTheme({
        palette: {
            secondary: {
                main: green[500],
            },
        },
    });
    return (
        <ThemeProvider theme={theme}>
            <Container component="main" maxWidth="xs">
                <div style={{ fontSize: '40px' }} > Dashboard</div>
                <div>
                    {
                        data.map((item, i) => (
                            <div style={{ padding: '20px' }} key={i} >
                                Unique ID: {item._id}
                                <br></br>
                                {item.pname}
                                -
                                {item.price}
                                <br></br>
                                <Button onClick={() => putInCart(item.pname)} variant="outlined"> Add to cart
                                </Button>
                            </div>
                        ))
                    }
                </div>
            </Container>
        </ThemeProvider>
    );
}
```

create a new API endpoint
```
app/
└── api/                
    └── getProducts/          
        └── route.js    
```

add code to `route.js`

```javascript
export async function GET(req, res) {
    // Make a note we are on
    // the api. This goes to the console.
    console.log("in the api page")
    // =================================================
    const { MongoClient } = require('mongodb');
    const url = 'mongodb://root:example@localhost:27017/';
    const client = new MongoClient(url);
    const dbName = 'app'; // database name
    await client.connect();
    console.log('Connected successfully to server');
    const db = client.db(dbName);
    const collection = db.collection('shopping_cart'); // collection name
    const findResult = await collection.find({}).toArray();
    console.log('Found documents =>', findResult);
    //==========================================================
    // at the end of the process we need to send something back.
    return Response.json(findResult)
}
```

### Adding a shopping cart

#### Creating a database collection

create a new collection `shopping_cart`

#### Creating the API page

create a new API endpoint

```
app/
└── api/                
    └── putInCart/          
        └── route.js    
```

add code to `route.js`

```javascript
export async function GET(req, res) {
    // Make a note we are on
    // the api. This goes to the console.
    console.log("in the putInCart api page")
    // get the values
    // that were sent across to us.
    const { searchParams } = new URL(req.url)
    const pname = searchParams.get('pname')
    console.log(pname);
    // =================================================
    const { MongoClient } = require('mongodb');
    const url = 'mongodb://root:example@localhost:27017/';
    const client = new MongoClient(url);
    const dbName = 'app'; // database name
    await client.connect();
    console.log('Connected successfully to server');
    const db = client.db(dbName);
    const collection = db.collection('shopping_cart'); // collection name
    var myobj = { pname: pname, username: "sample@test.com" };
    const insertResult = await collection.insertOne(myobj);
    //==========================================================
    // at the end of the process we need to send something back.
    return Response.json({ "data": "" + "inserted" + "" })
}
```

#### Creating the Cart page

create a new page

```
app/
└── cart/                
    └── page.js  
```

add `app/dashboard/page.js` code to `page.js`

change fetch method
```javascript
fetch('http://localhost:3000/api/getCartProducts')
```

create a new API endpoint

```
app/
└── api/                
    └── getCartProducts/          
        └── route.js    
```

add `app/api/getProducts/route.js` code to `route.js`

change collection name

```javascript
const collection = db.collection('shopping_cart');
```

## Week six

### Working with the register page

#### Creating the register page

create a new page

```
app/
└── register/                
    └── page.js  
```

add `app/login/page.js` code to `page.js`, adjust it for the register page.

add a Date of Birth field to `page.js`

```javascript
<TextField
  margin="normal"
  required
  fullWidth
  id="dob"
  label="Date of Birth"
  name="dob"
  autoComplete=""
  autoFocus
/>
```

add a variable for the date of birth field to `handleSubmit` function
add a query parameter for the date of birth field

```javascript
const dob = data.get('dob');
runDBCallAsync(`http://localhost:3000/api/register?email=${email}&pass=${password}&dob=${dob}`);
```

create a new API endpoint

```
app/
└── api/                
    └── register/          
        └── route.js    
```

add `app/api/register/route.js` code to `route.js`

add a variable for the date of birth field

```javascript
const dob = req.nextUrl.searchParams.get('dob');
```


On the login page, a database query was executed to find an entry; on the register page, a database query is to be executed to add an entry.

```javascript
const findResult = await collection.insertOne({"username": email, "pass": pass, "dob": dob});
```

## Week seven

### Integrating the weather API

Register to https://www.weatherapi.com/

#### Exploring the API documentation

#### Integrating into your application

create a new API endpoint

```
app/
└── api/                
    └── getWeather/          
        └── route.js    
```

add code to `route.js`

```javascript
export async function GET(req, res) {
    // Make a note we are on
    // the api. This goes to the console.
    console.log("in the weather api page")

    const res2 = await fetch("")
    const data = await res2.json()
    console.log(data.current.temp_c)

    let currentTemp = data.current.temp_c
    
    // at the end of the process we need to send something back.
    return Response.json({"temp": currentTemp})
}
```

add code to `dashboard/page.js` useState and useEffects definiton.

```javascript
const [weather, setWeatherData] = useState(0)
```

```javascript
fetch('http://localhost:3000/api/getWeather')
    .then((res)=>res.json())
    .then((weather)=>{
        setWeatherData(weather)
})
```

add code to jsx template

```javascript
if(!weather) return <p>Noweather</p>

Today's temperature: {JSON.stringify(weather.temp)}
```

## Week eight

### Deploying the application

#### MongoDB in the cloud

login to https://account.mongodb.com/account/login

create a database
* choose free plan (M0 Free)
* create user
* choose Cloud Environment
* add 0.0.0.0/0 to IP Access list

migrate the local collection to cloud
* click "Browse Collections"
* click "Add My Own Data"
* use "app" for Database name
* use "login" for Collection name
* click "Create"
* click "Insert Document"
* add two users in JSON Format

```json
{ 
    "username": "kyle@goslin.ie",
    "pass": "1234", 
    "acc_type": "customer" 
}
```


```json
{ 
    "username": "kyle@goslin.ie",
    "pass": "1234", 
    "acc_type": "manager" 
}
```

* click "Create Database"
* use "app" for Database name again
* use "products" for Collection name
* click "Create"
* click "Insert Document"
* add a product in JSON Format

```json
{
    "pname":"JamDoughnut",
    "price":"1euro"
}
```

Getting the Connection Details
* click "Connect"
* click "Drivers"
* copy connection string and add your username and password to it
* change all occurences of MongoDB localhost to 

```javascript
mongodb+srv://haasphilipp:GtPV1ONQReDtHUXE@cluster0.uqlamu8.mongodb.net/?retryWrites=true&w=majority'
```

#### GitHub

Create a new repository on GitHub

```console
git init
git add .
git commit -m "Initial commit"
git branch -M main 
git remote add origin https://github.com/haasphilipp/rich-web-app.git
git push -u origin main
```

#### Vercel

import the GitHub project to Vercel and deploy it

Since I have already deployed a lot of projects via GitHub and Vercel, not much more documentation is needed here. :)