Query multiple documents inside home page

Hello, I'm building a course platform using Primsic with Slice Machine, Next JS and GraphQL. I have two questions, the first one regarding my approach on content modeling and the other on querying data from other document inside the home page.

I plan to display a two level Mega Menu where people will be able to filter the courses first by Scholarly (elementary school, secondary school, high school, uni) and then, on the second level by grade/semester. Finally this will result on a list of filtered courses.

My current approach for this (not sure if the best one) was to create a Course custom type where I can add all the information for the course including a multi select for level and grade. Then I fetch all the documents and use JavaScript to do the filtering part. This way whenever someone adds a new course it will be added to the Course Mega Menu.

My first question is if it makes sense to use a multi select filed in the Course custom type rather than making a relationship field. And in the case a relationship is the way to go, how would that look?

My second question is regarding the use of slices on the home page and how to query the data.

I was able to make the Mega Menu work using this code to get all the documents:

export async function getStaticProps({ params }) {
  const client = Client()

  const courses = await client.query(
    Prismic.Predicates.at('document.type', 'curso')
  )

  return {
    props: {
      courses: courses.results,
    },
  }
}

However this was done in a separate Next Page called Courses. I would like it to be a separate component to be able to drop in inside the pages/couses.js and pages/index.js

This is how my index.js currently looks.

export default function Home(props) {
  return <SliceZone {...props} resolver={resolver} />
}

// Fetch content from prismic
export const getStaticProps = useGetStaticProps({
  client: Client(),
  type: 'home-page',
  queryType: 'single',
})

For the Courses Component I planned to pass all the courses as props but can't figure out how to fetch all the courses documents as well as the slices for the homepage.

I tried doing the fetch like this

export async function getAllHome() {
  const data = await fetchAPI(`
    {
      homePage(uid: "homepage", lang: "es-mx") {
        slices {
          __typename
        }
      }
      allCursos {
        edges {
          node {
            title
            description
            grade
            level
          }
        }
      }
    }
  `)

  return {
    cursos: { ...data?.allCursos?.edges },
    home: { ...data?.homePage?.slices },
  }
}

But I'm not sure if that is the right way to do it and couldn't figure out how to pass the home slices to the <SliceZone {...props} resolver={resolver} /> Component since the only thing that comes back for the homePage is this:

"homePage": {
      "slices": [
        {
          "__typename": "HomePageSlicesBanner_slice"
        },
        {
          "__typename": "HomePageSlicesCourse_menu"
        }
      ]
    },

Another strange thing is that when fetching the courses I'm not able to get a field property called shortTitle, this property is there when using Prismic.Predicates.at('document.type', 'curso') to get the documents.

Bonus question:

Since my Couses component is currently not a slice I'm not sure how to insert it between all the homePage slices. My current approach was to create a simple Courses slice with only a title and the drop my custom courses component inside of it, seems a bit hacky tho...

Sorry for the super long post that ended being 3 questions in one :sweat_smile: Thank you in advance!

Hey @jprzpam,

Welcome to the Prismic community, and thanks for posting this question! I'm going to try to answer one thing at a time.

Content Modeling

If you basically want to create a "tag" or category" field, you can see some information on how to do that with Content Relationships, here:

The main benefit of doing it with a Content Relationship is that you can have a document for each level and grade, so you can add content and metadata, like a title, description, image, etc. However, I don't see any problem with doing that with a multi-select.

Fetching

To fetch the homepage Slices plus all of the Course documents, you might use a GraphQuery like this:

query{
  allHomepages {
    pageInfo {
      startCursor
      endCursor
    } 
    edges {
      node {
        body {
          ... on HomepageBanner {
            primary {
              image
              text
            }
          }
          ... on HomepageEmbed {
            primary {
              embed
            }
          }
        }
      }
    }
  }
  allArticles {
    edges {
      node {
        title
        meta_description
      }
    }
  }
}

You can also do this with the Rest API. Here's some info on how to perform multiple queries with useGetStaticProps:

Courses Slice

Your solution for the Courses Slice actually sounds okay to me! But let me know if it's creating any problems.

Let me know if this helps, or if I missed any of your questions.

Sam

Hi @samlittlefair! Thank you for your help. I might stick with the multi select for now :wink:

I did this to fetch the HomePage Slices and the course documents

export default function Home({ homepage }) {
  return <SliceZone {...homepage} resolver={resolver} />
}

export const getStaticProps = async (...args) => {
  // Same useGetStaticProps call
  const homepage = await useGetStaticProps({
    client: Client(),
    type: 'home-page',
    queryType: 'single',
  })(...args)

  // Query for courses data
  const courses = await getAllCourses()

  return {
    props: {
      homepage: homepage.props,
      courses,
    },
  }
}

but I'm unsure on how to pass the props to the CourseSlice slice to use on the Course Component. I also tried to pass the props like this to the SliceZone

