@rovela-ai/sdk 0.3.17 → 0.3.20
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/dist/admin/api/settings.d.ts.map +1 -1
- package/dist/admin/api/settings.js +4 -0
- package/dist/admin/api/settings.js.map +1 -1
- package/dist/admin/components/AdminAcceptInviteForm.js +1 -1
- package/dist/admin/components/AdminAcceptInviteForm.js.map +1 -1
- package/dist/admin/components/AdminAccountPage.js +1 -1
- package/dist/admin/components/AdminAccountPage.js.map +1 -1
- package/dist/admin/components/AdminForgotPasswordForm.js +1 -1
- package/dist/admin/components/AdminForgotPasswordForm.js.map +1 -1
- package/dist/admin/components/AdminLoginForm.js +1 -1
- package/dist/admin/components/AdminLoginForm.js.map +1 -1
- package/dist/admin/components/AdminResetPasswordForm.js +1 -1
- package/dist/admin/components/AdminResetPasswordForm.js.map +1 -1
- package/dist/admin/components/AdminSetupForm.js +1 -1
- package/dist/admin/components/AdminSetupForm.js.map +1 -1
- package/dist/admin/components/InviteUserDialog.js +1 -1
- package/dist/admin/components/InviteUserDialog.js.map +1 -1
- package/dist/admin/components/StoreSettings.d.ts.map +1 -1
- package/dist/admin/components/StoreSettings.js +11 -3
- package/dist/admin/components/StoreSettings.js.map +1 -1
- package/dist/admin/config.d.ts +30 -38
- package/dist/admin/config.d.ts.map +1 -1
- package/dist/admin/config.js +106 -67
- package/dist/admin/config.js.map +1 -1
- package/dist/admin/hooks/index.d.ts +2 -0
- package/dist/admin/hooks/index.d.ts.map +1 -1
- package/dist/admin/hooks/index.js +1 -0
- package/dist/admin/hooks/index.js.map +1 -1
- package/dist/admin/hooks/useAdminAuth.d.ts +3 -14
- package/dist/admin/hooks/useAdminAuth.d.ts.map +1 -1
- package/dist/admin/hooks/useAdminAuth.js +110 -55
- package/dist/admin/hooks/useAdminAuth.js.map +1 -1
- package/dist/admin/hooks/useAdminSession.d.ts +23 -0
- package/dist/admin/hooks/useAdminSession.d.ts.map +1 -0
- package/dist/admin/hooks/useAdminSession.js +117 -0
- package/dist/admin/hooks/useAdminSession.js.map +1 -0
- package/dist/admin/index.d.ts +2 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/server/admin-service.d.ts.map +1 -1
- package/dist/admin/server/admin-service.js +15 -0
- package/dist/admin/server/admin-service.js.map +1 -1
- package/dist/admin/server/admin-session.d.ts +11 -12
- package/dist/admin/server/admin-session.d.ts.map +1 -1
- package/dist/admin/server/admin-session.js +20 -20
- package/dist/admin/server/admin-session.js.map +1 -1
- package/dist/admin/types.d.ts +5 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/auth/api/request-refund.d.ts.map +1 -1
- package/dist/auth/api/request-refund.js +7 -8
- package/dist/auth/api/request-refund.js.map +1 -1
- package/dist/auth/api/request-return.d.ts.map +1 -1
- package/dist/auth/api/request-return.js +7 -8
- package/dist/auth/api/request-return.js.map +1 -1
- package/dist/auth/components/ForgotPasswordForm.d.ts.map +1 -1
- package/dist/auth/components/ForgotPasswordForm.js +2 -1
- package/dist/auth/components/ForgotPasswordForm.js.map +1 -1
- package/dist/auth/components/Label.d.ts +19 -0
- package/dist/auth/components/Label.d.ts.map +1 -0
- package/dist/auth/components/Label.js +18 -0
- package/dist/auth/components/Label.js.map +1 -0
- package/dist/auth/components/ResetPasswordForm.d.ts.map +1 -1
- package/dist/auth/components/ResetPasswordForm.js +2 -1
- package/dist/auth/components/ResetPasswordForm.js.map +1 -1
- package/dist/auth/components/SignInForm.d.ts.map +1 -1
- package/dist/auth/components/SignInForm.js +2 -1
- package/dist/auth/components/SignInForm.js.map +1 -1
- package/dist/auth/components/SignUpForm.d.ts.map +1 -1
- package/dist/auth/components/SignUpForm.js +2 -1
- package/dist/auth/components/SignUpForm.js.map +1 -1
- package/dist/auth/components/index.d.ts +2 -0
- package/dist/auth/components/index.d.ts.map +1 -1
- package/dist/auth/components/index.js +1 -0
- package/dist/auth/components/index.js.map +1 -1
- package/dist/auth/config.d.ts +22 -10
- package/dist/auth/config.d.ts.map +1 -1
- package/dist/auth/config.js +51 -98
- package/dist/auth/config.js.map +1 -1
- package/dist/auth/hooks/useAuth.d.ts.map +1 -1
- package/dist/auth/hooks/useAuth.js +11 -1
- package/dist/auth/hooks/useAuth.js.map +1 -1
- package/dist/auth/index.d.ts +2 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/server/customer-session.d.ts +81 -0
- package/dist/auth/server/customer-session.d.ts.map +1 -0
- package/dist/auth/server/customer-session.js +115 -0
- package/dist/auth/server/customer-session.js.map +1 -0
- package/dist/auth/server/index.d.ts +2 -0
- package/dist/auth/server/index.d.ts.map +1 -1
- package/dist/auth/server/index.js +2 -0
- package/dist/auth/server/index.js.map +1 -1
- package/dist/core/cookie-consent/CookieBanner.d.ts +2 -0
- package/dist/core/cookie-consent/CookieBanner.d.ts.map +1 -0
- package/dist/core/cookie-consent/CookieBanner.js +207 -0
- package/dist/core/cookie-consent/CookieBanner.js.map +1 -0
- package/dist/core/cookie-consent/CookieConsentProvider.d.ts +53 -0
- package/dist/core/cookie-consent/CookieConsentProvider.d.ts.map +1 -0
- package/dist/core/cookie-consent/CookieConsentProvider.js +162 -0
- package/dist/core/cookie-consent/CookieConsentProvider.js.map +1 -0
- package/dist/core/cookie-consent/CookiePreferencesLink.d.ts +15 -0
- package/dist/core/cookie-consent/CookiePreferencesLink.d.ts.map +1 -0
- package/dist/core/cookie-consent/CookiePreferencesLink.js +12 -0
- package/dist/core/cookie-consent/CookiePreferencesLink.js.map +1 -0
- package/dist/core/cookie-consent/index.d.ts +17 -0
- package/dist/core/cookie-consent/index.d.ts.map +1 -0
- package/dist/core/cookie-consent/index.js +16 -0
- package/dist/core/cookie-consent/index.js.map +1 -0
- package/dist/core/cookie-consent/types.d.ts +31 -0
- package/dist/core/cookie-consent/types.d.ts.map +1 -0
- package/dist/core/cookie-consent/types.js +10 -0
- package/dist/core/cookie-consent/types.js.map +1 -0
- package/dist/core/cookie-consent/useCookieConsent.d.ts +14 -0
- package/dist/core/cookie-consent/useCookieConsent.d.ts.map +1 -0
- package/dist/core/cookie-consent/useCookieConsent.js +25 -0
- package/dist/core/cookie-consent/useCookieConsent.js.map +1 -0
- package/dist/core/db/queries.d.ts +1 -0
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +6 -0
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +17 -0
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +5 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/server/index.d.ts +1 -1
- package/dist/core/server/index.d.ts.map +1 -1
- package/dist/core/server/index.js +3 -1
- package/dist/core/server/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customer-session.js","sourceRoot":"","sources":["../../../src/auth/server/customer-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAsBrD,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF,SAAS,YAAY;IACnB,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,EAC/C,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;AACH,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,EACzC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,UAAmB,CAAA;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,gBAAgB,CAAC,yBAAyB,EAAE,CAAC,CAAA;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAA;QAC/D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAA;IAChD,CAAC;IAED,MAAM,WAAW,GAAI,UAEZ,EAAE,IAAI,CAAA;IAEf,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAA;IAChD,CAAC;IAED,kEAAkE;IAClE,oEAAoE;IACpE,sEAAsE;IACtE,+CAA+C;IAC/C,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAA;IAC7C,CAAC;IAED,uEAAuE;IACvE,2DAA2D;IAC3D,IAAI,QAA0B,CAAA;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAA;QAChD,CAAC;QACD,QAAQ,GAAG;YACT,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,IAAI;YACtB,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa;SACnC,CAAA;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,GAAG,CAAC,CAAA;QACpE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAA;IAChD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;AAC/B,CAAC"}
|
|
@@ -8,6 +8,8 @@ export { hashPassword, verifyPassword, validatePassword, MIN_PASSWORD_LENGTH, }
|
|
|
8
8
|
export { sendVerificationEmail, sendPasswordResetEmail, sendWelcomeEmail, getStoreName, } from './email-sender';
|
|
9
9
|
export { createCustomer, authenticateCustomer, findCustomerForSession, findCustomerByEmail, findCustomerById, updateCustomer, updateCustomerPassword, markEmailVerified, emailExists, } from './customer-service';
|
|
10
10
|
export type { CreateCustomerResult, AuthenticateResult, AuthenticateError, } from './customer-service';
|
|
11
|
+
export { requireCustomer } from './customer-session';
|
|
12
|
+
export type { VerifiedCustomer, RequireCustomerResult } from './customer-session';
|
|
11
13
|
export { createVerificationToken, verifyEmail, deleteVerificationTokens, resendVerificationEmail, isEmailVerified, cleanupExpiredTokens, } from './verification-service';
|
|
12
14
|
export { requestPasswordReset, validateResetToken, resetPassword, deletePasswordResetTokens, cleanupExpiredResetTokens, } from './password-reset-service';
|
|
13
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,GACb,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,GACZ,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,GACb,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,GACZ,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAGjF,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA"}
|
|
@@ -10,6 +10,8 @@ export { hashPassword, verifyPassword, validatePassword, MIN_PASSWORD_LENGTH, }
|
|
|
10
10
|
export { sendVerificationEmail, sendPasswordResetEmail, sendWelcomeEmail, getStoreName, } from './email-sender';
|
|
11
11
|
// Customer service
|
|
12
12
|
export { createCustomer, authenticateCustomer, findCustomerForSession, findCustomerByEmail, findCustomerById, updateCustomer, updateCustomerPassword, markEmailVerified, emailExists, } from './customer-service';
|
|
13
|
+
// Customer session guard (mirror of requireAdmin on the admin side)
|
|
14
|
+
export { requireCustomer } from './customer-session';
|
|
13
15
|
// Verification service
|
|
14
16
|
export { createVerificationToken, verifyEmail, deleteVerificationTokens, resendVerificationEmail, isEmailVerified, cleanupExpiredTokens, } from './verification-service';
|
|
15
17
|
// Password reset service
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAqB;AACrB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,kBAAkB;AAClB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,GACb,MAAM,gBAAgB,CAAA;AAEvB,mBAAmB;AACnB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,GACZ,MAAM,oBAAoB,CAAA;AAO3B,uBAAuB;AACvB,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAA;AAE/B,yBAAyB;AACzB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAqB;AACrB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,kBAAkB;AAClB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,GACb,MAAM,gBAAgB,CAAA;AAEvB,mBAAmB;AACnB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,GACZ,MAAM,oBAAoB,CAAA;AAO3B,oEAAoE;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGpD,uBAAuB;AACvB,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAA;AAE/B,yBAAyB;AACzB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieBanner.d.ts","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookieBanner.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,YAAY,mDAgG3B"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/core/cookie-consent/CookieBanner (R021)
|
|
5
|
+
*
|
|
6
|
+
* EDPB-compliant cookie consent banner for the storefront. Two layers:
|
|
7
|
+
*
|
|
8
|
+
* Layer 1 (first visit) — short intro + three equally-prominent
|
|
9
|
+
* buttons: Accept all · Reject all · Customize.
|
|
10
|
+
*
|
|
11
|
+
* Layer 2 (on Customize or via footer preferences link) — three
|
|
12
|
+
* category toggles (Essential=locked-on, Analytics, Marketing) +
|
|
13
|
+
* Save preferences.
|
|
14
|
+
*
|
|
15
|
+
* Compliance notes applied:
|
|
16
|
+
* - No pre-ticked boxes (EDPB §2.7)
|
|
17
|
+
* - Reject All same prominence as Accept All (EDPB §2.2)
|
|
18
|
+
* - No "continued browsing = consent" (EDPB §3.3)
|
|
19
|
+
* - Closing = refusal (×) — not silent acceptance
|
|
20
|
+
* - `aria-live` for screen readers, explicit focus trap in layer 2
|
|
21
|
+
*
|
|
22
|
+
* Styling uses the storefront's own CSS tokens (hsl(var(--accent)),
|
|
23
|
+
* hsl(var(--foreground))) so the banner blends with the merchant's
|
|
24
|
+
* theme. Inline styles on critical layout bits so Tailwind purge or
|
|
25
|
+
* accidental CSS-reset strips can't erase the compliance UX.
|
|
26
|
+
*/
|
|
27
|
+
import * as React from 'react';
|
|
28
|
+
import { useConsentContext } from './CookieConsentProvider';
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Component
|
|
31
|
+
// =============================================================================
|
|
32
|
+
export function CookieBanner() {
|
|
33
|
+
const { consent, hasDecided, bannerDisabled, preferencesOpen, update, closePreferences, } = useConsentContext();
|
|
34
|
+
// Local state for the customize layer's pending toggles (only
|
|
35
|
+
// committed to the provider when user clicks Save).
|
|
36
|
+
const [pendingAnalytics, setPendingAnalytics] = React.useState(false);
|
|
37
|
+
const [pendingMarketing, setPendingMarketing] = React.useState(false);
|
|
38
|
+
const [showLayer2, setShowLayer2] = React.useState(false);
|
|
39
|
+
// Reset pending toggles to current consent whenever the customize
|
|
40
|
+
// layer opens (from footer link or Layer 1's Customize button).
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (preferencesOpen || showLayer2) {
|
|
43
|
+
setPendingAnalytics(consent.analytics);
|
|
44
|
+
setPendingMarketing(consent.marketing);
|
|
45
|
+
}
|
|
46
|
+
}, [preferencesOpen, showLayer2, consent.analytics, consent.marketing]);
|
|
47
|
+
// Render gates.
|
|
48
|
+
if (bannerDisabled)
|
|
49
|
+
return null;
|
|
50
|
+
const showLayer1 = !hasDecided && !showLayer2 && !preferencesOpen;
|
|
51
|
+
const showPreferences = showLayer2 || preferencesOpen;
|
|
52
|
+
if (!showLayer1 && !showPreferences)
|
|
53
|
+
return null;
|
|
54
|
+
const handleAcceptAll = () => {
|
|
55
|
+
update({ analytics: true, marketing: true });
|
|
56
|
+
setShowLayer2(false);
|
|
57
|
+
closePreferences();
|
|
58
|
+
};
|
|
59
|
+
const handleRejectAll = () => {
|
|
60
|
+
update({ analytics: false, marketing: false });
|
|
61
|
+
setShowLayer2(false);
|
|
62
|
+
closePreferences();
|
|
63
|
+
};
|
|
64
|
+
const handleSave = () => {
|
|
65
|
+
update({ analytics: pendingAnalytics, marketing: pendingMarketing });
|
|
66
|
+
setShowLayer2(false);
|
|
67
|
+
closePreferences();
|
|
68
|
+
};
|
|
69
|
+
const handleClose = () => {
|
|
70
|
+
// Closing = refusal (EDPB). Explicit user rejection.
|
|
71
|
+
handleRejectAll();
|
|
72
|
+
};
|
|
73
|
+
return (_jsxs("div", { role: "dialog", "aria-modal": "false", "aria-label": "Cookie consent", "aria-live": "polite", className: "rovela-cookie-banner", style: {
|
|
74
|
+
position: 'fixed',
|
|
75
|
+
bottom: '1rem',
|
|
76
|
+
left: '1rem',
|
|
77
|
+
zIndex: 2147483000,
|
|
78
|
+
// Anchor to bottom-left. `maxWidth` sizes the card; removing the
|
|
79
|
+
// matching `right` + `margin: '0 auto'` is what stops the browser
|
|
80
|
+
// from centering it via equal left/right insets.
|
|
81
|
+
maxWidth: `min(${showPreferences ? '28rem' : '26rem'}, calc(100vw - 2rem))`,
|
|
82
|
+
background: 'hsl(var(--card, 0 0% 100%))',
|
|
83
|
+
border: '1px solid hsl(var(--border, 220 13% 91%))',
|
|
84
|
+
borderRadius: '0.75rem',
|
|
85
|
+
boxShadow: '0 10px 25px -5px rgba(0,0,0,0.15), 0 8px 10px -6px rgba(0,0,0,0.08)',
|
|
86
|
+
padding: '1.25rem',
|
|
87
|
+
fontFamily: 'inherit',
|
|
88
|
+
color: 'hsl(var(--foreground, 224 71.4% 4.1%))',
|
|
89
|
+
}, children: [showLayer1 && _jsx(Layer1, { onAcceptAll: handleAcceptAll, onRejectAll: handleRejectAll, onCustomize: () => setShowLayer2(true), onClose: handleClose }), showPreferences && _jsx(Layer2, { analytics: pendingAnalytics, marketing: pendingMarketing, onAnalyticsChange: setPendingAnalytics, onMarketingChange: setPendingMarketing, onSave: handleSave, onAcceptAll: handleAcceptAll, onRejectAll: handleRejectAll, onClose: handleClose })] }));
|
|
90
|
+
}
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Layer 1 — initial banner
|
|
93
|
+
// =============================================================================
|
|
94
|
+
function Layer1({ onAcceptAll, onRejectAll, onCustomize, onClose, }) {
|
|
95
|
+
return (_jsxs("div", { style: { position: 'relative' }, children: [_jsx("button", { type: "button", onClick: onClose, "aria-label": "Close and reject non-essential cookies", style: closeButtonStyle, children: "\u00D7" }), _jsx("h2", { style: titleStyle, children: "Cookie preferences" }), _jsxs("p", { style: bodyStyle, children: ["We use cookies to make this store work and, with your consent, to understand how it's used and show you relevant content. You can choose which categories to allow.", ' ', _jsx("a", { href: "/privacy#cookies", style: linkStyle, target: "_blank", rel: "noopener noreferrer", children: "Learn more" })] }), _jsxs("div", { style: {
|
|
96
|
+
display: 'flex',
|
|
97
|
+
flexWrap: 'wrap',
|
|
98
|
+
gap: '0.5rem',
|
|
99
|
+
marginTop: '1rem',
|
|
100
|
+
}, children: [_jsx("button", { type: "button", onClick: onAcceptAll, style: primaryButtonStyle, children: "Accept all" }), _jsx("button", { type: "button", onClick: onRejectAll, style: secondaryButtonStyle, children: "Reject all" }), _jsx("button", { type: "button", onClick: onCustomize, style: tertiaryButtonStyle, children: "Customize" })] })] }));
|
|
101
|
+
}
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// Layer 2 — category preferences
|
|
104
|
+
// =============================================================================
|
|
105
|
+
function Layer2({ analytics, marketing, onAnalyticsChange, onMarketingChange, onSave, onAcceptAll, onRejectAll, onClose, }) {
|
|
106
|
+
return (_jsxs("div", { style: { position: 'relative' }, children: [_jsx("button", { type: "button", onClick: onClose, "aria-label": "Close without saving", style: closeButtonStyle, children: "\u00D7" }), _jsx("h2", { style: titleStyle, children: "Cookie preferences" }), _jsx("p", { style: bodyStyle, children: "Choose which categories of cookies you allow." }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '0.75rem', marginTop: '0.75rem' }, children: [_jsx(CategoryRow, { title: "Essential", description: "Required for core features like cart and login. Always on.", checked: true, locked: true }), _jsx(CategoryRow, { title: "Analytics", description: "Help us understand how the store is used so we can improve it.", checked: analytics, onChange: onAnalyticsChange }), _jsx(CategoryRow, { title: "Marketing", description: "Used to measure ads and show you relevant content across sites.", checked: marketing, onChange: onMarketingChange })] }), _jsxs("div", { style: {
|
|
107
|
+
display: 'flex',
|
|
108
|
+
flexWrap: 'wrap',
|
|
109
|
+
gap: '0.5rem',
|
|
110
|
+
marginTop: '1rem',
|
|
111
|
+
justifyContent: 'space-between',
|
|
112
|
+
}, children: [_jsxs("div", { style: { display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }, children: [_jsx("button", { type: "button", onClick: onAcceptAll, style: tertiaryButtonStyle, children: "Accept all" }), _jsx("button", { type: "button", onClick: onRejectAll, style: tertiaryButtonStyle, children: "Reject all" })] }), _jsx("button", { type: "button", onClick: onSave, style: primaryButtonStyle, children: "Save preferences" })] })] }));
|
|
113
|
+
}
|
|
114
|
+
function CategoryRow({ title, description, checked, onChange, locked, }) {
|
|
115
|
+
return (_jsxs("div", { style: {
|
|
116
|
+
display: 'flex',
|
|
117
|
+
alignItems: 'flex-start',
|
|
118
|
+
justifyContent: 'space-between',
|
|
119
|
+
gap: '0.75rem',
|
|
120
|
+
padding: '0.75rem',
|
|
121
|
+
border: '1px solid hsl(var(--border, 220 13% 91%))',
|
|
122
|
+
borderRadius: '0.5rem',
|
|
123
|
+
}, children: [_jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 600, fontSize: '0.875rem' }, children: title }), _jsx("p", { style: {
|
|
124
|
+
margin: '0.125rem 0 0',
|
|
125
|
+
fontSize: '0.8125rem',
|
|
126
|
+
lineHeight: 1.45,
|
|
127
|
+
color: 'hsl(var(--muted-foreground, 215 16% 47%))',
|
|
128
|
+
}, children: description })] }), _jsx("label", { style: {
|
|
129
|
+
display: 'inline-flex',
|
|
130
|
+
alignItems: 'center',
|
|
131
|
+
gap: '0.5rem',
|
|
132
|
+
cursor: locked ? 'not-allowed' : 'pointer',
|
|
133
|
+
opacity: locked ? 0.6 : 1,
|
|
134
|
+
}, children: _jsx("input", { type: "checkbox", checked: checked, disabled: locked, onChange: (e) => onChange?.(e.target.checked), "aria-label": `Allow ${title.toLowerCase()} cookies`, style: { width: '1rem', height: '1rem', accentColor: 'hsl(var(--accent, 142 71% 45%))' } }) })] }));
|
|
135
|
+
}
|
|
136
|
+
// =============================================================================
|
|
137
|
+
// Inline styles — kept together so CSS-reset strips can't wreck them
|
|
138
|
+
// =============================================================================
|
|
139
|
+
const titleStyle = {
|
|
140
|
+
margin: 0,
|
|
141
|
+
fontSize: '1rem',
|
|
142
|
+
fontWeight: 600,
|
|
143
|
+
lineHeight: 1.3,
|
|
144
|
+
};
|
|
145
|
+
const bodyStyle = {
|
|
146
|
+
margin: '0.375rem 0 0',
|
|
147
|
+
fontSize: '0.875rem',
|
|
148
|
+
lineHeight: 1.5,
|
|
149
|
+
color: 'hsl(var(--muted-foreground, 215 16% 47%))',
|
|
150
|
+
};
|
|
151
|
+
const linkStyle = {
|
|
152
|
+
color: 'hsl(var(--accent, 142 71% 45%))',
|
|
153
|
+
textDecoration: 'underline',
|
|
154
|
+
textUnderlineOffset: '2px',
|
|
155
|
+
};
|
|
156
|
+
const primaryButtonStyle = {
|
|
157
|
+
flex: '1 1 auto',
|
|
158
|
+
padding: '0.5rem 1rem',
|
|
159
|
+
fontSize: '0.875rem',
|
|
160
|
+
fontWeight: 500,
|
|
161
|
+
color: 'hsl(var(--accent-foreground, 0 0% 100%))',
|
|
162
|
+
background: 'hsl(var(--accent, 142 71% 45%))',
|
|
163
|
+
border: 'none',
|
|
164
|
+
borderRadius: '0.5rem',
|
|
165
|
+
cursor: 'pointer',
|
|
166
|
+
};
|
|
167
|
+
const secondaryButtonStyle = {
|
|
168
|
+
flex: '1 1 auto',
|
|
169
|
+
padding: '0.5rem 1rem',
|
|
170
|
+
fontSize: '0.875rem',
|
|
171
|
+
fontWeight: 500,
|
|
172
|
+
color: 'hsl(var(--foreground, 224 71.4% 4.1%))',
|
|
173
|
+
background: 'hsl(var(--muted, 220 14% 96%))',
|
|
174
|
+
border: '1px solid hsl(var(--border, 220 13% 91%))',
|
|
175
|
+
borderRadius: '0.5rem',
|
|
176
|
+
cursor: 'pointer',
|
|
177
|
+
};
|
|
178
|
+
const tertiaryButtonStyle = {
|
|
179
|
+
flex: '0 1 auto',
|
|
180
|
+
padding: '0.5rem 1rem',
|
|
181
|
+
fontSize: '0.875rem',
|
|
182
|
+
fontWeight: 500,
|
|
183
|
+
color: 'hsl(var(--foreground, 224 71.4% 4.1%))',
|
|
184
|
+
background: 'transparent',
|
|
185
|
+
border: '1px solid hsl(var(--border, 220 13% 91%))',
|
|
186
|
+
borderRadius: '0.5rem',
|
|
187
|
+
cursor: 'pointer',
|
|
188
|
+
};
|
|
189
|
+
const closeButtonStyle = {
|
|
190
|
+
position: 'absolute',
|
|
191
|
+
top: '-0.25rem',
|
|
192
|
+
right: '-0.25rem',
|
|
193
|
+
width: '1.5rem',
|
|
194
|
+
height: '1.5rem',
|
|
195
|
+
display: 'flex',
|
|
196
|
+
alignItems: 'center',
|
|
197
|
+
justifyContent: 'center',
|
|
198
|
+
padding: 0,
|
|
199
|
+
fontSize: '1.125rem',
|
|
200
|
+
lineHeight: 1,
|
|
201
|
+
color: 'hsl(var(--muted-foreground, 215 16% 47%))',
|
|
202
|
+
background: 'transparent',
|
|
203
|
+
border: 'none',
|
|
204
|
+
borderRadius: '0.25rem',
|
|
205
|
+
cursor: 'pointer',
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=CookieBanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieBanner.js","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookieBanner.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/core/cookie-consent/CookieConsentProvider (R021)
|
|
3
|
+
*
|
|
4
|
+
* Stores + shares cookie-consent state across the storefront. Drives the
|
|
5
|
+
* `<CookieBanner>` component and the `useCookieConsent()` hook.
|
|
6
|
+
*
|
|
7
|
+
* Design notes:
|
|
8
|
+
* - Persistence is localStorage-only. EDPB "consent record" expectation
|
|
9
|
+
* is satisfied for SMB scale; server-side logging is an enterprise
|
|
10
|
+
* feature and out of scope.
|
|
11
|
+
* - Re-prompts after 12 months (industry-converged interpretation of
|
|
12
|
+
* the EDPB Task Force dark-pattern analysis) or when `VERSION` bumps.
|
|
13
|
+
* - When the store admin disables the banner entirely (master toggle
|
|
14
|
+
* off), the provider short-circuits and grants all categories so
|
|
15
|
+
* consumer scripts don't stall. This matches the merchant's stated
|
|
16
|
+
* intent — if they've disabled the banner, they've accepted the risk
|
|
17
|
+
* and want scripts to run unconditionally.
|
|
18
|
+
*/
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
import type { ConsentCategories, ConsentRecord } from './types';
|
|
21
|
+
interface CookieConsentContextValue {
|
|
22
|
+
/** The current consent record. `decidedAt === null` means the user
|
|
23
|
+
* has not yet chosen. */
|
|
24
|
+
consent: ConsentRecord;
|
|
25
|
+
/** True once the user has made an explicit choice in-window. Scripts
|
|
26
|
+
* should gate on `consent.analytics` / `consent.marketing` instead of
|
|
27
|
+
* this — this is mostly for the banner's own render logic. */
|
|
28
|
+
hasDecided: boolean;
|
|
29
|
+
/** True when the master toggle is off (admin disabled banner). Scripts
|
|
30
|
+
* treat this as implicit-grant; the banner never renders. */
|
|
31
|
+
bannerDisabled: boolean;
|
|
32
|
+
/** Set full consent (essentials always on). Used by banner's Accept /
|
|
33
|
+
* Reject / Save actions. */
|
|
34
|
+
update: (categories: Partial<ConsentCategories>) => void;
|
|
35
|
+
/** Open the preferences layer of the banner. Triggered by the footer
|
|
36
|
+
* "Cookie preferences" link. */
|
|
37
|
+
openPreferences: () => void;
|
|
38
|
+
/** Whether the preferences layer should currently be shown. The
|
|
39
|
+
* banner reads this; external code just calls `openPreferences`. */
|
|
40
|
+
preferencesOpen: boolean;
|
|
41
|
+
/** Banner uses this to close its own preferences layer after Save. */
|
|
42
|
+
closePreferences: () => void;
|
|
43
|
+
}
|
|
44
|
+
export interface CookieConsentProviderProps {
|
|
45
|
+
/** Master toggle from store_settings.cookie_banner_enabled. When
|
|
46
|
+
* `false`, the banner never renders and scripts get implicit grant. */
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
children: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
export declare function CookieConsentProvider({ enabled, children, }: CookieConsentProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export declare function useConsentContext(): CookieConsentContextValue;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=CookieConsentProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieConsentProvider.d.ts","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookieConsentProvider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAsB/D,UAAU,yBAAyB;IACjC;8BAC0B;IAC1B,OAAO,EAAE,aAAa,CAAA;IACtB;;mEAE+D;IAC/D,UAAU,EAAE,OAAO,CAAA;IACnB;kEAC8D;IAC9D,cAAc,EAAE,OAAO,CAAA;IACvB;iCAC6B;IAC7B,MAAM,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IACxD;qCACiC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B;yEACqE;IACrE,eAAe,EAAE,OAAO,CAAA;IACxB,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B;AA6ED,MAAM,WAAW,0BAA0B;IACzC;4EACwE;IACxE,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,QAAQ,GACT,EAAE,0BAA0B,2CAgE5B;AAMD,wBAAgB,iBAAiB,IAAI,yBAAyB,CAQ7D"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/core/cookie-consent/CookieConsentProvider (R021)
|
|
5
|
+
*
|
|
6
|
+
* Stores + shares cookie-consent state across the storefront. Drives the
|
|
7
|
+
* `<CookieBanner>` component and the `useCookieConsent()` hook.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - Persistence is localStorage-only. EDPB "consent record" expectation
|
|
11
|
+
* is satisfied for SMB scale; server-side logging is an enterprise
|
|
12
|
+
* feature and out of scope.
|
|
13
|
+
* - Re-prompts after 12 months (industry-converged interpretation of
|
|
14
|
+
* the EDPB Task Force dark-pattern analysis) or when `VERSION` bumps.
|
|
15
|
+
* - When the store admin disables the banner entirely (master toggle
|
|
16
|
+
* off), the provider short-circuits and grants all categories so
|
|
17
|
+
* consumer scripts don't stall. This matches the merchant's stated
|
|
18
|
+
* intent — if they've disabled the banner, they've accepted the risk
|
|
19
|
+
* and want scripts to run unconditionally.
|
|
20
|
+
*/
|
|
21
|
+
import * as React from 'react';
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Constants
|
|
24
|
+
// =============================================================================
|
|
25
|
+
/** localStorage key for the stored consent record. */
|
|
26
|
+
const STORAGE_KEY = 'rovela-cookie-consent';
|
|
27
|
+
/** Schema version — bump when adding a category or changing what an
|
|
28
|
+
* existing category covers; existing stored consent gets invalidated
|
|
29
|
+
* and the user is re-prompted. */
|
|
30
|
+
const VERSION = 1;
|
|
31
|
+
/** Re-prompt after this many days. 365 matches the DPA industry-
|
|
32
|
+
* converged window (12 months). */
|
|
33
|
+
const REPROMPT_AFTER_DAYS = 365;
|
|
34
|
+
const CookieConsentContext = React.createContext(null);
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Defaults
|
|
37
|
+
// =============================================================================
|
|
38
|
+
function defaultConsent() {
|
|
39
|
+
return {
|
|
40
|
+
essential: true,
|
|
41
|
+
analytics: false,
|
|
42
|
+
marketing: false,
|
|
43
|
+
decidedAt: null,
|
|
44
|
+
version: VERSION,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function fullGrant() {
|
|
48
|
+
return {
|
|
49
|
+
essential: true,
|
|
50
|
+
analytics: true,
|
|
51
|
+
marketing: true,
|
|
52
|
+
decidedAt: new Date().toISOString(),
|
|
53
|
+
version: VERSION,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// =============================================================================
|
|
57
|
+
// Persistence helpers
|
|
58
|
+
// =============================================================================
|
|
59
|
+
function readStoredConsent() {
|
|
60
|
+
if (typeof window === 'undefined')
|
|
61
|
+
return null;
|
|
62
|
+
try {
|
|
63
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
64
|
+
if (!raw)
|
|
65
|
+
return null;
|
|
66
|
+
const parsed = JSON.parse(raw);
|
|
67
|
+
// Version bump invalidates old consent.
|
|
68
|
+
if (parsed.version !== VERSION)
|
|
69
|
+
return null;
|
|
70
|
+
// Decision expired (>12 months) → re-prompt.
|
|
71
|
+
if (parsed.decidedAt) {
|
|
72
|
+
const ageDays = (Date.now() - new Date(parsed.decidedAt).getTime()) /
|
|
73
|
+
(1000 * 60 * 60 * 24);
|
|
74
|
+
if (ageDays > REPROMPT_AFTER_DAYS)
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
essential: true,
|
|
79
|
+
analytics: !!parsed.analytics,
|
|
80
|
+
marketing: !!parsed.marketing,
|
|
81
|
+
decidedAt: parsed.decidedAt ?? null,
|
|
82
|
+
version: VERSION,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function writeStoredConsent(record) {
|
|
90
|
+
if (typeof window === 'undefined')
|
|
91
|
+
return;
|
|
92
|
+
try {
|
|
93
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Private-mode localStorage throws. Ignore — in-memory state is fine
|
|
97
|
+
// for the session; user re-prompts next visit.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export function CookieConsentProvider({ enabled, children, }) {
|
|
101
|
+
// SSR-safe initial state — provider always starts with "not decided";
|
|
102
|
+
// the post-mount effect reads localStorage and updates. Means we don't
|
|
103
|
+
// hydration-mismatch between server and client.
|
|
104
|
+
const [consent, setConsent] = React.useState(defaultConsent);
|
|
105
|
+
const [hydrated, setHydrated] = React.useState(false);
|
|
106
|
+
const [preferencesOpen, setPreferencesOpen] = React.useState(false);
|
|
107
|
+
// On mount, read the stored decision (if any within re-prompt window).
|
|
108
|
+
React.useEffect(() => {
|
|
109
|
+
if (!enabled) {
|
|
110
|
+
// Admin disabled the banner — grant everything so analytics/
|
|
111
|
+
// marketing scripts can run. This is the merchant's call.
|
|
112
|
+
setConsent(fullGrant());
|
|
113
|
+
setHydrated(true);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const stored = readStoredConsent();
|
|
117
|
+
if (stored)
|
|
118
|
+
setConsent(stored);
|
|
119
|
+
setHydrated(true);
|
|
120
|
+
}, [enabled]);
|
|
121
|
+
const update = React.useCallback((categories) => {
|
|
122
|
+
const next = {
|
|
123
|
+
essential: true,
|
|
124
|
+
analytics: categories.analytics ?? false,
|
|
125
|
+
marketing: categories.marketing ?? false,
|
|
126
|
+
decidedAt: new Date().toISOString(),
|
|
127
|
+
version: VERSION,
|
|
128
|
+
};
|
|
129
|
+
setConsent(next);
|
|
130
|
+
writeStoredConsent(next);
|
|
131
|
+
}, []);
|
|
132
|
+
const openPreferences = React.useCallback(() => {
|
|
133
|
+
setPreferencesOpen(true);
|
|
134
|
+
}, []);
|
|
135
|
+
const closePreferences = React.useCallback(() => {
|
|
136
|
+
setPreferencesOpen(false);
|
|
137
|
+
}, []);
|
|
138
|
+
const value = React.useMemo(() => ({
|
|
139
|
+
consent,
|
|
140
|
+
hasDecided: consent.decidedAt !== null,
|
|
141
|
+
bannerDisabled: !enabled,
|
|
142
|
+
update,
|
|
143
|
+
openPreferences,
|
|
144
|
+
preferencesOpen,
|
|
145
|
+
closePreferences,
|
|
146
|
+
}), [consent, enabled, update, openPreferences, preferencesOpen, closePreferences]);
|
|
147
|
+
// Don't flash children with stale SSR state → the first client render
|
|
148
|
+
// is default (not-decided) which is safe: no scripts gate on it yet.
|
|
149
|
+
void hydrated;
|
|
150
|
+
return (_jsx(CookieConsentContext.Provider, { value: value, children: children }));
|
|
151
|
+
}
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// Internal hook
|
|
154
|
+
// =============================================================================
|
|
155
|
+
export function useConsentContext() {
|
|
156
|
+
const ctx = React.useContext(CookieConsentContext);
|
|
157
|
+
if (!ctx) {
|
|
158
|
+
throw new Error('useCookieConsent must be used within <CookieConsentProvider>');
|
|
159
|
+
}
|
|
160
|
+
return ctx;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=CookieConsentProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieConsentProvider.js","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookieConsentProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/core/cookie-consent/CookiePreferencesLink (R021)
|
|
3
|
+
*
|
|
4
|
+
* Persistent "Cookie preferences" link/button for the storefront footer.
|
|
5
|
+
* Clicking it re-opens the banner's customize layer so users can change
|
|
6
|
+
* their decision at any time — fulfills the GDPR Art. 7(3) "withdrawal
|
|
7
|
+
* as easy as consent" requirement.
|
|
8
|
+
*
|
|
9
|
+
* Accepts any standard button attributes so the merchant's storefront
|
|
10
|
+
* can style it to match the footer (or use the default unstyled look).
|
|
11
|
+
*/
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
export type CookiePreferencesLinkProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'type'>;
|
|
14
|
+
export declare function CookiePreferencesLink({ children, ...props }: CookiePreferencesLinkProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
//# sourceMappingURL=CookiePreferencesLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookiePreferencesLink.d.ts","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookiePreferencesLink.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,SAAS,GAAG,MAAM,CACnB,CAAA;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAA+B,EAC/B,GAAG,KAAK,EACT,EAAE,0BAA0B,kDAY5B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useConsentContext } from './CookieConsentProvider';
|
|
4
|
+
export function CookiePreferencesLink({ children = 'Cookie preferences', ...props }) {
|
|
5
|
+
const { openPreferences, bannerDisabled } = useConsentContext();
|
|
6
|
+
// If the merchant has disabled the banner entirely, there are no
|
|
7
|
+
// preferences to manage — don't render the link at all.
|
|
8
|
+
if (bannerDisabled)
|
|
9
|
+
return null;
|
|
10
|
+
return (_jsx("button", { type: "button", onClick: openPreferences, ...props, children: children }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=CookiePreferencesLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookiePreferencesLink.js","sourceRoot":"","sources":["../../../src/core/cookie-consent/CookiePreferencesLink.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAeZ,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAO3D,MAAM,UAAU,qBAAqB,CAAC,EACpC,QAAQ,GAAG,oBAAoB,EAC/B,GAAG,KAAK,EACmB;IAC3B,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAAA;IAE/D,iEAAiE;IACjE,wDAAwD;IACxD,IAAI,cAAc;QAAE,OAAO,IAAI,CAAA;IAE/B,OAAO,CACL,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,eAAe,KAAM,KAAK,YACtD,QAAQ,GACF,CACV,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/core/cookie-consent
|
|
3
|
+
*
|
|
4
|
+
* EDPB-compliant cookie consent primitives for Rovela storefronts
|
|
5
|
+
* (R021). Public surface:
|
|
6
|
+
*
|
|
7
|
+
* - `<CookieConsentProvider>` — wraps the storefront in `app/layout`.
|
|
8
|
+
* - `<CookieBanner />` — the layered consent UI.
|
|
9
|
+
* - `<CookiePreferencesLink />` — footer link to re-open preferences.
|
|
10
|
+
* - `useCookieConsent()` — hook for gating scripts on category grant.
|
|
11
|
+
*/
|
|
12
|
+
export { CookieConsentProvider, type CookieConsentProviderProps, } from './CookieConsentProvider';
|
|
13
|
+
export { CookieBanner } from './CookieBanner';
|
|
14
|
+
export { CookiePreferencesLink, type CookiePreferencesLinkProps, } from './CookiePreferencesLink';
|
|
15
|
+
export { useCookieConsent, type UseCookieConsentReturn } from './useCookieConsent';
|
|
16
|
+
export type { ConsentCategories, ConsentRecord, CategoryKey } from './types';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/cookie-consent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAClF,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/core/cookie-consent
|
|
3
|
+
*
|
|
4
|
+
* EDPB-compliant cookie consent primitives for Rovela storefronts
|
|
5
|
+
* (R021). Public surface:
|
|
6
|
+
*
|
|
7
|
+
* - `<CookieConsentProvider>` — wraps the storefront in `app/layout`.
|
|
8
|
+
* - `<CookieBanner />` — the layered consent UI.
|
|
9
|
+
* - `<CookiePreferencesLink />` — footer link to re-open preferences.
|
|
10
|
+
* - `useCookieConsent()` — hook for gating scripts on category grant.
|
|
11
|
+
*/
|
|
12
|
+
export { CookieConsentProvider, } from './CookieConsentProvider';
|
|
13
|
+
export { CookieBanner } from './CookieBanner';
|
|
14
|
+
export { CookiePreferencesLink, } from './CookiePreferencesLink';
|
|
15
|
+
export { useCookieConsent } from './useCookieConsent';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/cookie-consent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,qBAAqB,GAEtB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EACL,qBAAqB,GAEtB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAA+B,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie consent types (R021).
|
|
3
|
+
*
|
|
4
|
+
* Shared shape between provider, banner, hook. Keep lean — the minimum
|
|
5
|
+
* viable EDPB-compliant categorization is Essential / Analytics /
|
|
6
|
+
* Marketing. We do NOT ship per-vendor granularity; categories are the
|
|
7
|
+
* contract any storefront script follows via `useCookieConsent()`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ConsentCategories {
|
|
10
|
+
/** Strictly necessary (cart, session, login). Always on, never
|
|
11
|
+
* user-toggleable. The field exists for symmetry in checks like
|
|
12
|
+
* `consent.essential` — every script can assume true. */
|
|
13
|
+
essential: true;
|
|
14
|
+
/** Analytics scripts (GA4, Matomo, etc.). Defaults to `false` until
|
|
15
|
+
* the user opts in. */
|
|
16
|
+
analytics: boolean;
|
|
17
|
+
/** Marketing / ad-tech scripts (Meta Pixel, Google Ads, TikTok, etc.).
|
|
18
|
+
* Defaults to `false` until the user opts in. */
|
|
19
|
+
marketing: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ConsentRecord extends ConsentCategories {
|
|
22
|
+
/** ISO timestamp when the decision was last made. `null` before the
|
|
23
|
+
* user has interacted with the banner. */
|
|
24
|
+
decidedAt: string | null;
|
|
25
|
+
/** Schema version of the categories list. Bumping this invalidates
|
|
26
|
+
* stored consent and re-prompts the user — use when adding a new
|
|
27
|
+
* category or materially changing what an existing category covers. */
|
|
28
|
+
version: number;
|
|
29
|
+
}
|
|
30
|
+
export type CategoryKey = 'analytics' | 'marketing';
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/cookie-consent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAChC;;8DAE0D;IAC1D,SAAS,EAAE,IAAI,CAAA;IACf;4BACwB;IACxB,SAAS,EAAE,OAAO,CAAA;IAClB;sDACkD;IAClD,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD;+CAC2C;IAC3C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;4EAEwE;IACxE,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie consent types (R021).
|
|
3
|
+
*
|
|
4
|
+
* Shared shape between provider, banner, hook. Keep lean — the minimum
|
|
5
|
+
* viable EDPB-compliant categorization is Essential / Analytics /
|
|
6
|
+
* Marketing. We do NOT ship per-vendor granularity; categories are the
|
|
7
|
+
* contract any storefront script follows via `useCookieConsent()`.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|