Build a blog profile in Next using Cloudinary and Xata
Tags: hackmamba, javascript, jamstack
Published: 2022-11-30 22:34:27

##Prerequisite

1. Javascript
2. Next | React

 

##Introduction

Building a blog profile using xata as the backend and cloudinary to handle images.
xata is a serverless backend created to connect with your front-end application.


##Setting up NextJS

In this section we’ll be building the structure of our front-end application with next js. 

N:B at the moment of this article, version 12.2.0 was implemented and there can be slight changes to version 13 which will be out soon.

- Installation of NextJS : 
Before the installation of next, the article assumes we have the node and npm installed 
https://nodejs.org/en/download/package-manager/

**Npm installation.**

https://docs.npmjs.com/cli/v6/commands/npm-install


**Install NextJS**

https://nextjs.org/learn/basics/create-nextjs-app/setup


Upon the successful installation of these tools, we’d have a structure of 

![](https://paper-attachments.dropboxusercontent.com/s_60F65572AD72324D98DCC346F2D121B874DEF30FB11472356AAF47A21AF5D8EC_1667837287554_Screenshot+from+2022-11-07+17-04-23.png)


In my app folder, we need to create a component folder, the folder will hold every component of our web app.
We’ll be creating files

- Header.js
- post.js
- uploadwidget.js

In our `Header.js` file, we’re going to build a navigation bar and button that handles our authentication upon signing into the app for us to render in the `pages/index.js`.

```javascript
 import { useSession, signIn, signOut } from "next-auth/react";
    import Link from "next/link";
    export default function Header() {
      const handleSignin = (e) => {
        e.preventDefault();
        signIn();
      };
      const handleSignout = (e) => {
        e.preventDefault();
        signOut();
      };
      const { data: session } = useSession();
      return (
        <div className="header">
          <Link href="/">
            <a className="logo">FlauntSpace</a>
          </Link>
          {session && (
            <a href="#" onClick={handleSignout} className="btn-signin">
              SIGN OUT
            </a>
          )}
          {!session && (
            <a href="#" onClick={handleSignin} className="btn-signin">
              SIGN IN
            </a>
          )}
        </div>
      );
    }

```
We imported the next link and the next-auth for it to handle authentication using third-party (GitHub, google) while we did this, the next auth library gives us the functionality to handle the signing.

Now, we open up our `pages/index.js` and clear the default code that makes us thinker

```javascript
import { useSession } from "next-auth/react";
    
   export default function Home() {
     const { data: session, status } = useSession();
     const loading = status === "loading";
    
     return (
        <>
          <div className={styles.container}>
            <Head>
              <title>FlauntSpace</title>
              <link rel="icon" href="/favicon.ico" />
            </Head>
            <Header />
          </div>
      </>
      )
    }

```
We have to style our code to beautify it for a better interface and experience. The next package gives the default `styles/global.css`

```css
html,
body {
 padding: 0;
 margin: 0;
 background-color: #2d3436;
 font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
 }
 a {
  color: inherit;
  ext-decoration: none;
 }
    * {
      box-sizing: border-box;
    }
    .header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      background-color: rgb(110, 90, 90);
      color: #fff;
      padding: 0 2rem;
      width: 100%;
        box-shadow: 0 10px 20px rgba(82, 71, 71, 0.19), 0 6px 6px rgba(0,0,0,0.23);
    }
    .logo {
      font-weight: 800;
      color: #fff;
      font-size: 1.8rem;
      font-style: oblique;
    }
    .btn-signin {
       box-sizing: border-box;
      -webkit-appearance: none;
         -moz-appearance: none;
              appearance: none;
      background-color: #000;;
      outline: none;
      border: 0;
      cursor: pointer;
      display: -webkit-box;
      display: flex;
      align-self: center;
      font-size: 1.2rem;
      line-height: 1;
      margin: 20px;
      font-weight: 700;
      padding: 1.2rem;
        width: 14rem;
        text-align: center;
        display: flex;
        align-items: center;
        justify-content: center;
      text-align: center;
      font-family: inherit;
      user-select: none;
      color: #000;
      background-color: #353430;  
    }
    .btn-signin:hover {
      background-color: #353430;
      color: #000;  
    }

```
We’d use this CSS code snippet.
Moving forward that we create our authentication to go into our app profile, and we’re using GitHub and google authentication to bypass this phase. 
To create a GitHub client Id and secret key

https://www.knowband.com/blog/user-manual/get-github-client-id-client-secret-api-details/


We’d do the same to google authentication.
https://developers.google.com/adwords/api/docs/guides/authentication

Now we will be creating our `.env` file in our app, this is for us not to reveal our security keys to users 
Our `.env` file should look like this after following the procedure on
https://next-auth.js.org/providers/github

```javascript
GOOGLE_ID=<your googleID generated>
GOOGLE_SECRET=<secret key generated by google>
GITHUB_ID=<githubID>
GITHUB_SECRET=<AUTHENTICATION SECRETKEY BY GITHUB USING THE ACTION>
NEXTAUTH_URL=http://localhost:3000

```

In the `pages/api/auth/…nextauth.js` file, import the generated authentication from Google and GitHub for our application to interact with API.

```javascript
    import NextAuth from "next-auth";
    import GitHubProvider from "next-auth/providers/github";
    import GoogleProvider from "next-auth/providers/google";
    const options = {
      providers: [
        GitHubProvider({
          clientId: process.env.GITHUB_ID,
          clientSecret: process.env.GITHUB_SECRET,
          authorization: { params: { scope: "notifications" } },
        }),
        GoogleProvider({
          clientId: process.env.GOOGLE_ID,
          clientSecret: process.env.GOOGLE_SECRET,
          authorization: {
            params: {
              scope: "notifications",
            },
          },
        }),
      ],
    };
 export default (req, res) => NextAuth(req, res, options);

```
We’ve securely added our authentication and it should allow our app to be displayed when authentication is passed
In our app, we’re to have a display that lets users upload a profile picture and they can also post a mini blog. 

Create a `post.js` file in our components folder that takes in a text area and post button to allow users to post content

```javascript
    import { useState } from "react";
    import styles from "../styles/Home.module.css";
    export function Post() {
      return (
        <form action="api/form" method="post">
          <label htmlFor="body-content" className={styles.flauntText}>
            Flaunt
          </label>
          <textarea rows="4" cols="50" className={styles.bodyText}>
            Enter text here...
          </textarea>
          <br />
          <button type="submit" className={styles.postbut}>
            Post
          </button>
        </form>
      );
    }
   
``` 
Also, we’d create `uploadWidget.js` in the components.

```javascript
 import { useState } from "react";
    import styles from "../styles/Home.module.css";
    export function ImageUpload() {
      const [isImageUploaded, setIsImageUploaded] = useState(false);
      async function handleWidgetClick() {
        const widget = window.cloudinary.createUploadWidget(
          {
            cloudName: "dhpp7gaty",
            uploadPreset: "my upload",
            resourceType: "image",
          },
          (error, result) => {
            if (!error && result && result.event === "success") {
              console.log("Done! Here is the image info: ", result.info);
              setIsImageUploaded(true);
            } else if (error) {
              console.log(error);
            }
          }
        );
        widget.open();
      }
      return (
        <div className={styles.container}>
          <div className={styles.vertical}>
            <button
              className={styles.button}
              type="button"
              onClick={handleWidgetClick}
            >
              Upload image
            </button>
          </div>
          {isImageUploaded ? (
            <>
              <div>Successfully uploaded</div>
            </>
          ) : null}
        </div>
      );
    }


```
   
We have our upload button is working using cloudinary upload widget.
https://cloudinary.com/documentation/upload_widget and now we’ll be styling our app.
Let’s create `Home.module.css` file in the styles folder and we should use this snippet.

```css
    @import url('https://fonts.googleapis.com/css2?family=Island+Moments&display=swap');
    .container {
      min-height: 10vh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    .main {
     
    }
    .title {
      border-radius: 50%
    }
    .profile {
      grid-column: 2;
      grid-row: 2;
      background-color: #eef6f8;
    }
    .content {
      display: grid;
      grid-column: 1/3;
      grid-row: 1;
    }
    .uploadsec {
      grid-column: 1;
      grid-row: 2;
      background-color: #ccc;
    }
    .profileimg {
      border-radius: 50%;
    }
    
    
    .avatar {
      flex: 1;
      flex-basis: 250px;
    }
    .details {
      flex: 2;
    }
    .button {
      background-color: #449a79; /* Green */
      border-radius: 10px;
      border: none;
      color: white;
      padding: 15px 32px;
      text-align: center;
      cursor: pointer;
      text-decoration: none;
      display: inline-block;
      font-size: 16px;
    }
    .bodyText {
      width: 100%;
      height: 150px;
      padding: 12px 20px;
      box-sizing: border-box;
      border: 2px solid #ccc;
      border-radius: 4px;
      background-color: #f8f8f8;
      resize: none;
    }
    .post {
      align-items: center;
      justify-content: center;
      display: flex;
    }
    .flauntText {
      font-family: 'Island Moments', cursive;
      font-weight: bold;
      font-size: 40px;
    }
    .postbut {
      background-color: #449a79; /* Green */
      border-radius: 10px;
      border: none;
      color: white;
      padding: 15px 30px;
      text-align: center;
      cursor: pointer;
      text-decoration: none;
      display: inline-block;
      font-size: 16px;  
    }
    .imageCloud {
      /*border: 5px solid #555;*/
      border-radius: 50%;
      display: inline-block;
      justify-content: center;
      align-items: center;
      width: 100px;
      border: 3px solid black;
    }

```

Now we have to render all those components on `pages/index.js` file
```javascript
import Head from "next/head";
import Header from "../components/Header";
import styles from "../styles/Home.module.css";
import { useSession } from "next-auth/react";
import { ImageUpload } from "../components/uploadWidget";
import { Post } from "../components/post";
import { getXataClient, XataClient } from "../src/xata";

export default function Home() {
  const { data: session, status } = useSession();
  const loading = status === "loading";
  // const [url, updateUrl] = useState();
  // const [error, updateError] = useState();

  return (
    <>
      <div className={styles.container}>
        <Head>
          <title>FlauntSpace</title>
          <link rel="icon" href="/favicon.ico" />
        </Head>
        <Header />
      </div>
      <main className={styles.main}>
        <div className={styles.user}>
          {loading && <div className={styles.title}>Loading...</div>}{" "}
          {/*authentication process */}
          {/**Renders the home page after authentication passed of third-party */}
          {session && (
            <div className={styles.content}>
              <div className={styles.profile}>
                <>
                  <p>
                    You're logged in as
                    {/**Get's the name and mail from the third-party nextauth and display it as the user name on the home page */}
                    {session.user.name ?? session.user.email}
                  </p>
                  {/**SPLIT spage to two section where one is for the upload preset and the other is for posting blog post */}
                  <form className={styles.post}>
                    <Post />
                  </form>
                </>
              </div>
              <div className={styles.uploadsec}>
                <img
                  src="https://res.cloudinary.com/dhpp7gaty/image/upload/v1667560004/Profile-uploads/jnbkgndxzlnhapxv8eed.jpg"
                  alt="upload here"
                  className={styles.imageCloud}
                />
                <ImageUpload />
              </div>
            </div>
          )}
        </div>
      </main>
    </>
  );
}
```

##Building a Backend with Xata

A quick tour of how xata works on the video.


https://www.youtube.com/watch?v=-KNRS2fIWdA&


https://youtu.be/-KNRS2fIWdA

Initializing the xata our project making it auto-generate the code into an `src` file either in javascript or typescript.

```
 xata init
```
Now,let's import xata into our `pages/index.js`

```javascript
import Head from "next/head";
import Header from "../components/Header";
import styles from "../styles/Home.module.css";
import { useSession } from "next-auth/react";
import { ImageUpload } from "../components/uploadWidget";
import { Post } from "../components/post";
import { getXataClient, XataClient } from "../src/xata";

export default function Home() {
  const { data: session, status } = useSession();
  const loading = status === "loading";

  return (
    <>
      <div className={styles.container}>
        <Head>
          <title>FlauntSpace</title>
          <link rel="icon" href="/favicon.ico" />
        </Head>
        <Header />
      </div>
      <main className={styles.main}>
        <div className={styles.user}>
          {loading && <div className={styles.title}>Loading...</div>}{" "}
          {/*authentication process */}
          {/**Renders the home page after authentication passed of third-party */}
          {session && (
            <div className={styles.content}>
              <div className={styles.profile}>
                <>
                  <p>
                    You're logged in as
                    {/**Get's the name and mail from the third-party nextauth and display it as the user name on the home page */}
                    {session.user.name ?? session.user.email}
                  </p>
                  {/**SPLIT spage to two section where one is for the upload preset and the other is for posting blog post */}
                  <form className={styles.post}>
                    <Post />
                  </form>
                </>
              </div>
              <div className={styles.uploadsec}>
                <img
                  src="https://res.cloudinary.com/dhpp7gaty/image/upload/v1667560004/Profile-uploads/jnbkgndxzlnhapxv8eed.jpg"
                  alt="upload here"
                  className={styles.imageCloud}
                />
                <ImageUpload />
              </div>
            </div>
          )}
        </div>
      </main>
    </>
  );
}
{
  /**Connecting the xata to our app */
}
const xata = new XataClient();
export const getServerSideProps = async () => {
  const FlauntSpace = await xata.db.items.getAll();
  return {
    props: {
      FlauntSpace,
    },
  };
};

```
We successfully connected our database of xata to the front-end application and more functionality is querying data from our database to render it on the front-end.

> N:B This article intend to add more functionality and would be edited as soon as the changes are made.