return <SliceZone {...props} resolver={resolver} />

but when I do that I get Your SliceZone is empty. displayed on the screen.

I was also unable to complete the GraphQL query the way you suggested. There seems to not be a body property under node.

Looking forward to read what you think, wish you a nice day.

Hi @jprzpam,

Can you explain more about your project structure? Where are you using the SliceZone that is appearing empty?

Here are the docs on how to query Slices in GraphQL. Let me know if this helps you with building your query.

Sam

This is my project structure:

components/shared/CourseSelect ➜ The component that will display the MegaMenu for the Courses.

pages/index ➜ Here I show the HomePage custom type and plan to fetch all the courses and send them as props to CouseSelect Component. This file looks like this:

export default function Home({ homepage }) {
  return <SliceZone {...homepage} resolver={resolver} />
}

export const getStaticProps = async (...args) => {
  // Same useGetStaticProps call
  const homepage = await useGetStaticProps({
    client: Client(),
    type: 'home-page',
    queryType: 'single',
  })(...args)
  console.log('homepage', homepage)

  // Query for courses data
  const courses = await getAllCourses()

  return {
    props: {
      homepage: homepage.props,
      courses,
    },
  }
}

The home page will have several slices like Banner, Services, Contact, and I added the CouseMenu that only has a title and description property. I plan to then use the CourseSelect component to add the interactivity and still be able to add to the homepage as a slice. For that I need a way to pass props from the index page to the CourseMenu and then pass the props down to the CurseSelect component.

This is how my CourseMenu currently looks like.

import React from 'react'
import { RichText } from 'prismic-reactjs'
import CourseSelect from '../../components/shared/CourseSelect'

function CourseMenu({ slice }) {
  return (
    <section>
      <span className="title">
        {slice.primary.title ? (
          <RichText render={slice.primary.title} />
        ) : (
          <h2>Template slice, update me!</h2>
        )}
      </span>
      {slice.primary.description ? (
        <RichText render={slice.primary.description} />
      ) : (
        <p>start by editing this slice from inside Prismic builder!</p>
      )}

      {/* use course props here */}
      <CourseSelect />

    </section>
  )
}

export default CourseMenu

and I would expect to do something like this:

function CourseMenu({ slice, courses }) {
  return (
   .
   .
   .
    <CourseSelect courses={ courses } />
   .
   .
  )
}

Hi Juan,

This helps a lot. Thanks for explaining. I think you should be able to accomplish what you want using the Slice Zone's sliceProps prop. More info here.

Let me know if that helps.

Sam

Hi Sam, thank you for the help! I think what you shared should help me pass props to the specific component. However I'm still unsure on how to get both; the slices and the CourseSlice props in one query.

As I said before I tried fetching like this:

export default function Home({ homepage }) {
  return <SliceZone {...homepage} resolver={resolver} />
}

export const getStaticProps = async (...args) => {
  // Same useGetStaticProps call
  const homepage = await useGetStaticProps({
    client: Client(),
    type: 'home-page',
    queryType: 'single',
  })(...args)

  // Query for courses data
  const courses = await getAllCourses()

  return {
    props: {
      homepage: homepage.props,
      courses,
    },
  }
}

and pass the props like this

return <SliceZone {...props} resolver={resolver} />

but when I do that I get Your SliceZone is empty. displayed on the screen.

I am also unable to complete the GraphQL query the way you suggested. There seems to not be a body property under node. You can see a picture of what my GraphQL interface looks like when I try that query.

I'm sure I must be missing something foolish but can't figure it out to save my life! :sweat_smile:

Thanks again and looking forward to see what you think.

Hey @jprzpam,

I see that you're spreading your props to the SliceZone component. Instead, trying passing the body property from the homepage argument to the slice prop of the SliceZone and your sliceProps separately.

<SliceZone resolver={resolver} sliceProps={courses} slices={homepage.data.body} />

Let me know if that helps :slight_smile:

Sam

Hey @samlittlefair,

That seems to have done it! Thank you so much for your help!

I only have one question left regarding this matter and is about the graphQL query. You mentioned earlier on this thread that I could use a GraphQuery like this to fetch slices plus documents:

query{
  allHomepages {
    pageInfo {
      startCursor
      endCursor
    } 
    edges {
      node {
        body {
          ... on HomepageBanner {
            primary {
              image
              text
            }
          }
          ... on HomepageEmbed {
            primary {
              embed
            }
          }
        }
      }
    }
  }
  allArticles {
    edges {
      node {
        title
        meta_description
      }
    }
  }
}

however the property body under node never seems to be available, even for other documents. Any idea on why?

Thank you!

Hi @jprzpam,

That's great! I'm glad it's working. I can try to look at your GraphQL API to see if I can figure out the syntax. Can you let me know your repo name? (You can send it in a DM if you don't want to share it publicly.)

Sam