# Building A Frontend

We've got the contract setup and use [Chainlink Functions](https://functions.chain.link/) to pull in the latest news article. We can see the titles, links, and dates published in Remix. That's awesome but not super user-friendly. Let's add a simplistic front end to present this data.&#x20;

### 🚀 Initiate Liftoff

{% hint style="success" %}
All of the code for this project can be found on [GitHub](https://github.com/smartcontractkit/workshop-distributed-news)
{% endhint %}

We'll be using [Astro](https://astro.build) to build out the frontend. Let's create a skeleton project.

`npm create astro@latest`

<figure><img src="https://3055332972-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoLxCy1ScGXQTXyBRI4Zu%2Fuploads%2FQ77GS25fldDR4K9UGIoq%2FCleanShot%202023-11-10%20at%2009.42.14%203%402x.png?alt=media&#x26;token=7938e6b5-8f6f-4843-abb5-c793aca9944c" alt=""><figcaption></figcaption></figure>

Head to `cd ./distributed-news` and run `npm run dev`. You should now be able to access Astro at <http://localhost:4321>, if you visit that site, **Astro** should greet you. The basics are in place.&#x20;

### Read From The Blockchain

To read our data from the smart contract we deployed, we'll need to create 2 files. To do that, we must install a few NPM packages first. If your server is running, stop it with `Ctrl-C`, and run&#x20;

```
npm install ethers dotenv node-fetch jsdom
```

to add them to our project. Now, we can move to creating our files.&#x20;

&#x20;First, we'll get the ABI (Application Binary Interface) from Remix. This will allow `ethers.js` to know how to interact with our contract. To find the ABI, head back to [Remix](https://remix.ethereum.org/).

Under the compiler tab, look for the copy ABI button at the bottom.&#x20;

<figure><img src="https://3055332972-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoLxCy1ScGXQTXyBRI4Zu%2Fuploads%2FtEkl0UOc3EohheHttHn7%2FCleanShot%202023-11-10%20at%2009.56.39%402x.png?alt=media&#x26;token=2d74ca4e-b444-451d-9292-ebec220f8df9" alt="" width="375"><figcaption></figcaption></figure>

Once you've copied the code, head to your code editor, create a new file, `distributed-news/src/lib/newsArchiveABI.json`, and paste the ABI.

Next, we'll need to create the script to pull the data off the blockchain. Create a new file, `distributed-news/src/lib/newsArchive.js` and add the following code.

```javascript
// Import necessary modules from ethers library
import { ethers, JsonRpcProvider } from "ethers";
// Import the dotenv module to load environment variables
import { config } from "dotenv";

// Import the ABI of the NewsArchive contract
import NewsArchiveABI from "./newsArchiveABI.json";

// Load environment variables from .env file
config();

// Get provider URL and contract address from environment variables
const providerUrl = process.env.PROVIDER_URL;
const contractAddress = process.env.CONTRACT_ADDRESS;

// Create a new JSON-RPC provider
const provider = new JsonRpcProvider(providerUrl);

// Create a new contract instance with the NewsArchive ABI
const newsArchiveContract = new ethers.Contract(
  contractAddress,
  NewsArchiveABI,
  provider
);

// Define an async function to get all articles from the contract
async function getAllArticles() {
  try {
    // Call the getAllArticles function of the contract
    const articles = await newsArchiveContract.getAllArticles();
    // Return the articles
    return articles;
  } catch (error) {
    // Log the error and return an empty array
    console.error("Error fetching articles:", error);
    return [];
  }
}

// Export the getAllArticles function as the default export
export default getAllArticles;
```

### Environment Variables

You may have noticed that we are using `dotenv` to load values for `PROVIDER_URL` and `CONTRACT_ADDRESS`, you'll need to create `distributed-news/.env` to house those values. Be sure to replace the value for `CONTRACT_ADDRESS` with the contract address you deployed.&#x20;

```dotenv
# RPC for sepolia
PROVIDER_URL="https://rpc.sepolia.org"
CONTRACT_ADDRESS="YOUR_CONTRACT_ADDRESS"
```

### Displaying The Results

One last step! We are almost there. We need to update `distributed-news/src/pages/index.astro` to display the articles we've saved.&#x20;

First, let's update the frontmatter.&#x20;

```javascript
---
import fetch from "node-fetch";
import { JSDOM } from "jsdom";
// Import the getAllArticles function from the newsArchive.js file
import getAllArticles from "../lib/newsArchive.js";

// Initialize articles variable and error flag
let articles;
let errorOccurred = false;

try {
  // Try to fetch all articles
  articles = await getAllArticles();
} catch (error) {
  // If an error occurs, log it and set the error flag
  console.error("Failed to get articles:", error);
  articles = [];
  errorOccurred = true;
}
async function fetchOGData(url) {
  try {
    const response = await fetch(url);
    const html = await response.text();
    const dom = new JSDOM(html);
    const doc = dom.window.document;
    let ogTitle =
      doc.querySelector('meta[property="og:title"]')?.content || url;
    const ogImage = doc.querySelector('meta[property="og:image"]')?.content;
    return { ogTitle, ogImage, url };
  } catch (error) {
    console.error("Error fetching OG data:", error);
    return { ogTitle: "No title", ogImage: "No image", url };
  }
}

async function articlesWithOGData(articles) {
  return await Promise.all(articles.map(fetchOGData));
}
let allArticles = await articlesWithOGData(articles);
---
```

Once that's updated we can use the variable `articles` to display them in the browser.\
We'll setup a conditional rendering block to check for any errors and if there are none, display the articles.&#x20;

```javascript
<html>
  <body>
    <h1>News Articles</h1>
    {
      // If an error occurred, display an error message
      // Otherwise, display the list of articles
      errorOccurred ? (
        <p>Sorry, we're unable to fetch articles at the moment.</p>
      ) : (
        <ul>
          {allArticles.map((article) => (
            <li>
              <article>
                <a href={article.url}>
                  <h2>{article?.ogTitle}</h2>
                </a>
                <img src={article?.ogImage} alt="" />
              </article>
            </li>
          ))}
        </ul>
      )
    }
  </body>
</html>
```

With these two changes you should see the results at <http://localhost:4321>\
Your front end should look something like this. \
![](https://3055332972-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoLxCy1ScGXQTXyBRI4Zu%2Fuploads%2Fxt6QQJpadiEN61M1IXOV%2FCleanShot%202023-12-06%20at%2018.21.13%402x.png?alt=media\&token=2715f550-c3eb-485d-a96f-96804a4398c9)

What it lacks in style, it makes up for in functionality.

### Add Some Style

You might be cringing at the lack of style, lets fix that and make things look just a little bit nicer.&#x20;

Below the `</html>` tag add in the following.&#x20;

```css
<style>
  body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
  }
  
  h1 {
    text-align: center;
  }
  
  ul {
    list-style-type: none;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    grid-gap: 20px;
  }
  
  article {
    background-color: #f4f4f4;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease;
  }
  
  article:hover {
    transform: translateY(-5px);
  }
  
  article a {
    text-decoration: none;
    color: #333;
  }
  
  article h2 {
    font-size: 18px;
    margin-top: 0;
  }
  
  article img {
    width: 100%;
    height: auto;
    border-radius: 4px;
    margin-top: 10px;
  }
</style>
```

Great, now, you've got some style!

### Congratulations!

Awesome! You've successfully deployed a smart contract using Chainlink Functions and connected it to a front end!&#x20;


---

# 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://cll-devrel.gitbook.io/javascript-for-blockchain-master-class/building-a-frontend.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.
