Skip to content

Commit becb67d

Browse files
authored
Revert "Version Packages (canary) (#2729)" (#2806)
This reverts commit e00281e.
1 parent e00281e commit becb67d

25 files changed

+891
-861
lines changed

.changeset/afraid-islands-hang.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Upgrade c15t to 1.8.2, migrate from custom mode to offline mode, refactor consent cookie handling to use c15t's compact format, add script location support for HEAD/BODY rendering, and add privacy policy link support to CookieBanner.
6+
7+
## What Changed
8+
9+
- Upgraded `@c15t/nextjs` to version `1.8.2`
10+
- Changed consent manager mode from `custom` (with endpoint handlers) to `offline` mode
11+
- Removed custom `handlers.ts` implementation
12+
- Added `enabled` prop to `C15TConsentManagerProvider` to control consent manager functionality
13+
- Removed custom consent cookie encoder/decoder implementations (`decoder.ts`, `encoder.ts`)
14+
- Added `parse-compact-format.ts` to handle c15t's compact cookie format
15+
- Compact format: `i.t:timestamp,c.necessary:1,c.functionality:1,etc...`
16+
- Updated cookie parsing logic in both client and server to use the new compact format parser
17+
- Scripts now support `location` field from BigCommerce API and can be rendered in `<head>` or `<body>` based on the `target` property
18+
- `CookieBanner` now supports the `privacyPolicyUrl` field from BigCommerce API and will be rendered in the banner description if available.
19+
20+
## Migration Path
21+
22+
### Consent Manager Provider Changes
23+
24+
The `ConsentManagerProvider` now uses `offline` mode instead of `custom` mode with endpoint handlers. The provider configuration has been simplified:
25+
26+
**Before:**
27+
```typescript
28+
<C15TConsentManagerProvider
29+
options={{
30+
mode: 'custom',
31+
consentCategories: ['necessary', 'functionality', 'marketing', 'measurement'],
32+
endpointHandlers: {
33+
showConsentBanner: () => showConsentBanner(isCookieConsentEnabled),
34+
setConsent,
35+
verifyConsent,
36+
},
37+
}}
38+
>
39+
<ClientSideOptionsProvider scripts={scripts}>
40+
{children}
41+
</ClientSideOptionsProvider>
42+
</C15TConsentManagerProvider>
43+
```
44+
45+
**After:**
46+
```typescript
47+
<C15TConsentManagerProvider
48+
options={{
49+
mode: 'offline',
50+
storageConfig: {
51+
storageKey: CONSENT_COOKIE_NAME,
52+
crossSubdomain: true,
53+
},
54+
consentCategories: ['necessary', 'functionality', 'marketing', 'measurement'],
55+
enabled: isCookieConsentEnabled,
56+
}}
57+
>
58+
<ClientSideOptionsProvider scripts={scripts}>
59+
{children}
60+
</ClientSideOptionsProvider>
61+
</C15TConsentManagerProvider>
62+
```
63+
64+
**Key changes:**
65+
- `mode` changed from `'custom'` to `'offline'`
66+
- Removed `endpointHandlers` - no longer needed in offline mode
67+
- Added `enabled` prop to control consent manager functionality
68+
- Added `storageConfig` for cookie storage configuration
69+
70+
### Cookie Handling
71+
72+
If you have custom code that directly reads or writes consent cookies, you'll need to update it:
73+
74+
**Before:**
75+
The previous implementation used custom encoding/decoding. If you were directly accessing consent cookie values, you would have needed to use the custom decoder.
76+
77+
**After:**
78+
The consent cookie now uses c15t's compact format. The public API for reading cookies remains the same:
79+
80+
```typescript
81+
import { getConsentCookie } from '~/lib/consent-manager/cookies/client'; // client-side
82+
// or
83+
import { getConsentCookie } from '~/lib/consent-manager/cookies/server'; // server-side
84+
85+
const consent = getConsentCookie();
86+
```
87+
88+
The `getConsentCookie()` function now internally uses `parseCompactFormat()` to parse the compact format cookie string. If you were directly parsing cookie values, you should now use the `getConsentCookie()` helper instead.
89+
90+
`getConsentCookie` now returns a compact version of the consent values:
91+
92+
```typescript
93+
{
94+
i.t: 123456789,
95+
c.necessary: true,
96+
c.functionality: true,
97+
c.marketing: false,
98+
c.measurment: false
99+
}
100+
```
101+
102+
Updated instances where `getConsentCookie` is used to reflect this new schema.
103+
104+
Removed `setConsentCookie` from server and client since this is now handled by the c15t library.
105+
106+
### Script Location Support
107+
108+
Scripts now support rendering in either `<head>` or `<body>` based on the `location` field from the BigCommerce API:
109+
110+
```typescript
111+
// Scripts transformer now includes target based on location
112+
target: script.location === 'HEAD' ? 'head' : 'body'
113+
```
114+
115+
The `ScriptsFragment` GraphQL query now includes the `location` field, allowing scripts to be placed in the appropriate DOM location. `FOOTER` location is still not supported.
116+
117+
### Privacy Policy
118+
119+
The `RootLayoutMetadataQuery` GraphQL query now includes the `privacyPolicyUrl` field, which renders a provicy policy link in the `CookieBanner` description.
120+
121+
```typescript
122+
<CookieBanner
123+
privacyPolicyUrl="https://example.com/privacy-policy"
124+
// ... other props
125+
/>
126+
```
127+
128+
The privacy policy link:
129+
- Opens in a new tab (`target="_blank"`)
130+
- Only renders if `privacyPolicyUrl` is provided as a non-empty string
131+
132+
Add translatable `privacyPolicy` field to `Components.ConsentManager.CookieBanner` translation namespace for the privacy policy link text.

.changeset/clean-days-search.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
"@bigcommerce/catalyst-core": patch
3+
---
4+
5+
Update /login/token route error handling and messaging
6+
7+
## Migration steps
8+
9+
### 1. Add `invalidToken` translation key to the `Auth.Login` namespace:
10+
```json
11+
"invalidToken": "Your login link is invalid or has expired. Please try logging in again.",
12+
```
13+
14+
### 2. In `core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts`, add a `console.error` in the `catch` block to log the error details:
15+
```typescript
16+
} catch (error) {
17+
// eslint-disable-next-line no-console
18+
console.error(error);
19+
20+
// ...
21+
}
22+
```
23+
24+
### 3. In `core/app/[locale]/(default)/(auth)/login/page.tsx`, add `error` prop to searchParams and pass it down into the `SignInSection` component:
25+
```typescript
26+
export default async function Login({ params, searchParams }: Props) {
27+
const { locale } = await params;
28+
const { redirectTo = '/account/orders', error } = await searchParams;
29+
30+
setRequestLocale(locale);
31+
32+
const t = await getTranslations('Auth.Login');
33+
const vanityUrl = buildConfig.get('urls').vanityUrl;
34+
const redirectUrl = new URL(redirectTo, vanityUrl);
35+
const redirectTarget = redirectUrl.pathname + redirectUrl.search;
36+
const tokenErrorMessage = error === 'InvalidToken' ? t('invalidToken') : undefined;
37+
38+
return (
39+
<>
40+
<ForceRefresh />
41+
<SignInSection
42+
action={login.bind(null, { redirectTo: redirectTarget })}
43+
emailLabel={t('email')}
44+
error={tokenErrorMessage}
45+
...
46+
```
47+
48+
49+
### 4. Update `core/vibes/soul/sections/sign-in-section/index.tsx` and add the `error` prop, and pass it down to `SignInForm`:
50+
```typescript
51+
interface Props {
52+
// ... existing props
53+
error?: string;
54+
}
55+
56+
// ...
57+
58+
export function SignInSection({
59+
// ... existing variables
60+
error,
61+
}: Props) {
62+
// ...
63+
<SignInForm
64+
action={action}
65+
emailLabel={emailLabel}
66+
error={error}
67+
```
68+
69+
### 5. Update `core/vibes/soul/sections/sign-in-section/sign-in-form.tsx` to take the error prop and display it in the form errors:
70+
71+
```typescript
72+
interface Props {
73+
// ... existing props
74+
error?: string;
75+
}
76+
77+
export function SignInForm({
78+
// ... existing variables
79+
error,
80+
}: Props) {
81+
// ...
82+
useEffect(() => {
83+
// If the form errors change when an "error" search param is in the URL,
84+
// the search param should be removed to prevent showing stale errors.
85+
if (form.errors) {
86+
const url = new URL(window.location.href);
87+
88+
if (url.searchParams.has('error')) {
89+
url.searchParams.delete('error');
90+
window.history.replaceState({}, '', url.toString());
91+
}
92+
}
93+
}, [form.errors]);
94+
95+
const formErrors = () => {
96+
// Form errors should take precedence over the error prop that is passed in.
97+
// This ensures that the most recent errors are displayed to avoid confusion.
98+
if (form.errors) {
99+
return form.errors;
100+
}
101+
102+
if (error) {
103+
return [error];
104+
}
105+
106+
return [];
107+
};
108+
109+
return (
110+
<form {...getFormProps(form)} action={formAction} className="flex grow flex-col gap-5">
111+
// ...
112+
<SubmitButton>{submitLabel}</SubmitButton>
113+
{formErrors().map((err, index) => (
114+
<FormStatus key={index} type="error">
115+
{err}
116+
</FormStatus>
117+
))}
118+
</form>
119+
);
120+
}
121+
```
122+
123+
### 6. Copy all changes in the `core/tests` directory

.changeset/common-queens-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-core": patch
3+
---
4+
5+
Passes `formButtonLabel` from `Reviews` to `ReviewsEmptyState` (was missing) and sets a default value for `formButtonLabel`

.changeset/cute-trees-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Conditionally display product ratings in the storefront based on `site.settings.display.showProductRating`. The storefront logic when this setting is enabled/disabled matches exactly the logic of Stencil + Cornerstone.

.changeset/eleven-bugs-deny.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Adds product review submission functionality to the product detail page via a modal form with validation for rating, title, review text, name, and email fields. Integrates with BigCommerce's GraphQL API using Conform and Zod for form validation and real-time feedback.

.changeset/facets-displayName.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Introduce displayName and displayKey fields to facets for improved labeling and filtering
6+
7+
Facet filters now use the `displayName` field for more descriptive labels in the UI, replacing the deprecated `name` field. Product attribute facets now support the `filterKey` field for consistent parameter naming. The facet transformer has been updated to use `displayName` with a fallback to `filterName` when `displayName` is not available.

.changeset/five-corners-try.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
"@bigcommerce/catalyst-core": patch
3+
---
4+
5+
Remove "Exclusive Offers" field temporarily. Currently, the field is not fully implemented in GraphQL, so it may be misleading to display it on the storefront if it's not actually doing anything when registering a customer.
6+
7+
Once the Register Customer operation takes this field into account, we can display it again.
8+
9+
## Migration
10+
11+
Update `core/app/[locale]/(default)/(auth)/register/page.tsx` and add the function:
12+
```ts
13+
// There is currently a GraphQL gap where the "Exclusive Offers" field isn't accounted for
14+
// during customer registration, so the field should not be shown on the Catalyst storefront until it is hooked up.
15+
function removeExlusiveOffersField(field: Field | Field[]): boolean {
16+
if (Array.isArray(field)) {
17+
// Exclusive offers field will always have ID '25', since it is made upon store creation and is also read-only.
18+
return !field.some((f) => f.id === '25');
19+
}
20+
21+
return field.id !== '25';
22+
}
23+
```
24+
25+
Then, add the following code at the end of the `const fields` declaration:
26+
```ts
27+
})
28+
.filter(exists)
29+
.filter(removeExlusiveOffersField); // <---
30+
```

.changeset/funny-dingos-accept.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@bigcommerce/catalyst-core': minor
3+
---
4+
5+
Updated product and brand pages to include the number of reviews in the product data. Fixed visual spacing within product cards. Enhanced the Rating component to display the number of reviews alongside the rating. Introduced a new RatingLink component for smooth scrolling to reviews section on PDP.

.changeset/hot-plums-give.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Make newsletter signup component on homepage render conditionally based on BigCommerce settings.
6+
7+
## What Changed
8+
9+
- Newsletter signup component (`Subscribe`) on homepage now conditionally renders based on `showNewsletterSignup` setting from BigCommerce.
10+
- Added `showNewsletterSignup` field to `HomePageQuery` GraphQL query to fetch newsletter settings.
11+
- Newsletter signup now uses `Stream` component with `Streamable` pattern for progressive loading.
12+
13+
## Migration
14+
15+
To make newsletter signup component render conditionally based on BigCommerce settings, update your homepage code:
16+
17+
### 1. Update GraphQL Query (`page-data.ts`)
18+
19+
Add the `newsletter` field to your `HomePageQuery`:
20+
21+
```typescript
22+
const HomePageQuery = graphql(
23+
`
24+
query HomePageQuery($currencyCode: currencyCode) {
25+
site {
26+
// ... existing fields
27+
settings {
28+
inventory {
29+
defaultOutOfStockMessage
30+
showOutOfStockMessage
31+
showBackorderMessage
32+
}
33+
newsletter {
34+
showNewsletterSignup
35+
}
36+
}
37+
}
38+
}
39+
`,
40+
[FeaturedProductsCarouselFragment, FeaturedProductsListFragment],
41+
);
42+
```
43+
44+
### 2. Update Homepage Component (`page.tsx`)
45+
46+
Import `Stream` and create a streamable for newsletter settings:
47+
48+
```typescript
49+
import { Stream, Streamable } from '@/vibes/soul/lib/streamable';
50+
51+
// Inside your component, create the streamable:
52+
const streamableShowNewsletterSignup = Streamable.from(async () => {
53+
const data = await streamablePageData;
54+
const { showNewsletterSignup } = data.site.settings?.newsletter ?? {};
55+
return showNewsletterSignup;
56+
});
57+
58+
// Replace direct rendering with conditional Stream:
59+
<Stream fallback={null} value={streamableShowNewsletterSignup}>
60+
{(showNewsletterSignup) => showNewsletterSignup && <Subscribe />}
61+
</Stream>
62+
```
63+
64+
**Before:**
65+
```typescript
66+
<Subscribe />
67+
```
68+
69+
**After:**
70+
```typescript
71+
<Stream fallback={null} value={streamableShowNewsletterSignup}>
72+
{(showNewsletterSignup) => showNewsletterSignup && <Subscribe />}
73+
</Stream>
74+
```

0 commit comments

Comments
 (0)