@jotul/jotul-widgets 1.2.6 → 2.1.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 +355 -165
- 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 +13 -5
- 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 +59 -2
- 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 +11 -1
- package/dist/utils.js +52 -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, normalizeDealerMarkets, 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,21 +61,14 @@ 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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (!Array.isArray(marketsProp))
|
|
44
|
-
return undefined;
|
|
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 apiLocaleTag = useMemo(() => (localeProp?.trim() ? localeProp.trim() : DEFAULT_WIDGET_LOCALE_TAG), [localeProp]);
|
|
66
|
+
const apiMarkets = useMemo(() => normalizeDealerMarkets(marketsProp), [marketsProp]);
|
|
67
|
+
const apiBrands = useMemo(() => normalizeWidgetFilterList(brands), [brands]);
|
|
50
68
|
const firstMarket = apiMarkets?.[0];
|
|
51
|
-
const resolvedUiLocale = useMemo(() => resolveWidgetUiLocale(localeProp
|
|
69
|
+
const resolvedUiLocale = useMemo(() => resolveWidgetUiLocale(localeProp), [localeProp]);
|
|
52
70
|
const t = WIDGET_STRINGS[resolvedUiLocale];
|
|
53
|
-
const
|
|
71
|
+
const resolvedTurnstileSiteKey = useTurnstileSiteKey(turnstileSiteKeyProp, turnstileConfigEndpoint);
|
|
54
72
|
const [auth, setAuth] = useState(null);
|
|
55
73
|
const [isLoading, setIsLoading] = useState(false);
|
|
56
74
|
const [searchResult, setSearchResult] = useState(null);
|
|
@@ -65,23 +83,92 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
65
83
|
const [isOpen, setIsOpen] = useState(false);
|
|
66
84
|
const [shouldAutoLocateAfterAuth, setShouldAutoLocateAfterAuth] = useState(false);
|
|
67
85
|
const [selectedDealerName, setSelectedDealerName] = useState(null);
|
|
86
|
+
const [selectedDealerId, setSelectedDealerId] = useState(null);
|
|
68
87
|
const [inquiryValues, setInquiryValues] = useState(null);
|
|
69
88
|
const [inquiryError, setInquiryError] = useState(null);
|
|
89
|
+
const [isSubmittingInquiry, setIsSubmittingInquiry] = useState(false);
|
|
90
|
+
const [turnstileResetKey, setTurnstileResetKey] = useState(0);
|
|
70
91
|
const [isInquirySubmitted, setIsInquirySubmitted] = useState(false);
|
|
71
92
|
const [FindDealerDrawerWidgetComp, setFindDealerDrawerWidgetComp] = useState(null);
|
|
72
93
|
const [ProductPageWidgetComp, setProductPageWidgetComp] = useState(null);
|
|
73
94
|
const [isComponentLoading, setIsComponentLoading] = useState(false);
|
|
74
95
|
const [mounted, setMounted] = useState(false);
|
|
96
|
+
const [urlDealerId, setUrlDealerId] = useState(null);
|
|
97
|
+
const [isLoadingUrlDealer, setIsLoadingUrlDealer] = useState(false);
|
|
75
98
|
const autocompleteCacheRef = useRef(new Map());
|
|
99
|
+
const locationQueryRef = useRef('');
|
|
100
|
+
const pendingDealerSearchTermRef = useRef(null);
|
|
101
|
+
const urlDealerHandledRef = useRef(false);
|
|
102
|
+
const trackingStateRef = useRef({
|
|
103
|
+
inquiryValues: null,
|
|
104
|
+
isInquirySubmitted: false,
|
|
105
|
+
selectedDealerId: null,
|
|
106
|
+
selectedDealerName: null,
|
|
107
|
+
});
|
|
76
108
|
const productPageCampaignSlug = type === 'productPage' ? campaignSlug : undefined;
|
|
109
|
+
const widgetFormId = type === 'findDealerDrawer'
|
|
110
|
+
? 'findDealerDrawer'
|
|
111
|
+
: type === 'productPage'
|
|
112
|
+
? 'productPage'
|
|
113
|
+
: null;
|
|
114
|
+
const resolvedPageType = pageTypeProp?.trim() ||
|
|
115
|
+
(widgetFormId === 'findDealerDrawer' ? 'page' : 'product_page');
|
|
116
|
+
const tracker = useMemo(() => {
|
|
117
|
+
if (widgetFormId == null)
|
|
118
|
+
return null;
|
|
119
|
+
return createWidgetTracker({
|
|
120
|
+
formId: widgetFormId,
|
|
121
|
+
language: apiLocaleTag,
|
|
122
|
+
market: firstMarket,
|
|
123
|
+
pageType: resolvedPageType,
|
|
124
|
+
productId: widgetFormId === 'productPage' ? productId?.trim() || undefined : undefined,
|
|
125
|
+
productName: widgetFormId === 'productPage' ? productName?.trim() || undefined : undefined,
|
|
126
|
+
}, () => trackingStateRef.current);
|
|
127
|
+
}, [
|
|
128
|
+
widgetFormId,
|
|
129
|
+
apiLocaleTag,
|
|
130
|
+
firstMarket,
|
|
131
|
+
resolvedPageType,
|
|
132
|
+
productId,
|
|
133
|
+
productName,
|
|
134
|
+
]);
|
|
135
|
+
trackingStateRef.current = {
|
|
136
|
+
inquiryValues,
|
|
137
|
+
isInquirySubmitted,
|
|
138
|
+
selectedDealerId,
|
|
139
|
+
selectedDealerName,
|
|
140
|
+
};
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
locationQueryRef.current = locationQuery;
|
|
143
|
+
}, [locationQuery]);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!isOpen || tracker == null)
|
|
146
|
+
return;
|
|
147
|
+
ensureDataLayer();
|
|
148
|
+
}, [isOpen, tracker]);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!isOpen || tracker == null || searchResult == null || isSearching)
|
|
151
|
+
return;
|
|
152
|
+
const resultCount = searchResult.ok === true
|
|
153
|
+
? (searchResult.total ?? searchResult.dealers?.length ?? 0)
|
|
154
|
+
: 0;
|
|
155
|
+
const pendingSearchTerm = pendingDealerSearchTermRef.current;
|
|
156
|
+
if (pendingSearchTerm != null) {
|
|
157
|
+
tracker.trackDealerSearch(pendingSearchTerm, resultCount);
|
|
158
|
+
pendingDealerSearchTermRef.current = null;
|
|
159
|
+
}
|
|
160
|
+
if (searchResult.ok === true && resultCount > 0) {
|
|
161
|
+
tracker.trackDealerListView(resultCount);
|
|
162
|
+
}
|
|
163
|
+
}, [isOpen, tracker, searchResult, isSearching]);
|
|
77
164
|
const dealerSearchOptions = useMemo(() => ({
|
|
78
165
|
endpoint,
|
|
79
166
|
locale: apiLocaleTag,
|
|
80
167
|
markets: apiMarkets,
|
|
81
168
|
scope,
|
|
82
|
-
brands,
|
|
169
|
+
brands: apiBrands,
|
|
83
170
|
campaignSlug: productPageCampaignSlug,
|
|
84
|
-
}), [apiLocaleTag, apiMarkets,
|
|
171
|
+
}), [apiLocaleTag, apiMarkets, apiBrands, endpoint, productPageCampaignSlug, scope]);
|
|
85
172
|
const runDealerSearchByCoordinates = useCallback(async (latitude, longitude) => {
|
|
86
173
|
setLocationError(null);
|
|
87
174
|
setIsSearching(true);
|
|
@@ -94,7 +181,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
94
181
|
finally {
|
|
95
182
|
setIsSearching(false);
|
|
96
183
|
}
|
|
97
|
-
}, [dealerSearchOptions
|
|
184
|
+
}, [dealerSearchOptions]);
|
|
185
|
+
const runUserDealerSearchByCoordinates = useCallback(async (latitude, longitude, searchTerm) => {
|
|
186
|
+
pendingDealerSearchTermRef.current = searchTerm;
|
|
187
|
+
await runDealerSearchByCoordinates(latitude, longitude);
|
|
188
|
+
}, [runDealerSearchByCoordinates]);
|
|
98
189
|
const runFallbackDealerSearch = useCallback(() => {
|
|
99
190
|
const fallbackCenter = (firstMarket != null ? MARKET_FALLBACK_CENTER[firstMarket] : undefined) ??
|
|
100
191
|
MARKET_FALLBACK_CENTER.NO;
|
|
@@ -166,7 +257,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
166
257
|
};
|
|
167
258
|
}, [apiLocaleTag, firstMarket, productPageCampaignSlug, dealerSearchOptions, locationQuery]);
|
|
168
259
|
useEffect(() => {
|
|
169
|
-
if ((type === 'productPage' || type === 'findDealerDrawer') && !isOpen)
|
|
260
|
+
if ((type === 'productPage' || type === 'findDealerDrawer') && !isOpen && !urlDealerId)
|
|
170
261
|
return;
|
|
171
262
|
if (auth != null)
|
|
172
263
|
return;
|
|
@@ -183,7 +274,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
183
274
|
return () => {
|
|
184
275
|
cancelled = true;
|
|
185
276
|
};
|
|
186
|
-
}, [auth, endpoint, isOpen, type]);
|
|
277
|
+
}, [auth, endpoint, isOpen, type, urlDealerId]);
|
|
187
278
|
useEffect(() => {
|
|
188
279
|
if (!shouldAutoLocateAfterAuth)
|
|
189
280
|
return;
|
|
@@ -209,6 +300,21 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
209
300
|
return 'typeReady';
|
|
210
301
|
}, [type]);
|
|
211
302
|
const widgetType = isWidgetType(type) ? type : undefined;
|
|
303
|
+
useEffect(() => {
|
|
304
|
+
if (widgetType !== 'findDealerDrawer' || typeof window === 'undefined')
|
|
305
|
+
return;
|
|
306
|
+
const syncFromUrl = () => {
|
|
307
|
+
setUrlDealerId(readDealerIdFromUrlSearch(window.location.search));
|
|
308
|
+
};
|
|
309
|
+
syncFromUrl();
|
|
310
|
+
window.addEventListener('popstate', syncFromUrl);
|
|
311
|
+
return () => {
|
|
312
|
+
window.removeEventListener('popstate', syncFromUrl);
|
|
313
|
+
};
|
|
314
|
+
}, [widgetType]);
|
|
315
|
+
useEffect(() => {
|
|
316
|
+
urlDealerHandledRef.current = false;
|
|
317
|
+
}, [urlDealerId]);
|
|
212
318
|
useEffect(() => {
|
|
213
319
|
if (!isOpen)
|
|
214
320
|
return;
|
|
@@ -243,6 +349,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
243
349
|
setLocationQuery('');
|
|
244
350
|
setLocationSuggestions([]);
|
|
245
351
|
setIsSuggestionListOpen(false);
|
|
352
|
+
setSelectedDealerId(null);
|
|
353
|
+
pendingDealerSearchTermRef.current = null;
|
|
354
|
+
tracker?.resetSession();
|
|
355
|
+
ensureDataLayer();
|
|
356
|
+
tracker?.trackWidgetOpened();
|
|
246
357
|
setIsOpen(true);
|
|
247
358
|
if (auth?.ok && auth.authorized === true && !isLoading) {
|
|
248
359
|
setShouldAutoLocateAfterAuth(false);
|
|
@@ -251,24 +362,150 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
251
362
|
else {
|
|
252
363
|
setShouldAutoLocateAfterAuth(true);
|
|
253
364
|
}
|
|
254
|
-
}, [auth, isLoading, runLocationSearch]);
|
|
365
|
+
}, [auth, isLoading, runLocationSearch, tracker]);
|
|
255
366
|
const closeDealerWidget = useCallback(() => {
|
|
256
367
|
setIsOpen(false);
|
|
257
368
|
setLocationSuggestions([]);
|
|
258
369
|
setIsSuggestionListOpen(false);
|
|
259
370
|
setIsSearchingSuggestions(false);
|
|
260
371
|
setMapSearchResult(null);
|
|
261
|
-
|
|
372
|
+
setSelectedDealerId(null);
|
|
373
|
+
pendingDealerSearchTermRef.current = null;
|
|
374
|
+
tracker?.resetSession();
|
|
375
|
+
}, [tracker]);
|
|
262
376
|
useImperativeHandle(widgetRef, () => ({
|
|
263
377
|
open: openProductPageWidget,
|
|
264
378
|
close: closeDealerWidget,
|
|
265
379
|
isOpen,
|
|
266
380
|
}), [openProductPageWidget, closeDealerWidget, isOpen]);
|
|
381
|
+
const handleInquiryClose = useCallback(() => {
|
|
382
|
+
setSelectedDealerName(null);
|
|
383
|
+
setSelectedDealerId(null);
|
|
384
|
+
setInquiryValues(null);
|
|
385
|
+
setInquiryError(null);
|
|
386
|
+
}, []);
|
|
387
|
+
const handleInquirySubmit = useCallback(async (turnstileToken) => {
|
|
388
|
+
if (inquiryValues == null || widgetFormId == null)
|
|
389
|
+
return;
|
|
390
|
+
const validationError = validateInquiryFormValues(inquiryValues);
|
|
391
|
+
if (validationError) {
|
|
392
|
+
setInquiryError(validationError.type === 'invalid_email'
|
|
393
|
+
? t.formValidationEmail
|
|
394
|
+
: t.formValidationRequired);
|
|
395
|
+
tracker?.trackFormError(validationError);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
setInquiryError(null);
|
|
399
|
+
setIsSubmittingInquiry(true);
|
|
400
|
+
try {
|
|
401
|
+
const payload = inquiryFormValuesToApiPayload(inquiryValues, {
|
|
402
|
+
formId: widgetFormId,
|
|
403
|
+
categoryLabel: inquiryCategoryLabel(inquiryValues.requestCategory, t),
|
|
404
|
+
domain: typeof window !== 'undefined' ? window.location.hostname : undefined,
|
|
405
|
+
});
|
|
406
|
+
if (turnstileToken?.trim()) {
|
|
407
|
+
payload.turnstileToken = turnstileToken.trim();
|
|
408
|
+
}
|
|
409
|
+
const result = await submitInquiry(payload, { endpoint: submissionEndpoint });
|
|
410
|
+
if (result.ok !== true) {
|
|
411
|
+
setInquiryError(typeof result.error === 'string' ? result.error : t.genericWidgetError);
|
|
412
|
+
setTurnstileResetKey((current) => current + 1);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
setIsInquirySubmitted(true);
|
|
416
|
+
setSelectedDealerName(null);
|
|
417
|
+
setSelectedDealerId(null);
|
|
418
|
+
setInquiryValues(null);
|
|
419
|
+
setTurnstileResetKey((current) => current + 1);
|
|
420
|
+
tracker?.trackSuccessfulSubmit();
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
setInquiryError(t.genericWidgetError);
|
|
424
|
+
setTurnstileResetKey((current) => current + 1);
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
setIsSubmittingInquiry(false);
|
|
428
|
+
}
|
|
429
|
+
}, [
|
|
430
|
+
inquiryValues,
|
|
431
|
+
widgetFormId,
|
|
432
|
+
t,
|
|
433
|
+
tracker,
|
|
434
|
+
submissionEndpoint,
|
|
435
|
+
]);
|
|
436
|
+
const handleStartInquiry = useCallback((dealer) => {
|
|
437
|
+
const dealerName = getDealerName(dealer, t.unknownDealer);
|
|
438
|
+
const dealerId = getDealerId(dealer);
|
|
439
|
+
setSelectedDealerName(dealerName);
|
|
440
|
+
setSelectedDealerId(dealerId ?? null);
|
|
441
|
+
setInquiryValues(createInquiryFormValues(productName, dealer, t.unknownDealer, apiMarkets?.[0]));
|
|
442
|
+
setInquiryError(null);
|
|
443
|
+
setIsInquirySubmitted(false);
|
|
444
|
+
tracker?.trackFormStart(dealerId, dealerName);
|
|
445
|
+
}, [apiMarkets, productName, t.unknownDealer, tracker]);
|
|
446
|
+
const openDrawerFromUrlDealer = useCallback(async (dealerId) => {
|
|
447
|
+
setIsLoadingUrlDealer(true);
|
|
448
|
+
try {
|
|
449
|
+
const result = await fetchDealerById(dealerId, dealerSearchOptions);
|
|
450
|
+
if (result.ok !== true || result.dealer == null) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
setShouldAutoLocateAfterAuth(false);
|
|
454
|
+
setLocationError(null);
|
|
455
|
+
setSearchResult(null);
|
|
456
|
+
setMapSearchResult(null);
|
|
457
|
+
setLocationQuery('');
|
|
458
|
+
setLocationSuggestions([]);
|
|
459
|
+
setIsSuggestionListOpen(false);
|
|
460
|
+
pendingDealerSearchTermRef.current = null;
|
|
461
|
+
tracker?.resetSession();
|
|
462
|
+
ensureDataLayer();
|
|
463
|
+
tracker?.trackWidgetOpened();
|
|
464
|
+
const dealer = result.dealer;
|
|
465
|
+
const latitude = typeof dealer.latitude === 'number' && Number.isFinite(dealer.latitude)
|
|
466
|
+
? dealer.latitude
|
|
467
|
+
: undefined;
|
|
468
|
+
const longitude = typeof dealer.longitude === 'number' && Number.isFinite(dealer.longitude)
|
|
469
|
+
? dealer.longitude
|
|
470
|
+
: undefined;
|
|
471
|
+
const singleResult = {
|
|
472
|
+
ok: true,
|
|
473
|
+
type: 'geolocation',
|
|
474
|
+
total: 1,
|
|
475
|
+
dealers: [dealer],
|
|
476
|
+
...(latitude != null && longitude != null
|
|
477
|
+
? { origin: { latitude, longitude } }
|
|
478
|
+
: {}),
|
|
479
|
+
};
|
|
480
|
+
setSearchResult(singleResult);
|
|
481
|
+
setMapSearchResult(singleResult);
|
|
482
|
+
setIsOpen(true);
|
|
483
|
+
handleStartInquiry(dealer);
|
|
484
|
+
}
|
|
485
|
+
finally {
|
|
486
|
+
setIsLoadingUrlDealer(false);
|
|
487
|
+
}
|
|
488
|
+
}, [dealerSearchOptions, handleStartInquiry, tracker]);
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
if (widgetType !== 'findDealerDrawer' || urlDealerId == null)
|
|
491
|
+
return;
|
|
492
|
+
if (auth == null || isLoading)
|
|
493
|
+
return;
|
|
494
|
+
if (!auth.ok || !auth.authorized)
|
|
495
|
+
return;
|
|
496
|
+
if (urlDealerHandledRef.current)
|
|
497
|
+
return;
|
|
498
|
+
urlDealerHandledRef.current = true;
|
|
499
|
+
void openDrawerFromUrlDealer(urlDealerId);
|
|
500
|
+
}, [auth, isLoading, openDrawerFromUrlDealer, urlDealerId, widgetType]);
|
|
267
501
|
const shellClass = 'jwi-box-border jwi-flex jwi-w-[540px] jwi-max-w-full jwi-flex-col jwi-font-sans jwi-text-[#111111]';
|
|
268
502
|
const rootClass = className != null && className !== '' ? `${shellClass} ${className}` : shellClass;
|
|
269
503
|
if (typeState !== 'typeReady') {
|
|
270
504
|
return _jsx("div", { className: rootClass, children: t.invalidWidgetTypeError });
|
|
271
505
|
}
|
|
506
|
+
if (widgetType === 'warrantyForm') {
|
|
507
|
+
return (_jsx(WarrantyFormWidget, { endpoint: warrantyEndpoint, className: className, locale: localeProp, market: marketProp, styling: styling, turnstileSiteKey: turnstileSiteKeyProp, turnstileConfigEndpoint: turnstileConfigEndpoint }));
|
|
508
|
+
}
|
|
272
509
|
if (widgetType === 'productPage' && !isOpen) {
|
|
273
510
|
if (button == null)
|
|
274
511
|
return null;
|
|
@@ -278,7 +515,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
278
515
|
isOpen &&
|
|
279
516
|
(auth === null || isLoading);
|
|
280
517
|
if (productPageAuthPending) {
|
|
281
|
-
return
|
|
518
|
+
return resolveButtonLoading(button, buttonLoading, t.loading);
|
|
282
519
|
}
|
|
283
520
|
const waitingForAuth = auth === null &&
|
|
284
521
|
!((widgetType === 'productPage' || widgetType === 'findDealerDrawer') &&
|
|
@@ -288,7 +525,13 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
288
525
|
type !== 'findDealerDrawer') {
|
|
289
526
|
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-w-full jwi-flex-col", children: _jsx(FinderSearchRowSkeleton, {}) }) }));
|
|
290
527
|
}
|
|
291
|
-
const deferAuthErrorUntilDrawerOpens = widgetType === 'findDealerDrawer' && !isOpen && auth === null;
|
|
528
|
+
const deferAuthErrorUntilDrawerOpens = widgetType === 'findDealerDrawer' && !isOpen && auth === null && urlDealerId == null;
|
|
529
|
+
if (urlDealerId != null &&
|
|
530
|
+
auth != null &&
|
|
531
|
+
!isLoading &&
|
|
532
|
+
(!auth.ok || !auth.authorized)) {
|
|
533
|
+
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
534
|
+
}
|
|
292
535
|
const deferAuthUntilFindDealerDrawerResolves = widgetType === 'findDealerDrawer' && isOpen && (auth === null || isLoading);
|
|
293
536
|
if (!deferAuthErrorUntilDrawerOpens &&
|
|
294
537
|
!deferAuthUntilFindDealerDrawerResolves &&
|
|
@@ -296,77 +539,50 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
296
539
|
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
297
540
|
}
|
|
298
541
|
if (widgetType === 'productPage') {
|
|
299
|
-
return ProductPageWidgetComp != null && mounted
|
|
300
|
-
? createPortal(_jsx(ProductPageWidgetComp, { t: t, buttonStyling: styling?.button, borderStyling: styling?.border, markets: apiMarkets, scope: scope, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
542
|
+
return ProductPageWidgetComp != null && mounted && tracker != null
|
|
543
|
+
? 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
|
|
544
|
+
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
545
|
+
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
546
|
+
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
547
|
+
: 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) => {
|
|
548
|
+
setLocationQuery(value);
|
|
549
|
+
const trimmed = value.trim();
|
|
550
|
+
setIsSuggestionListOpen(trimmed.length > 0);
|
|
551
|
+
if (trimmed.length < 3) {
|
|
552
|
+
setLocationSuggestions([]);
|
|
553
|
+
}
|
|
554
|
+
}, onQuerySubmit: async (value) => {
|
|
555
|
+
const query = value.trim();
|
|
556
|
+
if (query.length < 3)
|
|
557
|
+
return;
|
|
558
|
+
setIsSearchingSuggestions(true);
|
|
559
|
+
const result = await searchLocationSuggestions(query, dealerSearchOptions);
|
|
560
|
+
const resolvedSuggestions = result.ok && Array.isArray(result.suggestions) ? result.suggestions : [];
|
|
561
|
+
setLocationSuggestions(resolvedSuggestions);
|
|
562
|
+
setIsSearchingSuggestions(false);
|
|
563
|
+
const suggestion = resolvedSuggestions[0];
|
|
564
|
+
if (!suggestion)
|
|
565
|
+
return;
|
|
566
|
+
setLocationQuery(suggestion.label);
|
|
567
|
+
setLocationSuggestions([]);
|
|
568
|
+
setIsSearchingSuggestions(false);
|
|
569
|
+
setIsSuggestionListOpen(false);
|
|
570
|
+
await runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, query);
|
|
571
|
+
}, onSuggestionSelect: (suggestion) => {
|
|
572
|
+
setLocationQuery(suggestion.label);
|
|
309
573
|
setLocationSuggestions([]);
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return;
|
|
323
|
-
setLocationQuery(suggestion.label);
|
|
324
|
-
setLocationSuggestions([]);
|
|
325
|
-
setIsSearchingSuggestions(false);
|
|
326
|
-
setIsSuggestionListOpen(false);
|
|
327
|
-
await runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
328
|
-
}, onSuggestionSelect: (suggestion) => {
|
|
329
|
-
setLocationQuery(suggestion.label);
|
|
330
|
-
setLocationSuggestions([]);
|
|
331
|
-
setIsSearchingSuggestions(false);
|
|
332
|
-
setIsSuggestionListOpen(false);
|
|
333
|
-
void runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
334
|
-
}, onDismissSuggestions: () => {
|
|
335
|
-
setLocationSuggestions([]);
|
|
336
|
-
setIsSearchingSuggestions(false);
|
|
337
|
-
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) => {
|
|
366
|
-
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
367
|
-
return;
|
|
368
|
-
void runDealerSearchByCoordinates(dealer.latitude, dealer.longitude);
|
|
369
|
-
}, onClosePopup: closeDealerWidget }), document.body)
|
|
574
|
+
setIsSearchingSuggestions(false);
|
|
575
|
+
setIsSuggestionListOpen(false);
|
|
576
|
+
void runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, suggestion.label);
|
|
577
|
+
}, onDismissSuggestions: () => {
|
|
578
|
+
setLocationSuggestions([]);
|
|
579
|
+
setIsSearchingSuggestions(false);
|
|
580
|
+
setIsSuggestionListOpen(false);
|
|
581
|
+
}, onInquiryClose: handleInquiryClose, onInquirySubmit: handleInquirySubmit, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: handleStartInquiry, onMapDealerSelect: (dealer) => {
|
|
582
|
+
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
583
|
+
return;
|
|
584
|
+
void runUserDealerSearchByCoordinates(dealer.latitude, dealer.longitude, locationQueryRef.current.trim());
|
|
585
|
+
}, onClosePopup: closeDealerWidget }) }), document.body)
|
|
370
586
|
: null;
|
|
371
587
|
}
|
|
372
588
|
if (widgetType === 'findDealerDrawer') {
|
|
@@ -374,10 +590,11 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
374
590
|
(auth === null ||
|
|
375
591
|
isLoading ||
|
|
376
592
|
isComponentLoading ||
|
|
377
|
-
|
|
593
|
+
isLoadingUrlDealer ||
|
|
594
|
+
(isSearching && searchResult == null && mapSearchResult == null && urlDealerId == null));
|
|
378
595
|
return (_jsxs(_Fragment, { children: [button != null &&
|
|
379
596
|
(drawerLoading
|
|
380
|
-
? buttonLoading
|
|
597
|
+
? resolveButtonLoading(button, buttonLoading, t.loading)
|
|
381
598
|
: renderButton(button, openProductPageWidget)), mounted &&
|
|
382
599
|
createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "jwi-fixed jwi-inset-0 jwi-z-[2147483647] jwi-bg-black/35", style: {
|
|
383
600
|
opacity: isOpen ? 1 : 0,
|
|
@@ -387,76 +604,49 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
387
604
|
transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
|
|
388
605
|
transition: 'transform 300ms ease-out',
|
|
389
606
|
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
|
-
|
|
607
|
+
}, "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
|
|
608
|
+
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
609
|
+
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
610
|
+
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
611
|
+
: 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) => {
|
|
612
|
+
setLocationQuery(value);
|
|
613
|
+
const trimmed = value.trim();
|
|
614
|
+
setIsSuggestionListOpen(trimmed.length > 0);
|
|
615
|
+
if (trimmed.length < 3) {
|
|
616
|
+
setLocationSuggestions([]);
|
|
617
|
+
}
|
|
618
|
+
}, onQuerySubmit: async (value) => {
|
|
619
|
+
const query = value.trim();
|
|
620
|
+
if (query.length < 3)
|
|
621
|
+
return;
|
|
622
|
+
setIsSearchingSuggestions(true);
|
|
623
|
+
const result = await searchLocationSuggestions(query, dealerSearchOptions);
|
|
624
|
+
const resolvedSuggestions = result.ok && Array.isArray(result.suggestions) ? result.suggestions : [];
|
|
625
|
+
setLocationSuggestions(resolvedSuggestions);
|
|
626
|
+
setIsSearchingSuggestions(false);
|
|
627
|
+
const suggestion = resolvedSuggestions[0];
|
|
628
|
+
if (!suggestion)
|
|
629
|
+
return;
|
|
630
|
+
setLocationQuery(suggestion.label);
|
|
631
|
+
setLocationSuggestions([]);
|
|
632
|
+
setIsSearchingSuggestions(false);
|
|
633
|
+
setIsSuggestionListOpen(false);
|
|
634
|
+
await runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, query);
|
|
635
|
+
}, onSuggestionSelect: (suggestion) => {
|
|
636
|
+
setLocationQuery(suggestion.label);
|
|
637
|
+
setLocationSuggestions([]);
|
|
638
|
+
setIsSearchingSuggestions(false);
|
|
639
|
+
setIsSuggestionListOpen(false);
|
|
640
|
+
void runUserDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude, suggestion.label);
|
|
641
|
+
}, onDismissSuggestions: () => {
|
|
399
642
|
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)] }));
|
|
643
|
+
setIsSearchingSuggestions(false);
|
|
644
|
+
setIsSuggestionListOpen(false);
|
|
645
|
+
}, onInquiryClose: handleInquiryClose, onInquirySubmit: handleInquirySubmit, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: handleStartInquiry, onMapDealerSelect: (dealer) => {
|
|
646
|
+
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
647
|
+
return;
|
|
648
|
+
void runUserDealerSearchByCoordinates(dealer.latitude, dealer.longitude, locationQueryRef.current.trim());
|
|
649
|
+
}, onClose: closeDealerWidget }) })) : null) })] }), document.body)] }));
|
|
460
650
|
}
|
|
461
651
|
return _jsx("div", { className: rootClass, children: renderReadyState(widgetType, t) });
|
|
462
652
|
}
|