@jotul/jotul-widgets 1.0.5 → 1.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 +21 -1
- package/dist/JotulWidget.css +1 -1
- package/dist/JotulWidget.d.ts +2 -2
- package/dist/JotulWidget.js +160 -32
- package/dist/api.d.ts +2 -2
- package/dist/api.js +4 -2
- package/dist/components/FindDealerDrawerWidget.d.ts +37 -0
- package/dist/components/FindDealerDrawerWidget.js +314 -0
- package/dist/components/ProductPageWidget.d.ts +8 -1
- package/dist/components/ProductPageWidget.js +203 -21
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/dist/images/dealer-pin.svg +8 -3
- package/dist/types.d.ts +11 -5
- package/dist/utils/cssColor.d.ts +5 -0
- package/dist/utils/cssColor.js +31 -0
- package/dist/utils/dealerMapClustering.d.ts +28 -0
- package/dist/utils/dealerMapClustering.js +71 -0
- package/dist/utils/loadLeafletMarkerCluster.d.ts +5 -0
- package/dist/utils/loadLeafletMarkerCluster.js +20 -0
- package/dist/utils/markerClusterIconHtml.d.ts +2 -0
- package/dist/utils/markerClusterIconHtml.js +7 -0
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +10 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -40,7 +40,20 @@ Custom trigger button:
|
|
|
40
40
|
```tsx
|
|
41
41
|
<JotulWidget
|
|
42
42
|
type="productPage"
|
|
43
|
-
|
|
43
|
+
trigger={({ onOpen, label, className, style }) => (
|
|
44
|
+
<button type="button" onClick={onOpen} className={className} style={style}>
|
|
45
|
+
{label}
|
|
46
|
+
</button>
|
|
47
|
+
)}
|
|
48
|
+
/>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Find dealer drawer with custom trigger:
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<JotulWidget
|
|
55
|
+
type="findDealerDrawer"
|
|
56
|
+
trigger={({ onOpen, label, className, style }) => (
|
|
44
57
|
<button type="button" onClick={onOpen} className={className} style={style}>
|
|
45
58
|
{label}
|
|
46
59
|
</button>
|
|
@@ -54,3 +67,10 @@ Current behavior:
|
|
|
54
67
|
- missing permission -> `Insufficient permissions`
|
|
55
68
|
- invalid widget type -> `Invalid widget type`
|
|
56
69
|
- `productPage` renders zipcode input + search button + dealer list
|
|
70
|
+
- `findDealerDrawer` opens the dealer experience in a right-side drawer
|
|
71
|
+
|
|
72
|
+
List/map data behavior:
|
|
73
|
+
|
|
74
|
+
- List uses closest dealers and paginates 10 + 10 via "Show more".
|
|
75
|
+
- Map uses a broader dealer dataset for marker coverage.
|
|
76
|
+
- Widget route calls dealer search with `scope=list` (list) and `scope=map` (map).
|
package/dist/JotulWidget.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.jwi-pointer-events-none{pointer-events:none}.jwi-fixed{position:fixed}.jwi-absolute{position:absolute}.jwi-relative{position:relative}.jwi-inset-0{inset:0}.jwi-inset-x-0{left:0;right:0}.jwi-bottom-0{bottom:0}.jwi-left-0{left:0}.jwi-right-0{right:0}.jwi-right-3{right:.75rem}.jwi-top-3{top:.75rem}.jwi-z-20{z-index:20}.jwi-z-30{z-index:30}.jwi-z-\[1200\]{z-index:1200}.jwi-z-\[9999\]{z-index:9999}.jwi-m-0{margin:0}.jwi--mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.-jwi-mt-px{margin-top:-1px}.jwi-mb-3{margin-bottom:.75rem}.jwi-mr-\[-12px\]{margin-right:-12px}.jwi-mt-2{margin-top:.5rem}.jwi-mt-3{margin-top:.75rem}.jwi-mt-4{margin-top:1rem}.jwi-box-border{box-sizing:border-box}.jwi-flex{display:flex}.jwi-inline-flex{display:inline-flex}.jwi-h-10{height:2.5rem}.jwi-h-12{height:3rem}.jwi-h-14{height:3.5rem}.jwi-h-3\.5{height:.875rem}.jwi-h-4{height:1rem}.jwi-h-5{height:1.25rem}.jwi-h-6{height:1.5rem}.jwi-h-9{height:2.25rem}.jwi-h-\[14px\]{height:14px}.jwi-h-\[18px\]{height:18px}.jwi-h-\[22px\]{height:22px}.jwi-h-\[45\%\]{height:45%}.jwi-h-\[60px\]{height:60px}.jwi-h-\[78vh\]{height:78vh}.jwi-h-\[calc\(78vh-48px\)\]{height:calc(78vh - 48px)}.jwi-h-\[min\(85vh\,860px\)\]{height:min(85vh,860px)}.jwi-h-auto{height:auto}.jwi-h-full{height:100%}.jwi-max-h-\[min\(60vh\,480px\)\]{max-height:min(60vh,480px)}.jwi-max-h-none{max-height:none}.jwi-min-h-0{min-height:0}.jwi-min-h-\[48px\]{min-height:48px}.jwi-min-h-\[56px\]{min-height:56px}.jwi-w-14{width:3.5rem}.jwi-w-2\/3{width:66.666667%}.jwi-w-24{width:6rem}.jwi-w-28{width:7rem}.jwi-w-3\.5{width:.875rem}.jwi-w-4{width:1rem}.jwi-w-48{width:12rem}.jwi-w-5{width:1.25rem}.jwi-w-9{width:2.25rem}.jwi-w-\[14px\]{width:14px}.jwi-w-\[18px\]{width:18px}.jwi-w-\[22px\]{width:22px}.jwi-w-\[40px\]{width:40px}.jwi-w-\[540px\]{width:540px}.jwi-w-\[min\(96vw\,1200px\)\]{width:min(96vw,1200px)}.jwi-w-auto{width:auto}.jwi-w-fit{width:-moz-fit-content;width:fit-content}.jwi-w-full{width:100%}.jwi-min-w-0{min-width:0}.jwi-max-w-\[220px\]{max-width:220px}.jwi-max-w-\[70\%\]{max-width:70%}.jwi-max-w-\[calc\(100\%-5rem\)\]{max-width:calc(100% - 5rem)}.jwi-max-w-full{max-width:100%}.jwi-flex-1{flex:1 1 0%}.jwi-flex-shrink-0,.jwi-shrink-0{flex-shrink:0}.jwi-scale-100{--tw-scale-x:1;--tw-scale-y:1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes jwi-pulse{50%{opacity:.5}}.jwi-animate-pulse{animation:jwi-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes jwi-spin{to{transform:rotate(1turn)}}.jwi-animate-spin{animation:jwi-spin 1s linear infinite}.jwi-cursor-pointer{cursor:pointer}.jwi-resize-y{resize:vertical}.jwi-flex-row{flex-direction:row}.jwi-flex-col{flex-direction:column}.jwi-items-start{align-items:flex-start}.jwi-items-center{align-items:center}.jwi-items-stretch{align-items:stretch}.jwi-justify-end{justify-content:flex-end}.jwi-justify-center{justify-content:center}.jwi-justify-between{justify-content:space-between}.jwi-gap-0\.5{gap:.125rem}.jwi-gap-1{gap:.25rem}.jwi-gap-1\.5{gap:.375rem}.jwi-gap-2{gap:.5rem}.jwi-gap-3{gap:.75rem}.jwi-gap-4{gap:1rem}.jwi-space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.jwi-self-stretch{align-self:stretch}.jwi-overflow-hidden{overflow:hidden}.jwi-overflow-y-auto{overflow-y:auto}.jwi-overscroll-y-contain{overscroll-behavior-y:contain}.jwi-whitespace-nowrap{white-space:nowrap}.jwi-break-all{word-break:break-all}.jwi-rounded-\[10px\]{border-radius:10px}.jwi-rounded-full{border-radius:9999px}.jwi-rounded-b-\[10px\]{border-bottom-right-radius:10px;border-bottom-left-radius:10px}.jwi-rounded-t-\[10px\]{border-top-left-radius:10px;border-top-right-radius:10px}.jwi-rounded-t-\[16px\]{border-top-left-radius:16px;border-top-right-radius:16px}.jwi-border{border-width:1px}.jwi-border-0{border-width:0}.jwi-border-b{border-bottom-width:1px}.jwi-border-t{border-top-width:1px}.jwi-border-t-0{border-top-width:0}.jwi-border-\[\#b7e5c2\]{--tw-border-opacity:1;border-color:rgb(183 229 194/var(--tw-border-opacity,1))}.jwi-border-\[\#d8d2c7\]{--tw-border-opacity:1;border-color:rgb(216 210 199/var(--tw-border-opacity,1))}.jwi-border-\[\#e6e1d7\]{--tw-border-opacity:1;border-color:rgb(230 225 215/var(--tw-border-opacity,1))}.jwi-border-\[\#ef2b18\]{--tw-border-opacity:1;border-color:rgb(239 43 24/var(--tw-border-opacity,1))}.jwi-border-\[\#f0c7c2\]{--tw-border-opacity:1;border-color:rgb(240 199 194/var(--tw-border-opacity,1))}.jwi-bg-\[\#FCFCFC\]{--tw-bg-opacity:1;background-color:rgb(252 252 252/var(--tw-bg-opacity,1))}.jwi-bg-\[\#ece8df\]{--tw-bg-opacity:1;background-color:rgb(236 232 223/var(--tw-bg-opacity,1))}.jwi-bg-\[\#eefbf2\]{--tw-bg-opacity:1;background-color:rgb(238 251 242/var(--tw-bg-opacity,1))}.jwi-bg-\[\#ef2b18\]{--tw-bg-opacity:1;background-color:rgb(239 43 24/var(--tw-bg-opacity,1))}.jwi-bg-\[\#f0f0f0\]{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity,1))}.jwi-bg-\[\#f7f5ef\]{--tw-bg-opacity:1;background-color:rgb(247 245 239/var(--tw-bg-opacity,1))}.jwi-bg-\[\#fbf3db\]{--tw-bg-opacity:1;background-color:rgb(251 243 219/var(--tw-bg-opacity,1))}.jwi-bg-\[\#fff3f1\]{--tw-bg-opacity:1;background-color:rgb(255 243 241/var(--tw-bg-opacity,1))}.jwi-bg-black\/45{background-color:rgba(0,0,0,.45)}.jwi-bg-transparent{background-color:transparent}.jwi-bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.jwi-bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.jwi-from-white{--tw-gradient-from:#fff var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.jwi-to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.jwi-p-0{padding:0}.jwi-p-1{padding:.25rem}.jwi-p-4{padding:1rem}.jwi-p-6{padding:1.5rem}.jwi-px-2\.5{padding-left:.625rem;padding-right:.625rem}.jwi-px-4{padding-left:1rem;padding-right:1rem}.jwi-px-5{padding-left:1.25rem;padding-right:1.25rem}.jwi-px-6{padding-left:1.5rem;padding-right:1.5rem}.jwi-px-7{padding-left:1.75rem;padding-right:1.75rem}.jwi-py-1{padding-top:.25rem;padding-bottom:.25rem}.jwi-py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.jwi-py-3{padding-top:.75rem;padding-bottom:.75rem}.jwi-py-4{padding-top:1rem;padding-bottom:1rem}.jwi-py-8{padding-top:2rem;padding-bottom:2rem}.jwi-pb-24{padding-bottom:6rem}.jwi-pb-3{padding-bottom:.75rem}.jwi-pl-5{padding-left:1.25rem}.jwi-pr-1{padding-right:.25rem}.jwi-pr-3{padding-right:.75rem}.jwi-pr-\[12px\]{padding-right:12px}.jwi-pt-3{padding-top:.75rem}.jwi-text-left{text-align:left}.jwi-font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.jwi-text-\[13px\]{font-size:13px}.jwi-text-base{font-size:1rem;line-height:1.5rem}.jwi-text-sm{font-size:.875rem;line-height:1.25rem}.jwi-text-xl{font-size:1.25rem;line-height:1.75rem}.jwi-text-xs{font-size:.75rem;line-height:1rem}.jwi-font-medium{font-weight:500}.jwi-font-normal{font-weight:400}.jwi-font-semibold{font-weight:600}.jwi-tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.jwi-leading-\[1\.35\]{line-height:1.35}.jwi-leading-\[1\.4\]{line-height:1.4}.jwi-leading-none{line-height:1}.jwi-leading-snug{line-height:1.375}.jwi-text-\[\#000000\]{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.jwi-text-\[\#111111\]{--tw-text-opacity:1;color:rgb(17 17 17/var(--tw-text-opacity,1))}.jwi-text-\[\#1b5e20\]{--tw-text-opacity:1;color:rgb(27 94 32/var(--tw-text-opacity,1))}.jwi-text-\[\#555555\]{--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity,1))}.jwi-text-\[\#767676\]{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.jwi-text-\[\#8f2d21\]{--tw-text-opacity:1;color:rgb(143 45 33/var(--tw-text-opacity,1))}.jwi-text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.jwi-text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.jwi-opacity-25{opacity:.25}.jwi-opacity-75{opacity:.75}.jwi-opacity-95{opacity:.95}.jwi-shadow-\[0_-12px_36px_rgba\(0\,0\,0\,0\.22\)\]{--tw-shadow:0 -12px 36px rgba(0,0,0,.22);--tw-shadow-colored:0 -12px 36px var(--tw-shadow-color)}.jwi-shadow-\[0_-12px_36px_rgba\(0\,0\,0\,0\.22\)\],.jwi-shadow-\[0_-6px_20px_rgba\(0\,0\,0\,0\.12\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_-6px_20px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 -6px 20px rgba(0,0,0,.12);--tw-shadow-colored:0 -6px 20px var(--tw-shadow-color)}.jwi-shadow-\[0_1px_2px_rgba\(17\,17\,17\,0\.03\)\]{--tw-shadow:0 1px 2px hsla(0,0%,7%,.03);--tw-shadow-colored:0 1px 2px var(--tw-shadow-color)}.jwi-shadow-\[0_1px_2px_rgba\(17\,17\,17\,0\.03\)\],.jwi-shadow-\[0_20px_60px_rgba\(0\,0\,0\,0\.25\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_20px_60px_rgba\(0\,0\,0\,0\.25\)\]{--tw-shadow:0 20px 60px rgba(0,0,0,.25);--tw-shadow-colored:0 20px 60px var(--tw-shadow-color)}.jwi-shadow-\[0_2px_8px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 8px rgba(0,0,0,.12);--tw-shadow-colored:0 2px 8px var(--tw-shadow-color)}.jwi-shadow-\[0_2px_8px_rgba\(0\,0\,0\,0\.12\)\],.jwi-shadow-\[0_8px_24px_rgba\(17\,17\,17\,0\.08\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_8px_24px_rgba\(17\,17\,17\,0\.08\)\]{--tw-shadow:0 8px 24px hsla(0,0%,7%,.08);--tw-shadow-colored:0 8px 24px var(--tw-shadow-color)}.jwi-outline-none{outline:2px solid transparent;outline-offset:2px}.jwi-transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.placeholder\:jwi-text-\[13px\]::-moz-placeholder{font-size:13px}.placeholder\:jwi-text-\[13px\]::placeholder{font-size:13px}.placeholder\:jwi-text-\[\#767676\]::-moz-placeholder{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.placeholder\:jwi-text-\[\#767676\]::placeholder{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.hover\:jwi-bg-\[\#d92817\]:hover{--tw-bg-opacity:1;background-color:rgb(217 40 23/var(--tw-bg-opacity,1))}.hover\:jwi-bg-\[\#f7f5f0\]:hover{--tw-bg-opacity:1;background-color:rgb(247 245 240/var(--tw-bg-opacity,1))}.hover\:jwi-text-\[\#444444\]:hover{--tw-text-opacity:1;color:rgb(68 68 68/var(--tw-text-opacity,1))}.hover\:jwi-underline:hover{text-decoration-line:underline}.focus\:jwi-border-\[\#111111\]:focus{--tw-border-opacity:1;border-color:rgb(17 17 17/var(--tw-border-opacity,1))}.disabled\:jwi-cursor-wait:disabled{cursor:wait}.disabled\:hover\:jwi-bg-\[\#ef2b18\]:hover:disabled{--tw-bg-opacity:1;background-color:rgb(239 43 24/var(--tw-bg-opacity,1))}@media (min-width:768px){.md\:jwi-h-full{height:100%}.md\:jwi-w-\[48\%\]{width:48%}.md\:jwi-w-\[52\%\]{width:52%}.md\:jwi-max-w-\[220px\]{max-width:220px}.md\:jwi-flex-row{flex-direction:row}.md\:jwi-items-center{align-items:center}.md\:jwi-justify-between{justify-content:space-between}.md\:jwi-border-r{border-right-width:1px}.md\:jwi-border-\[\#ece8df\]{--tw-border-opacity:1;border-color:rgb(236 232 223/var(--tw-border-opacity,1))}.md\:jwi-text-\[14px\]{font-size:14px}.md\:jwi-text-base{font-size:1rem;line-height:1.5rem}.md\:placeholder\:jwi-text-\[14px\]::-moz-placeholder{font-size:14px}.md\:placeholder\:jwi-text-\[14px\]::placeholder{font-size:14px}}
|
|
1
|
+
.jwi-pointer-events-none{pointer-events:none}.jwi-fixed{position:fixed}.jwi-absolute{position:absolute}.jwi-relative{position:relative}.jwi-inset-0{inset:0}.jwi-inset-x-0{left:0;right:0}.jwi-bottom-0{bottom:0}.jwi-left-0{left:0}.jwi-right-0{right:0}.jwi-right-3{right:.75rem}.jwi-top-0{top:0}.jwi-top-3{top:.75rem}.jwi-z-20{z-index:20}.jwi-z-30{z-index:30}.jwi-z-\[1200\]{z-index:1200}.jwi-z-\[9998\]{z-index:9998}.jwi-z-\[9999\]{z-index:9999}.jwi-m-0{margin:0}.jwi--mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.-jwi-mt-px{margin-top:-1px}.jwi-mb-3{margin-bottom:.75rem}.jwi-mr-\[-12px\]{margin-right:-12px}.jwi-mt-2{margin-top:.5rem}.jwi-mt-3{margin-top:.75rem}.jwi-mt-4{margin-top:1rem}.jwi-box-border{box-sizing:border-box}.jwi-flex{display:flex}.jwi-inline-flex{display:inline-flex}.jwi-h-10{height:2.5rem}.jwi-h-12{height:3rem}.jwi-h-14{height:3.5rem}.jwi-h-3\.5{height:.875rem}.jwi-h-4{height:1rem}.jwi-h-5{height:1.25rem}.jwi-h-6{height:1.5rem}.jwi-h-9{height:2.25rem}.jwi-h-\[14px\]{height:14px}.jwi-h-\[18px\]{height:18px}.jwi-h-\[22px\]{height:22px}.jwi-h-\[45\%\]{height:45%}.jwi-h-\[60px\]{height:60px}.jwi-h-\[78vh\]{height:78vh}.jwi-h-\[calc\(78vh-48px\)\]{height:calc(78vh - 48px)}.jwi-h-\[min\(85vh\,860px\)\]{height:min(85vh,860px)}.jwi-h-auto{height:auto}.jwi-h-full{height:100%}.jwi-max-h-\[min\(60vh\,480px\)\]{max-height:min(60vh,480px)}.jwi-max-h-none{max-height:none}.jwi-min-h-0{min-height:0}.jwi-min-h-\[48px\]{min-height:48px}.jwi-min-h-\[56px\]{min-height:56px}.jwi-w-1\/2{width:50%}.jwi-w-14{width:3.5rem}.jwi-w-2\/3{width:66.666667%}.jwi-w-24{width:6rem}.jwi-w-28{width:7rem}.jwi-w-3\.5{width:.875rem}.jwi-w-4{width:1rem}.jwi-w-48{width:12rem}.jwi-w-5{width:1.25rem}.jwi-w-9{width:2.25rem}.jwi-w-\[14px\]{width:14px}.jwi-w-\[18px\]{width:18px}.jwi-w-\[22px\]{width:22px}.jwi-w-\[40px\]{width:40px}.jwi-w-\[540px\]{width:540px}.jwi-w-\[min\(100vw\,1200px\)\]{width:min(100vw,1200px)}.jwi-w-\[min\(96vw\,1200px\)\]{width:min(96vw,1200px)}.jwi-w-auto{width:auto}.jwi-w-fit{width:-moz-fit-content;width:fit-content}.jwi-w-full{width:100%}.jwi-min-w-0{min-width:0}.jwi-max-w-\[220px\]{max-width:220px}.jwi-max-w-\[70\%\]{max-width:70%}.jwi-max-w-\[calc\(100\%-5rem\)\]{max-width:calc(100% - 5rem)}.jwi-max-w-full{max-width:100%}.jwi-flex-1{flex:1 1 0%}.jwi-flex-shrink-0,.jwi-shrink-0{flex-shrink:0}.jwi-scale-100{--tw-scale-x:1;--tw-scale-y:1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes jwi-pulse{50%{opacity:.5}}.jwi-animate-pulse{animation:jwi-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes jwi-spin{to{transform:rotate(1turn)}}.jwi-animate-spin{animation:jwi-spin 1s linear infinite}.jwi-cursor-pointer{cursor:pointer}.jwi-resize-y{resize:vertical}.jwi-flex-row{flex-direction:row}.jwi-flex-col{flex-direction:column}.jwi-items-start{align-items:flex-start}.jwi-items-center{align-items:center}.jwi-items-stretch{align-items:stretch}.jwi-justify-end{justify-content:flex-end}.jwi-justify-center{justify-content:center}.jwi-justify-between{justify-content:space-between}.jwi-gap-0\.5{gap:.125rem}.jwi-gap-1{gap:.25rem}.jwi-gap-1\.5{gap:.375rem}.jwi-gap-2{gap:.5rem}.jwi-gap-3{gap:.75rem}.jwi-gap-4{gap:1rem}.jwi-space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.jwi-self-stretch{align-self:stretch}.jwi-overflow-hidden{overflow:hidden}.jwi-overflow-y-auto{overflow-y:auto}.jwi-overscroll-y-contain{overscroll-behavior-y:contain}.jwi-whitespace-nowrap{white-space:nowrap}.jwi-break-all{word-break:break-all}.jwi-rounded-\[10px\]{border-radius:10px}.jwi-rounded-full{border-radius:9999px}.jwi-rounded-md{border-radius:.375rem}.jwi-rounded-b-\[10px\]{border-bottom-right-radius:10px;border-bottom-left-radius:10px}.jwi-rounded-t-\[10px\]{border-top-left-radius:10px;border-top-right-radius:10px}.jwi-rounded-t-\[16px\]{border-top-left-radius:16px;border-top-right-radius:16px}.jwi-border{border-width:1px}.jwi-border-0{border-width:0}.jwi-border-b{border-bottom-width:1px}.jwi-border-t{border-top-width:1px}.jwi-border-t-0{border-top-width:0}.jwi-border-\[\#b7e5c2\]{--tw-border-opacity:1;border-color:rgb(183 229 194/var(--tw-border-opacity,1))}.jwi-border-\[\#d8d2c7\]{--tw-border-opacity:1;border-color:rgb(216 210 199/var(--tw-border-opacity,1))}.jwi-border-\[\#e6e1d7\]{--tw-border-opacity:1;border-color:rgb(230 225 215/var(--tw-border-opacity,1))}.jwi-border-\[\#ef2b18\]{--tw-border-opacity:1;border-color:rgb(239 43 24/var(--tw-border-opacity,1))}.jwi-border-\[\#f0c7c2\]{--tw-border-opacity:1;border-color:rgb(240 199 194/var(--tw-border-opacity,1))}.jwi-bg-\[\#FCFCFC\]{--tw-bg-opacity:1;background-color:rgb(252 252 252/var(--tw-bg-opacity,1))}.jwi-bg-\[\#e8eef1\]{--tw-bg-opacity:1;background-color:rgb(232 238 241/var(--tw-bg-opacity,1))}.jwi-bg-\[\#ece8df\]{--tw-bg-opacity:1;background-color:rgb(236 232 223/var(--tw-bg-opacity,1))}.jwi-bg-\[\#eefbf2\]{--tw-bg-opacity:1;background-color:rgb(238 251 242/var(--tw-bg-opacity,1))}.jwi-bg-\[\#ef2b18\]{--tw-bg-opacity:1;background-color:rgb(239 43 24/var(--tw-bg-opacity,1))}.jwi-bg-\[\#f0f0f0\]{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity,1))}.jwi-bg-\[\#f7f5ef\]{--tw-bg-opacity:1;background-color:rgb(247 245 239/var(--tw-bg-opacity,1))}.jwi-bg-\[\#fbf3db\]{--tw-bg-opacity:1;background-color:rgb(251 243 219/var(--tw-bg-opacity,1))}.jwi-bg-\[\#fff3f1\]{--tw-bg-opacity:1;background-color:rgb(255 243 241/var(--tw-bg-opacity,1))}.jwi-bg-black\/35{background-color:rgba(0,0,0,.35)}.jwi-bg-black\/45{background-color:rgba(0,0,0,.45)}.jwi-bg-transparent{background-color:transparent}.jwi-bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.jwi-bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.jwi-from-white{--tw-gradient-from:#fff var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.jwi-to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.jwi-p-0{padding:0}.jwi-p-1{padding:.25rem}.jwi-p-4{padding:1rem}.jwi-p-6{padding:1.5rem}.jwi-px-2\.5{padding-left:.625rem;padding-right:.625rem}.jwi-px-3{padding-left:.75rem;padding-right:.75rem}.jwi-px-4{padding-left:1rem;padding-right:1rem}.jwi-px-5{padding-left:1.25rem;padding-right:1.25rem}.jwi-px-6{padding-left:1.5rem;padding-right:1.5rem}.jwi-px-7{padding-left:1.75rem;padding-right:1.75rem}.jwi-py-1{padding-top:.25rem;padding-bottom:.25rem}.jwi-py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.jwi-py-2{padding-top:.5rem;padding-bottom:.5rem}.jwi-py-3{padding-top:.75rem;padding-bottom:.75rem}.jwi-py-4{padding-top:1rem;padding-bottom:1rem}.jwi-py-8{padding-top:2rem;padding-bottom:2rem}.jwi-pb-24{padding-bottom:6rem}.jwi-pb-3{padding-bottom:.75rem}.jwi-pl-5{padding-left:1.25rem}.jwi-pr-1{padding-right:.25rem}.jwi-pr-3{padding-right:.75rem}.jwi-pr-\[12px\]{padding-right:12px}.jwi-pt-3{padding-top:.75rem}.jwi-text-left{text-align:left}.jwi-font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.jwi-text-\[13px\]{font-size:13px}.jwi-text-base{font-size:1rem;line-height:1.5rem}.jwi-text-sm{font-size:.875rem;line-height:1.25rem}.jwi-text-xl{font-size:1.25rem;line-height:1.75rem}.jwi-text-xs{font-size:.75rem;line-height:1rem}.jwi-font-medium{font-weight:500}.jwi-font-normal{font-weight:400}.jwi-font-semibold{font-weight:600}.jwi-tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.jwi-leading-\[1\.35\]{line-height:1.35}.jwi-leading-\[1\.4\]{line-height:1.4}.jwi-leading-none{line-height:1}.jwi-leading-snug{line-height:1.375}.jwi-text-\[\#000000\]{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.jwi-text-\[\#111111\]{--tw-text-opacity:1;color:rgb(17 17 17/var(--tw-text-opacity,1))}.jwi-text-\[\#1b5e20\]{--tw-text-opacity:1;color:rgb(27 94 32/var(--tw-text-opacity,1))}.jwi-text-\[\#555555\]{--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity,1))}.jwi-text-\[\#767676\]{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.jwi-text-\[\#8f2d21\]{--tw-text-opacity:1;color:rgb(143 45 33/var(--tw-text-opacity,1))}.jwi-text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.jwi-text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.jwi-opacity-25{opacity:.25}.jwi-opacity-75{opacity:.75}.jwi-opacity-95{opacity:.95}.jwi-shadow-\[-8px_0_32px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow:-8px 0 32px rgba(0,0,0,.2);--tw-shadow-colored:-8px 0 32px var(--tw-shadow-color)}.jwi-shadow-\[-8px_0_32px_rgba\(0\,0\,0\,0\.2\)\],.jwi-shadow-\[0_-12px_36px_rgba\(0\,0\,0\,0\.22\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_-12px_36px_rgba\(0\,0\,0\,0\.22\)\]{--tw-shadow:0 -12px 36px rgba(0,0,0,.22);--tw-shadow-colored:0 -12px 36px var(--tw-shadow-color)}.jwi-shadow-\[0_-6px_20px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 -6px 20px rgba(0,0,0,.12);--tw-shadow-colored:0 -6px 20px var(--tw-shadow-color)}.jwi-shadow-\[0_-6px_20px_rgba\(0\,0\,0\,0\.12\)\],.jwi-shadow-\[0_1px_2px_rgba\(17\,17\,17\,0\.03\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_1px_2px_rgba\(17\,17\,17\,0\.03\)\]{--tw-shadow:0 1px 2px hsla(0,0%,7%,.03);--tw-shadow-colored:0 1px 2px var(--tw-shadow-color)}.jwi-shadow-\[0_20px_60px_rgba\(0\,0\,0\,0\.25\)\]{--tw-shadow:0 20px 60px rgba(0,0,0,.25);--tw-shadow-colored:0 20px 60px var(--tw-shadow-color)}.jwi-shadow-\[0_20px_60px_rgba\(0\,0\,0\,0\.25\)\],.jwi-shadow-\[0_2px_8px_rgba\(0\,0\,0\,0\.12\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-shadow-\[0_2px_8px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 8px rgba(0,0,0,.12);--tw-shadow-colored:0 2px 8px var(--tw-shadow-color)}.jwi-shadow-\[0_8px_24px_rgba\(17\,17\,17\,0\.08\)\]{--tw-shadow:0 8px 24px hsla(0,0%,7%,.08);--tw-shadow-colored:0 8px 24px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.jwi-outline-none{outline:2px solid transparent;outline-offset:2px}.jwi-transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.placeholder\:jwi-text-\[13px\]::-moz-placeholder{font-size:13px}.placeholder\:jwi-text-\[13px\]::placeholder{font-size:13px}.placeholder\:jwi-text-\[\#767676\]::-moz-placeholder{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.placeholder\:jwi-text-\[\#767676\]::placeholder{--tw-text-opacity:1;color:rgb(118 118 118/var(--tw-text-opacity,1))}.hover\:jwi-bg-\[\#d92817\]:hover{--tw-bg-opacity:1;background-color:rgb(217 40 23/var(--tw-bg-opacity,1))}.hover\:jwi-bg-\[\#f7f5f0\]:hover{--tw-bg-opacity:1;background-color:rgb(247 245 240/var(--tw-bg-opacity,1))}.hover\:jwi-text-\[\#444444\]:hover{--tw-text-opacity:1;color:rgb(68 68 68/var(--tw-text-opacity,1))}.hover\:jwi-underline:hover{text-decoration-line:underline}.focus\:jwi-border-\[\#111111\]:focus{--tw-border-opacity:1;border-color:rgb(17 17 17/var(--tw-border-opacity,1))}.disabled\:jwi-cursor-wait:disabled{cursor:wait}.disabled\:hover\:jwi-bg-\[\#ef2b18\]:hover:disabled{--tw-bg-opacity:1;background-color:rgb(239 43 24/var(--tw-bg-opacity,1))}@media (min-width:768px){.md\:jwi-h-full{height:100%}.md\:jwi-w-\[48\%\]{width:48%}.md\:jwi-w-\[52\%\]{width:52%}.md\:jwi-max-w-\[220px\]{max-width:220px}.md\:jwi-flex-row{flex-direction:row}.md\:jwi-items-center{align-items:center}.md\:jwi-justify-between{justify-content:space-between}.md\:jwi-border-r{border-right-width:1px}.md\:jwi-border-\[\#ece8df\]{--tw-border-opacity:1;border-color:rgb(236 232 223/var(--tw-border-opacity,1))}.md\:jwi-text-\[14px\]{font-size:14px}.md\:jwi-text-base{font-size:1rem;line-height:1.5rem}.md\:placeholder\:jwi-text-\[14px\]::-moz-placeholder{font-size:14px}.md\:placeholder\:jwi-text-\[14px\]::placeholder{font-size:14px}}
|
package/dist/JotulWidget.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ import type { JotulWidgetProps } from './types';
|
|
|
4
4
|
export { DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, } from './i18n/widgetStrings';
|
|
5
5
|
export type { JotulWidgetLocale } from './i18n/widgetStrings';
|
|
6
6
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
7
|
-
export type { CheckWidgetAuthorizationOptions, DealerSearchResponse, JotulWidgetButtonStyling, JotulWidgetProps,
|
|
8
|
-
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, market: marketProp, brands, styling, productPageTrigger, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export type { CheckWidgetAuthorizationOptions, DealerSearchResponse, JotulWidgetButtonStyling, JotulWidgetProps, WidgetTriggerRenderProps, JotulWidgetStyling, JotulWidgetType, WidgetAuthClientResponse, } from './types';
|
|
8
|
+
export declare function JotulWidget({ type, endpoint, className, productName, locale: localeProp, market: marketProp, brands, styling, trigger, productPageTrigger, findDealerDrawerTrigger, }: JotulWidgetProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/JotulWidget.js
CHANGED
|
@@ -3,11 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import './JotulWidget.css';
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { FinderSearchRowSkeleton } from './components/FinderSearchRowSkeleton';
|
|
6
|
+
import { DealerCardSkeleton } from './components/DealerCardSkeleton';
|
|
6
7
|
import { ProductPageWidget } from './widgets/ProductPageWidget';
|
|
8
|
+
import { FindDealerDrawerWidget } from './components/FindDealerDrawerWidget';
|
|
7
9
|
import { ButtonSpinner } from './icons/ButtonSpinner';
|
|
8
10
|
import { DEFAULT_WIDGET_LOCALE_TAG, resolveWidgetUiLocale, WIDGET_STRINGS, } from './i18n/widgetStrings';
|
|
9
11
|
import { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, } from './api';
|
|
10
|
-
import { createInquiryFormValues, getSafeWidgetErrorMessage, isValidEmail, isWidgetType, renderReadyState, } from './utils';
|
|
12
|
+
import { createInquiryFormValues, getSafeWidgetErrorMessage, isDealerInSearchResult, isValidEmail, isWidgetType, renderReadyState, } from './utils';
|
|
11
13
|
import { getWidgetPrimaryButtonPresentation } from './utils/widgetPrimaryButtonPresentation';
|
|
12
14
|
export { DEFAULT_WIDGET_LOCALE_TAG, normalizeWidgetLocale, resolveWidgetUiLocale, } from './i18n/widgetStrings';
|
|
13
15
|
export { checkWidgetAuthorization, searchLocationSuggestions, searchDealersByCoordinates, searchDealersByPostalCode, };
|
|
@@ -19,7 +21,14 @@ const GEOLOCATION_OPTIONS = {
|
|
|
19
21
|
timeout: 15000,
|
|
20
22
|
maximumAge: 300000,
|
|
21
23
|
};
|
|
22
|
-
|
|
24
|
+
const MARKET_FALLBACK_CENTER = {
|
|
25
|
+
NO: [59.9139, 10.7522],
|
|
26
|
+
SE: [59.3293, 18.0686],
|
|
27
|
+
DK: [55.6761, 12.5683],
|
|
28
|
+
FI: [60.1699, 24.9384],
|
|
29
|
+
DE: [52.52, 13.405],
|
|
30
|
+
};
|
|
31
|
+
export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, productName, locale: localeProp, market: marketProp, brands, styling, trigger, productPageTrigger, findDealerDrawerTrigger, }) {
|
|
23
32
|
const resolvedUiLocale = useMemo(() => resolveWidgetUiLocale(localeProp, marketProp), [localeProp, marketProp]);
|
|
24
33
|
const t = WIDGET_STRINGS[resolvedUiLocale];
|
|
25
34
|
const apiLocaleTag = useMemo(() => (localeProp?.trim() ? localeProp.trim() : DEFAULT_WIDGET_LOCALE_TAG), [localeProp]);
|
|
@@ -36,6 +45,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
36
45
|
const [auth, setAuth] = useState(null);
|
|
37
46
|
const [isLoading, setIsLoading] = useState(false);
|
|
38
47
|
const [searchResult, setSearchResult] = useState(null);
|
|
48
|
+
const [mapSearchResult, setMapSearchResult] = useState(null);
|
|
39
49
|
const [isSearching, setIsSearching] = useState(false);
|
|
40
50
|
const [isSearchingSuggestions, setIsSearchingSuggestions] = useState(false);
|
|
41
51
|
const [locationError, setLocationError] = useState(null);
|
|
@@ -60,13 +70,20 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
60
70
|
setLocationError(null);
|
|
61
71
|
setIsSearching(true);
|
|
62
72
|
try {
|
|
63
|
-
const result = await searchDealersByCoordinates(latitude, longitude, dealerSearchOptions);
|
|
73
|
+
const result = await searchDealersByCoordinates(latitude, longitude, dealerSearchOptions, 'list');
|
|
64
74
|
setSearchResult(result);
|
|
75
|
+
const mapResult = await searchDealersByCoordinates(latitude, longitude, dealerSearchOptions, 'map');
|
|
76
|
+
setMapSearchResult(mapResult);
|
|
65
77
|
}
|
|
66
78
|
finally {
|
|
67
79
|
setIsSearching(false);
|
|
68
80
|
}
|
|
69
81
|
}, [dealerSearchOptions]);
|
|
82
|
+
const runFallbackDealerSearch = useCallback(() => {
|
|
83
|
+
const fallbackCenter = (apiMarket != null ? MARKET_FALLBACK_CENTER[apiMarket] : undefined) ??
|
|
84
|
+
MARKET_FALLBACK_CENTER.NO;
|
|
85
|
+
return runDealerSearchByCoordinates(fallbackCenter[0], fallbackCenter[1]);
|
|
86
|
+
}, [apiMarket, runDealerSearchByCoordinates]);
|
|
70
87
|
const runLocationSearch = useCallback(() => {
|
|
71
88
|
const messages = WIDGET_STRINGS[resolvedUiLocale];
|
|
72
89
|
setShouldAutoLocateAfterAuth(false);
|
|
@@ -77,6 +94,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
77
94
|
setIsSuggestionListOpen(false);
|
|
78
95
|
if (typeof navigator === 'undefined' || !navigator.geolocation) {
|
|
79
96
|
setLocationError(messages.locationUnavailableBrowser);
|
|
97
|
+
void runFallbackDealerSearch();
|
|
80
98
|
return;
|
|
81
99
|
}
|
|
82
100
|
setIsSearching(true);
|
|
@@ -99,8 +117,9 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
99
117
|
else {
|
|
100
118
|
setLocationError(messages.locationGenericFailure);
|
|
101
119
|
}
|
|
120
|
+
void runFallbackDealerSearch();
|
|
102
121
|
}, GEOLOCATION_OPTIONS);
|
|
103
|
-
}, [resolvedUiLocale, runDealerSearchByCoordinates]);
|
|
122
|
+
}, [resolvedUiLocale, runDealerSearchByCoordinates, runFallbackDealerSearch]);
|
|
104
123
|
useEffect(() => {
|
|
105
124
|
const query = locationQuery.trim();
|
|
106
125
|
if (query.length < 3) {
|
|
@@ -131,7 +150,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
131
150
|
};
|
|
132
151
|
}, [apiLocaleTag, apiMarket, dealerSearchOptions, locationQuery]);
|
|
133
152
|
useEffect(() => {
|
|
134
|
-
if (type === 'productPage' && !isOpen)
|
|
153
|
+
if ((type === 'productPage' || type === 'findDealerDrawer') && !isOpen)
|
|
135
154
|
return;
|
|
136
155
|
if (auth != null)
|
|
137
156
|
return;
|
|
@@ -152,7 +171,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
152
171
|
useEffect(() => {
|
|
153
172
|
if (!shouldAutoLocateAfterAuth)
|
|
154
173
|
return;
|
|
155
|
-
if (type !== 'productPage' || !isOpen)
|
|
174
|
+
if ((type !== 'productPage' && type !== 'findDealerDrawer') || !isOpen)
|
|
156
175
|
return;
|
|
157
176
|
if (auth == null || isLoading)
|
|
158
177
|
return;
|
|
@@ -174,6 +193,7 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
174
193
|
const openProductPageWidget = useCallback(() => {
|
|
175
194
|
setLocationError(null);
|
|
176
195
|
setSearchResult(null);
|
|
196
|
+
setMapSearchResult(null);
|
|
177
197
|
setLocationQuery('');
|
|
178
198
|
setLocationSuggestions([]);
|
|
179
199
|
setIsSuggestionListOpen(false);
|
|
@@ -186,43 +206,72 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
186
206
|
setShouldAutoLocateAfterAuth(true);
|
|
187
207
|
}
|
|
188
208
|
}, [auth, isLoading, runLocationSearch]);
|
|
209
|
+
const closeDealerWidget = useCallback(() => {
|
|
210
|
+
setIsOpen(false);
|
|
211
|
+
setLocationSuggestions([]);
|
|
212
|
+
setIsSuggestionListOpen(false);
|
|
213
|
+
setIsSearchingSuggestions(false);
|
|
214
|
+
setMapSearchResult(null);
|
|
215
|
+
}, []);
|
|
189
216
|
const shellClass = 'jwi-box-border jwi-flex jwi-w-[540px] jwi-max-w-full jwi-flex-col jwi-font-sans jwi-text-[#111111]';
|
|
190
217
|
const rootClass = className != null && className !== '' ? `${shellClass} ${className}` : shellClass;
|
|
191
218
|
if (typeState !== 'typeReady') {
|
|
192
219
|
return _jsx("div", { className: rootClass, children: t.invalidWidgetTypeError });
|
|
193
220
|
}
|
|
221
|
+
const resolvedTrigger = trigger ?? productPageTrigger ?? findDealerDrawerTrigger;
|
|
222
|
+
const resolvedTriggerNode = typeof resolvedTrigger === 'function'
|
|
223
|
+
? resolvedTrigger({
|
|
224
|
+
onOpen: openProductPageWidget,
|
|
225
|
+
isLoading,
|
|
226
|
+
label: t.findDealer,
|
|
227
|
+
className: heroPrimaryButton.className,
|
|
228
|
+
style: heroPrimaryButton.style,
|
|
229
|
+
})
|
|
230
|
+
: resolvedTrigger;
|
|
231
|
+
const renderTrigger = (alwaysClickable = false) => {
|
|
232
|
+
if (resolvedTriggerNode == null) {
|
|
233
|
+
return (_jsx("button", { type: "button", onClick: openProductPageWidget, className: heroPrimaryButton.className, style: heroPrimaryButton.style, children: t.findDealer }));
|
|
234
|
+
}
|
|
235
|
+
if (typeof resolvedTrigger === 'function' && !alwaysClickable) {
|
|
236
|
+
return resolvedTriggerNode;
|
|
237
|
+
}
|
|
238
|
+
return (_jsx("div", { role: "button", tabIndex: 0, onClick: openProductPageWidget, onKeyDown: (event) => {
|
|
239
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
openProductPageWidget();
|
|
242
|
+
}
|
|
243
|
+
}, children: resolvedTriggerNode }));
|
|
244
|
+
};
|
|
194
245
|
if (widgetType === 'productPage' && !isOpen) {
|
|
195
|
-
|
|
196
|
-
? productPageTrigger({
|
|
197
|
-
onOpen: openProductPageWidget,
|
|
198
|
-
isLoading,
|
|
199
|
-
label: t.findDealer,
|
|
200
|
-
className: heroPrimaryButton.className,
|
|
201
|
-
style: heroPrimaryButton.style,
|
|
202
|
-
})
|
|
203
|
-
: productPageTrigger;
|
|
204
|
-
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-py-8 jwi-items-center jwi-justify-center", children: trigger != null ? (_jsx("div", { role: "button", tabIndex: 0, onClick: openProductPageWidget, onKeyDown: (event) => {
|
|
205
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
206
|
-
event.preventDefault();
|
|
207
|
-
openProductPageWidget();
|
|
208
|
-
}
|
|
209
|
-
}, children: trigger })) : (_jsx("button", { type: "button", onClick: openProductPageWidget, className: heroPrimaryButton.className, style: heroPrimaryButton.style, children: t.findDealer })) }) }));
|
|
246
|
+
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-py-8 jwi-items-center jwi-justify-center", children: renderTrigger() }) }));
|
|
210
247
|
}
|
|
211
|
-
const productPageAuthPending = widgetType === 'productPage' &&
|
|
248
|
+
const productPageAuthPending = widgetType === 'productPage' &&
|
|
249
|
+
isOpen &&
|
|
250
|
+
(auth === null || isLoading);
|
|
212
251
|
if (productPageAuthPending) {
|
|
213
252
|
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-py-8 jwi-items-center jwi-justify-center", children: _jsx("button", { type: "button", disabled: true, className: `${heroPrimaryButton.className} jwi-opacity-95`, style: heroPrimaryButton.style, children: _jsxs("span", { className: "jwi-inline-flex jwi-items-center jwi-gap-2", children: [_jsx(ButtonSpinner, {}), t.loading] }) }) }) }));
|
|
214
253
|
}
|
|
215
|
-
const waitingForAuth = auth === null &&
|
|
216
|
-
|
|
254
|
+
const waitingForAuth = auth === null &&
|
|
255
|
+
!((widgetType === 'productPage' || widgetType === 'findDealerDrawer') &&
|
|
256
|
+
!isOpen);
|
|
257
|
+
if ((isLoading || waitingForAuth) &&
|
|
258
|
+
type !== 'productPage' &&
|
|
259
|
+
type !== 'findDealerDrawer') {
|
|
217
260
|
return (_jsx("div", { className: rootClass, children: _jsx("div", { className: "jwi-flex jwi-w-full jwi-flex-col", children: _jsx(FinderSearchRowSkeleton, {}) }) }));
|
|
218
261
|
}
|
|
219
|
-
|
|
262
|
+
const deferAuthErrorUntilDrawerOpens = widgetType === 'findDealerDrawer' && !isOpen && auth === null;
|
|
263
|
+
const deferAuthUntilFindDealerDrawerResolves = widgetType === 'findDealerDrawer' && isOpen && (auth === null || isLoading);
|
|
264
|
+
if (!deferAuthErrorUntilDrawerOpens &&
|
|
265
|
+
!deferAuthUntilFindDealerDrawerResolves &&
|
|
266
|
+
(!auth?.ok || !auth.authorized)) {
|
|
220
267
|
return _jsx("div", { className: rootClass, children: getSafeWidgetErrorMessage(auth?.error, t) });
|
|
221
268
|
}
|
|
222
269
|
if (widgetType === 'productPage') {
|
|
223
270
|
return (_jsx("div", { className: rootClass, children: _jsx(ProductPageWidget, { t: t, buttonStyling: styling?.button, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
224
271
|
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
225
|
-
: searchResult,
|
|
272
|
+
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
273
|
+
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
274
|
+
: mapSearchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
226
275
|
setLocationQuery(value);
|
|
227
276
|
const trimmed = value.trim();
|
|
228
277
|
setIsSuggestionListOpen(trimmed.length > 0);
|
|
@@ -283,12 +332,91 @@ export function JotulWidget({ type, endpoint = '/api/jotul/widget', className, p
|
|
|
283
332
|
setInquiryValues(createInquiryFormValues(productName, dealerName));
|
|
284
333
|
setInquiryError(null);
|
|
285
334
|
setIsInquirySubmitted(false);
|
|
286
|
-
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
335
|
+
}, onMapDealerSelect: (dealer) => {
|
|
336
|
+
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
337
|
+
return;
|
|
338
|
+
void runDealerSearchByCoordinates(dealer.latitude, dealer.longitude);
|
|
339
|
+
}, onClosePopup: closeDealerWidget }) }));
|
|
340
|
+
}
|
|
341
|
+
if (widgetType === 'findDealerDrawer') {
|
|
342
|
+
const drawerLoading = isOpen &&
|
|
343
|
+
(auth === null ||
|
|
344
|
+
isLoading ||
|
|
345
|
+
(isSearching && searchResult == null && mapSearchResult == null));
|
|
346
|
+
return (_jsxs("div", { className: rootClass, children: [_jsx("div", { className: "jwi-flex jwi-items-center jwi-justify-center jwi-py-8", children: renderTrigger() }), isOpen && (_jsx("div", { className: "jwi-fixed jwi-inset-0 jwi-z-[9998] jwi-bg-black/35", onClick: closeDealerWidget })), _jsx("div", { className: "jwi-fixed jwi-right-0 jwi-top-0 jwi-z-[9999] jwi-h-full jwi-w-[min(100vw,1200px)] jwi-bg-white jwi-shadow-[-8px_0_32px_rgba(0,0,0,0.2)]", style: {
|
|
347
|
+
transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
|
|
348
|
+
transition: 'transform 300ms ease-out',
|
|
349
|
+
willChange: 'transform',
|
|
350
|
+
}, "aria-hidden": !isOpen, children: drawerLoading ? (_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-animate-pulse jwi-rounded-[10px] jwi-bg-[#ece8df]" }), _jsx("div", { className: "jwi-h-5 jwi-w-48 jwi-animate-pulse jwi-rounded-full jwi-bg-[#ece8df]" }), _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(FindDealerDrawerWidget, { t: t, buttonStyling: styling?.button, isSearching: isSearching, locationError: locationError, searchResult: searchResult?.ok === false
|
|
351
|
+
? { ...searchResult, error: getSafeWidgetErrorMessage(searchResult.error, t) }
|
|
352
|
+
: searchResult, mapSearchResult: mapSearchResult?.ok === false
|
|
353
|
+
? { ...mapSearchResult, error: getSafeWidgetErrorMessage(mapSearchResult.error, t) }
|
|
354
|
+
: mapSearchResult, inquiryValues: inquiryValues, inquiryError: inquiryError, isInquirySubmitted: isInquirySubmitted, selectedDealerName: selectedDealerName, isManualSearchEnabled: isManualLocationSearchEnabled, query: locationQuery, suggestions: locationSuggestions, suggestionsOpen: isSuggestionListOpen, isSuggestionsLoading: isSearchingSuggestions, onQueryChange: (value) => {
|
|
355
|
+
setLocationQuery(value);
|
|
356
|
+
const trimmed = value.trim();
|
|
357
|
+
setIsSuggestionListOpen(trimmed.length > 0);
|
|
358
|
+
if (trimmed.length < 3) {
|
|
359
|
+
setLocationSuggestions([]);
|
|
360
|
+
}
|
|
361
|
+
}, onQuerySubmit: async (value) => {
|
|
362
|
+
const query = value.trim();
|
|
363
|
+
if (query.length < 3)
|
|
364
|
+
return;
|
|
365
|
+
setIsSearchingSuggestions(true);
|
|
366
|
+
const result = await searchLocationSuggestions(query, dealerSearchOptions);
|
|
367
|
+
const resolvedSuggestions = result.ok && Array.isArray(result.suggestions) ? result.suggestions : [];
|
|
368
|
+
setLocationSuggestions(resolvedSuggestions);
|
|
369
|
+
setIsSearchingSuggestions(false);
|
|
370
|
+
const suggestion = resolvedSuggestions[0];
|
|
371
|
+
if (!suggestion)
|
|
372
|
+
return;
|
|
373
|
+
setLocationQuery(suggestion.label);
|
|
374
|
+
setLocationSuggestions([]);
|
|
375
|
+
setIsSearchingSuggestions(false);
|
|
376
|
+
setIsSuggestionListOpen(false);
|
|
377
|
+
await runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
378
|
+
}, onSuggestionSelect: (suggestion) => {
|
|
379
|
+
setLocationQuery(suggestion.label);
|
|
380
|
+
setLocationSuggestions([]);
|
|
381
|
+
setIsSearchingSuggestions(false);
|
|
382
|
+
setIsSuggestionListOpen(false);
|
|
383
|
+
void runDealerSearchByCoordinates(suggestion.latitude, suggestion.longitude);
|
|
384
|
+
}, onDismissSuggestions: () => {
|
|
385
|
+
setLocationSuggestions([]);
|
|
386
|
+
setIsSearchingSuggestions(false);
|
|
387
|
+
setIsSuggestionListOpen(false);
|
|
388
|
+
}, onInquiryClose: () => {
|
|
389
|
+
setSelectedDealerName(null);
|
|
390
|
+
setInquiryValues(null);
|
|
391
|
+
setInquiryError(null);
|
|
392
|
+
}, onInquirySubmit: () => {
|
|
393
|
+
if (inquiryValues == null)
|
|
394
|
+
return;
|
|
395
|
+
const trimmedName = inquiryValues.name.trim();
|
|
396
|
+
const trimmedEmail = inquiryValues.email.trim();
|
|
397
|
+
const trimmedPhone = inquiryValues.phone.trim();
|
|
398
|
+
if (!trimmedName || !trimmedEmail || !trimmedPhone) {
|
|
399
|
+
setInquiryError(t.formValidationRequired);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (!isValidEmail(trimmedEmail)) {
|
|
403
|
+
setInquiryError(t.formValidationEmail);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
setInquiryError(null);
|
|
407
|
+
setIsInquirySubmitted(true);
|
|
408
|
+
setSelectedDealerName(null);
|
|
409
|
+
setInquiryValues(null);
|
|
410
|
+
}, onInquiryFieldChange: (key, value) => setInquiryValues((current) => current == null ? current : { ...current, [key]: value }), onStartInquiry: (dealerName) => {
|
|
411
|
+
setSelectedDealerName(dealerName);
|
|
412
|
+
setInquiryValues(createInquiryFormValues(productName, dealerName));
|
|
413
|
+
setInquiryError(null);
|
|
414
|
+
setIsInquirySubmitted(false);
|
|
415
|
+
}, onMapDealerSelect: (dealer) => {
|
|
416
|
+
if (isDealerInSearchResult(dealer.dealerName, searchResult, t.unknownDealer))
|
|
417
|
+
return;
|
|
418
|
+
void runDealerSearchByCoordinates(dealer.latitude, dealer.longitude);
|
|
419
|
+
}, onClose: closeDealerWidget })) })] }));
|
|
292
420
|
}
|
|
293
421
|
return _jsx("div", { className: rootClass, children: renderReadyState(widgetType, t) });
|
|
294
422
|
}
|
package/dist/api.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import type { CheckWidgetAuthorizationOptions, DealerSearchResponse, LocationAut
|
|
|
2
2
|
/** Client-side default when JSON parse fails (English; localized in UI). */
|
|
3
3
|
export declare const GENERIC_WIDGET_ERROR = "Dealer finder is currently unavailable. Please try again later.";
|
|
4
4
|
export declare function checkWidgetAuthorization(options?: CheckWidgetAuthorizationOptions): Promise<WidgetAuthClientResponse>;
|
|
5
|
-
export declare function searchDealersByPostalCode(postalCode: string, options?: CheckWidgetAuthorizationOptions): Promise<DealerSearchResponse>;
|
|
6
|
-
export declare function searchDealersByCoordinates(latitude: number, longitude: number, options?: CheckWidgetAuthorizationOptions): Promise<DealerSearchResponse>;
|
|
5
|
+
export declare function searchDealersByPostalCode(postalCode: string, options?: CheckWidgetAuthorizationOptions, scope?: 'list' | 'map'): Promise<DealerSearchResponse>;
|
|
6
|
+
export declare function searchDealersByCoordinates(latitude: number, longitude: number, options?: CheckWidgetAuthorizationOptions, scope?: 'list' | 'map'): Promise<DealerSearchResponse>;
|
|
7
7
|
export declare function searchLocationSuggestions(query: string, options?: CheckWidgetAuthorizationOptions): Promise<LocationAutocompleteResponse>;
|
package/dist/api.js
CHANGED
|
@@ -35,10 +35,11 @@ export async function checkWidgetAuthorization(options) {
|
|
|
35
35
|
return { ok: false, error: GENERIC_WIDGET_ERROR };
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
export async function searchDealersByPostalCode(postalCode, options) {
|
|
38
|
+
export async function searchDealersByPostalCode(postalCode, options, scope = 'list') {
|
|
39
39
|
const endpoint = options?.endpoint ?? '/api/jotul/widget';
|
|
40
40
|
const fetcher = options?.fetcher ?? fetch;
|
|
41
41
|
const params = new URLSearchParams({ postalCode: postalCode.trim() });
|
|
42
|
+
params.set('scope', scope);
|
|
42
43
|
appendLocaleAndMarket(params, options);
|
|
43
44
|
if (Array.isArray(options?.brands)) {
|
|
44
45
|
for (const brand of options.brands) {
|
|
@@ -65,13 +66,14 @@ export async function searchDealersByPostalCode(postalCode, options) {
|
|
|
65
66
|
return { ok: false, error: GENERIC_WIDGET_ERROR };
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
|
-
export async function searchDealersByCoordinates(latitude, longitude, options) {
|
|
69
|
+
export async function searchDealersByCoordinates(latitude, longitude, options, scope = 'list') {
|
|
69
70
|
const endpoint = options?.endpoint ?? '/api/jotul/widget';
|
|
70
71
|
const fetcher = options?.fetcher ?? fetch;
|
|
71
72
|
const params = new URLSearchParams({
|
|
72
73
|
latitude: String(latitude),
|
|
73
74
|
longitude: String(longitude),
|
|
74
75
|
});
|
|
76
|
+
params.set('scope', scope);
|
|
75
77
|
appendLocaleAndMarket(params, options);
|
|
76
78
|
if (Array.isArray(options?.brands)) {
|
|
77
79
|
for (const brand of options.brands) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import 'leaflet/dist/leaflet.css';
|
|
2
|
+
import 'leaflet.markercluster/dist/MarkerCluster.css';
|
|
3
|
+
import type { WidgetStrings } from '../i18n/widgetStrings';
|
|
4
|
+
import type { DealerSearchResponse, InquiryFormValues, JotulWidgetButtonStyling, LocationSuggestion } from '../types';
|
|
5
|
+
type FindDealerDrawerWidgetProps = {
|
|
6
|
+
t: WidgetStrings;
|
|
7
|
+
buttonStyling?: JotulWidgetButtonStyling;
|
|
8
|
+
isSearching: boolean;
|
|
9
|
+
locationError: string | null;
|
|
10
|
+
searchResult: DealerSearchResponse | null;
|
|
11
|
+
mapSearchResult?: DealerSearchResponse | null;
|
|
12
|
+
inquiryValues: InquiryFormValues | null;
|
|
13
|
+
inquiryError: string | null;
|
|
14
|
+
isInquirySubmitted: boolean;
|
|
15
|
+
selectedDealerName: string | null;
|
|
16
|
+
isManualSearchEnabled: boolean;
|
|
17
|
+
query: string;
|
|
18
|
+
suggestions: LocationSuggestion[];
|
|
19
|
+
suggestionsOpen: boolean;
|
|
20
|
+
isSuggestionsLoading: boolean;
|
|
21
|
+
onQueryChange: (value: string) => void;
|
|
22
|
+
onQuerySubmit: (value: string) => void | Promise<void>;
|
|
23
|
+
onSuggestionSelect: (suggestion: LocationSuggestion) => void;
|
|
24
|
+
onDismissSuggestions: () => void;
|
|
25
|
+
onInquiryClose: () => void;
|
|
26
|
+
onInquirySubmit: () => void;
|
|
27
|
+
onInquiryFieldChange: (key: keyof InquiryFormValues, value: string) => void;
|
|
28
|
+
onStartInquiry: (dealerName: string) => void;
|
|
29
|
+
onMapDealerSelect?: (dealer: {
|
|
30
|
+
dealerName: string;
|
|
31
|
+
latitude: number;
|
|
32
|
+
longitude: number;
|
|
33
|
+
}) => void;
|
|
34
|
+
onClose: () => void;
|
|
35
|
+
};
|
|
36
|
+
export declare function FindDealerDrawerWidget({ t, buttonStyling, isSearching, locationError, searchResult, mapSearchResult, inquiryValues, inquiryError, isInquirySubmitted, selectedDealerName, isManualSearchEnabled, query, suggestions, suggestionsOpen, isSuggestionsLoading, onQueryChange, onQuerySubmit, onSuggestionSelect, onDismissSuggestions, onInquiryClose, onInquirySubmit, onInquiryFieldChange, onStartInquiry, onMapDealerSelect, onClose, }: FindDealerDrawerWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export {};
|