Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@

# create a file name it as .env.preview for preview environment
# create a file name it as .env.production for production environment
# copy & paste below content to the newly created env file.
# Running Compass Starter App locally for Development and Production Build
# Create a file, name it as .env.local
# to execute app in either preview or production environment, update CONTENTSTACK_DELIVERY_TOKEN,
# CONTENTSTACK_PREVIEW_TOKEN and CONTENTSTACK_ENVIRONMENT to respective environment name and its tokens,
# with all others config which is given below.

CONTENTSTACK_API_KEY=YOUR_API_KEY
CONTENTSTACK_DELIVERY_TOKEN=YOUR_DELIVERY_TOKEN
CONTENTSTACK_ENVIRONMENT=YOUR_PUBLISHING_ENVIRONMENT

CONTENTSTACK_BRANCH=main
# For other branches add CONTENTSTACK_BRANCH=YOUR_BRANCH_NAME by default it is set to main

CONTENTSTACK_HOST=cdn.contentstack.io
# For EU region add CONTENTSTACK_HOST=eu-cdn.contentstack.com


# To fetch locales
CONTENTSTACK_MANAGEMENT_TOKEN=YOUR_MANAGEMENT_TOKEN

Expand All @@ -23,17 +25,18 @@ CONTENTSTACK_API_HOST=api.contentstack.io
CONTENTSTACK_PREVIEW_TOKEN=YOUR_CONTENTSTACK_PREVIEW_TOKEN

CONTENTSTACK_PREVIEW_HOST=rest-preview.contentstack.com
# For EU region add CONTENTSTACK_API_HOST=eu-api.contentstack.com
# For EU region add CONTENTSTACK_PREVIEW_HOST=eu-rest-preview.contentstack.com

CONTENTSTACK_APP_HOST=app.contentstack.com
# For EU region add CONTENTSTACK_APP_HOST=eu-app.contentstack.com

CONTENTSTACK_LIVE_PREVIEW=true

CONTENTSTACK_LIVE_EDIT_TAGS=true
# To disable live editing tags for this project set CONTENTSTACK_LIVE_PREVIEW=false
# To disable live editing tags for this project set CONTENTSTACK_LIVE_EDIT_TAGS=false

# Stack Master Locale, default is en
DEFAULT_LOCALE=YOUR_STACKS_MASTER_LOCALE
# Default Locale is used to fetch the personalized config from CMS

# For Personalize
CONTENTSTACK_PERSONALIZE_PROJECT_UID=YOUR_CONTENTSTACK_PERSONALIZE_PROJECT_UID
Expand All @@ -55,5 +58,5 @@ CONTENTSTACK_VISUAL_BUILDER_MODE=builder
# To switch off builder mode set CONTENTSTACK_VISUAL_BUILDER_MODE=preview
# if CONTENTSTACK_LIVE_PREVIEW=false then builder/preview will be disabled

#Optional Environment variables
# Optional Environment variables
LOCALE_COOKIE_NAME=YOUR_LOCALE_COOKIE_NAME
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
.env
.env.*

# vercel
.vercel
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v22.6.0
v22.11.0
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Contentstack
Copyright (c) 2025 Contentstack

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
80 changes: 80 additions & 0 deletions MainLayout/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use client'

import React, { useEffect, useState } from 'react'
import { Footer, Header } from '@/components'
import { App } from '@/types'

import { onEntryChange } from '@/config'
import useRouterHook from '@/hooks/useRouterHook'
import { LocaleContext, usePersonalization } from '@/context'
import { footerJsonRtePathIncludes, footerReferenceIncludes, getEntries, navigationReferenceIncludes } from '@/services'

const MainLayout: React.FC<App.MainLayout> = (
props: React.PropsWithChildren<App.MainLayout>
) => {

const [webConfig, setWebConfig] = useState<App.WebConfig>()
const { locale } = useRouterHook()
const {personalizationSDK} = usePersonalization()

const fetchAppConfig = async () => {
try {
const refUids = [
...navigationReferenceIncludes,
...footerReferenceIncludes
]
const jsonRtePaths = [
...footerJsonRtePathIncludes
]

const webConfigRes = await getEntries('web_configuration', locale, refUids, jsonRtePaths, {}, personalizationSDK) as App.WebConfig[]

if (webConfigRes && webConfigRes?.length > 0) {

setWebConfig(webConfigRes[0])

} else {

throw 'Unable to fetch Web Config | 404'

}

} catch (err) {
console.error('Main Layout failed to load,\n', err)
}
}

useEffect(() => {
onEntryChange(fetchAppConfig)
}, [])

return (
<>
{locale && <LocaleContext.Provider
value={{
currentLocale: locale
}}
>
{
webConfig?.main_navigation?.[0] && webConfig?.logo
&& <Header
{...webConfig.main_navigation[0]}
logo={webConfig.logo}
/>
}
<div className='main-layout mx-auto h-screen min-h-screen justify-center relative'>
{props.children}
</div>
{
webConfig?.footer_navigation?.[0] && webConfig?.logo
&& <Footer
{...webConfig.footer_navigation[0]}
logo={webConfig.logo}
/>
}
</LocaleContext.Provider>}
</>
)
}

