rsnext/examples/cms-agilitycms/lib/api.ts
Max Proske e955850dd4
Convert cms-agilitycms example to TypeScript (#38976)
Converted `cms-agilitycms` example to TypeScript to match Contribution docs.

## Documentation / Examples

- [X] Make sure the linting passes by running `pnpm lint`
- [X] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
2022-07-27 19:24:54 +00:00

207 lines
5.5 KiB
TypeScript

import agility from '@agility/content-fetch'
import { CMS_LANG, CMS_CHANNEL } from './constants'
import { asyncForEach } from './utils'
export { validatePreview } from './preview'
import { normalizePosts } from './normalize'
import { requireComponentDependancyByName } from './dependancies'
// Our LIVE API client
const liveClient = agility.getApi({
guid: process.env.AGILITY_CMS_GUID,
apiKey: process.env.AGILITY_CMS_API_FETCH_KEY,
})
// Our PREVIEW API client
const previewClient = agility.getApi({
guid: process.env.AGILITY_CMS_GUID,
apiKey: process.env.AGILITY_CMS_API_PREVIEW_KEY,
isPreview: true,
})
export const getClient = (preview = false) =>
preview ? previewClient : liveClient
// This client is used by nested components to fetch additional data within `getStaticProps`
export class APIClient {
public preview: any
public client: any
constructor({ preview = false }) {
this.preview = preview
this.client = getClient(preview)
}
async getAllPosts(take) {
const data = await this.client.getContentList({
referenceName: `posts`,
languageCode: CMS_LANG,
contentLinkDepth: 1,
take: take, // TODO: Implement pagination
})
return data.items
}
async getLatestPost() {
const data = await this.getAllPosts(1)
const normalizedPosts = normalizePosts(data)
return normalizedPosts[0] || null
}
async getPostDetails({ contentID, preview }) {
const post = await this.client.getContentItem({
contentID,
languageCode: CMS_LANG,
contentLinkDepth: 1,
})
const normalizedPost = normalizePosts([post])[0]
return normalizedPost
}
async getPostsForMoreStories({ postToExcludeContentID }) {
let allPosts = await this.getAllPosts(5)
//if we don't have a post to exclude, assume we should exclude the latest one
if (postToExcludeContentID < 0) {
allPosts.shift()
}
const postsLessThisPost = allPosts.filter((p) => {
return p.contentID !== postToExcludeContentID
})
const normalizedMorePosts = normalizePosts(postsLessThisPost)
return normalizedMorePosts
}
}
export async function getAgilityPaths() {
console.log(`Agility CMS => Fetching sitemap for getAgilityPaths...`)
const sitemapFlat = await getClient().getSitemapFlat({
channelName: CMS_CHANNEL,
languageCode: CMS_LANG,
})
//returns an array of paths as a string (i.e. ['/home', '/posts']
//skips folders...
const paths = Object.keys(sitemapFlat)
.filter((s) => sitemapFlat[s].isFolder !== true)
.map((s) => {
return s
})
return paths
}
export async function getAgilityPageProps({ params, preview }) {
//determine if we are in preview mode
const client = getClient(preview)
let path = '/'
if (params) {
//build path by iterating through slugs
path = ''
params.slug.forEach((slug) => {
path += '/' + slug
})
}
console.log(`Agility CMS => Getting page props for '${path}'...`)
//get sitemap
const sitemap = await client.getSitemapFlat({
channelName: CMS_CHANNEL,
languageCode: CMS_LANG,
})
let pageInSitemap = sitemap[path]
let page = null
if (path === '/') {
let firstPagePathInSitemap = Object.keys(sitemap)[0]
pageInSitemap = sitemap[firstPagePathInSitemap]
}
if (pageInSitemap) {
//get the page
page = await client.getPage({
pageID: pageInSitemap.pageID,
languageCode: CMS_LANG,
contentLinkDepth: 1,
})
} else {
//Could not find page
console.error('page [' + path + '] not found in sitemap.')
return
}
if (!page) {
console.error('page [' + path + '] not found in getpage method.')
return
}
//resolve the page template
let pageTemplateName = page.templateName.replace(/[^0-9a-zA-Z]/g, '')
//resolve the modules per content zone
await asyncForEach(Object.keys(page.zones), async (zoneName) => {
let modules = []
//grab the modules for this content zone
const modulesForThisContentZone = page.zones[zoneName]
//loop through the zone's modules
await asyncForEach(modulesForThisContentZone, async (moduleItem) => {
let ModuleComponentToRender = requireComponentDependancyByName(
moduleItem.module
)
if (ModuleComponentToRender) {
//resolve any additional data for the modules
let moduleData = null
if (ModuleComponentToRender.getCustomInitialProps) {
//we have some additional data in the module we'll need, execute that method now, so it can be included in SSG
console.log(
`Agility CMS => Fetching additional data via getCustomInitialProps for ${moduleItem.module}...`
)
moduleData = await ModuleComponentToRender.getCustomInitialProps({
client: new APIClient({ preview }),
item: moduleItem.item,
languageCode: CMS_LANG,
channelName: CMS_CHANNEL,
pageInSitemap: pageInSitemap,
})
}
//if we have additional module data, then overwrite our props that will be sent to the module
if (moduleData != null) {
moduleItem.item = moduleData
}
modules.push({
moduleName: moduleItem.module,
item: moduleItem.item,
})
} else {
console.error(
`No react component found for the module "${moduleItem.module}". Cannot render module.`
)
}
})
//store as dictionary
page.zones[zoneName] = modules
})
return {
sitemapNode: pageInSitemap,
page: page,
pageTemplateName: pageTemplateName,
languageCode: CMS_LANG,
channelName: CMS_CHANNEL,
}
}