@cartbase/storefront 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/package.json +258 -256
- package/src/api/auth.ts +108 -108
- package/src/api/carts.ts +523 -523
- package/src/api/categories.ts +184 -184
- package/src/api/checkout.ts +526 -526
- package/src/api/collections.ts +130 -130
- package/src/api/consent.ts +75 -75
- package/src/api/content.ts +125 -125
- package/src/api/customers.ts +303 -303
- package/src/api/gift-cards.ts +112 -112
- package/src/api/http.ts +180 -180
- package/src/api/index.ts +30 -30
- package/src/api/menus.ts +77 -77
- package/src/api/metaobjects.ts +136 -136
- package/src/api/orders.ts +290 -290
- package/src/api/products.ts +43 -1
- package/src/api/redirects.ts +37 -37
- package/src/api/regions.ts +200 -200
- package/src/api/reviews.ts +259 -259
- package/src/api/search.ts +163 -163
- package/src/api/store.ts +35 -35
- package/src/api/types.ts +91 -91
- package/src/cart-drawer/context.tsx +277 -164
- package/src/cart-drawer/cross-sell-carousel.tsx +211 -211
- package/src/cart-drawer/cross-sell-sidebar.tsx +158 -158
- package/src/cart-drawer/gift-wrap.tsx +82 -82
- package/src/cart-drawer/index.ts +71 -68
- package/src/cart-drawer/item/index.tsx +162 -162
- package/src/cart-drawer/item/quantity.tsx +8 -14
- package/src/cart-drawer/item/upsell.tsx +110 -110
- package/src/cart-drawer/labels.ts +123 -123
- package/src/cart-drawer/mutation-queue.ts +78 -0
- package/src/cart-drawer/notes.tsx +131 -131
- package/src/cart-drawer/sticky-footer.tsx +73 -73
- package/src/cart-drawer/summary-breakdown.tsx +197 -197
- package/src/checkout/address-error-copy.ts +117 -117
- package/src/checkout/boxnow-locker-selector.tsx +410 -410
- package/src/checkout/compare-addresses.ts +40 -40
- package/src/checkout/discount-section.tsx +218 -218
- package/src/checkout/error-copy-codes.ts +63 -63
- package/src/checkout/geocode.ts +154 -154
- package/src/checkout/gift-card-section.tsx +224 -224
- package/src/checkout/index.ts +72 -72
- package/src/checkout/labels.ts +495 -495
- package/src/checkout/payment-button.tsx +372 -372
- package/src/checkout/payment-error-copy.ts +154 -154
- package/src/checkout/promotion-error-copy.ts +91 -91
- package/src/checkout/use-checkout-orchestration.ts +1592 -1592
- package/src/common/country-flag.tsx +52 -52
- package/src/common/country-select.tsx +11 -11
- package/src/common/index.ts +20 -20
- package/src/common/market-select.tsx +57 -57
- package/src/index.ts +12 -12
- package/src/lib/country-name.ts +59 -59
- package/src/lib/get-product-price.ts +133 -133
- package/src/lib/media-image.tsx +39 -39
- package/src/lib/payment-constants.ts +53 -53
- package/src/lib/platform.ts +13 -13
- package/src/lib/price.tsx +39 -39
- package/src/lib/store-api-error.ts +36 -36
- package/src/lib/variant-caption.ts +32 -32
- package/src/locales/bg.ts +467 -467
- package/src/locales/context.ts +37 -37
- package/src/locales/en.ts +26 -26
- package/src/locales/es.ts +466 -466
- package/src/locales/index.ts +19 -19
- package/src/locales/provider.tsx +59 -59
- package/src/locales/types.ts +77 -77
- package/src/order/index.ts +62 -62
- package/src/order/labels.ts +79 -79
- package/src/order/order-totals.tsx +250 -250
- package/src/primitives/select-field.tsx +93 -93
- package/src/products/image-gallery.tsx +43 -43
- package/src/products/index.ts +68 -59
- package/src/products/option-select.tsx +67 -67
- package/src/products/product-actions-wrapper.tsx +63 -62
- package/src/products/product-actions.tsx +151 -150
- package/src/products/product-price.tsx +69 -69
- package/src/products/product-promises.tsx +61 -61
- package/src/products/product-specs.tsx +65 -65
- package/src/products/product-tabs.tsx +123 -123
- package/src/products/product-template.tsx +163 -162
- package/src/products/purchase-options.tsx +130 -130
- package/src/products/sets.ts +110 -0
- package/src/products/use-product-actions.ts +199 -164
- package/src/products/variant-matching.ts +71 -71
- package/src/products/variant-url.ts +74 -74
- package/src/reviews-ui/index.ts +73 -73
- package/src/store/category-template.tsx +136 -136
- package/src/store/index.ts +40 -40
- package/src/tracking/chatgpt-pixel.tsx +99 -99
- package/src/tracking/consent-init.tsx +62 -62
- package/src/tracking/events.ts +348 -348
- package/src/tracking/ga4.tsx +93 -93
- package/src/tracking/google-ads.ts +84 -84
- package/src/tracking/gtm.tsx +60 -60
- package/src/tracking/inline-script.ts +49 -49
- package/src/tracking/oaiq.ts +206 -206
- package/src/tracking/tiktok-pixel.tsx +91 -91
- package/src/tracking/track-init.tsx +56 -56
- package/src/tracking/track-order-purchase.tsx +122 -122
- package/src/tracking/ttq.ts +180 -180
- package/src/tracking/use-tracking-config.ts +54 -54
- package/theme/index.css +25 -25
- package/theme/theme.css +150 -150
- package/theme/tokens.css +106 -106
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import Script from "next/script"
|
|
4
|
-
|
|
5
|
-
import { adsConsentSnippet } from "./consent"
|
|
6
|
-
import { jsStringLiteral } from "./inline-script"
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* ChatGptPixel — the OpenAI measurement pixel, the ChatGPT Ads twin of
|
|
10
|
-
* <MetaPixel> and <TikTokPixel>.
|
|
11
|
-
*
|
|
12
|
-
* The loader is OpenAI's own, verbatim from
|
|
13
|
-
* https://developers.openai.com/ads/measurement-pixel: a command queue on
|
|
14
|
-
* `window.oaiq` that buffers calls until the SDK arrives from
|
|
15
|
-
* bzrcdn.openai.com, injected with `<Script strategy="afterInteractive">`.
|
|
16
|
-
*
|
|
17
|
-
* CONSENT IS CLOSED BEFORE INIT, and that order is the whole point. Their
|
|
18
|
-
* consent default is TRUE, so an unconsented visitor is measured unless we
|
|
19
|
-
* say otherwise first:
|
|
20
|
-
*
|
|
21
|
-
* oaiq("consent", false) // queued BEFORE init — no pings
|
|
22
|
-
* oaiq("init", { pixelId })
|
|
23
|
-
* oaiq("consent", true) // only once the visitor accepted
|
|
24
|
-
*
|
|
25
|
-
* The script is LOADED either way, like the Meta and TikTok gates beside
|
|
26
|
-
* it, so a later grant costs no round trip. But the page view is fired
|
|
27
|
-
* only AFTER a grant, and that is deliberate rather than cautious: their
|
|
28
|
-
* docs state that with consent false the pixel sends no measurement
|
|
29
|
-
* pings, and they do NOT document whether a call made while consent was
|
|
30
|
-
* false is released on a later grant. TikTok documents exactly that
|
|
31
|
-
* (`holdConsent` queues, `grantConsent` flushes) and our TikTok gate
|
|
32
|
-
* relies on it. Nothing here relies on behaviour OpenAI has not written
|
|
33
|
-
* down: an unconsented page view is not sent, and not counted on later.
|
|
34
|
-
*
|
|
35
|
-
* The decision is the store's default overridden by the visitor's stored
|
|
36
|
-
* choice (`adsConsentSnippet`), resolved inside the snippet before anything
|
|
37
|
-
* can be sent: a store that collects consent starts closed, a store with
|
|
38
|
-
* no consent gate starts open, the cookie winning either way. Live changes
|
|
39
|
-
* arrive through `applyConsent()` in ./consent.ts — there is no cookie
|
|
40
|
-
* watcher. `consentRequired` is `tracking.consent_required`, passed by
|
|
41
|
-
* <StorefrontTags>, and required for the reason <ConsentInit> gives.
|
|
42
|
-
*
|
|
43
|
-
* The page view is ours to fire at all: their pixel sends nothing at init,
|
|
44
|
-
* unlike Meta's and TikTok's base code.
|
|
45
|
-
*
|
|
46
|
-
* Their SDK also captures `oppref` off the landing URL into a first-party
|
|
47
|
-
* `__oppref` cookie by itself. Our attribution module captures the same
|
|
48
|
-
* parameter into `_1c_oppref` independently, so the server-side
|
|
49
|
-
* Conversions API event can carry the click even on a visit where this
|
|
50
|
-
* script never loaded at all.
|
|
51
|
-
*
|
|
52
|
-
* Renders nothing when `pixelId` is falsy, so a layout can mount it
|
|
53
|
-
* unconditionally.
|
|
54
|
-
*/
|
|
55
|
-
export function ChatGptPixel({
|
|
56
|
-
pixelId,
|
|
57
|
-
consentRequired,
|
|
58
|
-
}: {
|
|
59
|
-
pixelId?: string
|
|
60
|
-
/** `tracking.consent_required`: does this store collect consent before it tracks? */
|
|
61
|
-
consentRequired: boolean
|
|
62
|
-
}) {
|
|
63
|
-
if (!pixelId) return null
|
|
64
|
-
|
|
65
|
-
const id = jsStringLiteral(pixelId)
|
|
66
|
-
|
|
67
|
-
const initSnippet = `
|
|
68
|
-
(function (w, d, s, u) {
|
|
69
|
-
if (w.oaiq) return;
|
|
70
|
-
var q = function () { q.q.push(arguments); };
|
|
71
|
-
q.q = [];
|
|
72
|
-
w.oaiq = q;
|
|
73
|
-
var js = d.createElement(s);
|
|
74
|
-
js.async = true;
|
|
75
|
-
js.src = u;
|
|
76
|
-
var f = d.getElementsByTagName(s)[0];
|
|
77
|
-
f.parentNode.insertBefore(js, f);
|
|
78
|
-
})(window, document, "script", "https://bzrcdn.openai.com/sdk/oaiq.min.js");
|
|
79
|
-
|
|
80
|
-
oaiq("consent", false);
|
|
81
|
-
oaiq("init", { pixelId: ${id} });
|
|
82
|
-
|
|
83
|
-
(function (d) {
|
|
84
|
-
${adsConsentSnippet(consentRequired, "d")}
|
|
85
|
-
if (ads) {
|
|
86
|
-
oaiq("consent", true);
|
|
87
|
-
oaiq("measure", "page_viewed", { type: "contents" });
|
|
88
|
-
}
|
|
89
|
-
})(document);
|
|
90
|
-
`.trim()
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<Script
|
|
94
|
-
id="chatgpt-pixel-init"
|
|
95
|
-
strategy="afterInteractive"
|
|
96
|
-
dangerouslySetInnerHTML={{ __html: initSnippet }}
|
|
97
|
-
/>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import Script from "next/script"
|
|
4
|
+
|
|
5
|
+
import { adsConsentSnippet } from "./consent"
|
|
6
|
+
import { jsStringLiteral } from "./inline-script"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ChatGptPixel — the OpenAI measurement pixel, the ChatGPT Ads twin of
|
|
10
|
+
* <MetaPixel> and <TikTokPixel>.
|
|
11
|
+
*
|
|
12
|
+
* The loader is OpenAI's own, verbatim from
|
|
13
|
+
* https://developers.openai.com/ads/measurement-pixel: a command queue on
|
|
14
|
+
* `window.oaiq` that buffers calls until the SDK arrives from
|
|
15
|
+
* bzrcdn.openai.com, injected with `<Script strategy="afterInteractive">`.
|
|
16
|
+
*
|
|
17
|
+
* CONSENT IS CLOSED BEFORE INIT, and that order is the whole point. Their
|
|
18
|
+
* consent default is TRUE, so an unconsented visitor is measured unless we
|
|
19
|
+
* say otherwise first:
|
|
20
|
+
*
|
|
21
|
+
* oaiq("consent", false) // queued BEFORE init — no pings
|
|
22
|
+
* oaiq("init", { pixelId })
|
|
23
|
+
* oaiq("consent", true) // only once the visitor accepted
|
|
24
|
+
*
|
|
25
|
+
* The script is LOADED either way, like the Meta and TikTok gates beside
|
|
26
|
+
* it, so a later grant costs no round trip. But the page view is fired
|
|
27
|
+
* only AFTER a grant, and that is deliberate rather than cautious: their
|
|
28
|
+
* docs state that with consent false the pixel sends no measurement
|
|
29
|
+
* pings, and they do NOT document whether a call made while consent was
|
|
30
|
+
* false is released on a later grant. TikTok documents exactly that
|
|
31
|
+
* (`holdConsent` queues, `grantConsent` flushes) and our TikTok gate
|
|
32
|
+
* relies on it. Nothing here relies on behaviour OpenAI has not written
|
|
33
|
+
* down: an unconsented page view is not sent, and not counted on later.
|
|
34
|
+
*
|
|
35
|
+
* The decision is the store's default overridden by the visitor's stored
|
|
36
|
+
* choice (`adsConsentSnippet`), resolved inside the snippet before anything
|
|
37
|
+
* can be sent: a store that collects consent starts closed, a store with
|
|
38
|
+
* no consent gate starts open, the cookie winning either way. Live changes
|
|
39
|
+
* arrive through `applyConsent()` in ./consent.ts — there is no cookie
|
|
40
|
+
* watcher. `consentRequired` is `tracking.consent_required`, passed by
|
|
41
|
+
* <StorefrontTags>, and required for the reason <ConsentInit> gives.
|
|
42
|
+
*
|
|
43
|
+
* The page view is ours to fire at all: their pixel sends nothing at init,
|
|
44
|
+
* unlike Meta's and TikTok's base code.
|
|
45
|
+
*
|
|
46
|
+
* Their SDK also captures `oppref` off the landing URL into a first-party
|
|
47
|
+
* `__oppref` cookie by itself. Our attribution module captures the same
|
|
48
|
+
* parameter into `_1c_oppref` independently, so the server-side
|
|
49
|
+
* Conversions API event can carry the click even on a visit where this
|
|
50
|
+
* script never loaded at all.
|
|
51
|
+
*
|
|
52
|
+
* Renders nothing when `pixelId` is falsy, so a layout can mount it
|
|
53
|
+
* unconditionally.
|
|
54
|
+
*/
|
|
55
|
+
export function ChatGptPixel({
|
|
56
|
+
pixelId,
|
|
57
|
+
consentRequired,
|
|
58
|
+
}: {
|
|
59
|
+
pixelId?: string
|
|
60
|
+
/** `tracking.consent_required`: does this store collect consent before it tracks? */
|
|
61
|
+
consentRequired: boolean
|
|
62
|
+
}) {
|
|
63
|
+
if (!pixelId) return null
|
|
64
|
+
|
|
65
|
+
const id = jsStringLiteral(pixelId)
|
|
66
|
+
|
|
67
|
+
const initSnippet = `
|
|
68
|
+
(function (w, d, s, u) {
|
|
69
|
+
if (w.oaiq) return;
|
|
70
|
+
var q = function () { q.q.push(arguments); };
|
|
71
|
+
q.q = [];
|
|
72
|
+
w.oaiq = q;
|
|
73
|
+
var js = d.createElement(s);
|
|
74
|
+
js.async = true;
|
|
75
|
+
js.src = u;
|
|
76
|
+
var f = d.getElementsByTagName(s)[0];
|
|
77
|
+
f.parentNode.insertBefore(js, f);
|
|
78
|
+
})(window, document, "script", "https://bzrcdn.openai.com/sdk/oaiq.min.js");
|
|
79
|
+
|
|
80
|
+
oaiq("consent", false);
|
|
81
|
+
oaiq("init", { pixelId: ${id} });
|
|
82
|
+
|
|
83
|
+
(function (d) {
|
|
84
|
+
${adsConsentSnippet(consentRequired, "d")}
|
|
85
|
+
if (ads) {
|
|
86
|
+
oaiq("consent", true);
|
|
87
|
+
oaiq("measure", "page_viewed", { type: "contents" });
|
|
88
|
+
}
|
|
89
|
+
})(document);
|
|
90
|
+
`.trim()
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Script
|
|
94
|
+
id="chatgpt-pixel-init"
|
|
95
|
+
strategy="afterInteractive"
|
|
96
|
+
dangerouslySetInnerHTML={{ __html: initSnippet }}
|
|
97
|
+
/>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import { consentInitSnippet } from "./consent"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ConsentInit — the synchronous Consent Mode v2 "default" snippet.
|
|
5
|
-
*
|
|
6
|
-
* Ported from the Cartbase reference implementation
|
|
7
|
-
* `src/components/storefront/consent/consent-init.tsx` (itself from
|
|
8
|
-
* `@1click/ui/src/tracking/consent-init.tsx` v2.3.1); the snippet lives in
|
|
9
|
-
* ./consent.ts (`consentInitSnippet`) so its ordering contract is
|
|
10
|
-
* unit-testable.
|
|
11
|
-
*
|
|
12
|
-
* Render it as the FIRST child of <body> (App Router layouts don't
|
|
13
|
-
* expose <head> for inline scripts). A plain inline <script>
|
|
14
|
-
* (deliberately NOT next/script) executes at HTML-parse time — long
|
|
15
|
-
* before the afterInteractive <GA4>/<MetaPixel> loaders, which run
|
|
16
|
-
* post-hydration. Google's consent-mode docs require the default to be
|
|
17
|
-
* set synchronously ahead of the tag; an async default races the
|
|
18
|
-
* loader and the first hit of a returning consented visitor would
|
|
19
|
-
* ship denied.
|
|
20
|
-
*
|
|
21
|
-
* `required` is the store's consent switch, `consent.enabled` from
|
|
22
|
-
* `GET /api/store/consent`, which the layout already fetches for the
|
|
23
|
-
* banner. It is REQUIRED on purpose: with it absent there is no safe
|
|
24
|
-
* default to fall back on. Defaulting to true would keep the pixels of a
|
|
25
|
-
* store that switched its banner off silent forever (the defect fixed on
|
|
26
|
-
* 2026-09-14); defaulting to false would fire them on an EU store whose
|
|
27
|
-
* layout forgot the prop. So the layout states it, and a layout that does
|
|
28
|
-
* not fails to compile.
|
|
29
|
-
*
|
|
30
|
-
* Behavior:
|
|
31
|
-
* - `required` and no stored choice (first visit) → default ALL DENIED.
|
|
32
|
-
* Tags still load (advanced consent mode): gtag sends cookieless
|
|
33
|
-
* pings, the Pixel queues client-side. The <ConsentBanner> then
|
|
34
|
-
* collects the choice and applies the live 'update'.
|
|
35
|
-
* - not `required` and no stored choice → default ALL GRANTED: the store
|
|
36
|
-
* collects no consent, so there is nothing to wait for.
|
|
37
|
-
* - Stored choice → default mirrors it, whatever the switch, so
|
|
38
|
-
* returning visitors are correct from the very first hit with no
|
|
39
|
-
* banner and no race, and a visitor who declined keeps that decision.
|
|
40
|
-
*
|
|
41
|
-
* `ads_data_redaction` strips ad-click identifiers (gclid et al.) from
|
|
42
|
-
* the cookieless pings while ad_storage is denied, per Google's docs.
|
|
43
|
-
*
|
|
44
|
-
* The script interpolates one boolean literal and the shared cookie name,
|
|
45
|
-
* nothing typed by a person — safe as a server-component inline script
|
|
46
|
-
* with a stable id. CARD TRAP: it must NEVER wait on the
|
|
47
|
-
* /api/store/consent fetch inside the browser; the layout resolves the
|
|
48
|
-
* setting on the server and inlines it here.
|
|
49
|
-
*/
|
|
50
|
-
export function ConsentInit({
|
|
51
|
-
required,
|
|
52
|
-
}: {
|
|
53
|
-
/** The store's consent switch: `consent.enabled` from `GET /api/store/consent`. */
|
|
54
|
-
required: boolean
|
|
55
|
-
}) {
|
|
56
|
-
return (
|
|
57
|
-
<script
|
|
58
|
-
id="1click-consent-init"
|
|
59
|
-
dangerouslySetInnerHTML={{ __html: consentInitSnippet(required) }}
|
|
60
|
-
/>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
1
|
+
import { consentInitSnippet } from "./consent"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ConsentInit — the synchronous Consent Mode v2 "default" snippet.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the Cartbase reference implementation
|
|
7
|
+
* `src/components/storefront/consent/consent-init.tsx` (itself from
|
|
8
|
+
* `@1click/ui/src/tracking/consent-init.tsx` v2.3.1); the snippet lives in
|
|
9
|
+
* ./consent.ts (`consentInitSnippet`) so its ordering contract is
|
|
10
|
+
* unit-testable.
|
|
11
|
+
*
|
|
12
|
+
* Render it as the FIRST child of <body> (App Router layouts don't
|
|
13
|
+
* expose <head> for inline scripts). A plain inline <script>
|
|
14
|
+
* (deliberately NOT next/script) executes at HTML-parse time — long
|
|
15
|
+
* before the afterInteractive <GA4>/<MetaPixel> loaders, which run
|
|
16
|
+
* post-hydration. Google's consent-mode docs require the default to be
|
|
17
|
+
* set synchronously ahead of the tag; an async default races the
|
|
18
|
+
* loader and the first hit of a returning consented visitor would
|
|
19
|
+
* ship denied.
|
|
20
|
+
*
|
|
21
|
+
* `required` is the store's consent switch, `consent.enabled` from
|
|
22
|
+
* `GET /api/store/consent`, which the layout already fetches for the
|
|
23
|
+
* banner. It is REQUIRED on purpose: with it absent there is no safe
|
|
24
|
+
* default to fall back on. Defaulting to true would keep the pixels of a
|
|
25
|
+
* store that switched its banner off silent forever (the defect fixed on
|
|
26
|
+
* 2026-09-14); defaulting to false would fire them on an EU store whose
|
|
27
|
+
* layout forgot the prop. So the layout states it, and a layout that does
|
|
28
|
+
* not fails to compile.
|
|
29
|
+
*
|
|
30
|
+
* Behavior:
|
|
31
|
+
* - `required` and no stored choice (first visit) → default ALL DENIED.
|
|
32
|
+
* Tags still load (advanced consent mode): gtag sends cookieless
|
|
33
|
+
* pings, the Pixel queues client-side. The <ConsentBanner> then
|
|
34
|
+
* collects the choice and applies the live 'update'.
|
|
35
|
+
* - not `required` and no stored choice → default ALL GRANTED: the store
|
|
36
|
+
* collects no consent, so there is nothing to wait for.
|
|
37
|
+
* - Stored choice → default mirrors it, whatever the switch, so
|
|
38
|
+
* returning visitors are correct from the very first hit with no
|
|
39
|
+
* banner and no race, and a visitor who declined keeps that decision.
|
|
40
|
+
*
|
|
41
|
+
* `ads_data_redaction` strips ad-click identifiers (gclid et al.) from
|
|
42
|
+
* the cookieless pings while ad_storage is denied, per Google's docs.
|
|
43
|
+
*
|
|
44
|
+
* The script interpolates one boolean literal and the shared cookie name,
|
|
45
|
+
* nothing typed by a person — safe as a server-component inline script
|
|
46
|
+
* with a stable id. CARD TRAP: it must NEVER wait on the
|
|
47
|
+
* /api/store/consent fetch inside the browser; the layout resolves the
|
|
48
|
+
* setting on the server and inlines it here.
|
|
49
|
+
*/
|
|
50
|
+
export function ConsentInit({
|
|
51
|
+
required,
|
|
52
|
+
}: {
|
|
53
|
+
/** The store's consent switch: `consent.enabled` from `GET /api/store/consent`. */
|
|
54
|
+
required: boolean
|
|
55
|
+
}) {
|
|
56
|
+
return (
|
|
57
|
+
<script
|
|
58
|
+
id="1click-consent-init"
|
|
59
|
+
dangerouslySetInnerHTML={{ __html: consentInitSnippet(required) }}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|