@rovela-ai/sdk 0.16.4 → 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/dist/admin/api/branding.d.ts +79 -0
- package/dist/admin/api/branding.d.ts.map +1 -0
- package/dist/admin/api/branding.js +238 -0
- package/dist/admin/api/branding.js.map +1 -0
- package/dist/admin/api/orders.d.ts.map +1 -1
- package/dist/admin/api/orders.js +10 -3
- package/dist/admin/api/orders.js.map +1 -1
- package/dist/admin/api/refund.d.ts.map +1 -1
- package/dist/admin/api/refund.js +1 -0
- package/dist/admin/api/refund.js.map +1 -1
- package/dist/admin/api/return.d.ts.map +1 -1
- package/dist/admin/api/return.js +1 -0
- package/dist/admin/api/return.js.map +1 -1
- package/dist/admin/api/settings.d.ts.map +1 -1
- package/dist/admin/api/settings.js +27 -4
- package/dist/admin/api/settings.js.map +1 -1
- package/dist/admin/api/stats.d.ts.map +1 -1
- package/dist/admin/api/stats.js +5 -2
- package/dist/admin/api/stats.js.map +1 -1
- package/dist/admin/components/AdminTopBar.d.ts +1 -1
- package/dist/admin/components/AdminTopBar.d.ts.map +1 -1
- package/dist/admin/components/AdminTopBar.js +19 -2
- package/dist/admin/components/AdminTopBar.js.map +1 -1
- package/dist/admin/components/BrandingAssetUpload.d.ts +14 -0
- package/dist/admin/components/BrandingAssetUpload.d.ts.map +1 -0
- package/dist/admin/components/BrandingAssetUpload.js +207 -0
- package/dist/admin/components/BrandingAssetUpload.js.map +1 -0
- package/dist/admin/components/CookieBannerConfigurator.d.ts +9 -0
- package/dist/admin/components/CookieBannerConfigurator.d.ts.map +1 -0
- package/dist/admin/components/CookieBannerConfigurator.js +97 -0
- package/dist/admin/components/CookieBannerConfigurator.js.map +1 -0
- package/dist/admin/components/CustomerDetails.d.ts.map +1 -1
- package/dist/admin/components/CustomerDetails.js +5 -17
- package/dist/admin/components/CustomerDetails.js.map +1 -1
- package/dist/admin/components/CustomerTable.d.ts.map +1 -1
- package/dist/admin/components/CustomerTable.js +4 -8
- package/dist/admin/components/CustomerTable.js.map +1 -1
- package/dist/admin/components/FilesManager.d.ts.map +1 -1
- package/dist/admin/components/FilesManager.js +7 -3
- package/dist/admin/components/FilesManager.js.map +1 -1
- package/dist/admin/components/LogoUpload.d.ts +11 -10
- package/dist/admin/components/LogoUpload.d.ts.map +1 -1
- package/dist/admin/components/LogoUpload.js +8 -192
- package/dist/admin/components/LogoUpload.js.map +1 -1
- package/dist/admin/components/OrderDetails.d.ts.map +1 -1
- package/dist/admin/components/OrderDetails.js +4 -10
- package/dist/admin/components/OrderDetails.js.map +1 -1
- package/dist/admin/components/OrderTable.d.ts.map +1 -1
- package/dist/admin/components/OrderTable.js +4 -10
- package/dist/admin/components/OrderTable.js.map +1 -1
- package/dist/admin/components/RecentOrders.d.ts.map +1 -1
- package/dist/admin/components/RecentOrders.js +4 -9
- package/dist/admin/components/RecentOrders.js.map +1 -1
- package/dist/admin/components/RevenueChart.d.ts.map +1 -1
- package/dist/admin/components/RevenueChart.js +6 -11
- package/dist/admin/components/RevenueChart.js.map +1 -1
- package/dist/admin/components/StoreSettings.d.ts.map +1 -1
- package/dist/admin/components/StoreSettings.js +54 -15
- package/dist/admin/components/StoreSettings.js.map +1 -1
- package/dist/admin/components/UsersTable.d.ts.map +1 -1
- package/dist/admin/components/UsersTable.js +5 -7
- package/dist/admin/components/UsersTable.js.map +1 -1
- package/dist/admin/components/index.d.ts +4 -0
- package/dist/admin/components/index.d.ts.map +1 -1
- package/dist/admin/components/index.js +2 -0
- package/dist/admin/components/index.js.map +1 -1
- package/dist/admin/hooks/useAdminDates.d.ts +11 -0
- package/dist/admin/hooks/useAdminDates.d.ts.map +1 -0
- package/dist/admin/hooks/useAdminDates.js +46 -0
- package/dist/admin/hooks/useAdminDates.js.map +1 -0
- package/dist/admin/index.d.ts +2 -2
- 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/types.d.ts +3 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/analytics/api/dashboard.d.ts.map +1 -1
- package/dist/analytics/api/dashboard.js +4 -1
- package/dist/analytics/api/dashboard.js.map +1 -1
- package/dist/analytics/server/queries.d.ts +1 -1
- package/dist/analytics/server/queries.d.ts.map +1 -1
- package/dist/analytics/server/queries.js +6 -4
- package/dist/analytics/server/queries.js.map +1 -1
- package/dist/analytics/views/DashboardsView.d.ts.map +1 -1
- package/dist/analytics/views/DashboardsView.js +5 -7
- package/dist/analytics/views/DashboardsView.js.map +1 -1
- package/dist/analytics/views/EventsView.d.ts.map +1 -1
- package/dist/analytics/views/EventsView.js +7 -2
- package/dist/analytics/views/EventsView.js.map +1 -1
- package/dist/analytics/views/VisitorsView.d.ts.map +1 -1
- package/dist/analytics/views/VisitorsView.js +6 -2
- package/dist/analytics/views/VisitorsView.js.map +1 -1
- package/dist/core/StoreSettingsProvider.d.ts +4 -0
- package/dist/core/StoreSettingsProvider.d.ts.map +1 -1
- package/dist/core/StoreSettingsProvider.js +4 -1
- package/dist/core/StoreSettingsProvider.js.map +1 -1
- package/dist/core/api/settings.d.ts +1 -0
- package/dist/core/api/settings.d.ts.map +1 -1
- package/dist/core/api/settings.js +6 -2
- package/dist/core/api/settings.js.map +1 -1
- package/dist/core/cookie-consent/CookieBanner.d.ts.map +1 -1
- package/dist/core/cookie-consent/CookieBanner.js +266 -92
- package/dist/core/cookie-consent/CookieBanner.js.map +1 -1
- package/dist/core/cookie-consent/CookieConsentProvider.d.ts +11 -2
- package/dist/core/cookie-consent/CookieConsentProvider.d.ts.map +1 -1
- package/dist/core/cookie-consent/CookieConsentProvider.js +26 -7
- package/dist/core/cookie-consent/CookieConsentProvider.js.map +1 -1
- package/dist/core/cookie-consent/CookiePreferencesLink.d.ts.map +1 -1
- package/dist/core/cookie-consent/CookiePreferencesLink.js +5 -3
- package/dist/core/cookie-consent/CookiePreferencesLink.js.map +1 -1
- package/dist/core/cookie-consent/index.d.ts +2 -1
- package/dist/core/cookie-consent/index.d.ts.map +1 -1
- package/dist/core/cookie-consent/index.js +1 -0
- package/dist/core/cookie-consent/index.js.map +1 -1
- package/dist/core/cookie-consent/types.d.ts +70 -4
- package/dist/core/cookie-consent/types.d.ts.map +1 -1
- package/dist/core/cookie-consent/types.js +117 -5
- package/dist/core/cookie-consent/types.js.map +1 -1
- package/dist/core/dates.d.ts +15 -0
- package/dist/core/dates.d.ts.map +1 -0
- package/dist/core/dates.js +22 -0
- package/dist/core/dates.js.map +1 -0
- package/dist/core/db/queries.d.ts +34 -30
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +46 -17
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +39 -1
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +10 -1
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/useStoreFormatting.js +1 -1
- package/dist/core/useStoreFormatting.js.map +1 -1
- package/dist/emails/config.d.ts +6 -0
- package/dist/emails/config.d.ts.map +1 -1
- package/dist/emails/config.js +19 -1
- package/dist/emails/config.js.map +1 -1
- package/dist/emails/send/auth.js +1 -1
- package/dist/emails/send/auth.js.map +1 -1
- package/dist/emails/types.d.ts +2 -0
- package/dist/emails/types.d.ts.map +1 -1
- package/dist/emails/utils.d.ts +2 -2
- package/dist/emails/utils.d.ts.map +1 -1
- package/dist/emails/utils.js +8 -2
- package/dist/emails/utils.js.map +1 -1
- package/package.json +5 -1
|
@@ -14,6 +14,7 @@ import { NextResponse } from 'next/server';
|
|
|
14
14
|
import { isSupportedLocale } from '../../core/i18n/types';
|
|
15
15
|
import { requireAdmin } from '../server/admin-session';
|
|
16
16
|
import { findSettings, upsertSettings, listMetafieldKeys } from '../../core/db/queries';
|
|
17
|
+
import { sanitizeCookieConsentConfig } from '../../core/cookie-consent/types';
|
|
17
18
|
// =============================================================================
|
|
18
19
|
// Default Values
|
|
19
20
|
// =============================================================================
|
|
@@ -31,8 +32,8 @@ function getDefaultSettings() {
|
|
|
31
32
|
storeName: process.env.STORE_NAME || 'My Store',
|
|
32
33
|
storeEmail: process.env.SUPPORT_EMAIL || process.env.RESEND_FROM_EMAIL || '',
|
|
33
34
|
storeCurrency: process.env.STORE_CURRENCY || 'USD',
|
|
34
|
-
storeTimezone:
|
|
35
|
-
storeCountry:
|
|
35
|
+
storeTimezone: 'UTC', // matches the seed's last-resort rule (STORE_TIMEZONE env read was dead)
|
|
36
|
+
storeCountry: null, // DB-only (STORE_COUNTRY env read was dead)
|
|
36
37
|
taxIncludedInPrices: true, // Default: prices include tax
|
|
37
38
|
shippingEnabled: true,
|
|
38
39
|
freeShippingThreshold: 0,
|
|
@@ -117,13 +118,30 @@ export async function PUT(request) {
|
|
|
117
118
|
data.storeName = body.storeName.trim().slice(0, 255);
|
|
118
119
|
}
|
|
119
120
|
if (typeof body.storeEmail === 'string') {
|
|
120
|
-
|
|
121
|
+
const email = body.storeEmail.trim().toLowerCase().slice(0, 255);
|
|
122
|
+
// Same RFC-5322-lite rule the generation seed applies — the store
|
|
123
|
+
// email feeds reply-to headers and legal pages; a malformed value
|
|
124
|
+
// breaks email sends silently. Empty string is allowed (= clear).
|
|
125
|
+
if (email !== '' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
126
|
+
return NextResponse.json({ error: 'Store email is not a valid email address.', code: 'VALIDATION_ERROR' }, { status: 400 });
|
|
127
|
+
}
|
|
128
|
+
data.storeEmail = email;
|
|
121
129
|
}
|
|
122
130
|
if (typeof body.storeCurrency === 'string') {
|
|
123
131
|
data.storeCurrency = body.storeCurrency.toUpperCase().slice(0, 10);
|
|
124
132
|
}
|
|
125
133
|
if (typeof body.storeTimezone === 'string') {
|
|
126
|
-
|
|
134
|
+
const tz = body.storeTimezone.slice(0, 100);
|
|
135
|
+
// Validate against the runtime's IANA database (same check the seed
|
|
136
|
+
// uses) — an invalid zone would crash every Intl.DateTimeFormat call
|
|
137
|
+
// that honors it.
|
|
138
|
+
try {
|
|
139
|
+
new Intl.DateTimeFormat('en-US', { timeZone: tz });
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return NextResponse.json({ error: 'Unknown timezone. Pick a valid IANA timezone.', code: 'VALIDATION_ERROR' }, { status: 400 });
|
|
143
|
+
}
|
|
144
|
+
data.storeTimezone = tz;
|
|
127
145
|
}
|
|
128
146
|
// Store home country (ISO 3166-1 alpha-2). Empty string clears is NOT
|
|
129
147
|
// supported (column stays as-is) — upsertSettings treats null/undefined
|
|
@@ -192,6 +210,11 @@ export async function PUT(request) {
|
|
|
192
210
|
if (typeof body.cookieBannerEnabled === 'boolean') {
|
|
193
211
|
data.cookieBannerEnabled = body.cookieBannerEnabled;
|
|
194
212
|
}
|
|
213
|
+
// Cookie-banner configuration — sanitizer is the ONLY ingress (whitelist
|
|
214
|
+
// of enums / hex colors / capped copy strings; unknown keys dropped).
|
|
215
|
+
if (body.cookieConsent !== undefined) {
|
|
216
|
+
data.cookieConsent = sanitizeCookieConsentConfig(body.cookieConsent);
|
|
217
|
+
}
|
|
195
218
|
// Storefront visibility allowlist for custom product fields (metafield keys).
|
|
196
219
|
if (Array.isArray(body.publicMetafieldKeys)) {
|
|
197
220
|
data.publicMetafieldKeys = body.publicMetafieldKeys
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/admin/api/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAqB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/admin/api/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/admin/api/stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/admin/api/stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAM3E,UAAU,aAAa;IACrB,KAAK,EAAE,cAAc,CAAA;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,EAAE,CAAA;IACvB,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAClD,cAAc,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACpD,qFAAqF;IACrF,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,aAAa,GAAG,aAAa,CAAC,CAAC,CA2EtD"}
|
package/dist/admin/api/stats.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { NextResponse } from 'next/server';
|
|
13
13
|
import { requireAdmin } from '../server/admin-session';
|
|
14
|
-
import { getStoreStats, getLowStockProducts, getLowStockCount, getRecentOrders, getRevenueByPeriod, getOrdersByStatus, getDashboardSummary, } from '../../core/db/queries';
|
|
14
|
+
import { getStoreStats, getLowStockProducts, getLowStockCount, getRecentOrders, getRevenueByPeriod, findSettings, getOrdersByStatus, getDashboardSummary, } from '../../core/db/queries';
|
|
15
15
|
// Map the public period code to a number of calendar days.
|
|
16
16
|
const PERIOD_DAYS = {
|
|
17
17
|
today: 1,
|
|
@@ -79,7 +79,10 @@ export async function GET(request) {
|
|
|
79
79
|
// Optionally include revenue data — match the requested period when set,
|
|
80
80
|
// otherwise default to 30 days.
|
|
81
81
|
if (includeRevenue) {
|
|
82
|
-
|
|
82
|
+
// Day buckets anchored to the STORE's timezone — the merchant's
|
|
83
|
+
// revenue day must match their local calendar day, not UTC.
|
|
84
|
+
const tzSettings = await findSettings().catch(() => null);
|
|
85
|
+
response.revenueByDay = await getRevenueByPeriod(periodDays ?? 30, tzSettings?.storeTimezone || 'UTC');
|
|
83
86
|
}
|
|
84
87
|
// Optionally include order status breakdown — scope to the period when set.
|
|
85
88
|
if (includeOrderStatus) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/admin/api/stats.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/admin/api/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminTopBar.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminTopBar.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"AdminTopBar.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminTopBar.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAQ3D,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EAAE,aAAuB,EAClC,IAAI,EACJ,QAAc,EACd,SAAc,GACf,EAAE,gBAAgB,2CA8FlB"}
|
|
@@ -17,6 +17,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
17
17
|
*/
|
|
18
18
|
import Link from 'next/link';
|
|
19
19
|
import { ExternalLink, Pencil } from 'lucide-react';
|
|
20
|
+
import { useEffect, useState } from 'react';
|
|
20
21
|
import { useStoreSettingsOptional } from '../../core';
|
|
21
22
|
import { AdminUserMenu } from './AdminUserMenu';
|
|
22
23
|
// =============================================================================
|
|
@@ -29,7 +30,23 @@ export function AdminTopBar({ storeName: storeNameProp = 'Admin', logo, storeUrl
|
|
|
29
30
|
const storeSettings = useStoreSettingsOptional();
|
|
30
31
|
const settingsLoading = storeNameProp === 'Admin' && !!storeSettings?.isLoading && !storeSettings?.settings;
|
|
31
32
|
const storeName = storeNameProp !== 'Admin' ? storeNameProp : (storeSettings?.storeName || storeNameProp);
|
|
33
|
+
// Brand tile mark: favicon FIRST (a square mark belongs in a 32px tile;
|
|
34
|
+
// wide logo lockups read cramped), then logo, then monogram. Each source
|
|
35
|
+
// is settings-first (live store_settings via the provider) with the
|
|
36
|
+
// build-time env var as fallback — the branding write contract keeps the
|
|
37
|
+
// settings mirror fresh, so store-side changes show without a redeploy.
|
|
38
|
+
const faviconUrl = storeSettings?.faviconUrl || process.env.NEXT_PUBLIC_STORE_FAVICON_URL || null;
|
|
32
39
|
const logoUrl = storeSettings?.logoUrl || process.env.NEXT_PUBLIC_STORE_LOGO_URL || null;
|
|
40
|
+
const tileUrl = faviconUrl || logoUrl;
|
|
41
|
+
// A stale pointer (e.g. asset deleted store-side while an env var still
|
|
42
|
+
// carries the fixed URL) must degrade to the monogram, never a broken img.
|
|
43
|
+
const [tileBroken, setTileBroken] = useState(false);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
// Pattern A — reset internal state on prop change (retry when the URL changes).
|
|
46
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
47
|
+
setTileBroken(false);
|
|
48
|
+
}, [tileUrl]);
|
|
49
|
+
const tileSrc = tileBroken ? null : tileUrl;
|
|
33
50
|
// Deep-link back to the Rovela editor (/generate/[id]) so the merchant has
|
|
34
51
|
// a clean Manage ↔ Edit loop. Only rendered when NEXT_PUBLIC_ROVELA_PROJECT_ID
|
|
35
52
|
// is set (present on every store rebuilt since buildStoreEnvVars started
|
|
@@ -41,8 +58,8 @@ export function AdminTopBar({ storeName: storeNameProp = 'Admin', logo, storeUrl
|
|
|
41
58
|
const editStoreUrl = rovelaProjectId
|
|
42
59
|
? `${rovelaBase.replace(/\/$/, '')}/generate/${rovelaProjectId}`
|
|
43
60
|
: null;
|
|
44
|
-
return (_jsxs("header", { className: `admin-topbar ${className}`.trim(), children: [_jsxs(Link, { href: "/admin", className: "admin-topbar-brand", children: [logo || (_jsx("span", { className: `admin-brand-tile ${
|
|
61
|
+
return (_jsxs("header", { className: `admin-topbar ${className}`.trim(), children: [_jsxs(Link, { href: "/admin", className: "admin-topbar-brand", children: [logo || (_jsx("span", { className: `admin-brand-tile ${tileSrc ? '' : 'admin-brand-tile-monogram'}`, children: tileSrc ? (
|
|
45
62
|
// eslint-disable-next-line @next/next/no-img-element
|
|
46
|
-
_jsx("img", { src:
|
|
63
|
+
_jsx("img", { src: tileSrc, alt: "", onError: () => setTileBroken(true) })) : settingsLoading ? (_jsx("span", { className: "admin-skeleton admin-brand-tile-skeleton" })) : (storeName.charAt(0).toUpperCase()) })), settingsLoading ? (_jsx("span", { className: "admin-skeleton admin-topbar-name-skeleton" })) : (_jsx("span", { className: "admin-topbar-store", children: storeName })), _jsx("span", { className: "admin-topbar-tag", children: "Admin" })] }), _jsxs("div", { className: "admin-topbar-actions", children: [_jsxs("a", { href: storeUrl, target: "_blank", rel: "noopener noreferrer", className: "admin-topbar-btn", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), "View store"] }), editStoreUrl && (_jsxs("a", { href: editStoreUrl, target: "_blank", rel: "noopener noreferrer", className: "admin-topbar-btn", children: [_jsx(Pencil, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), "Edit store"] })), _jsx("span", { className: "admin-topbar-divider", "aria-hidden": "true" }), _jsx(AdminUserMenu, { compact: true })] })] }));
|
|
47
64
|
}
|
|
48
65
|
//# sourceMappingURL=AdminTopBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminTopBar.js","sourceRoot":"","sources":["../../../src/admin/components/AdminTopBar.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;GAcG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"AdminTopBar.js","sourceRoot":"","sources":["../../../src/admin/components/AdminTopBar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BrandingAssetUploadProps {
|
|
2
|
+
/** Callback when the asset is successfully uploaded */
|
|
3
|
+
onUpload?: (url: string) => void;
|
|
4
|
+
/** Callback when the asset is successfully deleted */
|
|
5
|
+
onDelete?: () => void;
|
|
6
|
+
/** Additional CSS classes */
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function BrandingAssetUpload({ kind, onUpload, onDelete, className, }: BrandingAssetUploadProps & {
|
|
10
|
+
kind: 'logo' | 'favicon';
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export type FaviconUploadProps = BrandingAssetUploadProps;
|
|
13
|
+
export declare function FaviconUpload(props: FaviconUploadProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=BrandingAssetUpload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandingAssetUpload.d.ts","sourceRoot":"","sources":["../../../src/admin/components/BrandingAssetUpload.tsx"],"names":[],"mappings":"AAuBA,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA0DD,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,SAAc,GACf,EAAE,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,2CAuTzD;AAMD,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAEzD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAEtD"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/admin/components/BrandingAssetUpload
|
|
5
|
+
*
|
|
6
|
+
* Kind-parameterized branding asset upload (logo + favicon) for the admin
|
|
7
|
+
* settings page. `LogoUpload` (LogoUpload.tsx) and `FaviconUpload` (below)
|
|
8
|
+
* are thin instantiations — one implementation, two assets, zero drift.
|
|
9
|
+
*
|
|
10
|
+
* Talks to /api/admin/branding/{kind} (SDK handlers — R2 fixed key +
|
|
11
|
+
* store_settings mirror + R2-HEAD GET, see admin/api/branding.ts). The
|
|
12
|
+
* client-side `?v=` cache-buster on previews covers the fixed-URL byte
|
|
13
|
+
* replacement within this surface; the server sets max-age=300 for
|
|
14
|
+
* everything else.
|
|
15
|
+
*/
|
|
16
|
+
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
17
|
+
import { fetchAdminApi } from '../hooks/fetchAdminApi';
|
|
18
|
+
const BASE_TYPES = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp', 'image/svg+xml'];
|
|
19
|
+
const BASE_ACCEPT = 'image/png,image/jpeg,image/jpg,image/webp,image/svg+xml';
|
|
20
|
+
const KIND_CONFIG = {
|
|
21
|
+
logo: {
|
|
22
|
+
endpoint: '/api/admin/branding/logo',
|
|
23
|
+
formField: 'logo',
|
|
24
|
+
label: 'Store Logo',
|
|
25
|
+
helper: 'Your logo appears in the header and emails. Recommended: 200x80px.',
|
|
26
|
+
allowedTypes: BASE_TYPES,
|
|
27
|
+
accept: BASE_ACCEPT,
|
|
28
|
+
invalidTypeMessage: 'Invalid file type. Use PNG, JPG, WebP, or SVG.',
|
|
29
|
+
preview: 'wide',
|
|
30
|
+
},
|
|
31
|
+
favicon: {
|
|
32
|
+
endpoint: '/api/admin/branding/favicon',
|
|
33
|
+
formField: 'favicon',
|
|
34
|
+
label: 'Favicon',
|
|
35
|
+
helper: 'The small square icon in the browser tab and the admin top bar. Recommended: a square PNG or SVG, at least 64x64px. Your logo is used when no favicon is set.',
|
|
36
|
+
allowedTypes: [...BASE_TYPES, 'image/x-icon', 'image/vnd.microsoft.icon'],
|
|
37
|
+
accept: `${BASE_ACCEPT},image/x-icon,image/vnd.microsoft.icon,.ico`,
|
|
38
|
+
invalidTypeMessage: 'Invalid file type. Use PNG, JPG, WebP, SVG, or ICO.',
|
|
39
|
+
preview: 'tile',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const MAX_SIZE = 2 * 1024 * 1024; // 2MB (mirrored server-side)
|
|
43
|
+
// =============================================================================
|
|
44
|
+
// Component
|
|
45
|
+
// =============================================================================
|
|
46
|
+
export function BrandingAssetUpload({ kind, onUpload, onDelete, className = '', }) {
|
|
47
|
+
const cfg = KIND_CONFIG[kind];
|
|
48
|
+
const [asset, setAsset] = useState({
|
|
49
|
+
exists: false,
|
|
50
|
+
url: null,
|
|
51
|
+
isLoading: true,
|
|
52
|
+
isUploading: false,
|
|
53
|
+
isDeleting: false,
|
|
54
|
+
error: null,
|
|
55
|
+
});
|
|
56
|
+
const [preview, setPreview] = useState(null);
|
|
57
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
58
|
+
const [successMessage, setSuccessMessage] = useState(null);
|
|
59
|
+
const [cacheBuster, setCacheBuster] = useState(() => Date.now());
|
|
60
|
+
const fileInputRef = useRef(null);
|
|
61
|
+
// Fetch status on mount — the GET is an R2 HEAD, so this reflects the
|
|
62
|
+
// actual object, not a possibly-stale env var or settings row.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
let cancelled = false;
|
|
65
|
+
async function fetchStatus() {
|
|
66
|
+
const res = await fetchAdminApi(cfg.endpoint);
|
|
67
|
+
if (cancelled)
|
|
68
|
+
return;
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
setAsset((prev) => ({ ...prev, isLoading: false, error: res.error }));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
setAsset({
|
|
74
|
+
exists: res.data.data.exists,
|
|
75
|
+
url: res.data.data.url,
|
|
76
|
+
isLoading: false,
|
|
77
|
+
isUploading: false,
|
|
78
|
+
isDeleting: false,
|
|
79
|
+
error: null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
fetchStatus();
|
|
83
|
+
return () => {
|
|
84
|
+
cancelled = true;
|
|
85
|
+
};
|
|
86
|
+
}, [cfg.endpoint]);
|
|
87
|
+
const uploadAsset = useCallback(async (file) => {
|
|
88
|
+
setAsset((prev) => ({ ...prev, isUploading: true, error: null }));
|
|
89
|
+
const formData = new FormData();
|
|
90
|
+
formData.append(cfg.formField, file);
|
|
91
|
+
const res = await fetchAdminApi(cfg.endpoint, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
body: formData,
|
|
94
|
+
});
|
|
95
|
+
if (!res.ok) {
|
|
96
|
+
setAsset((prev) => ({ ...prev, isUploading: false, error: res.error }));
|
|
97
|
+
setPreview(null);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setCacheBuster(Date.now());
|
|
101
|
+
setAsset({
|
|
102
|
+
exists: true,
|
|
103
|
+
url: res.data.data.url,
|
|
104
|
+
isLoading: false,
|
|
105
|
+
isUploading: false,
|
|
106
|
+
isDeleting: false,
|
|
107
|
+
error: null,
|
|
108
|
+
});
|
|
109
|
+
setPreview(null);
|
|
110
|
+
setSuccessMessage(`${cfg.label} uploaded successfully!`);
|
|
111
|
+
setTimeout(() => setSuccessMessage(null), 3000);
|
|
112
|
+
onUpload?.(res.data.data.url);
|
|
113
|
+
}, [cfg.endpoint, cfg.formField, cfg.label, onUpload]);
|
|
114
|
+
const handleFileSelect = useCallback((file) => {
|
|
115
|
+
setAsset((prev) => ({ ...prev, error: null }));
|
|
116
|
+
setSuccessMessage(null);
|
|
117
|
+
if (!cfg.allowedTypes.includes(file.type)) {
|
|
118
|
+
setAsset((prev) => ({ ...prev, error: cfg.invalidTypeMessage }));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (file.size > MAX_SIZE) {
|
|
122
|
+
setAsset((prev) => ({ ...prev, error: 'File too large. Maximum size is 2MB.' }));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const reader = new FileReader();
|
|
126
|
+
reader.onload = (e) => {
|
|
127
|
+
setPreview(e.target?.result);
|
|
128
|
+
};
|
|
129
|
+
reader.readAsDataURL(file);
|
|
130
|
+
uploadAsset(file);
|
|
131
|
+
}, [cfg.allowedTypes, cfg.invalidTypeMessage, uploadAsset]);
|
|
132
|
+
const handleDelete = async () => {
|
|
133
|
+
if (!asset.exists)
|
|
134
|
+
return;
|
|
135
|
+
setAsset((prev) => ({ ...prev, isDeleting: true, error: null }));
|
|
136
|
+
setSuccessMessage(null);
|
|
137
|
+
const res = await fetchAdminApi(cfg.endpoint, { method: 'DELETE' });
|
|
138
|
+
if (!res.ok) {
|
|
139
|
+
setAsset((prev) => ({ ...prev, isDeleting: false, error: res.error }));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
setAsset({
|
|
143
|
+
exists: false,
|
|
144
|
+
url: null,
|
|
145
|
+
isLoading: false,
|
|
146
|
+
isUploading: false,
|
|
147
|
+
isDeleting: false,
|
|
148
|
+
error: null,
|
|
149
|
+
});
|
|
150
|
+
setSuccessMessage(`${cfg.label} removed successfully!`);
|
|
151
|
+
setTimeout(() => setSuccessMessage(null), 3000);
|
|
152
|
+
onDelete?.();
|
|
153
|
+
};
|
|
154
|
+
const handleFileInputChange = (e) => {
|
|
155
|
+
const file = e.target.files?.[0];
|
|
156
|
+
if (file) {
|
|
157
|
+
handleFileSelect(file);
|
|
158
|
+
}
|
|
159
|
+
if (fileInputRef.current) {
|
|
160
|
+
fileInputRef.current.value = '';
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const handleDragOver = (e) => {
|
|
164
|
+
e.preventDefault();
|
|
165
|
+
setIsDragging(true);
|
|
166
|
+
};
|
|
167
|
+
const handleDragLeave = (e) => {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
setIsDragging(false);
|
|
170
|
+
};
|
|
171
|
+
const handleDrop = (e) => {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
setIsDragging(false);
|
|
174
|
+
const file = e.dataTransfer.files?.[0];
|
|
175
|
+
if (file) {
|
|
176
|
+
handleFileSelect(file);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const getDisplayUrl = () => {
|
|
180
|
+
if (preview)
|
|
181
|
+
return preview;
|
|
182
|
+
if (asset.url)
|
|
183
|
+
return `${asset.url}?v=${cacheBuster}`;
|
|
184
|
+
return null;
|
|
185
|
+
};
|
|
186
|
+
const displayUrl = getDisplayUrl();
|
|
187
|
+
const isWorking = asset.isLoading || asset.isUploading || asset.isDeleting;
|
|
188
|
+
return (_jsxs("div", { className: className, children: [_jsx("label", { className: "admin-label", children: cfg.label }), _jsx("p", { className: "admin-helper-text mb-3", children: cfg.helper }), asset.error && (_jsx("div", { className: "admin-alert admin-alert-error mb-3", children: _jsx("div", { className: "admin-alert-description text-sm", children: asset.error }) })), successMessage && (_jsx("div", { className: "admin-alert admin-alert-success mb-3", children: _jsx("div", { className: "admin-alert-description text-sm", children: successMessage }) })), displayUrl ? (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "relative rounded-lg border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-background-subtle))] p-4", children: [_jsx("div", { className: cfg.preview === 'tile'
|
|
189
|
+
? 'flex items-center justify-center min-h-[56px]'
|
|
190
|
+
: 'flex items-center justify-center min-h-[80px]', children: _jsx("img", { src: displayUrl, alt: cfg.label, className: cfg.preview === 'tile'
|
|
191
|
+
? 'h-12 w-12 rounded-md object-contain'
|
|
192
|
+
: 'max-h-[80px] max-w-full object-contain' }) }), asset.isUploading && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-[hsl(var(--admin-background))]/80 rounded-lg", children: _jsxs("div", { className: "flex items-center gap-2 text-sm admin-text-muted", children: [_jsx("div", { className: "admin-spinner h-4 w-4" }), "Uploading..."] }) }))] }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { ref: fileInputRef, type: "file", accept: cfg.accept, onChange: handleFileInputChange, className: "hidden" }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: isWorking, className: "admin-btn admin-btn-secondary admin-btn-sm disabled:opacity-50", children: "Replace" }), _jsx("button", { type: "button", onClick: handleDelete, disabled: isWorking, className: "admin-btn admin-btn-destructive admin-btn-sm disabled:opacity-50", children: asset.isDeleting ? 'Removing...' : 'Remove' })] })] })) : (_jsxs("div", { onClick: () => !isWorking && fileInputRef.current?.click(), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, className: `
|
|
193
|
+
relative flex min-h-[120px] cursor-pointer flex-col items-center justify-center
|
|
194
|
+
rounded-lg border-2 border-dashed transition-all
|
|
195
|
+
${isDragging
|
|
196
|
+
? 'border-[hsl(var(--admin-primary))] bg-[hsl(var(--admin-primary)/0.05)]'
|
|
197
|
+
: 'border-[hsl(var(--admin-border))] hover:border-[hsl(var(--admin-primary)/0.5)]'}
|
|
198
|
+
${isWorking ? 'opacity-50 cursor-not-allowed' : ''}
|
|
199
|
+
`, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: cfg.accept, onChange: handleFileInputChange, className: "hidden" }), asset.isLoading ? (_jsxs("div", { className: "flex items-center gap-2 admin-text-muted", children: [_jsx("div", { className: "admin-spinner h-5 w-5" }), _jsx("span", { className: "text-sm", children: "Checking..." })] })) : (_jsxs("div", { className: "flex flex-col items-center gap-2 p-4 text-center", children: [_jsx("div", { className: `
|
|
200
|
+
flex h-10 w-10 items-center justify-center rounded-full transition-colors
|
|
201
|
+
${isDragging ? 'bg-[hsl(var(--admin-primary)/0.2)]' : 'bg-[hsl(var(--admin-background-subtle))]'}
|
|
202
|
+
`, children: _jsx("svg", { className: `h-5 w-5 transition-colors ${isDragging ? 'text-[hsl(var(--admin-primary))]' : 'admin-icon-muted'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium admin-text", children: isDragging ? 'Drop here' : 'Click or drag to upload' }), _jsx("p", { className: "admin-helper-text mt-1", children: kind === 'favicon' ? 'PNG, JPG, WebP, SVG, ICO (max 2MB)' : 'PNG, JPG, WebP, SVG (max 2MB)' })] })] }))] }))] }));
|
|
203
|
+
}
|
|
204
|
+
export function FaviconUpload(props) {
|
|
205
|
+
return _jsx(BrandingAssetUpload, { kind: "favicon", ...props });
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=BrandingAssetUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandingAssetUpload.js","sourceRoot":"","sources":["../../../src/admin/components/BrandingAssetUpload.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CookieConsentConfig } from '../../core/cookie-consent';
|
|
2
|
+
export interface CookieBannerConfiguratorProps {
|
|
3
|
+
value: CookieConsentConfig;
|
|
4
|
+
enabledLocales: string[];
|
|
5
|
+
defaultLocale: string | null;
|
|
6
|
+
onChange: (next: CookieConsentConfig) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function CookieBannerConfigurator({ value, enabledLocales, defaultLocale, onChange, }: CookieBannerConfiguratorProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=CookieBannerConfigurator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieBannerConfigurator.d.ts","sourceRoot":"","sources":["../../../src/admin/components/CookieBannerConfigurator.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,2BAA2B,CAAA;AAQlC,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,mBAAmB,CAAA;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAC9C;AAyBD,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,cAAc,EACd,aAAa,EACb,QAAQ,GACT,EAAE,6BAA6B,2CA4O/B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/admin/components/CookieBannerConfigurator
|
|
5
|
+
*
|
|
6
|
+
* The merchant-facing configurator for the storefront cookie banner —
|
|
7
|
+
* mirrors what the top Shopify consent apps (Pandectes, Consentmo, Shopify
|
|
8
|
+
* native) expose on their free tiers: layout preset + position, theme with
|
|
9
|
+
* an auto-from-brand default, per-locale copy editing, region rule and the
|
|
10
|
+
* reopen affordance.
|
|
11
|
+
*
|
|
12
|
+
* Compliance guardrails are deliberately ABSENT from this surface — reject
|
|
13
|
+
* parity, category set, close-equals-refusal and the re-consent window are
|
|
14
|
+
* hard-coded in the banner (core/cookie-consent). Enabling the banner means
|
|
15
|
+
* being compliant; nothing here can configure that away.
|
|
16
|
+
*
|
|
17
|
+
* State lives in the parent StoreSettings form (`store_settings.
|
|
18
|
+
* cookie_consent` jsonb); the server sanitizer is the write boundary.
|
|
19
|
+
*/
|
|
20
|
+
import { useState } from 'react';
|
|
21
|
+
import { AdminSelect } from './AdminSelect';
|
|
22
|
+
import { ColorField } from './emails/ColorField';
|
|
23
|
+
const COPY_FIELDS = [
|
|
24
|
+
{ key: 'title', label: 'Title', placeholder: 'Cookie preferences' },
|
|
25
|
+
{
|
|
26
|
+
key: 'intro',
|
|
27
|
+
label: 'Message',
|
|
28
|
+
placeholder: "We use cookies to make this store work and, with your consent, to understand how it's used…",
|
|
29
|
+
multiline: true,
|
|
30
|
+
},
|
|
31
|
+
{ key: 'acceptAll', label: 'Accept button', placeholder: 'Accept all' },
|
|
32
|
+
{ key: 'rejectAll', label: 'Reject button', placeholder: 'Reject all' },
|
|
33
|
+
{ key: 'customize', label: 'Customize button', placeholder: 'Customize' },
|
|
34
|
+
];
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Component
|
|
37
|
+
// =============================================================================
|
|
38
|
+
export function CookieBannerConfigurator({ value, enabledLocales, defaultLocale, onChange, }) {
|
|
39
|
+
const locales = enabledLocales.length > 0 ? enabledLocales : [defaultLocale || 'en'];
|
|
40
|
+
const [copyLocale, setCopyLocale] = useState(defaultLocale || locales[0]);
|
|
41
|
+
const multilingual = locales.length > 1;
|
|
42
|
+
const set = (patch) => onChange({ ...value, ...patch });
|
|
43
|
+
const layout = value.layout ?? 'card';
|
|
44
|
+
const theme = value.theme ?? 'auto';
|
|
45
|
+
const localeCopy = value.copy?.[copyLocale] ?? {};
|
|
46
|
+
const setCopy = (key, text) => {
|
|
47
|
+
const nextLocale = { ...localeCopy };
|
|
48
|
+
if (text.trim() === '') {
|
|
49
|
+
delete nextLocale[key];
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
nextLocale[key] = text;
|
|
53
|
+
}
|
|
54
|
+
const nextCopy = { ...(value.copy ?? {}) };
|
|
55
|
+
if (Object.keys(nextLocale).length === 0) {
|
|
56
|
+
delete nextCopy[copyLocale];
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
nextCopy[copyLocale] = nextLocale;
|
|
60
|
+
}
|
|
61
|
+
set({ copy: Object.keys(nextCopy).length > 0 ? nextCopy : undefined });
|
|
62
|
+
};
|
|
63
|
+
return (_jsxs("div", { className: "space-y-6 border-t border-[hsl(var(--admin-border))] pt-6", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "max-w-md", children: [_jsx("label", { className: "admin-label", children: "Who sees the banner" }), _jsx("p", { className: "text-sm text-[hsl(var(--admin-foreground-muted))] mt-1", children: value.region === 'eu-only'
|
|
64
|
+
? 'Shown to visitors in the EU, EEA, UK and Switzerland. Everyone else browses without a banner.'
|
|
65
|
+
: 'Shown to every visitor, everywhere.' })] }), _jsx(AdminSelect, { className: "w-56 shrink-0 mt-1", value: value.region ?? 'worldwide', onChange: (v) => set({ region: v }), options: [
|
|
66
|
+
{ value: 'worldwide', label: 'Everyone (recommended)' },
|
|
67
|
+
{ value: 'eu-only', label: 'EU, UK & Switzerland only' },
|
|
68
|
+
] })] }), _jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Layout" }), _jsx("p", { className: "text-sm text-[hsl(var(--admin-foreground-muted))] mt-1 mb-3", children: "Centered banners typically reach the highest consent rates; corner cards are the most discreet." }), _jsxs("div", { className: "flex flex-wrap gap-3", children: [_jsx(LayoutTile, { label: "Floating card", active: layout === 'card', onClick: () => set({ layout: 'card' }), preview: _jsx("span", { className: "absolute bottom-1 left-1 h-4 w-8 rounded-sm", style: { background: 'hsl(var(--admin-primary) / 0.55)' } }) }), _jsx(LayoutTile, { label: "Bottom bar", active: layout === 'bar', onClick: () => set({ layout: 'bar' }), preview: _jsx("span", { className: "absolute bottom-0 left-0 right-0 h-3 rounded-b-[3px]", style: { background: 'hsl(var(--admin-primary) / 0.55)' } }) }), _jsx(LayoutTile, { label: "Centered", active: layout === 'modal', onClick: () => set({ layout: 'modal' }), preview: _jsxs(_Fragment, { children: [_jsx("span", { className: "absolute inset-0 rounded-[3px] bg-black/20" }), _jsx("span", { className: "absolute left-1/2 top-1/2 h-5 w-9 -translate-x-1/2 -translate-y-1/2 rounded-sm", style: { background: 'hsl(var(--admin-primary) / 0.65)' } })] }) })] }), layout === 'card' && (_jsxs("div", { className: "mt-3 flex items-center gap-3", children: [_jsx("span", { className: "text-sm text-[hsl(var(--admin-foreground-muted))]", children: "Position" }), _jsx(AdminSelect, { className: "w-44", value: value.position ?? 'bottom-left', onChange: (v) => set({ position: v }), options: [
|
|
69
|
+
{ value: 'bottom-left', label: 'Bottom left' },
|
|
70
|
+
{ value: 'bottom-center', label: 'Bottom center' },
|
|
71
|
+
{ value: 'bottom-right', label: 'Bottom right' },
|
|
72
|
+
] })] }))] }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "max-w-md", children: [_jsx("label", { className: "admin-label", children: "Colors" }), _jsx("p", { className: "text-sm text-[hsl(var(--admin-foreground-muted))] mt-1", children: theme === 'auto'
|
|
73
|
+
? 'Matches your store theme automatically.'
|
|
74
|
+
: theme === 'custom'
|
|
75
|
+
? 'Your own colors, applied to the banner and its buttons.'
|
|
76
|
+
: 'Fixed neutral palette; buttons keep your brand color.' })] }), _jsx(AdminSelect, { className: "w-56 shrink-0 mt-1", value: theme, onChange: (v) => set({ theme: v }), options: [
|
|
77
|
+
{ value: 'auto', label: 'Match my store (recommended)' },
|
|
78
|
+
{ value: 'light', label: 'Light' },
|
|
79
|
+
{ value: 'dark', label: 'Dark' },
|
|
80
|
+
{ value: 'custom', label: 'Custom colors' },
|
|
81
|
+
] })] }), theme === 'custom' && (_jsxs("div", { className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsx(ColorField, { label: "Background", value: value.colors?.background, fallback: "#ffffff", onChange: (hex) => set({ colors: { ...value.colors, background: hex } }) }), _jsx(ColorField, { label: "Text", value: value.colors?.text, fallback: "#18181b", onChange: (hex) => set({ colors: { ...value.colors, text: hex } }) }), _jsx(ColorField, { label: "Accept button", value: value.colors?.accent, fallback: "#0CAF7D", onChange: (hex) => set({ colors: { ...value.colors, accent: hex } }) }), _jsx(ColorField, { label: "Accept button text", value: value.colors?.accentText, fallback: "#ffffff", onChange: (hex) => set({ colors: { ...value.colors, accentText: hex } }) })] }))] }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Text" }), _jsxs("p", { className: "text-sm text-[hsl(var(--admin-foreground-muted))] mt-1", children: ["Leave a field empty to use the built-in text", multilingual ? ' in that language' : '', "."] })] }), multilingual && (_jsx(AdminSelect, { className: "w-36 shrink-0", value: copyLocale, onChange: setCopyLocale, options: locales.map((l) => ({ value: l, label: l.toUpperCase() })) }))] }), _jsx("div", { className: "mt-3 space-y-3", children: COPY_FIELDS.map((field) => field.multiline ? (_jsxs("div", { children: [_jsx("label", { className: "admin-label text-xs", children: field.label }), _jsx("textarea", { className: "admin-input mt-1 w-full", rows: 2, maxLength: 500, value: localeCopy[field.key] ?? '', placeholder: field.placeholder, onChange: (e) => setCopy(field.key, e.target.value) })] }, field.key)) : (_jsxs("div", { children: [_jsx("label", { className: "admin-label text-xs", children: field.label }), _jsx("input", { className: "admin-input mt-1 w-full", maxLength: 120, value: localeCopy[field.key] ?? '', placeholder: field.placeholder, onChange: (e) => setCopy(field.key, e.target.value) })] }, field.key))) })] }), _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "max-w-md", children: [_jsx("label", { className: "admin-label", children: "Reopen preferences" }), _jsx("p", { className: "text-sm text-[hsl(var(--admin-foreground-muted))] mt-1", children: "How visitors change their mind after deciding. The footer link always works; the floating badge adds a small always-visible button." })] }), _jsx(AdminSelect, { className: "w-56 shrink-0 mt-1", value: value.reopen ?? 'link', onChange: (v) => set({ reopen: v }), options: [
|
|
82
|
+
{ value: 'link', label: 'Footer link (recommended)' },
|
|
83
|
+
{ value: 'badge', label: 'Floating badge' },
|
|
84
|
+
{ value: 'both', label: 'Link + badge' },
|
|
85
|
+
] })] })] }));
|
|
86
|
+
}
|
|
87
|
+
// =============================================================================
|
|
88
|
+
// Layout preset tile — mini mockup radio
|
|
89
|
+
// =============================================================================
|
|
90
|
+
function LayoutTile({ label, active, onClick, preview, }) {
|
|
91
|
+
return (_jsxs("button", { type: "button", onClick: onClick, "aria-pressed": active, className: `group flex w-28 flex-col items-center gap-1.5 rounded-lg border p-2 transition-colors ${active
|
|
92
|
+
? 'border-[hsl(var(--admin-primary))] bg-[hsl(var(--admin-primary)/0.06)]'
|
|
93
|
+
: 'border-[hsl(var(--admin-border))] hover:border-[hsl(var(--admin-foreground-muted))]'}`, children: [_jsx("span", { className: "relative block h-14 w-full overflow-hidden rounded-[3px] border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-background-subtle))]", children: preview }), _jsx("span", { className: `text-xs font-medium ${active
|
|
94
|
+
? 'text-[hsl(var(--admin-primary))]'
|
|
95
|
+
: 'text-[hsl(var(--admin-foreground-muted))]'}`, children: label })] }));
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=CookieBannerConfigurator.js.map
|