Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PDP regionalization #2681

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
25 changes: 17 additions & 8 deletions packages/api/src/platforms/vtex/clients/search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface SearchArgs {
showInvisibleItems?: boolean
showSponsored?: boolean
sponsoredCount?: number
regionId?: string
}

export interface ProductLocator {
Expand Down Expand Up @@ -101,24 +102,30 @@ export const IntelligentSearch = (
}
}

const getRegionFacet = (): IStoreSelectedFacet | null => {
const { regionId, seller } = ctx.storage.channel
const getRegionFacet = (
queryRegionId?: string
): IStoreSelectedFacet | null => {
const { regionId: channelRegionId, seller } = ctx.storage.channel
const sellerRegionId = seller
? Buffer.from(`SW#${seller}`).toString('base64')
: null
const facet = sellerRegionId ?? regionId
const regionId = sellerRegionId ?? channelRegionId
const regionFacet = regionId ?? queryRegionId

if (!facet) {
if (!regionFacet) {
return null
}

return {
key: REGION_KEY,
value: facet,
value: regionFacet,
}
}

const addDefaultFacets = (facets: SelectedFacet[]) => {
const addDefaultFacets = (
facets: SelectedFacet[],
queryRegionId?: string
) => {
const withDefaultFacets = facets.filter(
({ key }) => !EXTRA_FACETS_KEYS.has(key)
)
Expand All @@ -127,7 +134,8 @@ export const IntelligentSearch = (
facets.find(({ key }) => key === POLICY_KEY) ?? getPolicyFacet()

const regionFacet =
facets.find(({ key }) => key === REGION_KEY) ?? getRegionFacet()
facets.find(({ key }) => key === REGION_KEY) ??
getRegionFacet(queryRegionId)

if (policyFacet !== null) {
withDefaultFacets.push(policyFacet)
Expand Down Expand Up @@ -165,6 +173,7 @@ export const IntelligentSearch = (
type,
showInvisibleItems,
sponsoredCount,
regionId = undefined,
}: SearchArgs): Promise<T> => {
const params = new URLSearchParams({
page: (page + 1).toString(),
Expand Down Expand Up @@ -196,7 +205,7 @@ export const IntelligentSearch = (
params.append('sponsoredCount', sponsoredCount.toString())
}

const pathname = addDefaultFacets(selectedFacets)
const pathname = addDefaultFacets(selectedFacets, regionId)
.map(({ key, value }) => `${key}/${value}`)
.join('/')

Expand Down
3 changes: 3 additions & 0 deletions packages/api/src/platforms/vtex/resolvers/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
findSkuId,
findSlug,
transformSelectedFacet,
findRegionId,
} from '../utils/facets'
import { SORT_MAP } from '../utils/sort'
import { StoreCollection } from './collection'
Expand All @@ -34,6 +35,7 @@ export const Query = {
const locale = findLocale(locator)
const id = findSkuId(locator)
const slug = findSlug(locator)
const regionId = findRegionId(locator)

if (channel) {
mutateChannelContext(ctx, channel)
Expand Down Expand Up @@ -92,6 +94,7 @@ export const Query = {
page: 0,
count: 1,
query: `product:${route.id}`,
regionId,
})

if (!product) {
Expand Down
6 changes: 6 additions & 0 deletions packages/api/src/platforms/vtex/utils/facets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,9 @@ export const findLocale = (facets?: Maybe<SelectedFacet[]>) =>

export const findChannel = (facets?: Maybe<SelectedFacet[]>) =>
facets?.find((facet) => facet.key === 'channel')?.value ?? null

export const findRegionId = (facets?: Maybe<SelectedFacet[]>) => {
const regionId = facets?.find((facet) => facet.key === 'regionId')?.value

return regionId && regionId !== '' ? regionId : undefined
}
24 changes: 23 additions & 1 deletion packages/cli/src/utils/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ function checkDependencies(basePath: string, packagesToCheck: string[]) {
logger.warn(
`${chalk.yellow(
'warning'
)} - Version mismatch detected for ${packageName}.
)} - Version mismatch detected for ${packageName}.
Core: ${coreVersion}, Customization: ${rootVersion}. Please align both versions to prevent issues`
)
}
Expand Down Expand Up @@ -513,6 +513,27 @@ function enableSearchSSR(basePath: string) {
writeFileSync(searchPagePath, searchPageWithSSR)
}

function enablePdpSSR(basePath: string) {
const storeConfigPath = getCurrentUserStoreConfigFile(basePath)

if (!storeConfigPath) {
return
}

const storeConfig = require(storeConfigPath)
if (!storeConfig.experimental.enablePdpSSR) {
return
}

const { tmpDir } = withBasePath(basePath)
const pdpPath = path.join(tmpDir, 'src', 'pages', 'p.tsx')
const pdpData = String(readFileSync(pdpPath))

const pdpWithSSR = pdpData.replaceAll('getStaticProps', 'getServerSideProps')

writeFileSync(pdpPath, pdpWithSSR)
}

export async function generate(options: GenerateOptions) {
const { basePath, setup = false } = options

Expand All @@ -533,6 +554,7 @@ export async function generate(options: GenerateOptions) {
setupPromise,
checkDependencies(basePath, ['typescript']),
enableSearchSSR(basePath),
enablePdpSSR(basePath),
updateBuildTime(basePath),
copyUserStarterToCustomizations(basePath),
copyTheme(basePath),
Expand Down
1 change: 1 addition & 0 deletions packages/core/discovery.config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,6 @@ module.exports = {
preact: false,
enableRedirects: false,
enableSearchSSR: false,
enablePdpSSR: false,
},
}
16 changes: 16 additions & 0 deletions packages/core/src/components/region/RegionModal/RegionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
useUI,
} from '@faststore/ui'
import { useRef, useState } from 'react'
import type { Session } from '@faststore/sdk'

import { sessionStore, useSession, validateSession } from 'src/sdk/session'
import { setCookie } from 'src/utils/cookies'

import dynamic from 'next/dynamic'
import styles from './section.module.scss'
Expand Down Expand Up @@ -36,6 +38,17 @@ interface RegionModalProps {
}
}

async function setRegionIdCookie(session: Session) {
const ONE_WEEK_SECONDS = 7 * 24 * 3600
const channel = JSON.parse(session.channel ?? 'null')

setCookie(
'vtex-faststore-regionid',
channel?.regionId as string,
ONE_WEEK_SECONDS
)
}

function RegionModal({
title,
description,
Expand Down Expand Up @@ -70,6 +83,9 @@ function RegionModal({

const validatedSession = await validateSession(newSession)

// Set cookie for the regionId
await setRegionIdCookie(validatedSession ?? newSession)

sessionStore.set(validatedSession ?? newSession)
} catch (error) {
setErrorMessage(inputFieldErrorMessage)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import type { GetServerSideProps } from 'next'
import type { Locator } from '@vtex/client-cms'
import { isNotFoundError } from '@faststore/api'

import {
getGlobalSectionsData,
type GlobalSectionsData,
} from 'src/components/cms/GlobalSections'
import { execute } from 'src/server'
import { getPDP, type PDPContentType } from 'src/server/cms/pdp'
import { gql } from '@generated'
import type {
ServerProductQueryQuery,
ServerProductQueryQueryVariables,
} from '@generated/graphql'
import storeConfig from 'discovery.config'
import type { PDPProps, StoreConfig } from './getStaticProps'

const query = gql(`
query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {
...ServerProduct
product(locator: $locator) {
id: productID

seo {
title
description
canonical
}

brand {
name
}

sku
gtin
name
description
releaseDate

breadcrumbList {
itemListElement {
item
name
position
}
}

image {
url
alternateName
}

offers {
lowPrice
highPrice
lowPriceWithTaxes
priceCurrency
offers {
availability
price
priceValidUntil
priceCurrency
itemCondition
seller {
identifier
}
}
}

isVariantOf {
productGroupID
}

...ProductDetailsFragment_product
}
}
`)

export const getServerSideProps: GetServerSideProps<
PDPProps,
{ slug: string },
Locator
> = async ({ params, previewData, req, res }) => {
const slug = params?.slug ?? ''
const regionId = req.cookies['vtex-faststore-regionid'] ?? ''

const { data, errors = [] } = await execute<
ServerProductQueryQueryVariables,
ServerProductQueryQuery
>({
variables: {
locator: [
{ key: 'slug', value: slug },
{ key: 'regionId', value: regionId },
],
},
operation: query,
})

const notFound = errors.find(isNotFoundError)

if (notFound) {
return {
notFound: true,
}
}

if (errors.length > 0) {
throw errors[0]
}

const globalSections = await getGlobalSectionsData(previewData)
const cmsPage: PDPContentType = await getPDP(data.product, previewData)

const { seo } = data.product
const meta = {
title: seo.title || storeConfig.seo.title,
description: seo.description || storeConfig.seo.description,
canonical: `${storeConfig.storeUrl}${seo.canonical}`,
}

let offer = {}
if (data.product.offers.offers.length > 0) {
const { listPrice, ...offerData } = data.product.offers.offers[0]

offer = offerData
}

const offers = {
...offer,
priceCurrency: data.product.offers.priceCurrency,
url: meta.canonical,
}

// 5 minutes of fresh content and 1 year of stale content
res.setHeader(
'Cache-Control',
'public, s-maxage=300, stale-while-revalidate=31536000, stale-if-error=31536000'
)

return {
props: {
data,
...cmsPage,
meta,
offers,
globalSections,
key: seo.canonical,
},
revalidate: (storeConfig as StoreConfig).experimental.revalidate ?? false,
}
}
Loading
Loading