@jotul/jotul-widgets 1.2.5 → 2.0.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/README.md +112 -28
- package/dist/JotulWidget.css +1 -1
- package/dist/JotulWidget.d.ts +1 -1
- package/dist/JotulWidget.js +325 -132
- package/dist/analytics/WidgetTrackingContext.d.ts +14 -0
- package/dist/analytics/WidgetTrackingContext.js +5 -0
- package/dist/analytics/gtm.d.ts +7 -0
- package/dist/analytics/gtm.js +17 -0
- package/dist/analytics/widgetTracking.d.ts +54 -0
- package/dist/analytics/widgetTracking.js +144 -0
- package/dist/api.d.ts +27 -1
- package/dist/api.js +74 -0
- package/dist/components/FindDealerDrawerWidget.d.ts +7 -4
- package/dist/components/FindDealerDrawerWidget.js +17 -14
- package/dist/components/InquiryField.d.ts +3 -1
- package/dist/components/InquiryField.js +19 -2
- package/dist/components/InquirySelectField.d.ts +13 -0
- package/dist/components/InquirySelectField.js +5 -0
- package/dist/components/ProductPageWidget.d.ts +7 -4
- package/dist/components/ProductPageWidget.js +12 -14
- package/dist/components/TurnstileField.d.ts +7 -0
- package/dist/components/TurnstileField.js +48 -0
- package/dist/components/WarrantyFormWidget.d.ts +12 -0
- package/dist/components/WarrantyFormWidget.js +98 -0
- package/dist/components/product-page/DealerList.d.ts +1 -1
- package/dist/components/product-page/DealerList.js +14 -6
- package/dist/components/product-page/InquiryForm.d.ts +6 -2
- package/dist/components/product-page/InquiryForm.js +21 -3
- package/dist/constants/turnstile.d.ts +8 -0
- package/dist/constants/turnstile.js +19 -0
- package/dist/hooks/useTurnstileSiteKey.d.ts +1 -0
- package/dist/hooks/useTurnstileSiteKey.js +38 -0
- package/dist/i18n/locales/cz.json +34 -1
- package/dist/i18n/locales/de.json +34 -1
- package/dist/i18n/locales/en.json +34 -1
- package/dist/i18n/locales/fi.json +34 -1
- package/dist/i18n/locales/fr.json +34 -1
- package/dist/i18n/locales/nl.json +34 -1
- package/dist/i18n/locales/no.json +34 -1
- package/dist/i18n/locales/pl.json +34 -1
- package/dist/i18n/locales/se.json +34 -1
- package/dist/i18n/widgetStrings.d.ts +33 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/turnstile.d.ts +18 -0
- package/dist/turnstile.js +31 -0
- package/dist/types.d.ts +56 -0
- package/dist/utils/inquiryCategories.d.ts +8 -0
- package/dist/utils/inquiryCategories.js +24 -0
- package/dist/utils/inquirySubmit.d.ts +24 -0
- package/dist/utils/inquirySubmit.js +35 -0
- package/dist/utils/urlDealerId.d.ts +2 -0
- package/dist/utils/urlDealerId.js +5 -0
- package/dist/utils/usMarket.d.ts +2 -0
- package/dist/utils/usMarket.js +9 -0
- package/dist/utils/warrantyForm.d.ts +38 -0
- package/dist/utils/warrantyForm.js +80 -0
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +46 -3
- package/package.json +5 -2
package/dist/JotulWidget.js
CHANGED
|
@@ -6,8 +6,16 @@ import { createPortal } from 'react-dom';
|
|
|
6
6
|
import { FinderSearchRowSkeleton } from './components/FinderSearchRowSkeleton';
|
|
7
7
|
import { DealerCardSkeleton } from './components/DealerCardSkeleton';
|
|
8
8
|
import { DEFAULT_WIDGET_LOCALE_TAG, resolveWidgetUiLocale, WIDGET_STRINGS, } from './i18n/widgetStrings';
|
|
9
|
-
import { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, } from './api';
|
|
10
|
-
import { createInquiryFormValues, getSafeWidgetErrorMessage, isDealerInSearchResult,
|
|
9
|
+
import { checkWidgetAuthorization, fetchDealerById, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, submitInquiry, } from './api';
|
|
10
|
+
import { createInquiryFormValues, getDealerId, getDealerName, getSafeWidgetErrorMessage, isDealerInSearchResult, normalizeWidgetFilterList, validateInquiryFormValues, isWidgetType, renderReadyState, } from './utils';
|
|
11
|
+
import { inquiryCategoryLabel } from './utils/inquiryCategories';
|
|
12
|
+
import { inquiryFormValuesToApiPayload } from './utils/inquirySubmit';
|
|
13
|
+
import { useTurnstileSiteKey } from './hooks/useTurnstileSiteKey';
|
|
14
|
+
import { readDealerIdFromUrlSearch } from './utils/urlDealerId';
|
|
15
|
+
import { WidgetTrackingContext } from './analytics/WidgetTrackingContext';
|
|
16
|
+
import { createWidgetTracker, } from './analytics/widgetTracking';
|
|
17
|
+
import { ensureDataLayer } from './analytics/gtm';
|
|
18
|
+
import { WarrantyFormWidget } from './components/WarrantyFormWidget';
|
|
11
19
|
function renderButton(buttonElement, onClick) {
|
|
12
20
|
if (isValidElement(buttonElement)) {
|
|
13
21
|
return cloneElement(buttonElement, { onClick });
|
|
@@ -19,6 +27,23 @@ function renderButton(buttonElement, onClick) {
|
|
|
19
27
|
}
|
|
20
28
|
}, style: { cursor: 'pointer', display: 'inline-block' }, children: buttonElement }));
|
|
21
29
|
}
|
|
30
|
+
function renderLoadingButton(buttonElement, loadingText) {
|
|
31
|
+
if (isValidElement(buttonElement)) {
|
|
32
|
+
return cloneElement(buttonElement, {
|
|
33
|
+
disabled: true,
|
|
34
|
+
'aria-busy': true,
|
|
35
|
+
children: loadingText,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return (_jsx("span", { role: "button", "aria-busy": "true", style: { cursor: 'wait', display: 'inline-block' }, children: loadingText }));
|
|
39
|
+
}
|
|
40
|
+
function resolveButtonLoading(button, buttonLoading, loadingText) {
|
|
41
|
+
if (buttonLoading != null)
|
|
42
|
+
return buttonLoading;
|
|
43
|
+
if (button == null)
|
|
44
|
+
return null;
|
|
45
|
+
return renderLoadingButton(button, loadingText);
|
|
46
|
+
}
|
|
22
47
|
export { DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, } from './i18n/widgetStrings';
|
|
23
48
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
24
49
|
const GEO_PERMISSION_DENIED = 1;
|
|
@@ -36,20 +61,16 @@ const MARKET_FALLBACK_CENTER = {
|
|
|
36
61
|
FI: [60.1699, 24.9384],
|
|
37
62
|
DE: [52.52, 13.405],
|
|
38
63
|
};
|
|
39
|
-
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, markets: marketsProp, scope, brands, campaignSlug, styling, button, buttonLoading, widgetRef, }) {
|
|
40
|
-
const apiMarkets = useMemo(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const valid = marketsProp
|
|
46
|
-
.map((m) => m?.trim().toUpperCase())
|
|
47
|
-
.filter((m) => m.length === 2 && /^[A-Z]{2}$/.test(m));
|
|
48
|
-
return valid.length > 0 ? valid : undefined;
|
|
49
|
-
}, [marketsProp]);
|
|
64
|
+
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, market: marketProp, markets: marketsProp, scope, brands, campaignSlug, styling, button, buttonLoading, widgetRef, pageType: pageTypeProp, productId, warrantyEndpoint, submissionEndpoint = '/api/jotul/submission', turnstileSiteKey: turnstileSiteKeyProp, turnstileConfigEndpoint, }) {
|
|
65
|
+
const apiMarkets = useMemo(() => normalizeWidgetFilterList(marketsProp, (market) => {
|
|
66
|
+
const upper = market.toUpperCase();
|
|
67
|
+
return /^[A-Z]{2}$/.test(upper) ? upper : '';
|
|
68
|
+
}), [marketsProp]);
|
|
69
|
+
const apiBrands = useMemo(() => normalizeWidgetFilterList(brands), [brands]);
|
|
50
70
|
const firstMarket = apiMarkets?.[0];
|
|
51
71
|
const resolvedUiLocale = useMemo(() => resolveWidgetUiLocale(localeProp, firstMarket), [localeProp, firstMarket]);
|
|
52
72
|
const t = WIDGET_STRINGS[resolvedUiLocale];
|
|
73
|
+
const resolvedTurnstileSiteKey = useTurnstileSiteKey(turnstileSiteKeyProp, turnstileConfigEndpoint);
|
|
53
74
|
const apiLocaleTag = useMemo(() => (localeProp?.trim() ? localeProp.trim() : DEFAULT_WIDGET_LOCALE_TAG), [localeProp]);
|
|
54
75
|
const [auth, setAuth] = useState(null);
|
|
55
76
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -65,23 +86,92 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
65
86
|
const [isOpen, setIsOpen] = useState(false);
|
|
66
87
|
const [shouldAutoLocateAfterAuth, setShouldAutoLocateAfterAuth] = useState(false);
|
|
67
88
|
const [selectedDealerName, setSelectedDealerName] = useState(null);
|
|
89
|
+
const [selectedDealerId, setSelectedDealerId] = useState(null);
|
|
68
90
|
const [inquiryValues, setInquiryValues] = useState(null);
|
|
69
91
|
const [inquiryError, setInquiryError] = useState(null);
|
|
92
|
+
const [isSubmittingInquiry, setIsSubmittingInquiry] = useState(false);
|
|
93
|
+
const [turnstileResetKey, setTurnstileResetKey] = useState(0);
|
|
70
94
|
const [isInquirySubmitted, setIsInquirySubmitted] = useState(false);
|
|
71
|
-
const [mounted, setMounted] = useState(false);
|
|
72
95
|
const [FindDealerDrawerWidgetComp, setFindDealerDrawerWidgetComp] = useState(null);
|
|
73
96
|
const [ProductPageWidgetComp, setProductPageWidgetComp] = useState(null);
|
|
74
97
|
const [isComponentLoading, setIsComponentLoading] = useState(false);
|
|
98
|
+
const [mounted, setMounted] = useState(false);
|
|
99
|
+
const [urlDealerId, setUrlDealerId] = useState(null);
|
|
100
|
+
const [isLoadingUrlDealer, setIsLoadingUrlDealer] = useState(false);
|
|
75
101
|
const autocompleteCacheRef = useRef(new Map());
|
|
102
|
+
const locationQueryRef = useRef('');
|
|
103
|
+
const pendingDealerSearchTermRef = useRef(null);
|
|
104
|
+
const urlDealerHandledRef = useRef(false);
|
|
105
|
+
const trackingStateRef = useRef({
|
|
106
|
+
inquiryValues: null,
|
|
107
|
+
isInquirySubmitted: false,
|
|
108
|
+
selectedDealerId: null,
|
|
109
|
+
selectedDealerName: null,
|
|
110
|
+
});
|
|
76
111
|
const productPageCampaignSlug = type === 'productPage' ? campaignSlug : undefined;
|
|
112
|
+
const widgetFormId = type === 'findDealerDrawer'
|
|
113
|
+
? 'findDealerDrawer'
|
|
114
|
+
: type === 'productPage'
|
|
115
|
+
? 'productPage'
|
|
116
|
+
: null;
|
|
117
|
+
const resolvedPageType = pageTypeProp?.trim() ||
|
|
118
|
+
(widgetFormId === 'findDealerDrawer' ? 'page' : 'product_page');
|
|
119
|
+
const tracker = useMemo(() => {
|
|
120
|
+
if (widgetFormId == null)
|
|
121
|
+
return null;
|
|
122
|
+
return createWidgetTracker({
|
|
123
|
+
formId: widgetFormId,
|
|
124
|
+
language: apiLocaleTag,
|
|
125
|
+
market: firstMarket,
|
|
126
|
+
pageType: resolvedPageType,
|
|
127
|
+
productId: widgetFormId === 'productPage' ? productId?.trim() || undefined : undefined,
|
|
128
|
+
productName: widgetFormId === 'productPage' ? productName?.trim() || undefined : undefined,
|
|
129
|
+
}, () => trackingStateRef.current);
|
|
130
|
+
}, [
|
|
131
|
+
widgetFormId,
|
|
132
|
+
apiLocaleTag,
|
|
133
|
+
firstMarket,
|
|
134
|
+
resolvedPageType,
|
|
135
|
+
productId,
|
|
136
|
+
productName,
|
|
137
|
+
]);
|
|
138
|
+
trackingStateRef.current = {
|
|
139
|
+
inquiryValues,
|
|
140
|
+
isInquirySubmitted,
|
|
141
|
+
selectedDealerId,
|
|
142
|
+
selectedDealerName,
|
|
143
|
+
};
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
locationQueryRef.current = locationQuery;
|
|
146
|
+
}, [locationQuery]);
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (!isOpen || tracker == null)
|
|
149
|
+
return;
|
|
150
|
+
ensureDataLayer();
|
|
151
|
+
}, [isOpen, tracker]);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!isOpen || tracker == null || searchResult == null || isSearching)
|
|
154
|
+
return;
|
|
155
|
+
const resultCount = searchResult.ok === true
|
|
156
|
+
? (searchResult.total ?? searchResult.dealers?.length ?? 0)
|
|
157
|
+
: 0;
|
|
158
|
+
const pendingSearchTerm = pendingDealerSearchTermRef.current;
|
|
159
|
+
if (pendingSearchTerm != null) {
|
|
160
|
+
tracker.trackDealerSearch(pendingSearchTerm, resultCount);
|
|
161
|
+
pendingDealerSearchTermRef.current = null;
|
|
162
|
+
}
|
|
163
|
+
if (searchResult.ok === true && resultCount > 0) {
|
|
164
|
+
tracker.trackDealerListView(resultCount);
|
|
165
|
+
}
|
|
166
|
+
}, [isOpen, tracker, searchResult, isSearching]);
|
|
77
167
|
const dealerSearchOptions = useMemo(() => ({
|
|
78
168
|
endpoint,
|
|
79
169
|
locale: apiLocaleTag,
|
|
80
170
|
markets: apiMarkets,
|
|
81
171
|
scope,
|
|
82
|
-
brands,
|
|
172
|
+
brands: apiBrands,
|
|
83
173
|
campaignSlug: productPageCampaignSlug,
|
|
84
|
-
}), [apiLocaleTag, apiMarkets,
|
|
174
|
+
}), [apiLocaleTag, apiMarkets, apiBrands, endpoint, productPageCampaignSlug, scope]);
|
|
85
175
|
const runDealerSearchByCoordinates = useCallback(async (latitude, longitude) => {
|
|
86
176
|
setLocationError(null);
|
|
87
177
|
setIsSearching(true);
|
|
@@ -94,7 +184,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
94
184
|
finally {
|
|
95
185
|
setIsSearching(false);
|
|
96
186
|
}
|
|
97
|
-
}, [dealerSearchOptions
|
|
187
|
+
}, [dealerSearchOptions]);
|
|
188
|
+
const runUserDealerSearchByCoordinates = useCallback(async (latitude, longitude, searchTerm) => {
|
|
189
|
+
pendingDealerSearchTermRef.current = searchTerm;
|
|
190
|
+
await runDealerSearchByCoordinates(latitude, longitude);
|
|
191
|
+
}, [runDealerSearchByCoordinates]);
|
|
98
192
|
const runFallbackDealerSearch = useCallback(() => {
|
|
99
193
|
const fallbackCenter = (firstMarket != null ? MARKET_FALLBACK_CENTER[firstMarket] : undefined) ??
|
|
100
194
|
MARKET_FALLBACK_CENTER.NO;
|
|
@@ -166,7 +260,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
166
260
|
};
|
|
167
261
|
}, [apiLocaleTag, firstMarket, productPageCampaignSlug, dealerSearchOptions, locationQuery]);
|
|
168
262
|
useEffect(() => {
|
|
169
|
-
if ((type === 'productPage' || type === 'findDealerDrawer') && !isOpen)
|
|
263
|
+
if ((type === 'productPage' || type === 'findDealerDrawer') && !isOpen && !urlDealerId)
|
|
170
264
|
return;
|
|
171
265
|
if (auth != null)
|
|
172
266
|
return;
|
|
@@ -183,7 +277,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
183
277
|
return () => {
|
|
184
278
|
cancelled = true;
|
|
185
279
|
};
|
|
186
|
-
}, [auth, endpoint, isOpen, type]);
|
|
280
|
+
}, [auth, endpoint, isOpen, type, urlDealerId]);
|
|
187
281
|
useEffect(() => {
|
|
188
282
|
if (!shouldAutoLocateAfterAuth)
|
|
189
283
|
return;
|
|
@@ -209,6 +303,21 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
209
303
|
return 'typeReady';
|
|
210
304
|
}, [type]);
|
|
211
305
|
const widgetType = isWidgetType(type) ? type : undefined;
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
if (widgetType !== 'findDealerDrawer' || typeof window === 'undefined')
|
|
308
|
+
return;
|
|
309
|
+
const syncFromUrl = () => {
|
|
310
|
+
setUrlDealerId(readDealerIdFromUrlSearch(window.location.search));
|
|
311
|
+
};
|
|
312
|
+
syncFromUrl();
|
|
313
|
+
window.addEventListener('popstate', syncFromUrl);
|
|
314
|
+
return () => {
|
|
315
|
+
window.removeEventListener('popstate', syncFromUrl);
|
|
316
|
+
};
|
|
317
|
+
}, [widgetType]);
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
urlDealerHandledRef.current = false;
|
|
320
|
+
}, [urlDealerId]);
|
|
212
321
|
useEffect(() => {
|
|
213
322
|
if (!isOpen)
|
|
214
323
|
return;
|
|
@@ -243,6 +352,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
243
352
|
setLocationQuery('');
|
|
244
353
|
setLocationSuggestions([]);
|
|
245
354
|
setIsSuggestionListOpen(false);
|
|
355
|
+
setSelectedDealerId(null);
|
|
356
|
+
pendingDealerSearchTermRef.current = null;
|
|
357
|
+
tracker?.resetSession();
|
|
358
|
+
ensureDataLayer();
|
|
359
|
+
tracker?.trackWidgetOpened();
|
|
246
360
|
setIsOpen(true);
|
|
247
361
|
if (auth?.ok && auth.authorized === true && !isLoading) {
|
|
248
362
|
setShouldAutoLocateAfterAuth(false);
|
|
@@ -251,34 +365,160 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
251
365
|
else {
|
|
252
366
|
setShouldAutoLocateAfterAuth(true);
|
|
253
367
|
}
|
|
254
|
-
}, [auth, isLoading, runLocationSearch]);
|
|
368
|
+
}, [auth, isLoading, runLocationSearch, tracker]);
|
|
255
369
|
const closeDealerWidget = useCallback(() => {
|
|
256
370
|
setIsOpen(false);
|
|
257
371
|
setLocationSuggestions([]);
|
|
258
372
|
setIsSuggestionListOpen(false);
|
|
259
373
|
setIsSearchingSuggestions(false);
|
|
260
374
|
setMapSearchResult(null);
|
|
261
|
-
|
|
375
|
+
setSelectedDealerId(null);
|
|
376
|
+
pendingDealerSearchTermRef.current = null;
|
|
377
|
+
tracker?.resetSession();
|
|
378
|
+
}, [tracker]);
|
|
262
379
|
useImperativeHandle(widgetRef, () => ({
|
|
263
380
|
open: openProductPageWidget,
|
|
264
381
|
close: closeDealerWidget,
|
|
265
382
|
isOpen,
|
|
266
383
|
}), [openProductPageWidget, closeDealerWidget, isOpen]);
|
|
384
|
+
const handleInquiryClose = useCallback(() => {
|
|
385
|
+
setSelectedDealerName(null);
|
|
386
|
+
setSelectedDealerId(null);
|
|
387
|
+
setInquiryValues(null);
|
|
388
|
+
setInquiryError(null);
|
|
389
|
+
}, []);
|
|
390
|
+
const handleInquirySubmit = useCallback(async (turnstileToken) => {
|
|
391
|
+
if (inquiryValues == null || widgetFormId == null)
|
|
392
|
+
return;
|
|
393
|
+
const validationError = validateInquiryFormValues(inquiryValues);
|
|
394
|
+
if (validationError) {
|
|
395
|
+
setInquiryError(validationError.type === 'invalid_email'
|
|
396
|
+
? t.formValidationEmail
|
|
397
|
+
: t.formValidationRequired);
|
|
398
|
+
tracker?.trackFormError(validationError);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
setInquiryError(null);
|
|
402
|
+
setIsSubmittingInquiry(true);
|
|
403
|
+
try {
|
|
404
|
+
const payload = inquiryFormValuesToApiPayload(inquiryValues, {
|
|
405
|
+
formId: widgetFormId,
|
|
406
|
+
categoryLabel: inquiryCategoryLabel(inquiryValues.requestCategory, t),
|
|
407
|
+
domain: typeof window !== 'undefined' ? window.location.hostname : undefined,
|
|
408
|
+
});
|
|
409
|
+
if (turnstileToken?.trim()) {
|
|
410
|
+
payload.turnstileToken = turnstileToken.trim();
|
|
411
|
+
}
|
|
412
|
+
const result = await submitInquiry(payload, { endpoint: submissionEndpoint });
|
|
413
|
+
if (result.ok !== true) {
|
|
414
|
+
setInquiryError(typeof result.error === 'string' ? result.error : t.genericWidgetError);
|
|
415
|
+
setTurnstileResetKey((current) => current + 1);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
setIsInquirySubmitted(true);
|
|
419
|
+
setSelectedDealerName(null);
|
|
420
|
+
setSelectedDealerId(null);
|
|
421
|
+
setInquiryValues(null);
|
|
422
|
+
setTurnstileResetKey((current) => current + 1);
|
|
423
|
+
tracker?.trackSuccessfulSubmit();
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
setInquiryError(t.genericWidgetError);
|
|
427
|
+
setTurnstileResetKey((current) => current + 1);
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
setIsSubmittingInquiry(false);
|
|
431
|
+
}
|
|
432
|
+
}, [
|
|
433
|
+
inquiryValues,
|
|
434
|
+
widgetFormId,
|
|
435
|
+
t,
|
|
436
|
+
tracker,
|
|
437
|
+
submissionEndpoint,
|
|
438
|
+
]);
|
|
439
|
+
const handleStartInquiry = useCallback((dealer) => {
|
|
440
|
+
const dealerName = getDealerName(dealer, t.unknownDealer);
|
|
441
|
+
const dealerId = getDealerId(dealer);
|
|
442
|
+
setSelectedDealerName(dealerName);
|
|
443
|
+
setSelectedDealerId(dealerId ?? null);
|
|
444
|
+
setInquiryValues(createInquiryFormValues(productName, dealer, t.unknownDealer, apiMarkets?.[0]));
|
|
445
|
+
setInquiryError(null);
|
|
446
|
+
setIsInquirySubmitted(false);
|
|
447
|
+
tracker?.trackFormStart(dealerId, dealerName);
|
|
448
|
+
}, [apiMarkets, productName, t.unknownDealer, tracker]);
|
|
449
|
+
const openDrawerFromUrlDealer = useCallback(async (dealerId) => {
|
|
450
|
+
setIsLoadingUrlDealer(true);
|
|
451
|
+
try {
|
|
452
|
+
const result = await fetchDealerById(dealerId, dealerSearchOptions);
|
|
453
|
+
if (result.ok !== true || result.dealer == null) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
setShouldAutoLocateAfterAuth(false);
|
|
457
|
+
setLocationError(null);
|
|
458
|
+
setSearchResult(null);
|
|
459
|
+
setMapSearchResult(null);
|
|
460
|
+
setLocationQuery('');
|
|
461
|
+
setLocationSuggestions([]);
|
|
462
|
+
setIsSuggestionListOpen(false);
|
|
463
|
+
pendingDealerSearchTermRef.current = null;
|
|
464
|
+
tracker?.resetSession();
|
|
465
|
+
ensureDataLayer();
|
|
466
|
+
tracker?.trackWidgetOpened();
|
|
467
|
+
const dealer = result.dealer;
|
|
468
|
+
const latitude = typeof dealer.latitude === 'number' && Number.isFinite(dealer.latitude)
|
|
469
|
+
? dealer.latitude
|
|
470
|
+
: undefined;
|
|
471
|
+
const longitude = typeof dealer.longitude === 'number' && Number.isFinite(dealer.longitude)
|
|
472
|
+
? dealer.longitude
|
|
473
|
+
: undefined;
|
|
474
|
+
const singleResult = {
|
|
475
|
+
ok: true,
|
|
476
|
+
type: 'geolocation',
|
|
477
|
+
total: 1,
|
|
478
|
+
dealers: [dealer],
|
|
479
|
+
...(latitude != null && longitude != null
|
|
480
|
+
? { origin: { latitude, longitude } }
|
|
481
|
+
: {}),
|
|
482
|
+
};
|
|
483
|
+
setSearchResult(singleResult);
|
|
484
|
+
setMapSearchResult(singleResult);
|
|
485
|
+
setIsOpen(true);
|
|
486
|
+
handleStartInquiry(dealer);
|
|
487
|
+
}
|
|
488
|
+
finally {
|
|
489
|
+
setIsLoadingUrlDealer(false);
|
|
490
|
+
}
|
|
491
|
+
}, [dealerSearchOptions, handleStartInquiry, tracker]);
|
|
492
|
+
useEffect(() => {
|
|
493
|
+
if (widgetType !== 'findDealerDrawer' || urlDealerId == null)
|
|
494
|
+
return;
|
|
495
|
+
if (auth == null || isLoading)
|
|
496
|
+
return;
|
|
497
|
+
if (!auth.ok || !auth.authorized)
|
|
498
|
+
return;
|
|
499
|
+
if (urlDealerHandledRef.current)
|
|
500
|
+
return;
|
|
501
|
+
urlDealerHandledRef.current = true;
|
|
502
|
+
void openDrawerFromUrlDealer(urlDealerId);
|
|
503
|
+
}, [auth, isLoading, openDrawerFromUrlDealer, urlDealerId, widgetType]);
|
|
267
504
|
const shellClass = 'jwi-box-border jwi-flex jwi-w-[540px] jwi-max-w-full jwi-flex-col jwi-font-sans jwi-text-[#111111]';
|
|
268
505
|
const rootClass = className != null && className !== '' ? `${shellClass} ${className}` : shellClass;
|
|
269
506
|
if (typeState !== 'typeReady') {
|
|
270
507
|
return _jsx("div", { className: rootClass, children: t.invalidWidgetTypeError });
|
|
271
508
|
}
|
|
509
|
+
if (widgetType === 'warrantyForm') {
|
|
510
|
+
return (_jsx(WarrantyFormWidget, { endpoint: warrantyEndpoint, className: className, locale: localeProp, market: marketProp, styling: styling, turnstileSiteKey: turnstileSiteKeyProp, turnstileConfigEndpoint: turnstileConfigEndpoint }));
|
|
511
|
+
}
|
|
272
512
|
if (widgetType === 'productPage' && !isOpen) {
|
|
273
513
|
if (button == null)
|
|
274
514
|
return null;
|
|
275
|
-
return
|
|
515
|
+
return renderButton(button, openProductPageWidget);
|
|
276
516
|
}
|
|
277
517
|
const productPageAuthPending = widgetType === 'productPage' &&
|
|
278
518
|
isOpen &&
|
|
279
519
|
(auth === null || isLoading);
|
|
280
520
|
if (productPageAuthPending) {
|
|
281
|
-
return (
|
|
521
|
+
return resolveButtonLoading(button, buttonLoading, t.loading);
|
|
282
522
|
}
|
|
283
523
|
const waitingForAuth = auth === null &&
|
|
284
524
|
!((widgetType === 'productPage' || widgetType === 'findDealerDrawer') &&
|
|
@@ -288,7 +528,13 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
288
528
|
type !== 'findDealerDrawer') {
|
|
289
529
|
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-w-full jwi-flex-col", children: _jsx(FinderSearchRowSkeleton, {}) }) }));
|
|
290
530
|
}
|
|
291
|
-
const deferAuthErrorUntilDrawerOpens = widgetType === 'findDealerDrawer' && !isOpen && auth === null;
|
|
531
|
+
const deferAuthErrorUntilDrawerOpens = widgetType === 'findDealerDrawer' && !isOpen && auth === null && urlDealerId == null;
|
|
532
|
+
if (urlDealerId != null &&
|
|
533
|
+
auth != null &&
|
|
534
|
+
!isLoading &&
|
|
535
|
+
(!auth.ok || !auth.authorized)) {
|
|
536
|
+
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
537
|
+
}
|
|
292
538
|
const deferAuthUntilFindDealerDrawerResolves = widgetType === 'findDealerDrawer' && isOpen && (auth === null || isLoading);
|
|
293
539
|
if (!deferAuthErrorUntilDrawerOpens &&
|
|
294
540
|
!deferAuthUntilFindDealerDrawerResolves &&
|
|
@@ -296,12 +542,12 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
296
542
|
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
297
543
|
}
|
|
298
544
|
if (widgetType === 'productPage') {
|
|
299
|
-
return
|
|
300
|
-
|
|
545
|
+
return ProductPageWidgetComp != null && mounted && tracker != null
|
|
546
|
+
? createPortal(_jsx(WidgetTrackingContext.Provider, { value: tracker, children: _jsx(ProductPageWidgetComp, { t: t, buttonStyling: styling?.button, borderStyling: styling?.border, markets: apiMarkets, scope: scope, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
301
547
|
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
302
548
|
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
303
549
|
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
304
|
-
: mapSearchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
550
|
+
: mapSearchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isSubmittingInquiry: isSubmittingInquiry, turnstileSiteKey: resolvedTurnstileSiteKey, turnstileResetKey: turnstileResetKey, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
305
551
|
setLocationQuery(value);
|
|
306
552
|
const trimmed = value.trim();
|
|
307
553
|
setIsSuggestionListOpen(trimmed.length > 0);
|
|
@@ -324,60 +570,34 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
324
570
|
setLocationSuggestions([]);
|
|
325
571
|
setIsSearchingSuggestions(false);
|
|
326
572
|
setIsSuggestionListOpen(false);
|
|
327
|
-
await
|
|
573
|
+
await runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, query);
|
|
328
574
|
}, onSuggestionSelect: (suggestion) => {
|
|
329
575
|
setLocationQuery(suggestion.label);
|
|
330
576
|
setLocationSuggestions([]);
|
|
331
577
|
setIsSearchingSuggestions(false);
|
|
332
578
|
setIsSuggestionListOpen(false);
|
|
333
|
-
void
|
|
579
|
+
void runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, suggestion.label);
|
|
334
580
|
}, onDismissSuggestions: () => {
|
|
335
581
|
setLocationSuggestions([]);
|
|
336
582
|
setIsSearchingSuggestions(false);
|
|
337
583
|
setIsSuggestionListOpen(false);
|
|
338
|
-
}, onInquiryClose: () => {
|
|
339
|
-
setSelectedDealerName(null);
|
|
340
|
-
setInquiryValues(null);
|
|
341
|
-
setInquiryError(null);
|
|
342
|
-
}, onInquirySubmit: () => {
|
|
343
|
-
if (inquiryValues == null)
|
|
344
|
-
return;
|
|
345
|
-
const trimmedName = inquiryValues.name.trim();
|
|
346
|
-
const trimmedEmail = inquiryValues.email.trim();
|
|
347
|
-
const trimmedPhone = inquiryValues.phone.trim();
|
|
348
|
-
if (!trimmedName || !trimmedEmail || !trimmedPhone) {
|
|
349
|
-
setInquiryError(t.formValidationRequired);
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (!isValidEmail(trimmedEmail)) {
|
|
353
|
-
setInquiryError(t.formValidationEmail);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
setInquiryError(null);
|
|
357
|
-
setIsInquirySubmitted(true);
|
|
358
|
-
setSelectedDealerName(null);
|
|
359
|
-
setInquiryValues(null);
|
|
360
|
-
}, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: (dealerName) => {
|
|
361
|
-
setSelectedDealerName(dealerName);
|
|
362
|
-
setInquiryValues(createInquiryFormValues(productName, dealerName));
|
|
363
|
-
setInquiryError(null);
|
|
364
|
-
setIsInquirySubmitted(false);
|
|
365
|
-
}, onMapDealerSelect: (dealer) => {
|
|
584
|
+
}, onInquiryClose: handleInquiryClose, onInquirySubmit: handleInquirySubmit, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: handleStartInquiry, onMapDealerSelect: (dealer) => {
|
|
366
585
|
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
367
586
|
return;
|
|
368
|
-
void
|
|
369
|
-
}, onClosePopup: closeDealerWidget }), document.body)
|
|
370
|
-
|
|
587
|
+
void runUserDealerSearchByCoordinates(dealer.latitude, dealer.longitude, locationQueryRef.current.trim());
|
|
588
|
+
}, onClosePopup: closeDealerWidget }) }), document.body)
|
|
589
|
+
: null;
|
|
371
590
|
}
|
|
372
591
|
if (widgetType === 'findDealerDrawer') {
|
|
373
592
|
const drawerLoading = isOpen &&
|
|
374
593
|
(auth === null ||
|
|
375
594
|
isLoading ||
|
|
376
595
|
isComponentLoading ||
|
|
377
|
-
|
|
378
|
-
|
|
596
|
+
isLoadingUrlDealer ||
|
|
597
|
+
(isSearching && searchResult == null && mapSearchResult == null && urlDealerId == null));
|
|
598
|
+
return (_jsxs(_Fragment, { children: [button != null &&
|
|
379
599
|
(drawerLoading
|
|
380
|
-
? buttonLoading
|
|
600
|
+
? resolveButtonLoading(button, buttonLoading, t.loading)
|
|
381
601
|
: renderButton(button, openProductPageWidget)), mounted &&
|
|
382
602
|
createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "jwi-fixed jwi-inset-0 jwi-z-[2147483647] jwi-bg-black/35", style: {
|
|
383
603
|
opacity: isOpen ? 1 : 0,
|
|
@@ -387,76 +607,49 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
387
607
|
transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
|
|
388
608
|
transition: 'transform 300ms ease-out',
|
|
389
609
|
willChange: 'transform',
|
|
390
|
-
}, "aria-hidden": !isOpen, children: drawerLoading || FindDealerDrawerWidgetComp == null ? (_jsxs("div", { className: "jwi-flex jwi-h-full jwi-w-full jwi-bg-white", children: [_jsx("div", { className: "jwi-flex jwi-h-full jwi-min-h-0 jwi-w-1/2 jwi-flex-col jwi-overflow-hidden", children: _jsxs("div", { className: "jwi-flex jwi-h-full jwi-min-h-0 jwi-w-full jwi-flex-col jwi-gap-3 jwi-overflow-hidden jwi-bg-white jwi-p-6", children: [_jsx("div", { className: "jwi-h-12 jwi-w-full jwi-rounded-[10px] jwi-bg-[#ece8df] jwi-transition-opacity jwi-duration-300 jwi-ease-out" }), _jsx("div", { className: "jwi-h-5 jwi-w-48 jwi-rounded-full jwi-bg-[#ece8df] jwi-transition-opacity jwi-duration-300 jwi-ease-out" }), _jsxs("div", { className: "jwi-flex jwi-flex-col jwi-gap-4", children: [_jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {})] })] }) }), _jsx("div", { className: "jwi-h-full jwi-w-1/2 jwi-bg-[#e8eef1]" })] })) : (_jsx(FindDealerDrawerWidgetComp, { t: t, buttonStyling: styling?.button, borderStyling: styling?.border, markets: apiMarkets, scope: scope, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
610
|
+
}, "aria-hidden": !isOpen, children: drawerLoading || FindDealerDrawerWidgetComp == null ? (_jsxs("div", { className: "jwi-flex jwi-h-full jwi-w-full jwi-bg-white", children: [_jsx("div", { className: "jwi-flex jwi-h-full jwi-min-h-0 jwi-w-1/2 jwi-flex-col jwi-overflow-hidden", children: _jsxs("div", { className: "jwi-flex jwi-h-full jwi-min-h-0 jwi-w-full jwi-flex-col jwi-gap-3 jwi-overflow-hidden jwi-bg-white jwi-p-6", children: [_jsx("div", { className: "jwi-h-12 jwi-w-full jwi-rounded-[10px] jwi-bg-[#ece8df] jwi-transition-opacity jwi-duration-300 jwi-ease-out" }), _jsx("div", { className: "jwi-h-5 jwi-w-48 jwi-rounded-full jwi-bg-[#ece8df] jwi-transition-opacity jwi-duration-300 jwi-ease-out" }), _jsxs("div", { className: "jwi-flex jwi-flex-col jwi-gap-4", children: [_jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {}), _jsx(DealerCardSkeleton, {})] })] }) }), _jsx("div", { className: "jwi-h-full jwi-w-1/2 jwi-bg-[#e8eef1]" })] })) : (tracker != null ? (_jsx(WidgetTrackingContext.Provider, { value: tracker, children: _jsx(FindDealerDrawerWidgetComp, { t: t, buttonStyling: styling?.button, borderStyling: styling?.border, markets: apiMarkets, scope: scope, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
611
|
+
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
612
|
+
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
613
|
+
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
614
|
+
: mapSearchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isSubmittingInquiry: isSubmittingInquiry, turnstileSiteKey: resolvedTurnstileSiteKey, turnstileResetKey: turnstileResetKey, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
615
|
+
setLocationQuery(value);
|
|
616
|
+
const trimmed = value.trim();
|
|
617
|
+
setIsSuggestionListOpen(trimmed.length > 0);
|
|
618
|
+
if (trimmed.length < 3) {
|
|
619
|
+
setLocationSuggestions([]);
|
|
620
|
+
}
|
|
621
|
+
}, onQuerySubmit: async (value) => {
|
|
622
|
+
const query = value.trim();
|
|
623
|
+
if (query.length < 3)
|
|
624
|
+
return;
|
|
625
|
+
setIsSearchingSuggestions(true);
|
|
626
|
+
const result = await searchLocationSuggestions(query, dealerSearchOptions);
|
|
627
|
+
const resolvedSuggestions = result.ok && Array.isArray(result.suggestions) ? result.suggestions : [];
|
|
628
|
+
setLocationSuggestions(resolvedSuggestions);
|
|
629
|
+
setIsSearchingSuggestions(false);
|
|
630
|
+
const suggestion = resolvedSuggestions[0];
|
|
631
|
+
if (!suggestion)
|
|
632
|
+
return;
|
|
633
|
+
setLocationQuery(suggestion.label);
|
|
634
|
+
setLocationSuggestions([]);
|
|
635
|
+
setIsSearchingSuggestions(false);
|
|
636
|
+
setIsSuggestionListOpen(false);
|
|
637
|
+
await runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, query);
|
|
638
|
+
}, onSuggestionSelect: (suggestion) => {
|
|
639
|
+
setLocationQuery(suggestion.label);
|
|
640
|
+
setLocationSuggestions([]);
|
|
641
|
+
setIsSearchingSuggestions(false);
|
|
642
|
+
setIsSuggestionListOpen(false);
|
|
643
|
+
void runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, suggestion.label);
|
|
644
|
+
}, onDismissSuggestions: () => {
|
|
399
645
|
setLocationSuggestions([]);
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const resolvedSuggestions = result.ok && Array.isArray(result.suggestions) ? result.suggestions : [];
|
|
408
|
-
setLocationSuggestions(resolvedSuggestions);
|
|
409
|
-
setIsSearchingSuggestions(false);
|
|
410
|
-
const suggestion = resolvedSuggestions[0];
|
|
411
|
-
if (!suggestion)
|
|
412
|
-
return;
|
|
413
|
-
setLocationQuery(suggestion.label);
|
|
414
|
-
setLocationSuggestions([]);
|
|
415
|
-
setIsSearchingSuggestions(false);
|
|
416
|
-
setIsSuggestionListOpen(false);
|
|
417
|
-
await runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
418
|
-
}, onSuggestionSelect: (suggestion) => {
|
|
419
|
-
setLocationQuery(suggestion.label);
|
|
420
|
-
setLocationSuggestions([]);
|
|
421
|
-
setIsSearchingSuggestions(false);
|
|
422
|
-
setIsSuggestionListOpen(false);
|
|
423
|
-
void runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
424
|
-
}, onDismissSuggestions: () => {
|
|
425
|
-
setLocationSuggestions([]);
|
|
426
|
-
setIsSearchingSuggestions(false);
|
|
427
|
-
setIsSuggestionListOpen(false);
|
|
428
|
-
}, onInquiryClose: () => {
|
|
429
|
-
setSelectedDealerName(null);
|
|
430
|
-
setInquiryValues(null);
|
|
431
|
-
setInquiryError(null);
|
|
432
|
-
}, onInquirySubmit: () => {
|
|
433
|
-
if (inquiryValues == null)
|
|
434
|
-
return;
|
|
435
|
-
const trimmedName = inquiryValues.name.trim();
|
|
436
|
-
const trimmedEmail = inquiryValues.email.trim();
|
|
437
|
-
const trimmedPhone = inquiryValues.phone.trim();
|
|
438
|
-
if (!trimmedName || !trimmedEmail || !trimmedPhone) {
|
|
439
|
-
setInquiryError(t.formValidationRequired);
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
if (!isValidEmail(trimmedEmail)) {
|
|
443
|
-
setInquiryError(t.formValidationEmail);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
setInquiryError(null);
|
|
447
|
-
setIsInquirySubmitted(true);
|
|
448
|
-
setSelectedDealerName(null);
|
|
449
|
-
setInquiryValues(null);
|
|
450
|
-
}, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: (dealerName) => {
|
|
451
|
-
setSelectedDealerName(dealerName);
|
|
452
|
-
setInquiryValues(createInquiryFormValues(productName, dealerName));
|
|
453
|
-
setInquiryError(null);
|
|
454
|
-
setIsInquirySubmitted(false);
|
|
455
|
-
}, onMapDealerSelect: (dealer) => {
|
|
456
|
-
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
457
|
-
return;
|
|
458
|
-
void runDealerSearchByCoordinates(dealer.latitude, dealer.longitude);
|
|
459
|
-
}, onClose: closeDealerWidget })) })] }), document.body)] }));
|
|
646
|
+
setIsSearchingSuggestions(false);
|
|
647
|
+
setIsSuggestionListOpen(false);
|
|
648
|
+
}, onInquiryClose: handleInquiryClose, onInquirySubmit: handleInquirySubmit, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: handleStartInquiry, onMapDealerSelect: (dealer) => {
|
|
649
|
+
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
650
|
+
return;
|
|
651
|
+
void runUserDealerSearchByCoordinates(dealer.latitude, dealer.longitude, locationQueryRef.current.trim());
|
|
652
|
+
}, onClose: closeDealerWidget }) })) : null) })] }), document.body)] }));
|
|
460
653
|
}
|
|
461
654
|
return _jsx("div", { className: rootClass, children: renderReadyState(widgetType, t) });
|
|
462
655
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WidgetTracker } from './widgetTracking';
|
|
2
|
+
export declare const WidgetTrackingContext: import("react").Context<{
|
|
3
|
+
resetSession(): void;
|
|
4
|
+
trackWidgetOpened(): void;
|
|
5
|
+
trackDealerSearch(searchTerm: string, resultCount: number): void;
|
|
6
|
+
trackDealerListView(resultCount: number): void;
|
|
7
|
+
trackDealerSelect(dealerId: string | undefined, dealerName: string): void;
|
|
8
|
+
trackDealerPhoneClick(dealerId: string | undefined, dealerName: string): void;
|
|
9
|
+
trackFormStart(dealerId: string | undefined, dealerName: string): void;
|
|
10
|
+
trackFormStepComplete(field: "name" | "email" | "phone" | "comment"): void;
|
|
11
|
+
trackFormError(error: import("./widgetTracking").InquiryValidationError): void;
|
|
12
|
+
trackSuccessfulSubmit(): void;
|
|
13
|
+
} | null>;
|
|
14
|
+
export declare function useWidgetTracking(): WidgetTracker | null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
dataLayer?: Array<Record<string, unknown>>;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
export declare function ensureDataLayer(): Array<Record<string, unknown>>;
|
|
7
|
+
export declare function pushDataLayerEvent(event: string, payload: Record<string, unknown>): void;
|