Hello @alex.trost ,
Thank you for coming back to me!
Basically, the component is a advanced Filter system, visibile here: Entry level data analyst - Dataaxy
So depending on the filters selected by the users, different jobs will be returned.
That is why we are currently doing the following:
A JobsListSlice slice, returns a Next.js component, JobsList.
JobsList calls a custom hook, useJobsQuery.
useJobsQuery makes an API call to /api/jobs to fetch the jobs data.
Are you saying that I should not call useJobsQuery in the component JobsList, but directly doing it at the page template level [uid].tsx, in it's getStaticProps?
Here are the different part of the codes:
JobsListSlice
import JobsList from '@/components/JobsList'
/**
* @typedef {import("@prismicio/client").Content.HowWeWorkSlice} HowWeWorkSlice
* @typedef {import("@prismicio/react").SliceComponentProps<HowWeWorkSlice>} HowWeWorkProps
* @param { HowWeWorkProps }
*/
const JobsListSlice = ({ slice }) => <JobsList slice={slice} />
export default JobsListSlice
JobsList.tsx:
import { useState } from 'react'
import { useRouter } from 'next/router'
import { useForm } from 'react-hook-form'
import useCollection from '@/hooks/useCollection'
import useJobsQuery from '@/hooks/useJobsQuery'
import BaseDataCollection from '@/components/common/BaseDataCollection'
import JobCard from '@/components/JobCard'
import Filters from '@/components/JobsFilters'
export default function JobsList({ slice }) {
const router = useRouter()
// this will be used to populate the filters and also refine the search
const defaultValues = {
search: slice.primary.prefiltered_terms,
location: slice.primary.prefiltered_terms_location,
keywords: slice.primary.prefiltered_terms
? [slice.primary.prefiltered_terms]
: []
}
const form = useForm({
defaultValues: {
search: defaultValues.search,
location: defaultValues.location
}
})
const [formExtra, setFormExtra] = useState({
keywords: defaultValues.keywords.map((value) => ({ value, label: value })),
remoteType: [],
seniorityLevels: [],
workType: []
})
const onBuildParams = ({ values }) => {
const { search } = values || null
const newParams = {
where: { status: 'active' },
page: Number(router.query.page ?? 1)
} as any
if (search && search.length > 0) {
newParams.where.title = { contains: search, mode: 'insensitive' }
// newParams.where.description = { contains: search, mode: 'insensitive' }
}
if (values.location) {
newParams.where.location = {
contains: values.location,
mode: 'insensitive'
}
}
if (values.seniorityLevels && values.seniorityLevels.length > 0) {
newParams.where.seniorityLevels = { hasSome: values.seniorityLevels }
}
if (values.remoteType && values.remoteType.length > 0) {
newParams.where.remoteType = { in: values.remoteType }
}
newParams.where.workType = { in: values.workType }
// if (values.keywords && values.keywords.length > 0) {
// newParams.where.keywords = {
// hasSome: values.keywords.map((keyword) => keyword.value)
// }
// }
return newParams
}
const {
data: collection,
handleClearFilters,
handlePagination,
handleSetFilters,
isFetching,
} = useCollection({
defaultValues,
onBuildParams,
useQuery: useJobsQuery
})
return (
<div className="container-constrained container-spacing mt-10">
<div className="grid grid-cols-1 md:grid-cols-3 md:gap-6">
<div>
<Filters
defaultValues={defaultValues}
form={form}
formExtra={formExtra}
onChange={handleSetFilters}
setFormExtra={setFormExtra}
/>
</div>
<div className="col-span-2">
<BaseDataCollection
Card={JobCard}
collection={collection}
handleClearFilters={handleClearFilters}
handlePagination={handlePagination}
isFetching={isFetching}
/>
</div>
</div>
</div>
)
}
useJobsQuery:
import { useQuery } from 'react-query'
import { useRouter } from 'next/router'
import apiService from '@/services/apiService'
export default function useJobsQuery({ params }) {
const router = useRouter()
return useQuery(
['jobs', params],
async () => {
return apiService.get('/api/jobs', {
params: {
...params,
page: router.query.page,
perPage: 12,
orderBy: { publicationDate: 'desc' },
include: { company: true }
}
})
},
{
enabled: router.isReady
}
)
}
The page template [uid].tsx:
import Head from 'next/head'
import { SliceZone } from '@prismicio/react'
import * as prismicH from '@prismicio/helpers'
import { createClient } from '@/prismicio'
import { components } from '@/slices'
import { useRouter } from 'next/router'
import getSimilarPages from '@/utils/getSimilarPages'
import Statistics from '@/components/Statistics'
import JobAlertsCtaBasic from '@/components/JobAlertsCtaBasic'
export default function Page({
metaTitle,
metaDescription,
ogImage,
slices,
similarPages
}) {
const router = useRouter()
const canonicalUrl = `https://dataaxy.com` + router.asPath
const ogUrl = canonicalUrl
const metaTitleCompleted = `${metaTitle} - Dataaxy`
return (
<>
<Head>
....
</Head>
<SliceZone
slices={slices}
components={components}
context={{ similarPages }}
/>
<Statistics />
<JobAlertsCtaBasic />
</>
)
}
export async function getStaticProps({ params, previewData }) {
const client = createClient({ previewData })
const page = await client.getByUID('pillar_page', params.uid)
const similarPages = await getSimilarPages({ client, page })
const slices = await Promise.all(
page.data.slices.map(async (slice) => {
if (
slice.slice_type === 'reusable_topic_info' &&
slice.primary.reusabletopic.id
) {
const topic = await client.getByID(slice.primary.reusabletopic.id)
slice.primary.reusabletopic = topic
return slice
}
return slice
})
)
return {
props: {
metaTitle: page.data.meta_title,
metaDescription: page.data.meta_description,
ogImage: page.data.og_image.url,
slices,
similarPages
}
}
}
export async function getStaticPaths() {
const client = createClient()
const pages = await client.getAllByType('pillar_page')
return {
paths: pages.map((page) => prismicH.asLink(page)),
fallback: false
}
}
Thanks for your help!