Rendering a Page
Tags: gatsby, testing, typescript
Published: 2020-06-13 15:19:45

In [Part II](https://dev.to/_lexedwards/writing-the-first-test-component-5h1o) I covered the prototyping and implementation of writing components, today I'm going to cover how to create Pages from Contentful.

For this, I had to learn precisely how Contentful manages its database-style CMS, how the source plugin pulls information, and how base to utilise it.

My thoughts behind the difference between Page and Template are quite simple:

__A Page__ is purpose-built and has no ambiguity to what is displayed. Meaning a unique [content-model](https://www.contentful.com/developers/docs/concepts/data-model/) for each and every page. __A Template__ however, has to be generalised by design. A Template for my posts may include many different elements, components even, but I'll get onto that later. Likewise, some fields might be optional, but the key aspects need to be assured requirements. That might include elements such as a unique slug, or a publish date modifiable by the user.

## The Model

![Screenshot of a Page Content Model](//images.ctfassets.net/c6pc38xsagw4/1Yxiio6iGAmF3Dh7eQIGB4/b6dc550eb55a11431d4712e4db357ed4/Screen_Shot_2020-06-12_at_15.32.20.png)

'Top Level Page?' and Index came around because of a need in the code rather than instinct. Contentful generates its Indexes with UUID on every field; however, if it's a top-level page (think like a site map), then you would want to give it an index of importance.

The other two exciting fields are Meta and Blocks. Meta is another content model that exists globally. Ensuring that all content has the right information, and unique where needed, making sure things like publishing dates are correct, and slugs don't override each other.

Page Blocks are the unique aspect for every page. A new content model needed for every page.

![Homepage Content Model Block](//images.ctfassets.net/c6pc38xsagw4/6vXxwEHf4yKOltiHJ9HOKz/c2d74c0a65016c1b58c4c40cfeff0c41/Screen_Shot_2020-06-12_at_15.45.27.png)

My homepage needs nothing more than a greeting, subtext and a little about myself, which I'll include in my Author Bio; which in turn also houses all my social links and ways to contact me. 

Okay, so now the content model is established.

## The Code

Removing all the trailing curly-brackets, this is what I'm querying for:

```graphql
query Homepage {
  page: contentfulPage(title: {regex: "/homepage/i"}) {
    title
    blocks {
      ... on ContentfulPageHome {
        title
        subTitle
        authorBio {
          blurbTitle
          blurbDesc {
            blurbDesc
          }
          blurbLead
```

For simplicity, I've removed some styling choices, but this is what it rendered as in my TSX file:

```tsx
interface Props {
  data: PageHome
}

const IndexPage = ({ data } : Props) => {
  const blocks = data.page.blocks;
  const subBlack = blocks.subTitle?.split(' ').slice(0, 4).join(' ')
  const subColor = blocks.subTitle?.split(' ').slice(4).join(' ')
  return (
    <>
      <div>
        <h1>{blocks.title}✌️</h1>
        <h5>{subBlack} <span>{subColor}</span></h5>
      </div>

      <div>
        <div>
          <img />
        </div>

        <div>
          <h2>{blocks.authorBio.blurbTitle}</h2>
          <p>{blocks.authorBio.blurbDesc?blurbDesc}</p>
        </div>
      </div>
    </>
  )
}
```

Components with page queries necessarily have two elements to the file, the query variable, then the functional component that Gatsby passes the query into, via the `data` prop. Using Typescript, that data has an interface; otherwise, the TS Compiler will throw a hissy-fit. Typescript can get extensive, yet gives you complete confidence what elements are present, optional, and otherwise.

```ts
interface PageHome extends Page {
  blocks: HomeBlocks
}

interface HomeBlocks {
  title: string
  subTitle?: string
  authorBio: Bio
}
```

Some bits are missing here, such as the `Page` & `Bio` interfaces. However, each unique 'block' takes the original 'Page' with all the common elements and adds additional types where needed. Per the content model, subTitle hasn't deemed it as a requirement, so both interface and component need to cover that.

The next step is tricky, so I'll be covering that in its post; How I implemented rendering assistants to display typography, hyperlinks, and images into the code.

---

This post is an ongoing series along with my site development. All current process on my [website](https://alexedwards.co) and in the [open-source repo](https://github.com/lexedwards/alexedwards-co) is open for review. As I publish new features (Posts and Projects templates, changes in style), I'll continue to add to this series as a reflection of what I've learnt, and what reflections I have on the process.