ublo-lib 1.38.44 → 1.39.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.
Files changed (53) hide show
  1. package/es/market-place/components/instant-search/google-results.d.ts +9 -0
  2. package/es/market-place/components/instant-search/google-results.d.ts.map +1 -0
  3. package/es/market-place/components/instant-search/google-results.js +24 -0
  4. package/es/market-place/components/instant-search/google-results.module.css +109 -0
  5. package/es/market-place/components/instant-search/hooks/use-constant.d.ts +2 -0
  6. package/es/market-place/components/instant-search/hooks/use-constant.d.ts.map +1 -0
  7. package/es/market-place/components/instant-search/hooks/use-constant.js +8 -0
  8. package/es/market-place/components/instant-search/hooks/use-debounced-search.d.ts +7 -0
  9. package/es/market-place/components/instant-search/hooks/use-debounced-search.d.ts.map +1 -0
  10. package/es/market-place/components/instant-search/hooks/use-debounced-search.js +11 -0
  11. package/es/market-place/components/instant-search/hooks/use-google-search.d.ts +7 -0
  12. package/es/market-place/components/instant-search/hooks/use-google-search.d.ts.map +1 -0
  13. package/es/market-place/components/instant-search/hooks/use-google-search.js +7 -0
  14. package/es/market-place/components/instant-search/hooks/use-search.d.ts +17 -0
  15. package/es/market-place/components/instant-search/hooks/use-search.d.ts.map +1 -0
  16. package/es/market-place/components/instant-search/hooks/use-search.js +10 -0
  17. package/es/market-place/components/instant-search/i18n.json +67 -0
  18. package/es/market-place/components/instant-search/index.d.ts +3 -0
  19. package/es/market-place/components/instant-search/index.d.ts.map +1 -0
  20. package/es/market-place/components/instant-search/index.js +2 -0
  21. package/es/market-place/components/instant-search/instant-search.d.ts +14 -0
  22. package/es/market-place/components/instant-search/instant-search.d.ts.map +1 -0
  23. package/es/market-place/components/instant-search/instant-search.js +66 -0
  24. package/es/market-place/components/instant-search/instant-search.module.css +16 -0
  25. package/es/market-place/components/instant-search/links.d.ts +11 -0
  26. package/es/market-place/components/instant-search/links.d.ts.map +1 -0
  27. package/es/market-place/components/instant-search/links.js +31 -0
  28. package/es/market-place/components/instant-search/links.module.css +97 -0
  29. package/es/market-place/components/instant-search/no-product.d.ts +6 -0
  30. package/es/market-place/components/instant-search/no-product.d.ts.map +1 -0
  31. package/es/market-place/components/instant-search/no-product.js +4 -0
  32. package/es/market-place/components/instant-search/products.d.ts +13 -0
  33. package/es/market-place/components/instant-search/products.d.ts.map +1 -0
  34. package/es/market-place/components/instant-search/products.js +54 -0
  35. package/es/market-place/components/instant-search/products.module.css +169 -0
  36. package/es/market-place/components/instant-search/results.d.ts +20 -0
  37. package/es/market-place/components/instant-search/results.d.ts.map +1 -0
  38. package/es/market-place/components/instant-search/results.js +47 -0
  39. package/es/market-place/components/instant-search/results.module.css +95 -0
  40. package/es/market-place/components/instant-search/search-input.d.ts +15 -0
  41. package/es/market-place/components/instant-search/search-input.d.ts.map +1 -0
  42. package/es/market-place/components/instant-search/search-input.js +56 -0
  43. package/es/market-place/components/instant-search/search-input.module.css +87 -0
  44. package/es/market-place/components/instant-search/services/api.d.ts +17 -0
  45. package/es/market-place/components/instant-search/services/api.d.ts.map +1 -0
  46. package/es/market-place/components/instant-search/services/api.js +24 -0
  47. package/es/market-place/components/instant-search/services/messages.d.ts +2 -0
  48. package/es/market-place/components/instant-search/services/messages.d.ts.map +1 -0
  49. package/es/market-place/components/instant-search/services/messages.js +5 -0
  50. package/es/market-place/components/instant-search/services/utils.d.ts +4 -0
  51. package/es/market-place/components/instant-search/services/utils.d.ts.map +1 -0
  52. package/es/market-place/components/instant-search/services/utils.js +44 -0
  53. package/package.json +1 -1
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import Image from "next/image";
3
+ import Link from "ublo/link";
4
+ import Loader from "dt-design-system/es/loader";
5
+ import Button from "dt-design-system/es/button";
6
+ import * as Icons from "dt-design-system/es/icons";
7
+ import * as Ripple from "dt-design-system/es/ripple";
8
+ import * as Utils from "./services/utils";
9
+ import message from "./services/messages";
10
+ import NoProduct from "./no-product";
11
+ import pagePlaceholder from "./images/page-placeholder.png";
12
+ import lodgingPlaceholder from "./images/lodging-placeholder.png";
13
+ import css from "./products.module.css";
14
+ const PLACEHOLDERS = [...new Array(5)];
15
+ export default function Products({ lang, products, weekNumber, loading, sendPlausibleGoal, otherResultsRef, isOtherResultsEmpty, }) {
16
+ const filteredProducts = Utils.filterProducts(products, weekNumber);
17
+ const noProduct = !loading && !filteredProducts.length;
18
+ const scrollToOtherResults = () => {
19
+ if (otherResultsRef.current) {
20
+ otherResultsRef.current.scrollIntoView({
21
+ behavior: "smooth",
22
+ block: "start",
23
+ });
24
+ }
25
+ };
26
+ const createRipple = (e) => {
27
+ Ripple.create(e);
28
+ };
29
+ return (_jsxs(_Fragment, { children: [noProduct && (_jsxs("div", { className: css.noProduct, children: [_jsx(NoProduct, { className: css.noProductIcon }), message(lang, "noProducts")] })), loading &&
30
+ PLACEHOLDERS.map((_, i) => {
31
+ return (_jsx("div", { className: css.loaderContainer, children: _jsx(Loader, { className: css.loader, variant: "overlay" }) }, i));
32
+ }), !loading &&
33
+ filteredProducts.map((product) => {
34
+ const { id, title, subtitle, parentTitle, image = "", imagePlaceholder, price, time, text, path, target, type, } = product.document;
35
+ const decodedPath = decodeURIComponent(target || path);
36
+ const productTitle = Utils.getHighlight("title", product.highlight) || title;
37
+ const productSubTitle = Utils.getHighlight("subtitle", product.highlight) || subtitle;
38
+ const productTime = Utils.getHighlight("time", product.highlight) || time;
39
+ const productText = Utils.getHighlight("text", product.highlight) || text;
40
+ const showPrice = price !== undefined;
41
+ const imagePlaceholderStategy = imagePlaceholder ? "blur" : "empty";
42
+ const showImage = Boolean(image);
43
+ return (_jsxs(Link, { className: css.product, href: decodedPath, onClick: sendPlausibleGoal(decodedPath), onMouseDown: createRipple, children: [showImage ? (_jsx(Image, { className: css.productImage, src: image, alt: title, width: 220, height: 180, placeholder: imagePlaceholderStategy, blurDataURL: imagePlaceholder })) : (_jsx(Placeholder, { lang: lang, type: type })), _jsxs("div", { className: css.productContent, children: [parentTitle && (_jsx("div", { className: css.productParent, dangerouslySetInnerHTML: { __html: parentTitle } })), _jsx("div", { className: css.productTitle, dangerouslySetInnerHTML: { __html: productTitle } }), _jsx("div", { className: css.productSubtitle, dangerouslySetInnerHTML: { __html: productSubTitle } }), _jsx("div", { className: css.productTime, dangerouslySetInnerHTML: { __html: productTime } }), _jsx("div", { className: css.productText, dangerouslySetInnerHTML: { __html: productText } }), showPrice && (_jsx("div", { className: css.productPrice, dangerouslySetInnerHTML: { __html: price } }))] })] }, id));
44
+ }), !noProduct && !isOtherResultsEmpty && (_jsx("div", { className: css.otherProducts, children: _jsxs(Button, { className: css.otherProductsButton, onClick: scrollToOtherResults, children: [message(lang, "showOtherResults"), _jsx(Icons.ArrowDown, {})] }) }))] }));
45
+ }
46
+ function Placeholder({ type }) {
47
+ const icons = {
48
+ lodging: "Home",
49
+ page: "File",
50
+ };
51
+ const Icon = Icons[icons[type]];
52
+ const image = type === "lodging" ? lodgingPlaceholder : pagePlaceholder;
53
+ return (_jsxs("div", { className: css.placeholder, children: [_jsx(Image, { className: css.productImage, src: image, width: 220, height: 180, alt: "placeholder" }), _jsx(Icon, { className: css.icon })] }));
54
+ }
@@ -0,0 +1,169 @@
1
+ .noProduct {
2
+ grid-column: 1 / -1;
3
+ display: flex;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: 18px;
8
+ color: var(--ds-grey-500, #484848);
9
+ text-align: center;
10
+ font-size: 17px;
11
+ }
12
+
13
+ .noProductIcon {
14
+ flex: 0 0 140px;
15
+ width: 140px;
16
+ height: 140px;
17
+ }
18
+
19
+ .loaderContainer {
20
+ position: relative;
21
+ width: 100%;
22
+ height: 290px;
23
+ border-radius: var(--ds-radius-100, 6px);
24
+ }
25
+
26
+ .loader {
27
+ background: linear-gradient(
28
+ -45deg,
29
+ var(--ds-grey-300, #d4d4d4),
30
+ var(--ds-grey-400, #d2d2d2),
31
+ var(--ds-grey-200, #efefef),
32
+ var(--ds-grey-400, #d2d2d2)
33
+ );
34
+ background-size: 400% 400%;
35
+ background-position: 0% 50%;
36
+ }
37
+
38
+ .product {
39
+ position: relative;
40
+ display: flex;
41
+ flex-direction: column;
42
+ color: var(--ds-grey-500, #484848);
43
+ border-radius: var(--ds-radius-100, 6px);
44
+ background-color: var(--ds-grey-000, #fff);
45
+ }
46
+
47
+ .product mark {
48
+ position: relative;
49
+ display: inline-block;
50
+ font-weight: 700;
51
+ color: var(--ds-primary, var(--ds-blue-500, #002dcc));
52
+ background-color: transparent;
53
+ }
54
+
55
+ .product mark::before {
56
+ content: "";
57
+ position: absolute;
58
+ top: 0;
59
+ left: 0;
60
+ width: 100%;
61
+ height: 100%;
62
+ background-color: var(--ds-primary, var(--ds-blue-500, #002dcc));
63
+ border-radius: calc(var(--ds-radius-100, 6px) / 3);
64
+ opacity: 0.15;
65
+ }
66
+
67
+ .placeholder {
68
+ position: relative;
69
+ color: var(--ds-grey-000, #fff);
70
+ }
71
+
72
+ .placeholder,
73
+ .productImage {
74
+ width: 100%;
75
+ height: 180px;
76
+ object-fit: cover;
77
+ border-radius: var(--ds-radius-100, 6px) var(--ds-radius-100, 6px) 0 0;
78
+ }
79
+
80
+ .placeholder::after {
81
+ content: "";
82
+ position: absolute;
83
+ top: 0;
84
+ left: 0;
85
+ height: 100%;
86
+ width: 100%;
87
+ background-color: var(--ds-primary, var(--ds-blue-500, #002dcc));
88
+ opacity: 0.7;
89
+ pointer-events: none;
90
+ touch-action: none;
91
+ z-index: 1;
92
+ }
93
+
94
+ .icon {
95
+ position: absolute;
96
+ top: 50%;
97
+ left: 50%;
98
+ transform: translate(-50%, -50%);
99
+ width: 33px;
100
+ height: 33px;
101
+ fill: currentColor;
102
+ z-index: 2;
103
+ }
104
+
105
+ .productContent {
106
+ flex: 1 1 auto;
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 6px;
110
+ padding: 8px;
111
+ }
112
+
113
+ .productParent {
114
+ text-transform: uppercase;
115
+ font-size: 10px;
116
+ }
117
+
118
+ .productPageTitle {
119
+ font-weight: 700;
120
+ font-size: 14px;
121
+ line-height: 1;
122
+ }
123
+
124
+ .productTitle {
125
+ font-weight: 700;
126
+ font-size: 16px;
127
+ line-height: 1;
128
+ }
129
+
130
+ .productSubtitle {
131
+ font-size: 14px;
132
+ line-height: 1;
133
+ }
134
+
135
+ .productText {
136
+ font-size: 11px;
137
+ }
138
+
139
+ .productPrice {
140
+ position: absolute;
141
+ top: 6px;
142
+ left: 6px;
143
+ padding: 4px;
144
+ color: var(--ds-grey-100, #f5f5f5);
145
+ background-color: var(--ds-secondary, var(--ds-blue-400, #4177f6));
146
+ font-weight: 700;
147
+ font-size: 12px;
148
+ border-radius: var(--ds-radius-100, 6px);
149
+ }
150
+
151
+ .productTime {
152
+ font-size: 8px;
153
+ text-transform: uppercase;
154
+ font-weight: 700;
155
+ }
156
+
157
+ .otherProducts {
158
+ grid-column: 1 / -1;
159
+ position: sticky;
160
+ bottom: 16px;
161
+ display: flex;
162
+ justify-content: center;
163
+ }
164
+
165
+ @media (min-width: 730px) {
166
+ .otherProducts {
167
+ display: none;
168
+ }
169
+ }
@@ -0,0 +1,20 @@
1
+ type Props = {
2
+ lang: string;
3
+ text: string;
4
+ results: {
5
+ facet_counts?: any[];
6
+ found?: number;
7
+ grouped_hits?: GroupedHit[];
8
+ out_of?: number;
9
+ page?: number;
10
+ request_params?: RequestParams;
11
+ search_cutoff?: boolean;
12
+ search_time_ms?: number;
13
+ };
14
+ weekNumber: number | null;
15
+ sendPlausibleGoal: (path: string) => void;
16
+ loading: boolean;
17
+ };
18
+ export default function Results({ lang, text, results, weekNumber, loading, sendPlausibleGoal, }: Props): import("react/jsx-runtime").JSX.Element;
19
+ export {};
20
+ //# sourceMappingURL=results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../../src/market-place/components/instant-search/results.tsx"],"names":[],"mappings":"AAQA,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QACP,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,cAAc,CAAC,EAAE,aAAa,CAAC;QAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAC9B,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,UAAU,EACV,OAAO,EACP,iBAAiB,GAClB,EAAE,KAAK,2CA0GP"}
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import Links from "./links";
4
+ import OTLinks from "./google-results";
5
+ import Products from "./products";
6
+ import useGoogleSearch from "./hooks/use-google-search";
7
+ import message from "./services/messages";
8
+ import css from "./results.module.css";
9
+ export default function Results({ lang, text, results, weekNumber, loading, sendPlausibleGoal, }) {
10
+ const ref = React.useRef(null);
11
+ const { setText: setGoogleText, search: googleSearch } = useGoogleSearch(lang);
12
+ const { grouped_hits: groupedHits = [] } = results || {};
13
+ const flattenedHits = groupedHits.reduce((acc, group) => {
14
+ return [...acc, ...group.hits];
15
+ }, []);
16
+ const sortedHits = flattenedHits.reduce((acc, hit) => {
17
+ const { type } = hit.document;
18
+ return { ...acc, [type]: [...acc[type], hit] };
19
+ }, { page: [], product: [], information: [], faq: [], lodging: [] });
20
+ React.useEffect(() => {
21
+ const runEffect = () => {
22
+ if (sortedHits.product.length < 4) {
23
+ setGoogleText(text);
24
+ }
25
+ else {
26
+ setGoogleText("");
27
+ }
28
+ };
29
+ runEffect();
30
+ }, [text, sortedHits, setGoogleText]);
31
+ const { page: pages, product: products, information, faq: faqs, lodging: lodgings, } = sortedHits;
32
+ const filteredFaqs = faqs.reduce((acc, faq) => {
33
+ const isAlreadyInAcc = acc.some((item) => {
34
+ const hasSameTitle = item.document.title === faq.document.title;
35
+ const hasSameParentTitle = item.document.parentTitle === faq.document.parentTitle;
36
+ return hasSameTitle && hasSameParentTitle;
37
+ });
38
+ if (isAlreadyInAcc)
39
+ return acc;
40
+ return [...acc, faq];
41
+ }, []);
42
+ const isOtherResultsEmpty = !(pages.length ||
43
+ filteredFaqs.length ||
44
+ information.length);
45
+ const allProducts = [...products, ...pages, ...lodgings];
46
+ return (_jsx("div", { className: css.results, children: (loading || text.length > 0) && (_jsxs("div", { className: css.inner, children: [_jsxs("div", { ref: ref, className: css.left, children: [_jsx(Links, { linksTitle: message(lang, "faqs"), icon: "Question", links: filteredFaqs, loading: loading, sendPlausibleGoal: sendPlausibleGoal }), _jsx(OTLinks, { links: googleSearch.result, loading: googleSearch.loading, sendPlausibleGoal: sendPlausibleGoal }), _jsx(Links, { linksTitle: message(lang, "information"), icon: "Info", links: information, loading: loading, sendPlausibleGoal: sendPlausibleGoal, pageTitleAsTitle: true })] }), _jsx("div", { className: css.right, children: _jsx(Products, { lang: lang, products: allProducts, weekNumber: weekNumber, loading: loading, sendPlausibleGoal: sendPlausibleGoal, otherResultsRef: ref, isOtherResultsEmpty: isOtherResultsEmpty }) })] })) }));
47
+ }
@@ -0,0 +1,95 @@
1
+ .results {
2
+ width: calc(100% - 20px);
3
+ height: 600px;
4
+ max-height: 70vh;
5
+ display: flex;
6
+ flex-direction: column;
7
+ margin: 0 10px 10px 10px;
8
+ padding: 10px;
9
+ }
10
+
11
+ .results:not(:empty) {
12
+ padding: 0;
13
+ background-color: var(--ds-grey-000, #fff);
14
+ border-radius: var(--ds-radius-100, 6px);
15
+ box-shadow: var(--ds-shadow-200, 0 5px 10px rgba(0, 0, 0, 0.12));
16
+ }
17
+
18
+ .inner {
19
+ width: 100%;
20
+ height: 100%;
21
+ display: flex;
22
+ flex-direction: column;
23
+ border-radius: var(--ds-radius-100, 6px);
24
+ overflow: auto;
25
+ overscroll-behavior: contain;
26
+ -webkit-overflow-scrolling: touch;
27
+ }
28
+
29
+ @media (min-width: 730px) {
30
+ .inner {
31
+ flex-direction: row;
32
+ overflow: visible;
33
+ }
34
+ }
35
+
36
+ .left {
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: 10px;
40
+ padding: 16px;
41
+ order: 1;
42
+ }
43
+
44
+ .left:empty {
45
+ display: none;
46
+ }
47
+
48
+ @media (min-width: 730px) {
49
+ .left {
50
+ flex: 0 0 330px;
51
+ order: 0;
52
+ overflow: auto;
53
+ overscroll-behavior: contain;
54
+ -webkit-overflow-scrolling: touch;
55
+ }
56
+ }
57
+
58
+ .right {
59
+ position: relative;
60
+ flex: 1 1 auto;
61
+ display: grid;
62
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
63
+ align-content: flex-start;
64
+ background-color: var(--ds-grey-100, #f5f5f5);
65
+ border-radius: var(--ds-radius-100, 6px) var(--ds-radius-100, 6px) 0 0;
66
+ gap: 16px;
67
+ padding: 16px;
68
+ }
69
+
70
+ @media (min-width: 730px) {
71
+ .right {
72
+ border-radius: 0 var(--ds-radius-100, 6px) var(--ds-radius-100, 6px) 0;
73
+ overflow: auto;
74
+ overscroll-behavior: contain;
75
+ -webkit-overflow-scrolling: touch;
76
+ }
77
+ }
78
+
79
+ .resultsWithWeekTitle,
80
+ .resultsWithoutWeekTitle {
81
+ --ds-button-text-transform: none;
82
+
83
+ grid-column: 1 / -1;
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ flex-wrap: wrap;
88
+ gap: 10px;
89
+ padding: 12px 8px;
90
+ text-align: center;
91
+ font-size: 15px;
92
+ background-color: var(--ds-grey-000, #fff);
93
+ border-radius: var(--ds-radius-100, 6px);
94
+ z-index: 1;
95
+ }
@@ -0,0 +1,15 @@
1
+ type Suggestions = {
2
+ fr?: string[];
3
+ en?: string[];
4
+ };
5
+ type Props = {
6
+ lang: string;
7
+ text: string;
8
+ setText: (value: string) => void;
9
+ loading: boolean;
10
+ closeSearch: () => void;
11
+ suggestions?: Suggestions;
12
+ };
13
+ export default function SearchInput({ lang, text, setText, closeSearch, loading, suggestions, }: Props): import("react/jsx-runtime").JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=search-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-input.d.ts","sourceRoot":"","sources":["../../../../src/market-place/components/instant-search/search-input.tsx"],"names":[],"mappings":"AASA,KAAK,WAAW,GAAG;IACjB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;CACf,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAIF,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,WAAW,EACX,OAAO,EACP,WAAW,GACZ,EAAE,KAAK,2CAkFP"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import classNames from "classnames";
4
+ import Input from "dt-design-system/es/input";
5
+ import Button from "dt-design-system/es/button";
6
+ import * as Icons from "dt-design-system/es/icons";
7
+ import * as Ripple from "dt-design-system/es/ripple";
8
+ import message from "./services/messages";
9
+ import css from "./search-input.module.css";
10
+ const TRANSITION_DURATION = 1800;
11
+ export default function SearchInput({ lang, text, setText, closeSearch, loading, suggestions, }) {
12
+ const [currentSuggestion, setCurrentSuggestion] = React.useState(0);
13
+ const updateText = (value) => () => {
14
+ setText(value);
15
+ };
16
+ const classes = classNames(css.input, {
17
+ [css.inputLoading]: loading,
18
+ });
19
+ const inputIcon = loading ? "Loader2" : "Search";
20
+ const suggestionsSet = getSuggestions(suggestions)[lang];
21
+ const enableSuggestion = Boolean(suggestionsSet);
22
+ const createRipple = (e) => {
23
+ Ripple.create(e);
24
+ };
25
+ React.useEffect(() => {
26
+ if (enableSuggestion && !text) {
27
+ const interval = setInterval(() => {
28
+ setCurrentSuggestion((current) => {
29
+ const nextSuggestion = current >= suggestionsSet.length - 1 ? 0 : current + 1;
30
+ return nextSuggestion;
31
+ });
32
+ }, TRANSITION_DURATION);
33
+ return () => {
34
+ clearInterval(interval);
35
+ };
36
+ }
37
+ }, [enableSuggestion, suggestionsSet, text]);
38
+ return (_jsxs("div", { className: css.container, children: [_jsx(Input, { value: text, onValueChange: setText, icon: inputIcon, className: classes }), enableSuggestion && !text && (_jsxs("div", { className: css.suggestion, children: [message(lang, "try"), _jsx("div", { className: css.buttons, children: suggestionsSet.map((suggestion, i) => {
39
+ const isCurrent = i === currentSuggestion;
40
+ const isPrev = currentSuggestion === 0
41
+ ? i === suggestionsSet.length - 1
42
+ : i === currentSuggestion - 1;
43
+ const classes = classNames(css.button, {
44
+ [css.buttonCurrent]: isCurrent,
45
+ [css.buttonPrev]: isPrev,
46
+ });
47
+ return (_jsxs("button", { className: classes, onClick: updateText(suggestion), onMouseDown: createRipple, children: ["\u00AB ", suggestion, " \u00BB"] }, suggestion));
48
+ }) })] })), _jsx(Button, { variant: "transparent", className: css.close, onClick: () => closeSearch(), children: _jsx(Icons.Cross, {}) })] }));
49
+ }
50
+ function getSuggestions(suggestions = {}) {
51
+ return {
52
+ fr: ["cours de ski", "cours privés", "compétition", "cours débutants"],
53
+ en: ["ski lessons", "private lessons", "competition"],
54
+ ...suggestions,
55
+ };
56
+ }
@@ -0,0 +1,87 @@
1
+ .container {
2
+ position: relative;
3
+ padding: 10px;
4
+ }
5
+
6
+ .input {
7
+ --ds-input-padding: 14px;
8
+ --ds-input-background: var(--ds-grey-000, #fff);
9
+
10
+ width: 100%;
11
+ border-radius: var(--ds-radius-200, 10px);
12
+ box-shadow: var(--ds-shadow-200, 0 5px 10px rgba(0, 0, 0, 0.12));
13
+ }
14
+
15
+ .inputLoading svg {
16
+ animation: search-loader-spinning 1280ms
17
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9)) infinite;
18
+ }
19
+
20
+ @keyframes search-loader-spinning {
21
+ 100% {
22
+ transform: rotate(1turn);
23
+ }
24
+ }
25
+
26
+ .suggestion {
27
+ position: absolute;
28
+ top: 50%;
29
+ left: 54px;
30
+ height: 21px;
31
+ display: flex;
32
+ align-items: center;
33
+ line-height: 1;
34
+ color: var(--ds-grey-600, #484848);
35
+ transform: translateY(-50%);
36
+ pointer-events: none;
37
+ }
38
+
39
+ .buttons {
40
+ position: relative;
41
+ height: inherit;
42
+ color: inherit;
43
+ }
44
+
45
+ .button {
46
+ position: absolute;
47
+ top: 0;
48
+ left: 0;
49
+ width: max-content;
50
+ height: 100%;
51
+ padding: 2px 5px 4px 5px;
52
+ color: inherit;
53
+ line-height: 1;
54
+ font-weight: 700;
55
+ cursor: pointer;
56
+ pointer-events: auto;
57
+ border-radius: var(--ds-radius-100, 6px);
58
+ transform: translateY(100%);
59
+ opacity: 0;
60
+ pointer-events: none;
61
+ transition: background-color 160ms
62
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9)),
63
+ opacity 320ms var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9)),
64
+ transform 320ms
65
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9));
66
+ }
67
+
68
+ .buttonPrev {
69
+ transform: translateY(-100%);
70
+ }
71
+
72
+ .buttonCurrent {
73
+ opacity: 1;
74
+ transform: none;
75
+ pointer-events: auto;
76
+ }
77
+
78
+ .button:is(:hover, :focus) {
79
+ background-color: var(--ds-grey-100, #f5f5f5);
80
+ }
81
+
82
+ button.close {
83
+ position: absolute;
84
+ top: 17px;
85
+ right: 14px;
86
+ color: inherit;
87
+ }
@@ -0,0 +1,17 @@
1
+ export declare function fetchResults(site: string, lang: string, query: string, groupLimit?: number, queryBy?: string, queryByWeights?: string, semantic?: boolean): Promise<any>;
2
+ export type GoogleSearchResult = {
3
+ htmlTitle: string;
4
+ link: string;
5
+ displayLink: string;
6
+ htmlSnippet: string;
7
+ pagemap?: {
8
+ cse_image: {
9
+ src: string;
10
+ }[];
11
+ cse_thumbnail: {
12
+ src: string;
13
+ }[];
14
+ };
15
+ };
16
+ export declare function fetchOTResults(query: string, lang: string): Promise<GoogleSearchResult[]>;
17
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../src/market-place/components/instant-search/services/api.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,OAAO,GAAE,MAAgE,EACzE,cAAc,CAAC,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,OAAO,gBAmBnB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE;QACR,SAAS,EAAE;YACT,GAAG,EAAE,MAAM,CAAC;SACb,EAAE,CAAC;QACJ,aAAa,EAAE;YACb,GAAG,EAAE,MAAM,CAAC;SACb,EAAE,CAAC;KACL,CAAC;CACH,CAAC;AAEF,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iCAM/D"}
@@ -0,0 +1,24 @@
1
+ import getConfig from "next/config";
2
+ import * as Fetcher from "../../../../future/utils/fetcher";
3
+ const { publicRuntimeConfig } = getConfig();
4
+ const { searchApi: api, googleSites } = publicRuntimeConfig;
5
+ export function fetchResults(site, lang, query, groupLimit = 8, queryBy = "title,text,pageTitle,seoKeywords,parentTitle,seoTitle", queryByWeights, semantic) {
6
+ const endpoint = `${api}/ublo-search/search/market-place${semantic ? "/semantic" : ""}`;
7
+ return Fetcher.post(endpoint, {
8
+ q: query,
9
+ query_by: queryBy + (semantic ? ",embedding" : ""),
10
+ query_by_weights: semantic ? undefined : queryByWeights,
11
+ vector_query: semantic
12
+ ? "embedding:([], distance_threshold:0.50, alpha: 0.8)"
13
+ : undefined,
14
+ group_limit: groupLimit,
15
+ per_page: 30,
16
+ }, { site, lang });
17
+ }
18
+ export async function fetchOTResults(query, lang) {
19
+ const endpoint = `${api}/ublo-search/google-search`;
20
+ return Fetcher.get(endpoint, {
21
+ query,
22
+ siteSearch: googleSites[lang][0],
23
+ });
24
+ }
@@ -0,0 +1,2 @@
1
+ export default function message(lang: string, id: string): any;
2
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../src/market-place/components/instant-search/services/messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAGvD"}
@@ -0,0 +1,5 @@
1
+ import locales from "../i18n.json";
2
+ export default function message(lang, id) {
3
+ const messages = locales[lang] || locales.en;
4
+ return messages[id] || `??${id}??`;
5
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getHighlight(property: string, highlight: PurpleHighlight, withExtractQuotes?: boolean): any;
2
+ export declare function filterProducts(products: Hit[], weekNumber: number | null): Hit[];
3
+ export declare function sliceText(text: string): string;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/market-place/components/instant-search/services/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,eAAe,EAC1B,iBAAiB,GAAE,OAAe,OAoBnC;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,SAkBxE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,UAGrC"}
@@ -0,0 +1,44 @@
1
+ export function getHighlight(property, highlight, withExtractQuotes = false) {
2
+ if (!highlight[property]?.snippet)
3
+ return;
4
+ let snippet = highlight[property].snippet;
5
+ if (!withExtractQuotes)
6
+ return snippet;
7
+ const startsWithMaj = /[A-Z]/.test(snippet);
8
+ const endsWithDot = snippet[snippet.length - 1] === ".";
9
+ if (!startsWithMaj) {
10
+ snippet = `...${snippet}`;
11
+ }
12
+ if (!endsWithDot) {
13
+ snippet = `${snippet}...`;
14
+ }
15
+ return snippet;
16
+ }
17
+ export function filterProducts(products, weekNumber) {
18
+ if (weekNumber !== null) {
19
+ return products.filter((product) => {
20
+ const { weeks = [] } = product.document;
21
+ return weeks.length === 0 || weeks.includes(weekNumber);
22
+ });
23
+ }
24
+ return products.reduce((acc, product) => {
25
+ const { image, pageTitle } = product.document;
26
+ const isAlreadyInAcc = acc.some((item) => {
27
+ return (normalizeImage(item.document.image) === normalizeImage(image) &&
28
+ item.document.pageTitle === pageTitle);
29
+ });
30
+ if (isAlreadyInAcc)
31
+ return acc;
32
+ return [...acc, product];
33
+ }, []);
34
+ }
35
+ export function sliceText(text) {
36
+ if (!text)
37
+ return;
38
+ return text?.slice(0, 30) + "...";
39
+ }
40
+ function normalizeImage(image) {
41
+ if (!image)
42
+ return "";
43
+ return image.replace(/(-[0-9]+)?.(jpg|jpeg|png|gif)/, "");
44
+ }