willba-component-library 0.3.10 → 0.3.11
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/lib/components/FilterBar/FilterBar.d.ts +1 -2
- package/lib/components/FilterBar/FilterBarTypes.d.ts +3 -13
- package/lib/components/FilterBar/components/dates/Dates.d.ts +1 -0
- package/lib/components/FilterBar/utils/index.d.ts +1 -1
- package/lib/components/FilterBar/utils/parseLocations.d.ts +1 -2
- package/lib/index.d.ts +8 -16
- package/lib/index.esm.js +176 -103
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +424 -351
- package/lib/index.js.map +1 -1
- package/lib/index.umd.js +424 -351
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/FilterBar/FilterBar.css +1 -1
- package/src/components/FilterBar/FilterBar.stories.tsx +14 -49
- package/src/components/FilterBar/FilterBar.tsx +44 -13
- package/src/components/FilterBar/FilterBarTypes.ts +3 -14
- package/src/components/FilterBar/components/cards/image-card/ImageCard.css +0 -1
- package/src/components/FilterBar/components/common/FilterSectionHeader.css +1 -0
- package/src/components/FilterBar/components/dates/Dates.css +3 -0
- package/src/components/FilterBar/components/dates/Dates.tsx +2 -0
- package/src/components/FilterBar/components/guests/Guests.css +1 -1
- package/src/components/FilterBar/components/locations/Locations.css +1 -1
- package/src/components/FilterBar/components/locations/Locations.tsx +15 -35
- package/src/components/FilterBar/utils/calculateDropdownPosition.tsx +106 -0
- package/src/components/FilterBar/utils/index.tsx +1 -1
- package/src/components/FilterBar/utils/parseLocations.tsx +3 -7
- package/src/components/FilterBar/utils/getLocalizedContent.tsx +0 -21
package/package.json
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
flex-direction: column;
|
|
46
46
|
padding: 20px;
|
|
47
47
|
border-radius: 25px;
|
|
48
|
+
overflow: hidden;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -53,7 +54,6 @@
|
|
|
53
54
|
.will-filter-bar-container {
|
|
54
55
|
background-color: var(--will-white);
|
|
55
56
|
min-height: 100px;
|
|
56
|
-
padding: 20px;
|
|
57
57
|
position: absolute;
|
|
58
58
|
top: 125px;
|
|
59
59
|
z-index: 111;
|
|
@@ -59,21 +59,15 @@ export const Main: Story = {
|
|
|
59
59
|
tabs: [
|
|
60
60
|
{
|
|
61
61
|
path: '/rooms',
|
|
62
|
+
label: 'Rooms',
|
|
62
63
|
default: true,
|
|
63
64
|
order: 2,
|
|
64
|
-
label: {
|
|
65
|
-
en: 'Rooms',
|
|
66
|
-
fi: 'Rooms fi',
|
|
67
|
-
},
|
|
68
65
|
},
|
|
69
66
|
{
|
|
70
67
|
path: '/events',
|
|
68
|
+
label: 'Events',
|
|
71
69
|
default: false,
|
|
72
70
|
order: 1,
|
|
73
|
-
label: {
|
|
74
|
-
en: 'Events',
|
|
75
|
-
fi: 'Events fi',
|
|
76
|
-
},
|
|
77
71
|
},
|
|
78
72
|
],
|
|
79
73
|
outerLoading: false,
|
|
@@ -83,61 +77,32 @@ export const Main: Story = {
|
|
|
83
77
|
data: [
|
|
84
78
|
{
|
|
85
79
|
id: 1,
|
|
86
|
-
label:
|
|
87
|
-
|
|
88
|
-
{ content: 'Helsinki Keskusta', locale: 'fi' },
|
|
89
|
-
],
|
|
90
|
-
description: [
|
|
91
|
-
{ content: 'Main training facility in downtown', locale: 'en' },
|
|
92
|
-
{ content: 'Pääkoulutuslaitoksemme keskustassa', locale: 'fi' },
|
|
93
|
-
],
|
|
80
|
+
label: 'Helsinki Center',
|
|
81
|
+
description: 'Main training facility in downtown',
|
|
94
82
|
imageUrl: '',
|
|
95
83
|
},
|
|
96
84
|
{
|
|
97
85
|
id: 2,
|
|
98
|
-
label:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
],
|
|
102
|
-
description: [
|
|
103
|
-
{ content: 'Modern facilities with sea views', locale: 'en' },
|
|
104
|
-
{ content: 'Modernit tilat merinäköalalla', locale: 'fi' },
|
|
105
|
-
],
|
|
106
|
-
imageUrl: '',
|
|
86
|
+
label: 'Espoo Campus',
|
|
87
|
+
description: 'Modern facilities with sea views',
|
|
88
|
+
imageUrl: null,
|
|
107
89
|
},
|
|
108
90
|
{
|
|
109
91
|
id: 3,
|
|
110
|
-
label:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
],
|
|
114
|
-
description: [
|
|
115
|
-
{ content: 'Lakeside retreat with full amenities', locale: 'en' },
|
|
116
|
-
{ content: 'Järvenrannalla sijaitseva lomakeskus', locale: 'fi' },
|
|
117
|
-
],
|
|
118
|
-
imageUrl: '',
|
|
92
|
+
label: 'Tampere Resort',
|
|
93
|
+
description: 'Lakeside retreat with full amenities',
|
|
94
|
+
imageUrl: null,
|
|
119
95
|
},
|
|
120
96
|
{
|
|
121
97
|
id: 4,
|
|
122
|
-
label:
|
|
123
|
-
|
|
124
|
-
{ content: 'Turun Satama', locale: 'fi' },
|
|
125
|
-
],
|
|
98
|
+
label: 'Turku Harbor',
|
|
99
|
+
description: 'Modern facilities with sea views',
|
|
126
100
|
imageUrl: null,
|
|
127
101
|
},
|
|
128
102
|
{
|
|
129
103
|
id: 5,
|
|
130
|
-
label:
|
|
131
|
-
|
|
132
|
-
{ content: 'Oulun Pohjoinen', locale: 'fi' },
|
|
133
|
-
],
|
|
134
|
-
description: [
|
|
135
|
-
{
|
|
136
|
-
content: 'Northern location with winter activities',
|
|
137
|
-
locale: 'en',
|
|
138
|
-
},
|
|
139
|
-
{ content: 'Pohjoinen kohde talviaktiviteeteilla', locale: 'fi' },
|
|
140
|
-
],
|
|
104
|
+
label: 'Oulu North',
|
|
105
|
+
description: 'Northern location with winter activities',
|
|
141
106
|
imageUrl: null,
|
|
142
107
|
},
|
|
143
108
|
],
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
CSSProperties,
|
|
3
|
+
MutableRefObject,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react'
|
|
2
8
|
import { useTranslation } from 'react-i18next'
|
|
3
9
|
import { FaSearch } from 'react-icons/fa'
|
|
4
10
|
|
|
@@ -12,7 +18,7 @@ import {
|
|
|
12
18
|
import { SubmitButton } from '../../core/components'
|
|
13
19
|
import { parseDates } from '../../core/components/calendar/utils'
|
|
14
20
|
|
|
15
|
-
import { parseGuests, parseLocations } from './utils'
|
|
21
|
+
import { parseGuests, parseLocations, calculateDropdownPosition } from './utils'
|
|
16
22
|
import { FilterBarTypes, FilterSections, Pages } from './FilterBarTypes'
|
|
17
23
|
import { useFilterBar, useScrollInToView } from './hooks'
|
|
18
24
|
import {
|
|
@@ -51,6 +57,10 @@ export default function FilterBar({
|
|
|
51
57
|
const datesButtonRef = useRef<HTMLButtonElement>(null)
|
|
52
58
|
const guestsButtonRef = useRef<HTMLButtonElement>(null)
|
|
53
59
|
const previouslyFocusedButtonRef = useRef<HTMLButtonElement | null>(null)
|
|
60
|
+
const headerRef = useRef<HTMLDivElement>(null)
|
|
61
|
+
|
|
62
|
+
// Dropdown positioning
|
|
63
|
+
const [dropdownStyle, setDropdownStyle] = useState<CSSProperties>({})
|
|
54
64
|
|
|
55
65
|
// Filters
|
|
56
66
|
const {
|
|
@@ -83,6 +93,22 @@ export default function FilterBar({
|
|
|
83
93
|
// Handle close filter section
|
|
84
94
|
const { filtersRef } = useCloseFilterSection({ handleSelectedFilter })
|
|
85
95
|
|
|
96
|
+
// Enhanced handleSelectedFilter with positioning
|
|
97
|
+
const handleSelectedFilterWithPosition = (filter: FilterSections | false) => {
|
|
98
|
+
if (filter) {
|
|
99
|
+
const position = calculateDropdownPosition({
|
|
100
|
+
filterSection: filter,
|
|
101
|
+
headerRef,
|
|
102
|
+
locationsButtonRef,
|
|
103
|
+
datesButtonRef,
|
|
104
|
+
guestsButtonRef,
|
|
105
|
+
isMobile,
|
|
106
|
+
})
|
|
107
|
+
setDropdownStyle(position)
|
|
108
|
+
}
|
|
109
|
+
handleSelectedFilter(filter)
|
|
110
|
+
}
|
|
111
|
+
|
|
86
112
|
// Store previously focused button and restore focus when closing
|
|
87
113
|
useEffect(() => {
|
|
88
114
|
if (!selectedFilter && previouslyFocusedButtonRef.current) {
|
|
@@ -105,7 +131,6 @@ export default function FilterBar({
|
|
|
105
131
|
})
|
|
106
132
|
const parsedLocations = parseLocations({
|
|
107
133
|
selectedLocations,
|
|
108
|
-
language,
|
|
109
134
|
locationsPlaceholder: t('locations.placeholder'),
|
|
110
135
|
locationsSelectedLabel: t('locations.selected'),
|
|
111
136
|
})
|
|
@@ -122,11 +147,7 @@ export default function FilterBar({
|
|
|
122
147
|
.map((tab, idx) => (
|
|
123
148
|
<TabButton
|
|
124
149
|
key={`tab-${idx}`}
|
|
125
|
-
label={
|
|
126
|
-
tab.label && language
|
|
127
|
-
? tab.label[language]
|
|
128
|
-
: t(`tabs.${tab.path.substring(1)}`)
|
|
129
|
-
}
|
|
150
|
+
label={tab.label || t(`tabs.${tab.path.substring(1)}`)}
|
|
130
151
|
onClick={() => {
|
|
131
152
|
setSelectedPath(tab.path)
|
|
132
153
|
handleResetFilters()
|
|
@@ -141,7 +162,14 @@ export default function FilterBar({
|
|
|
141
162
|
|
|
142
163
|
<div
|
|
143
164
|
className={`will-filter-bar-header ${mode || 'light'}`}
|
|
144
|
-
ref={
|
|
165
|
+
ref={(el) => {
|
|
166
|
+
;(headerRef as MutableRefObject<HTMLDivElement | null>).current = el
|
|
167
|
+
if (tabs?.length === 1 && targetFilterBarRef) {
|
|
168
|
+
;(
|
|
169
|
+
targetFilterBarRef as MutableRefObject<HTMLDivElement | null>
|
|
170
|
+
).current = el
|
|
171
|
+
}
|
|
172
|
+
}}
|
|
145
173
|
>
|
|
146
174
|
{!!locations?.data?.length && (
|
|
147
175
|
<>
|
|
@@ -151,7 +179,7 @@ export default function FilterBar({
|
|
|
151
179
|
description={parsedLocations}
|
|
152
180
|
onClick={() => {
|
|
153
181
|
previouslyFocusedButtonRef.current = locationsButtonRef.current
|
|
154
|
-
|
|
182
|
+
handleSelectedFilterWithPosition(FilterSections.LOCATIONS)
|
|
155
183
|
}}
|
|
156
184
|
active={!!selectedLocations.length}
|
|
157
185
|
disabled={locations?.disabled}
|
|
@@ -175,7 +203,7 @@ export default function FilterBar({
|
|
|
175
203
|
}
|
|
176
204
|
onClick={() => {
|
|
177
205
|
previouslyFocusedButtonRef.current = datesButtonRef.current
|
|
178
|
-
|
|
206
|
+
handleSelectedFilterWithPosition(FilterSections.CALENDAR)
|
|
179
207
|
}}
|
|
180
208
|
active={!!parsedDates}
|
|
181
209
|
ariaExpanded={selectedFilter === FilterSections.CALENDAR}
|
|
@@ -192,7 +220,7 @@ export default function FilterBar({
|
|
|
192
220
|
description={parsedGuests.content}
|
|
193
221
|
onClick={() => {
|
|
194
222
|
previouslyFocusedButtonRef.current = guestsButtonRef.current
|
|
195
|
-
|
|
223
|
+
handleSelectedFilterWithPosition(FilterSections.GUESTS)
|
|
196
224
|
}}
|
|
197
225
|
active={!!parsedGuests.data.total}
|
|
198
226
|
ariaExpanded={selectedFilter === FilterSections.GUESTS}
|
|
@@ -212,7 +240,10 @@ export default function FilterBar({
|
|
|
212
240
|
{selectedFilter && (
|
|
213
241
|
<div
|
|
214
242
|
className={`will-filter-bar-container ${mode || 'light'}`}
|
|
215
|
-
style={
|
|
243
|
+
style={{
|
|
244
|
+
...((!tabs || tabs.length < 2) && !isMobile ? { top: 66 } : {}),
|
|
245
|
+
...dropdownStyle,
|
|
246
|
+
}}
|
|
216
247
|
>
|
|
217
248
|
{selectedFilter === FilterSections.CALENDAR && (
|
|
218
249
|
<div id="will-dates-filter">
|
|
@@ -50,22 +50,11 @@ export enum Pages {
|
|
|
50
50
|
SALES = '/sales',
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
type Translations = {
|
|
54
|
-
en: string
|
|
55
|
-
fi: string
|
|
56
|
-
[key: string]: string
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export type LocaleTranslation = Array<{
|
|
60
|
-
content: string
|
|
61
|
-
locale: string
|
|
62
|
-
}>
|
|
63
|
-
|
|
64
53
|
export type Tab = {
|
|
65
54
|
path: string
|
|
66
55
|
default?: boolean
|
|
67
56
|
order: number
|
|
68
|
-
label?:
|
|
57
|
+
label?: string
|
|
69
58
|
}
|
|
70
59
|
|
|
71
60
|
export type Locations = {
|
|
@@ -76,7 +65,7 @@ export type Locations = {
|
|
|
76
65
|
|
|
77
66
|
export type Location = {
|
|
78
67
|
id: number
|
|
79
|
-
label:
|
|
80
|
-
description?:
|
|
68
|
+
label: string
|
|
69
|
+
description?: string
|
|
81
70
|
imageUrl?: string | null
|
|
82
71
|
}
|
|
@@ -6,7 +6,6 @@ import { ImageCard } from '../cards/image-card/ImageCard'
|
|
|
6
6
|
import { Location } from '../../FilterBarTypes'
|
|
7
7
|
import { FilterSectionHeader } from '../common/FilterSectionHeader'
|
|
8
8
|
import { CloseButton } from '../../../../core/components'
|
|
9
|
-
import { getLocalizedContent } from '../../utils'
|
|
10
9
|
|
|
11
10
|
type Props = {
|
|
12
11
|
locations?: Location[]
|
|
@@ -72,40 +71,21 @@ export const Locations = forwardRef<HTMLDivElement, Props>(
|
|
|
72
71
|
|
|
73
72
|
<div className="will-locations-filter-container">
|
|
74
73
|
{!!(locations?.length && language) &&
|
|
75
|
-
locations
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
contents: location.description,
|
|
91
|
-
locale: language,
|
|
92
|
-
})
|
|
93
|
-
: null
|
|
94
|
-
|
|
95
|
-
return (
|
|
96
|
-
<ImageCard
|
|
97
|
-
key={location.id}
|
|
98
|
-
ref={index === 0 ? firstCardRef : null}
|
|
99
|
-
title={label}
|
|
100
|
-
description={description}
|
|
101
|
-
imageUrl={location.imageUrl}
|
|
102
|
-
isSelected={selectedLocations.some(
|
|
103
|
-
(loc) => loc.id === location.id
|
|
104
|
-
)}
|
|
105
|
-
onClick={() => handleLocationClick(location)}
|
|
106
|
-
/>
|
|
107
|
-
)
|
|
108
|
-
})}
|
|
74
|
+
locations.map((location, index) => {
|
|
75
|
+
return (
|
|
76
|
+
<ImageCard
|
|
77
|
+
key={location.id}
|
|
78
|
+
ref={index === 0 ? firstCardRef : null}
|
|
79
|
+
title={location.label}
|
|
80
|
+
description={location.description}
|
|
81
|
+
imageUrl={location.imageUrl}
|
|
82
|
+
isSelected={selectedLocations.some(
|
|
83
|
+
(loc) => loc.id === location.id
|
|
84
|
+
)}
|
|
85
|
+
onClick={() => handleLocationClick(location)}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
88
|
+
})}
|
|
109
89
|
</div>
|
|
110
90
|
</div>
|
|
111
91
|
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { CSSProperties, RefObject } from 'react'
|
|
2
|
+
import { FilterSections } from '../FilterBarTypes'
|
|
3
|
+
|
|
4
|
+
type CalculateDropdownPositionParams = {
|
|
5
|
+
filterSection: FilterSections
|
|
6
|
+
headerRef: RefObject<HTMLDivElement>
|
|
7
|
+
locationsButtonRef: RefObject<HTMLButtonElement>
|
|
8
|
+
datesButtonRef: RefObject<HTMLButtonElement>
|
|
9
|
+
guestsButtonRef: RefObject<HTMLButtonElement>
|
|
10
|
+
isMobile: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const calculateDropdownPosition = ({
|
|
14
|
+
filterSection,
|
|
15
|
+
headerRef,
|
|
16
|
+
locationsButtonRef,
|
|
17
|
+
datesButtonRef,
|
|
18
|
+
guestsButtonRef,
|
|
19
|
+
isMobile,
|
|
20
|
+
}: CalculateDropdownPositionParams): CSSProperties => {
|
|
21
|
+
// On mobile, don't apply any positioning - let CSS handle it naturally
|
|
22
|
+
// Dropdowns will start from leftmost point with position: relative
|
|
23
|
+
if (isMobile) {
|
|
24
|
+
return {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!headerRef.current) return {}
|
|
28
|
+
|
|
29
|
+
const containerRect = headerRef.current.getBoundingClientRect()
|
|
30
|
+
const containerLeft = 0
|
|
31
|
+
|
|
32
|
+
switch (filterSection) {
|
|
33
|
+
case FilterSections.LOCATIONS:
|
|
34
|
+
// Locations: Start from beginning, hug content
|
|
35
|
+
if (locationsButtonRef.current) {
|
|
36
|
+
const buttonRect = locationsButtonRef.current.getBoundingClientRect()
|
|
37
|
+
const relativeLeft = buttonRect.left - containerRect.left
|
|
38
|
+
return {
|
|
39
|
+
left: relativeLeft,
|
|
40
|
+
right: 'auto',
|
|
41
|
+
width: 'auto',
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
case FilterSections.CALENDAR:
|
|
47
|
+
// Calendar: Two months side-by-side, needs ~650-700px
|
|
48
|
+
// Start from dates button, but push left if not enough space
|
|
49
|
+
if (datesButtonRef.current) {
|
|
50
|
+
const buttonRect = datesButtonRef.current.getBoundingClientRect()
|
|
51
|
+
const relativeLeft = buttonRect.left - containerRect.left
|
|
52
|
+
const availableWidth = containerRect.width - relativeLeft
|
|
53
|
+
const calendarMinWidth = 650
|
|
54
|
+
|
|
55
|
+
if (availableWidth < calendarMinWidth) {
|
|
56
|
+
// Not enough space, align to the right edge
|
|
57
|
+
return {
|
|
58
|
+
left: 'auto',
|
|
59
|
+
right: containerLeft,
|
|
60
|
+
width: 'auto',
|
|
61
|
+
maxWidth: `${containerRect.width}px`,
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
// Enough space, start from dates button
|
|
65
|
+
return {
|
|
66
|
+
left: relativeLeft,
|
|
67
|
+
right: 'auto',
|
|
68
|
+
width: 'auto',
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
case FilterSections.GUESTS:
|
|
75
|
+
// Guests: Start from guests button, push left if not enough space
|
|
76
|
+
if (guestsButtonRef.current) {
|
|
77
|
+
const buttonRect = guestsButtonRef.current.getBoundingClientRect()
|
|
78
|
+
const relativeLeft = buttonRect.left - containerRect.left
|
|
79
|
+
const availableWidth = containerRect.width - relativeLeft
|
|
80
|
+
const dropdownMinWidth = 350
|
|
81
|
+
|
|
82
|
+
if (availableWidth < dropdownMinWidth) {
|
|
83
|
+
// Not enough space, align to the right
|
|
84
|
+
return {
|
|
85
|
+
left: 'auto',
|
|
86
|
+
right: containerLeft,
|
|
87
|
+
width: 'auto',
|
|
88
|
+
maxWidth: `${containerRect.width}px`,
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
// Enough space, start from button
|
|
92
|
+
return {
|
|
93
|
+
left: relativeLeft,
|
|
94
|
+
right: 'auto',
|
|
95
|
+
width: 'auto',
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
default:
|
|
102
|
+
return {}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {}
|
|
106
|
+
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { Location } from '../FilterBarTypes'
|
|
2
|
-
import { getLocalizedContent } from './getLocalizedContent'
|
|
3
2
|
|
|
4
3
|
type Props = {
|
|
5
4
|
selectedLocations: Location[]
|
|
6
|
-
language: string
|
|
7
5
|
locationsPlaceholder: string
|
|
8
6
|
locationsSelectedLabel?: string
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
export const parseLocations = ({
|
|
12
10
|
selectedLocations,
|
|
13
|
-
|
|
11
|
+
|
|
14
12
|
locationsPlaceholder,
|
|
15
13
|
locationsSelectedLabel = 'locations',
|
|
16
14
|
}: Props) => {
|
|
@@ -19,10 +17,8 @@ export const parseLocations = ({
|
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
if (selectedLocations.length === 1) {
|
|
22
|
-
const translation =
|
|
23
|
-
|
|
24
|
-
locale: language,
|
|
25
|
-
})
|
|
20
|
+
const translation = selectedLocations[0].label
|
|
21
|
+
|
|
26
22
|
if (!translation) {
|
|
27
23
|
return locationsPlaceholder
|
|
28
24
|
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { LocaleTranslation } from '../FilterBarTypes'
|
|
2
|
-
|
|
3
|
-
type Props = {
|
|
4
|
-
contents: LocaleTranslation
|
|
5
|
-
locale: string
|
|
6
|
-
fallbackLocale?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const getLocalizedContent = ({
|
|
10
|
-
contents,
|
|
11
|
-
locale,
|
|
12
|
-
fallbackLocale = 'en',
|
|
13
|
-
}: Props): string | undefined => {
|
|
14
|
-
const preferred = contents.find((content) => content.locale === locale)
|
|
15
|
-
if (preferred) return preferred.content
|
|
16
|
-
|
|
17
|
-
const fallback = contents.find((content) => content.locale === fallbackLocale)
|
|
18
|
-
if (fallback) return fallback.content
|
|
19
|
-
|
|
20
|
-
return contents[0]?.content
|
|
21
|
-
}
|