Skip to content

Commit

Permalink
feat: Multiple global content types (#2668)
Browse files Browse the repository at this point in the history
๐ŸŽ—๏ธ delete both content types in storeframework account after PR got
merged.
๐ŸŽ—๏ธ sync FS + hCMS in vtex account.

## What's the purpose of this pull request?

This pull request handles multiple global content types. Now the global
sections are expected to have:
`globalHeaderSections` and `globalFooterSections`.

## How it works?

Added `globalHeaderSections` and `globalFooterSections`
`globalHeaderSections` - injected before the Children section from
`globalSections` content type.
`globalHeaderFooter` - injected after the Children section from
`globalSections` content type.

All the pages now are fetching these content types if they exist and
merging all global sections.

## How to test it?

with the version of this PR in the starter: 

1. login in your account `vtex switch <account>`
2. if the account didn't have the `globalHeaderSections` and
`globalFooterSections` content types, sync the hCMS with the command:
`yarn cms-sync`. you can use the dry option `yarn cms-sync -d` (just for
tests before really sync).
3. in the hCMS, add the 2 new documents with sections using the new
content types `globalHeaderSections` and `globalFooterSections`.
4. make sure the sections are shown in the expected places:
`globalHeaderSections` before the Children and `globalFooterSections`
after the children.

hCMS
<img width="400" alt="Screenshot 2025-02-04 at 12 42 17"
src="https://github.com/user-attachments/assets/b30dc7cb-f507-4109-8065-7bb5c5d6aac3"
/>

| globalHeaderSections | globalFooterSections |
|--------|--------|
| <img width="1234" alt="Screenshot 2025-02-04 at 12 18 01"
src="https://github.com/user-attachments/assets/fc9bfae8-0f7d-4a1b-aae8-5293a4007518"
/> | <img width="1241" alt="Screenshot 2025-02-04 at 12 18 14"
src="https://github.com/user-attachments/assets/1c1f5a5b-9689-4667-ae12-2c8732521b59"
/> |

### Starters Deploy Preview

- vtex-sites/starter.store#680

you can check the section in this preview
https://storeframework-cm652ufll028lmgv665a6xv0g-isf4taa08.b.vtex.app/

## References

https://vtex.slack.com/archives/C02JMH9AYR1/p1738007781146059

---------

Co-authored-by: Larรญcia Mota <laricia.mota@vtex.com.br>
  • Loading branch information
eduardoformiga and lariciamota authored Feb 26, 2025
1 parent 1ef5f7a commit 8555310
Show file tree
Hide file tree
Showing 17 changed files with 473 additions and 80 deletions.
14 changes: 14 additions & 0 deletions packages/core/cms/faststore/content-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
"configurationSchemaSets": [],
"isSingleton": true
},
{
"id": "globalHeaderSections",
"name": "Global Header Sections",
"scopes": ["global"],
"configurationSchemaSets": [],
"isSingleton": true
},
{
"id": "globalFooterSections",
"name": "Global Footer Sections",
"scopes": ["global"],
"configurationSchemaSets": [],
"isSingleton": true
},
{
"id": "landingPage",
"name": "Landing Page",
Expand Down
35 changes: 28 additions & 7 deletions packages/core/src/components/cms/GlobalSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@ import storeConfig from 'discovery.config'
import { type PageContentType, getPage } from 'src/server/cms'

export const GLOBAL_SECTIONS_CONTENT_TYPE = 'globalSections'
export const GLOBAL_SECTIONS_HEADER_CONTENT_TYPE = 'globalHeaderSections'
export const GLOBAL_SECTIONS_FOOTER_CONTENT_TYPE = 'globalFooterSections'

export type GlobalSectionsData = {
sections: Section[]
}

export const getGlobalSectionsData = async (
previewData: Locator
export const getGlobalSectionsByType = async (
previewData: Locator,
contentType: string
): Promise<GlobalSectionsData> => {
if (storeConfig.cms.data) {
const cmsData = JSON.parse(storeConfig.cms.data)
const page = cmsData[GLOBAL_SECTIONS_CONTENT_TYPE][0]
const page = cmsData[contentType][0]

if (page) {
const pageData = getPage<PageContentType>({
contentType: GLOBAL_SECTIONS_CONTENT_TYPE,
contentType: contentType,
documentId: page.documentId,
versionId: page.versionId,
})
Expand All @@ -27,10 +30,28 @@ export const getGlobalSectionsData = async (
}

const pageData = getPage<PageContentType>({
...(previewData?.contentType === GLOBAL_SECTIONS_CONTENT_TYPE &&
previewData),
contentType: GLOBAL_SECTIONS_CONTENT_TYPE,
...(previewData?.contentType === contentType && previewData),
contentType: contentType,
})

return pageData
}

export const getGlobalSectionsData = (
previewData: Locator
): Promise<GlobalSectionsData>[] => {
const globalSections = getGlobalSectionsByType(
previewData,
GLOBAL_SECTIONS_CONTENT_TYPE
)
const globalHeaderSections = getGlobalSectionsByType(
previewData,
GLOBAL_SECTIONS_HEADER_CONTENT_TYPE
)
const globalFooterSections = getGlobalSectionsByType(
previewData,
GLOBAL_SECTIONS_FOOTER_CONTENT_TYPE
)

return [globalSections, globalHeaderSections, globalFooterSections]
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { GetServerSideProps } from 'next'
import type { SearchPageProps } from './getStaticProps'

import { getGlobalSectionsData } from 'src/components/cms/GlobalSections'
import { type SearchContentType, getPage } from 'src/server/cms'
import type { Locator } from '@vtex/client-cms'
import storeConfig from 'discovery.config'
import { getGlobalSectionsData } from 'src/components/cms/GlobalSections'
import { type SearchContentType, getPage } from 'src/server/cms'
import { injectGlobalSections } from 'src/server/cms/global'

export const getServerSideProps: GetServerSideProps<
SearchPageProps,
Expand All @@ -14,26 +15,62 @@ export const getServerSideProps: GetServerSideProps<
const { previewData, query, res } = context
const searchTerm = (query.q as string)?.split('+').join(' ')

const globalSections = await getGlobalSectionsData(previewData)
const [
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
] = getGlobalSectionsData(previewData)

if (storeConfig.cms.data) {
const cmsData = JSON.parse(storeConfig.cms.data)
const page = cmsData['search'][0]
if (page) {
const pageData = await getPage<SearchContentType>({
contentType: 'search',
documentId: page.documentId,
versionId: page.versionId,
const [
pageData,
globalSections,
globalSectionsHeader,
globalSectionsFooter,
] = await Promise.all([
getPage<SearchContentType>({
contentType: 'search',
documentId: page.documentId,
versionId: page.versionId,
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})
return {
props: { page: pageData, globalSections, searchTerm },
props: {
page: pageData,
globalSections: globalSectionsResult,
searchTerm,
},
}
}
}

const page = await getPage<SearchContentType>({
...(previewData?.contentType === 'search' ? previewData : null),
contentType: 'search',
const [page, globalSections, globalSectionsHeader, globalSectionsFooter] =
await Promise.all([
getPage<SearchContentType>({
...(previewData?.contentType === 'search' ? previewData : null),
contentType: 'search',
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})

res.setHeader(
Expand All @@ -44,7 +81,7 @@ export const getServerSideProps: GetServerSideProps<
return {
props: {
page,
globalSections,
globalSections: globalSectionsResult,
searchTerm,
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import type { Locator } from '@vtex/client-cms'
import storeConfig from 'discovery.config'
import type { GetStaticProps } from 'next'
import {
getGlobalSectionsData,
type GlobalSectionsData,
} from 'src/components/cms/GlobalSections'
import { type SearchContentType, getPage } from 'src/server/cms'
import type { Locator } from '@vtex/client-cms'
import storeConfig from 'discovery.config'
import { getPage, type SearchContentType } from 'src/server/cms'
import { injectGlobalSections } from 'src/server/cms/global'

export type SearchPageProps = {
page: SearchContentType
globalSections: GlobalSectionsData
searchTerm?: string
}

/*
Depending on the value of the storeConfig.experimental.enableSearchSSR flag, the function used will be getServerSideProps (./getServerSideProps).
/*
Depending on the value of the storeConfig.experimental.enableSearchSSR flag, the function used will be getServerSideProps (./getServerSideProps).
Our CLI that does this process of converting from getStaticProps to getServerSideProps.
*/
export const getStaticProps: GetStaticProps<
Expand All @@ -24,34 +25,66 @@ export const getStaticProps: GetStaticProps<
> = async (context) => {
const { previewData } = context

const globalSections = await getGlobalSectionsData(previewData)
const [
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
] = getGlobalSectionsData(previewData)

if (storeConfig.cms.data) {
const cmsData = JSON.parse(storeConfig.cms.data)
const page = cmsData['search'][0]

if (page) {
const pageData = await getPage<SearchContentType>({
contentType: 'search',
documentId: page.documentId,
versionId: page.versionId,
const [
pageData,
globalSections,
globalSectionsHeader,
globalSectionsFooter,
] = await Promise.all([
getPage<SearchContentType>({
contentType: 'search',
documentId: page.documentId,
versionId: page.versionId,
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})

return {
props: { page: pageData, globalSections },
props: { page: pageData, globalSections: globalSectionsResult },
}
}
}

const page = await getPage<SearchContentType>({
...(previewData?.contentType === 'search' ? previewData : null),
contentType: 'search',
const [page, globalSections, globalSectionsHeader, globalSectionsFooter] =
await Promise.all([
getPage<SearchContentType>({
...(previewData?.contentType === 'search' ? previewData : null),
contentType: 'search',
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})

return {
props: {
page,
globalSections,
globalSections: globalSectionsResult,
},
}
}
34 changes: 25 additions & 9 deletions packages/core/src/pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import {
import { default as GLOBAL_COMPONENTS } from 'src/components/cms/global/Components'
import RenderSections from 'src/components/cms/RenderSections'
import { OverriddenDefaultEmptyState as EmptyState } from 'src/components/sections/EmptyState/OverriddenDefaultEmptyState'
import PLUGINS_COMPONENTS from 'src/plugins'
import CUSTOM_COMPONENTS from 'src/customizations/src/components'
import PLUGINS_COMPONENTS from 'src/plugins'
import { type PageContentType, getPage } from 'src/server/cms'
import { injectGlobalSections } from 'src/server/cms/global'

/* A list of components that can be used in the CMS. */
const COMPONENTS: Record<string, ComponentType<any>> = {
Expand Down Expand Up @@ -56,16 +57,31 @@ export const getStaticProps: GetStaticProps<
Record<string, string>,
Locator
> = async ({ previewData }) => {
const [page, globalSections] = await Promise.all([
getPage<PageContentType>({
...(previewData?.contentType === '404' && previewData),
contentType: '404',
}),
getGlobalSectionsData(previewData),
])
const [
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
] = getGlobalSectionsData(previewData)

const [page, globalSections, globalSectionsHeader, globalSectionsFooter] =
await Promise.all([
getPage<PageContentType>({
...(previewData?.contentType === '404' && previewData),
contentType: '404',
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})

return {
props: { page, globalSections },
props: { page, globalSections: globalSectionsResult },
}
}

Expand Down
34 changes: 25 additions & 9 deletions packages/core/src/pages/500.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import {
import { default as GLOBAL_COMPONENTS } from 'src/components/cms/global/Components'
import RenderSections from 'src/components/cms/RenderSections'
import { OverriddenDefaultEmptyState as EmptyState } from 'src/components/sections/EmptyState/OverriddenDefaultEmptyState'
import PLUGINS_COMPONENTS from 'src/plugins'
import CUSTOM_COMPONENTS from 'src/customizations/src/components'
import PLUGINS_COMPONENTS from 'src/plugins'
import { type PageContentType, getPage } from 'src/server/cms'
import { injectGlobalSections } from 'src/server/cms/global'

/* A list of components that can be used in the CMS. */
const COMPONENTS: Record<string, ComponentType<any>> = {
Expand Down Expand Up @@ -57,16 +58,31 @@ export const getStaticProps: GetStaticProps<
Record<string, string>,
Locator
> = async ({ previewData }) => {
const [page, globalSections] = await Promise.all([
getPage<PageContentType>({
...(previewData?.contentType === '500' && previewData),
contentType: '500',
}),
getGlobalSectionsData(previewData),
])
const [
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
] = getGlobalSectionsData(previewData)

const [page, globalSections, globalSectionsHeader, globalSectionsFooter] =
await Promise.all([
getPage<PageContentType>({
...(previewData?.contentType === '500' && previewData),
contentType: '500',
}),
globalSectionsPromise,
globalSectionsHeaderPromise,
globalSectionsFooterPromise,
])

const globalSectionsResult = injectGlobalSections({
globalSections,
globalSectionsHeader,
globalSectionsFooter,
})

return {
props: { page, globalSections },
props: { page, globalSections: globalSectionsResult },
}
}

Expand Down
Loading

0 comments on commit 8555310

Please sign in to comment.