export { MainLayout }
1 change: 1 addition & 0 deletions MainLayout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './MainLayout'
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ About this project: This is a [Next.js](https://nextjs.org/) project bootstrappe

![compass-starter-app](/public/starter-app.png)

##### Recommended Node version: v18.17.0 and App Supported till v22.6.0
##### Recommended Node version: v18.17.0 and App Supported till v22.11.0

## Getting Started

Expand All @@ -22,6 +22,8 @@ npm run dev

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

##### Note: The url : http://localhost:3000 will have `en` attached to it resulting http://localhost:3000/en, set this url in Contentstack Stack Environment.

You can start editing the page by modifying `app/[locale]/page.tsx`. The page auto-updates as you edit the file.

## Compass Starter Stack Content Repo
Expand All @@ -34,7 +36,7 @@ To import this content to your stack, perform the following steps:

1. Install the CLI by running the following command in your terminal:

```npm i -g @contentstack/cli@1.28.1```
```npm i -g @contentstack/cli@1.32.1```

2. By default, CLI uses the North America region. To use the Europe region, run this command in your terminal:

Expand Down
41 changes: 33 additions & 8 deletions app/[locale]/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,62 @@
import { useEffect, useState } from 'react'
import {isNull} from 'lodash'
import Personalize from '@contentstack/personalize-edge-sdk'
import { getLandingPage } from '@/loaders'
import { RenderComponents } from '@/components'
import { Page } from '@/types'
import { isDataInLiveEdit } from '@/utils'
import { NotFoundComponent, PageWrapper } from '@/components'
import { onEntryChange } from '@/config'
import useRouterHook from '@/hooks/useRouterHook'
import { setDataForChromeExtension } from '@/utils'
import { imageCardsReferenceIncludes, teaserReferenceIncludes, textAndImageReferenceIncludes, textJSONRtePaths } from '@/services/helper'
import { getEntryByUrl } from '@/services'
import { usePersonalization } from '@/context'

/**
* @component LandingPage - Slug Based
*
* @route '/{locale}/{slug}'
* @description Component that renders the landing page based on the slug
*
* @returns {JSX.Element}
*/
export default function LandingPage () {

const [data, setData] = useState<Page.LandingPage['entry'] | null>(null)
const [loading, setLoading] = useState<boolean>(true)
const {path, locale} = useRouterHook()
const [abEnabled, setABEnabled] = useState<boolean>(false)
const [isABTestEnabled, setIsABTestEnabled] = useState<boolean>(false)
const { personalizationSDK } = usePersonalization()

/**
* useEffect to conditionally trigger and impression for a configured AB testing
* */
useEffect(() => {
const variants = Personalize.getVariants()
const variants = personalizationSDK?.getVariants() ?? {}
if (path === process.env.CONTENTSTACK_AB_LANDING_PAGE_PATH
&& Personalize.getInitializationStatus()
&& Personalize.getInitializationStatus() === 'success'
&& variants[process.env.CONTENTSTACK_AB_EXPERIENCE_ID??'1']) {
setABEnabled(true)
Personalize.triggerImpression(process.env.CONTENTSTACK_AB_EXPERIENCE_ID??'1' as string)
setIsABTestEnabled(true)
personalizationSDK?.triggerImpression(process.env.CONTENTSTACK_AB_EXPERIENCE_ID??'1' as string)
}
}, [Personalize.getInitializationStatus()])

/**
* useEffect that fetches data to be rendered on the page
* */
useEffect(() => {
const fetchData = async () => {
try {
const res = await getLandingPage(path, locale) as Page.LandingPage['entry']
const refUids = [
...textAndImageReferenceIncludes,
...teaserReferenceIncludes,
...imageCardsReferenceIncludes
]
const jsonRtePaths = [
...textJSONRtePaths
]
const res = await getEntryByUrl<Page.LandingPage['entry']>('landing_page',locale, path, refUids, jsonRtePaths, personalizationSDK) as Page.LandingPage['entry']
setData(res)
setDataForChromeExtension({ entryUid: res?.uid || '', contenttype: 'landing_page', locale: locale })
if (!res && !isNull(res)) {
Expand All @@ -50,11 +75,11 @@ export default function LandingPage () {

return (<>
{data
? <PageWrapper {...data} contentType='landing_page'>
? <PageWrapper {...data}>
{data?.components
? <RenderComponents $={data?.$}
components={data?.components}
isABEnabled={abEnabled}
isABEnabled={isABTestEnabled}
/> : ''}
</PageWrapper>
: <>
Expand Down
Loading