@faststore/core 4.9.0-dev.2 → 4.9.0-dev.4
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/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +130 -125
- package/CHANGELOG.md +10 -0
- package/cms/faststore/my-account/components/cms_component__accountlistquotes.jsonc +240 -0
- package/cms/faststore/my-account/components/cms_component__accountnavigation.jsonc +76 -0
- package/cms/faststore/my-account/pages/cms_content_type__myaccountquotes.jsonc +18 -0
- package/package.json +6 -6
- package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/ContractSwitcher.tsx +129 -26
- package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerHeader.tsx +7 -1
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotes.tsx +42 -11
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotesTable/MyAccountListQuotesTable.tsx +45 -15
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotesTable/MyAccountQuoteStatusBadge.tsx +11 -3
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesFilterSlider/MyAccountQuotesFilterSlider.tsx +23 -0
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesSelectedTags/MyAccountQuotesSelectedTags.tsx +35 -11
- package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesStatusSelector/MyAccountQuotesStatusSelector.tsx +27 -10
- package/src/components/account/quotes/MyAccountListQuotes/index.ts +2 -0
- package/src/components/account/quotes/MyAccountListQuotes/quoteFilters.ts +16 -6
- package/src/components/account/quotes/MyAccountListQuotes/quotesLabels.ts +163 -0
- package/src/components/cms/account/Components.ts +2 -0
- package/src/components/sections/Account/AccountListQuotes.tsx +141 -0
- package/src/pages/pvt/account/quotes/index.tsx +59 -40
- package/src/sdk/account/accountPageContext.ts +17 -0
- package/src/sdk/account/getMyAccountRoutes.ts +17 -0
- package/src/sdk/account/resolveNonBlankLabels.ts +36 -0
- package/src/server/cms/myAccountDefaultSections.ts +2 -0
- package/src/utils/quoteStatus.ts +81 -0
- package/test/components/account/ContractSwitcher.browser.test.tsx +163 -0
- package/test/components/account/OrganizationDrawer.browser.test.tsx +4 -0
- package/test/components/account/OrganizationDrawerHeader.browser.test.tsx +44 -1
- package/test/components/quotes/MyAccountListQuotes.test.tsx +36 -2
- package/test/components/quotes/MyAccountListQuotesTable.test.tsx +68 -0
- package/test/components/quotes/MyAccountQuoteStatusBadge.test.tsx +25 -0
- package/test/components/quotes/MyAccountQuotesFilterSlider.test.tsx +52 -11
- package/test/components/quotes/MyAccountQuotesSelectedTags.test.tsx +32 -0
- package/test/components/quotes/MyAccountQuotesStatusSelector.test.tsx +100 -0
- package/test/components/quotes/quoteFilters.test.ts +34 -0
- package/test/components/sections/Account/AccountListQuotes.browser.test.tsx +122 -0
- package/test/server/cms/myAccountDefaultSections.test.ts +21 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$extends": ["#/$defs/base-component"],
|
|
3
|
+
"$componentKey": "AccountListQuotes",
|
|
4
|
+
"$componentTitle": "Account List Quotes",
|
|
5
|
+
"title": "Account List Quotes",
|
|
6
|
+
"description": "Quotes list section for My Account",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"pageTitle": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"title": "Page Title",
|
|
12
|
+
"default": "Quotes"
|
|
13
|
+
},
|
|
14
|
+
"searchPlaceholder": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"title": "Search Placeholder",
|
|
17
|
+
"default": "Search"
|
|
18
|
+
},
|
|
19
|
+
"openFiltersAriaLabel": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"title": "Open Filters Aria Label",
|
|
22
|
+
"default": "Open Filters"
|
|
23
|
+
},
|
|
24
|
+
"filtersLabel": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"title": "Filters Label",
|
|
27
|
+
"default": "Filters"
|
|
28
|
+
},
|
|
29
|
+
"clearAllLabel": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"title": "Clear All Label",
|
|
32
|
+
"default": "Clear All"
|
|
33
|
+
},
|
|
34
|
+
"viewResultsLabel": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"title": "View Results Label",
|
|
37
|
+
"default": "View Results"
|
|
38
|
+
},
|
|
39
|
+
"noResultsLabel": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"title": "No Results Label",
|
|
42
|
+
"default": "No results found"
|
|
43
|
+
},
|
|
44
|
+
"noQuotesLabel": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"title": "No Quotes Label",
|
|
47
|
+
"default": "You don't have any quotes"
|
|
48
|
+
},
|
|
49
|
+
"statusFacetLabel": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"title": "Status Facet Label",
|
|
52
|
+
"default": "Status"
|
|
53
|
+
},
|
|
54
|
+
"createdAtFacetLabel": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"title": "Created At Facet Label",
|
|
57
|
+
"default": "Created Date"
|
|
58
|
+
},
|
|
59
|
+
"expiresAtFacetLabel": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"title": "Expires At Facet Label",
|
|
62
|
+
"default": "Expiry Date"
|
|
63
|
+
},
|
|
64
|
+
"removeStatusAriaLabel": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"title": "Remove Status Chip Aria Label",
|
|
67
|
+
"description": "Supports a \"{status}\" placeholder, e.g. \"Remove {status}\".",
|
|
68
|
+
"default": "Remove {status}"
|
|
69
|
+
},
|
|
70
|
+
"fromLabel": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"title": "From Label",
|
|
73
|
+
"default": "From"
|
|
74
|
+
},
|
|
75
|
+
"toLabel": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"title": "To Label",
|
|
78
|
+
"default": "To"
|
|
79
|
+
},
|
|
80
|
+
"invalidDateRangeLabel": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"title": "Invalid Date Range Label",
|
|
83
|
+
"default": "Invalid date range"
|
|
84
|
+
},
|
|
85
|
+
"paginationOfLabel": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"title": "Pagination Of Label",
|
|
88
|
+
"default": "of"
|
|
89
|
+
},
|
|
90
|
+
"previousPageLabel": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"title": "Previous Page Label",
|
|
93
|
+
"default": "Previous Page"
|
|
94
|
+
},
|
|
95
|
+
"nextPageLabel": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"title": "Next Page Label",
|
|
98
|
+
"default": "Next Page"
|
|
99
|
+
},
|
|
100
|
+
"createdTagLabel": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"title": "Created Tag Label",
|
|
103
|
+
"default": "Created"
|
|
104
|
+
},
|
|
105
|
+
"expiresTagLabel": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"title": "Expires Tag Label",
|
|
108
|
+
"default": "Expires"
|
|
109
|
+
},
|
|
110
|
+
"dateRangeFromLabel": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"title": "Date Range From Label",
|
|
113
|
+
"default": "from"
|
|
114
|
+
},
|
|
115
|
+
"dateRangeToLabel": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"title": "Date Range To Label",
|
|
118
|
+
"default": "to"
|
|
119
|
+
},
|
|
120
|
+
"dateRangeSeparatorLabel": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"title": "Date Range Separator Label",
|
|
123
|
+
"default": "to"
|
|
124
|
+
},
|
|
125
|
+
"createdByLabel": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"title": "Created By Label",
|
|
128
|
+
"default": "Created by"
|
|
129
|
+
},
|
|
130
|
+
"creationDateLabel": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"title": "Creation Date Label",
|
|
133
|
+
"default": "Creation date"
|
|
134
|
+
},
|
|
135
|
+
"expiresOnLabel": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"title": "Expires On Label",
|
|
138
|
+
"default": "Expires on"
|
|
139
|
+
},
|
|
140
|
+
"totalLabel": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"title": "Total Label",
|
|
143
|
+
"default": "Total"
|
|
144
|
+
},
|
|
145
|
+
"hourLabel": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"title": "Hour Label (singular)",
|
|
148
|
+
"default": "hour"
|
|
149
|
+
},
|
|
150
|
+
"hoursLabel": {
|
|
151
|
+
"type": "string",
|
|
152
|
+
"title": "Hours Label (plural)",
|
|
153
|
+
"default": "hours"
|
|
154
|
+
},
|
|
155
|
+
"dayLabel": {
|
|
156
|
+
"type": "string",
|
|
157
|
+
"title": "Day Label (singular)",
|
|
158
|
+
"default": "day"
|
|
159
|
+
},
|
|
160
|
+
"daysLabel": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"title": "Days Label (plural)",
|
|
163
|
+
"default": "days"
|
|
164
|
+
},
|
|
165
|
+
"weekLabel": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"title": "Week Label (singular)",
|
|
168
|
+
"default": "week"
|
|
169
|
+
},
|
|
170
|
+
"weeksLabel": {
|
|
171
|
+
"type": "string",
|
|
172
|
+
"title": "Weeks Label (plural)",
|
|
173
|
+
"default": "weeks"
|
|
174
|
+
},
|
|
175
|
+
"monthLabel": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"title": "Month Label (singular)",
|
|
178
|
+
"default": "month"
|
|
179
|
+
},
|
|
180
|
+
"monthsLabel": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"title": "Months Label (plural)",
|
|
183
|
+
"default": "months"
|
|
184
|
+
},
|
|
185
|
+
"leftSuffixLabel": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"title": "Left Suffix Label",
|
|
188
|
+
"default": "left"
|
|
189
|
+
},
|
|
190
|
+
"draftStatus": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"title": "Draft Status",
|
|
193
|
+
"default": "Draft"
|
|
194
|
+
},
|
|
195
|
+
"requestedStatus": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"title": "Requested Status",
|
|
198
|
+
"default": "Requested"
|
|
199
|
+
},
|
|
200
|
+
"inReviewStatus": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"title": "In Review Status",
|
|
203
|
+
"default": "In Review"
|
|
204
|
+
},
|
|
205
|
+
"revisedStatus": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"title": "Revised Status",
|
|
208
|
+
"default": "Revised"
|
|
209
|
+
},
|
|
210
|
+
"approvedStatus": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"title": "Approved Status",
|
|
213
|
+
"default": "Approved"
|
|
214
|
+
},
|
|
215
|
+
"declinedStatus": {
|
|
216
|
+
"type": "string",
|
|
217
|
+
"title": "Declined Status",
|
|
218
|
+
"default": "Declined"
|
|
219
|
+
},
|
|
220
|
+
"expiredStatus": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"title": "Expired Status",
|
|
223
|
+
"default": "Expired"
|
|
224
|
+
},
|
|
225
|
+
"convertedStatus": {
|
|
226
|
+
"type": "string",
|
|
227
|
+
"title": "Converted Status",
|
|
228
|
+
"default": "Converted"
|
|
229
|
+
},
|
|
230
|
+
"convertedToOrderStatus": {
|
|
231
|
+
"type": "string",
|
|
232
|
+
"title": "Converted To Order Status",
|
|
233
|
+
"default": "Converted to Order"
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"readOnly": false,
|
|
237
|
+
"writeOnly": false,
|
|
238
|
+
"deprecated": false,
|
|
239
|
+
"$abstract": false
|
|
240
|
+
}
|
|
@@ -60,6 +60,82 @@
|
|
|
60
60
|
"type": "string",
|
|
61
61
|
"title": "Contract Label",
|
|
62
62
|
"default": "Contract"
|
|
63
|
+
},
|
|
64
|
+
"changeContractLabel": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"title": "Change Contract Label",
|
|
67
|
+
"default": "Change"
|
|
68
|
+
},
|
|
69
|
+
"contractSwitcherTitleLabel": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"title": "Contract Switcher Title Label",
|
|
72
|
+
"default": "Change contract"
|
|
73
|
+
},
|
|
74
|
+
"contractSwitcherBackLabel": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"title": "Contract Switcher Back Aria Label",
|
|
77
|
+
"default": "Back to account menu"
|
|
78
|
+
},
|
|
79
|
+
"contractSwitcherCloseLabel": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"title": "Contract Switcher Close Aria Label",
|
|
82
|
+
"default": "Close"
|
|
83
|
+
},
|
|
84
|
+
"contractSwitcherCurrentSessionLabel": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"title": "Contract Switcher Current Session Label",
|
|
87
|
+
"default": "Current session"
|
|
88
|
+
},
|
|
89
|
+
"contractSwitcherSearchPlaceholder": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"title": "Contract Switcher Search Placeholder",
|
|
92
|
+
"default": "Search"
|
|
93
|
+
},
|
|
94
|
+
"contractSwitcherSearchAriaLabel": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"title": "Contract Switcher Search Aria Label",
|
|
97
|
+
"default": "Search contracts"
|
|
98
|
+
},
|
|
99
|
+
"contractSwitcherClearSearchLabel": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"title": "Contract Switcher Clear Search Aria Label",
|
|
102
|
+
"default": "Clear search"
|
|
103
|
+
},
|
|
104
|
+
"contractSwitcherAvailableCountLabel": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"title": "Contract Switcher Available Count Label",
|
|
107
|
+
"description": "Supports a \"{count}\" placeholder, e.g. \"Select one of {count} available contracts:\".",
|
|
108
|
+
"default": "Select one of {count} available contracts:"
|
|
109
|
+
},
|
|
110
|
+
"contractSwitcherNoMatchLabel": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"title": "Contract Switcher No Match Label",
|
|
113
|
+
"default": "No contracts match your search."
|
|
114
|
+
},
|
|
115
|
+
"contractSwitcherEmptyLabel": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"title": "Contract Switcher Empty Label",
|
|
118
|
+
"default": "No other contracts are available for your organization."
|
|
119
|
+
},
|
|
120
|
+
"contractSwitcherLoadErrorLabel": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"title": "Contract Switcher Load Error Label",
|
|
123
|
+
"default": "We couldn't load your contracts. Please try again."
|
|
124
|
+
},
|
|
125
|
+
"contractSwitcherSwitchErrorLabel": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"title": "Contract Switcher Switch Error Label",
|
|
128
|
+
"default": "We couldn't switch your contract. The previous contract is still active."
|
|
129
|
+
},
|
|
130
|
+
"contractSwitcherCancelLabel": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"title": "Contract Switcher Cancel Label",
|
|
133
|
+
"default": "Cancel"
|
|
134
|
+
},
|
|
135
|
+
"contractSwitcherConfirmLabel": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"title": "Contract Switcher Confirm Label",
|
|
138
|
+
"default": "Confirm"
|
|
63
139
|
}
|
|
64
140
|
},
|
|
65
141
|
"readOnly": false,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"myAccountQuotes": {
|
|
3
|
+
"$extends": ["#/components/base-page-template"],
|
|
4
|
+
"$singleton": true,
|
|
5
|
+
"type": "object",
|
|
6
|
+
"title": "My Account — Quotes",
|
|
7
|
+
"properties": {
|
|
8
|
+
"sections": {
|
|
9
|
+
"$ref": "#/$defs/$ALLOW_ALL_COMPONENTS"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"readOnly": false,
|
|
13
|
+
"writeOnly": false,
|
|
14
|
+
"deprecated": false,
|
|
15
|
+
"$abstract": false,
|
|
16
|
+
"identifierKeys": []
|
|
17
|
+
}
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.9.0-dev.
|
|
3
|
+
"version": "4.9.0-dev.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -71,11 +71,11 @@
|
|
|
71
71
|
"style-loader": "^3.3.1",
|
|
72
72
|
"swr": "^2.2.5",
|
|
73
73
|
"use-sync-external-store": "^1.6.0",
|
|
74
|
-
"@faststore/api": "4.9.0-dev.
|
|
75
|
-
"@faststore/
|
|
76
|
-
"@faststore/
|
|
77
|
-
"@faststore/
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/api": "4.9.0-dev.4",
|
|
75
|
+
"@faststore/diagnostics": "4.9.0-dev.4",
|
|
76
|
+
"@faststore/lighthouse": "4.9.0-dev.4",
|
|
77
|
+
"@faststore/sdk": "4.9.0-dev.4",
|
|
78
|
+
"@faststore/ui": "4.9.0-dev.4"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/ContractSwitcher.tsx
CHANGED
|
@@ -1,10 +1,85 @@
|
|
|
1
1
|
import { Button, Icon, IconButton, Loader } from '@faststore/ui'
|
|
2
2
|
import { useState, type ReactNode } from 'react'
|
|
3
3
|
|
|
4
|
+
import { useAccountNavigationLabels } from 'src/sdk/account/accountPageContext'
|
|
5
|
+
import type { AccountNavigationLabels } from 'src/sdk/account/getMyAccountRoutes'
|
|
6
|
+
import {
|
|
7
|
+
resolveNonBlankLabels,
|
|
8
|
+
splitOnFirstToken,
|
|
9
|
+
} from 'src/sdk/account/resolveNonBlankLabels'
|
|
4
10
|
import { useAvailableContracts } from 'src/sdk/account/useAvailableContracts'
|
|
5
11
|
import { useSwitchContract } from 'src/sdk/account/useSwitchContract'
|
|
6
12
|
import { useSession } from 'src/sdk/session'
|
|
7
13
|
|
|
14
|
+
/** English fallbacks used when the CMS doesn't provide a `navigationLabels` override. */
|
|
15
|
+
const defaultContractSwitcherLabels = {
|
|
16
|
+
titleLabel: 'Change contract',
|
|
17
|
+
backLabel: 'Back to account menu',
|
|
18
|
+
closeLabel: 'Close',
|
|
19
|
+
currentSessionLabel: 'Current session',
|
|
20
|
+
searchPlaceholder: 'Search',
|
|
21
|
+
searchAriaLabel: 'Search contracts',
|
|
22
|
+
clearSearchLabel: 'Clear search',
|
|
23
|
+
availableCountLabel: 'Select one of {count} available contracts:',
|
|
24
|
+
noMatchLabel: 'No contracts match your search.',
|
|
25
|
+
emptyLabel: 'No other contracts are available for your organization.',
|
|
26
|
+
loadErrorLabel: "We couldn't load your contracts. Please try again.",
|
|
27
|
+
switchErrorLabel:
|
|
28
|
+
"We couldn't switch your contract. The previous contract is still active.",
|
|
29
|
+
cancelLabel: 'Cancel',
|
|
30
|
+
confirmLabel: 'Confirm',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type ContractSwitcherLabels = typeof defaultContractSwitcherLabels
|
|
34
|
+
|
|
35
|
+
const SWITCHER_CMS_KEYS = {
|
|
36
|
+
titleLabel: 'contractSwitcherTitleLabel',
|
|
37
|
+
backLabel: 'contractSwitcherBackLabel',
|
|
38
|
+
closeLabel: 'contractSwitcherCloseLabel',
|
|
39
|
+
currentSessionLabel: 'contractSwitcherCurrentSessionLabel',
|
|
40
|
+
searchPlaceholder: 'contractSwitcherSearchPlaceholder',
|
|
41
|
+
searchAriaLabel: 'contractSwitcherSearchAriaLabel',
|
|
42
|
+
clearSearchLabel: 'contractSwitcherClearSearchLabel',
|
|
43
|
+
availableCountLabel: 'contractSwitcherAvailableCountLabel',
|
|
44
|
+
noMatchLabel: 'contractSwitcherNoMatchLabel',
|
|
45
|
+
emptyLabel: 'contractSwitcherEmptyLabel',
|
|
46
|
+
loadErrorLabel: 'contractSwitcherLoadErrorLabel',
|
|
47
|
+
switchErrorLabel: 'contractSwitcherSwitchErrorLabel',
|
|
48
|
+
cancelLabel: 'contractSwitcherCancelLabel',
|
|
49
|
+
confirmLabel: 'contractSwitcherConfirmLabel',
|
|
50
|
+
} as const satisfies Record<
|
|
51
|
+
keyof ContractSwitcherLabels,
|
|
52
|
+
keyof AccountNavigationLabels
|
|
53
|
+
>
|
|
54
|
+
|
|
55
|
+
function resolveContractSwitcherLabels(
|
|
56
|
+
navigationLabels?: AccountNavigationLabels
|
|
57
|
+
): ContractSwitcherLabels {
|
|
58
|
+
const overrides: Partial<ContractSwitcherLabels> = {}
|
|
59
|
+
|
|
60
|
+
if (navigationLabels) {
|
|
61
|
+
for (const key of Object.keys(
|
|
62
|
+
SWITCHER_CMS_KEYS
|
|
63
|
+
) as (keyof ContractSwitcherLabels)[]) {
|
|
64
|
+
overrides[key] = navigationLabels[SWITCHER_CMS_KEYS[key]]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return resolveNonBlankLabels(defaultContractSwitcherLabels, overrides)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type ContractSwitcherLabelsProps = {
|
|
72
|
+
labels: ContractSwitcherLabels
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Splits `availableCountLabel` on the `{count}` placeholder so the count can be
|
|
77
|
+
* wrapped in a `<strong>`, keeping the CMS convention of plain string labels
|
|
78
|
+
* (no templating engine) while still allowing surrounding text to be localized.
|
|
79
|
+
*/
|
|
80
|
+
const splitAvailableCountLabel = (template: string) =>
|
|
81
|
+
splitOnFirstToken(template, '{count}')
|
|
82
|
+
|
|
8
83
|
export type ContractSwitcherProps = {
|
|
9
84
|
/** Returns to the drawer menu view (also used by Cancel). */
|
|
10
85
|
onBack: () => void
|
|
@@ -23,6 +98,7 @@ type SwitcherContract = {
|
|
|
23
98
|
const initialOf = (name: string) => name.trim().charAt(0).toUpperCase()
|
|
24
99
|
|
|
25
100
|
type ContractSwitcherContentProps = {
|
|
101
|
+
labels: ContractSwitcherLabels
|
|
26
102
|
loading: boolean
|
|
27
103
|
error: Error | null
|
|
28
104
|
currentContract: SwitcherContract | null
|
|
@@ -42,19 +118,20 @@ const ContractSwitcherLoading = () => (
|
|
|
42
118
|
</div>
|
|
43
119
|
)
|
|
44
120
|
|
|
45
|
-
const ContractSwitcherLoadError = () => (
|
|
121
|
+
const ContractSwitcherLoadError = ({ labels }: ContractSwitcherLabelsProps) => (
|
|
46
122
|
<div data-fs-contract-switcher-message role="alert">
|
|
47
|
-
<p>
|
|
123
|
+
<p>{labels.loadErrorLabel}</p>
|
|
48
124
|
</div>
|
|
49
125
|
)
|
|
50
126
|
|
|
51
127
|
const ContractSwitcherCurrentSession = ({
|
|
128
|
+
labels,
|
|
52
129
|
currentContract,
|
|
53
|
-
}: {
|
|
130
|
+
}: ContractSwitcherLabelsProps & {
|
|
54
131
|
currentContract: SwitcherContract | null
|
|
55
132
|
}) => (
|
|
56
133
|
<div data-fs-contract-switcher-current>
|
|
57
|
-
<span data-fs-contract-switcher-label>
|
|
134
|
+
<span data-fs-contract-switcher-label>{labels.currentSessionLabel}</span>
|
|
58
135
|
{currentContract && (
|
|
59
136
|
<div data-fs-contract-switcher-current-card>
|
|
60
137
|
<span data-fs-contract-switcher-avatar aria-hidden="true">
|
|
@@ -77,13 +154,16 @@ const ContractSwitcherCurrentSession = ({
|
|
|
77
154
|
</div>
|
|
78
155
|
)
|
|
79
156
|
|
|
80
|
-
const ContractSwitcherEmptyAlternatives = (
|
|
157
|
+
const ContractSwitcherEmptyAlternatives = ({
|
|
158
|
+
labels,
|
|
159
|
+
}: ContractSwitcherLabelsProps) => (
|
|
81
160
|
<div data-fs-contract-switcher-message data-fs-contract-switcher-empty>
|
|
82
|
-
<p>
|
|
161
|
+
<p>{labels.emptyLabel}</p>
|
|
83
162
|
</div>
|
|
84
163
|
)
|
|
85
164
|
|
|
86
165
|
type ContractSwitcherAlternativesProps = {
|
|
166
|
+
labels: ContractSwitcherLabels
|
|
87
167
|
alternatives: SwitcherContract[]
|
|
88
168
|
ordered: SwitcherContract[]
|
|
89
169
|
search: string
|
|
@@ -94,27 +174,28 @@ type ContractSwitcherAlternativesProps = {
|
|
|
94
174
|
}
|
|
95
175
|
|
|
96
176
|
const ContractSwitcherSearch = ({
|
|
177
|
+
labels,
|
|
97
178
|
search,
|
|
98
179
|
onSearchChange,
|
|
99
180
|
onSearchClear,
|
|
100
181
|
}: Pick<
|
|
101
182
|
ContractSwitcherAlternativesProps,
|
|
102
|
-
'search' | 'onSearchChange' | 'onSearchClear'
|
|
183
|
+
'labels' | 'search' | 'onSearchChange' | 'onSearchClear'
|
|
103
184
|
>) => (
|
|
104
185
|
<div data-fs-contract-switcher-search>
|
|
105
186
|
<Icon name="MagnifyingGlass" width={20} height={20} />
|
|
106
187
|
<input
|
|
107
188
|
type="text"
|
|
108
189
|
value={search}
|
|
109
|
-
placeholder=
|
|
110
|
-
aria-label=
|
|
190
|
+
placeholder={labels.searchPlaceholder}
|
|
191
|
+
aria-label={labels.searchAriaLabel}
|
|
111
192
|
onChange={(event) => onSearchChange(event.target.value)}
|
|
112
193
|
/>
|
|
113
194
|
{search && (
|
|
114
195
|
<button
|
|
115
196
|
type="button"
|
|
116
197
|
data-fs-contract-switcher-search-clear
|
|
117
|
-
aria-label=
|
|
198
|
+
aria-label={labels.clearSearchLabel}
|
|
118
199
|
onClick={onSearchClear}
|
|
119
200
|
>
|
|
120
201
|
<Icon name="X" width={18} height={18} />
|
|
@@ -167,6 +248,7 @@ const ContractSwitcherOptionList = ({
|
|
|
167
248
|
)
|
|
168
249
|
|
|
169
250
|
const ContractSwitcherAlternatives = ({
|
|
251
|
+
labels,
|
|
170
252
|
alternatives,
|
|
171
253
|
ordered,
|
|
172
254
|
search,
|
|
@@ -176,14 +258,14 @@ const ContractSwitcherAlternatives = ({
|
|
|
176
258
|
onSelectContract,
|
|
177
259
|
}: ContractSwitcherAlternativesProps) => {
|
|
178
260
|
if (alternatives.length === 0) {
|
|
179
|
-
return <ContractSwitcherEmptyAlternatives />
|
|
261
|
+
return <ContractSwitcherEmptyAlternatives labels={labels} />
|
|
180
262
|
}
|
|
181
263
|
|
|
182
264
|
let listContent: ReactNode
|
|
183
265
|
if (ordered.length === 0) {
|
|
184
266
|
listContent = (
|
|
185
267
|
<div data-fs-contract-switcher-message>
|
|
186
|
-
<p>
|
|
268
|
+
<p>{labels.noMatchLabel}</p>
|
|
187
269
|
</div>
|
|
188
270
|
)
|
|
189
271
|
} else {
|
|
@@ -196,13 +278,25 @@ const ContractSwitcherAlternatives = ({
|
|
|
196
278
|
)
|
|
197
279
|
}
|
|
198
280
|
|
|
281
|
+
const { found, prefix, suffix } = splitAvailableCountLabel(
|
|
282
|
+
labels.availableCountLabel
|
|
283
|
+
)
|
|
284
|
+
|
|
199
285
|
return (
|
|
200
286
|
<>
|
|
201
287
|
<p data-fs-contract-switcher-count>
|
|
202
|
-
|
|
203
|
-
|
|
288
|
+
{found ? (
|
|
289
|
+
<>
|
|
290
|
+
{prefix}
|
|
291
|
+
<strong>{alternatives.length}</strong>
|
|
292
|
+
{suffix}
|
|
293
|
+
</>
|
|
294
|
+
) : (
|
|
295
|
+
labels.availableCountLabel
|
|
296
|
+
)}
|
|
204
297
|
</p>
|
|
205
298
|
<ContractSwitcherSearch
|
|
299
|
+
labels={labels}
|
|
206
300
|
search={search}
|
|
207
301
|
onSearchChange={onSearchChange}
|
|
208
302
|
onSearchClear={onSearchClear}
|
|
@@ -212,15 +306,16 @@ const ContractSwitcherAlternatives = ({
|
|
|
212
306
|
)
|
|
213
307
|
}
|
|
214
308
|
|
|
215
|
-
const ContractSwitcherSwitchError = (
|
|
309
|
+
const ContractSwitcherSwitchError = ({
|
|
310
|
+
labels,
|
|
311
|
+
}: ContractSwitcherLabelsProps) => (
|
|
216
312
|
<div data-fs-contract-switcher-message role="alert">
|
|
217
|
-
<p>
|
|
218
|
-
We couldn't switch your contract. The previous contract is still active.
|
|
219
|
-
</p>
|
|
313
|
+
<p>{labels.switchErrorLabel}</p>
|
|
220
314
|
</div>
|
|
221
315
|
)
|
|
222
316
|
|
|
223
317
|
const ContractSwitcherContent = ({
|
|
318
|
+
labels,
|
|
224
319
|
loading,
|
|
225
320
|
error,
|
|
226
321
|
currentContract,
|
|
@@ -238,13 +333,17 @@ const ContractSwitcherContent = ({
|
|
|
238
333
|
}
|
|
239
334
|
|
|
240
335
|
if (error) {
|
|
241
|
-
return <ContractSwitcherLoadError />
|
|
336
|
+
return <ContractSwitcherLoadError labels={labels} />
|
|
242
337
|
}
|
|
243
338
|
|
|
244
339
|
return (
|
|
245
340
|
<>
|
|
246
|
-
<ContractSwitcherCurrentSession
|
|
341
|
+
<ContractSwitcherCurrentSession
|
|
342
|
+
labels={labels}
|
|
343
|
+
currentContract={currentContract}
|
|
344
|
+
/>
|
|
247
345
|
<ContractSwitcherAlternatives
|
|
346
|
+
labels={labels}
|
|
248
347
|
alternatives={alternatives}
|
|
249
348
|
ordered={ordered}
|
|
250
349
|
search={search}
|
|
@@ -253,7 +352,7 @@ const ContractSwitcherContent = ({
|
|
|
253
352
|
onSearchClear={onSearchClear}
|
|
254
353
|
onSelectContract={onSelectContract}
|
|
255
354
|
/>
|
|
256
|
-
{switchError && <ContractSwitcherSwitchError />}
|
|
355
|
+
{switchError && <ContractSwitcherSwitchError labels={labels} />}
|
|
257
356
|
</>
|
|
258
357
|
)
|
|
259
358
|
}
|
|
@@ -268,6 +367,9 @@ export const ContractSwitcher = ({
|
|
|
268
367
|
onBack,
|
|
269
368
|
onClose,
|
|
270
369
|
}: ContractSwitcherProps) => {
|
|
370
|
+
const navigationLabels = useAccountNavigationLabels()
|
|
371
|
+
const labels = resolveContractSwitcherLabels(navigationLabels)
|
|
372
|
+
|
|
271
373
|
const { contracts, loading, error } = useAvailableContracts(true)
|
|
272
374
|
const { b2b } = useSession()
|
|
273
375
|
const {
|
|
@@ -327,14 +429,14 @@ export const ContractSwitcher = ({
|
|
|
327
429
|
<header data-fs-contract-switcher-header>
|
|
328
430
|
<IconButton
|
|
329
431
|
data-fs-contract-switcher-back
|
|
330
|
-
aria-label=
|
|
432
|
+
aria-label={labels.backLabel}
|
|
331
433
|
icon={<Icon name="ArrowLeft" width={20} height={20} />}
|
|
332
434
|
onClick={onBack}
|
|
333
435
|
/>
|
|
334
|
-
<h2 data-fs-contract-switcher-title>
|
|
436
|
+
<h2 data-fs-contract-switcher-title>{labels.titleLabel}</h2>
|
|
335
437
|
<IconButton
|
|
336
438
|
data-fs-contract-switcher-close
|
|
337
|
-
aria-label=
|
|
439
|
+
aria-label={labels.closeLabel}
|
|
338
440
|
icon={<Icon name="X" width={20} height={20} />}
|
|
339
441
|
onClick={onClose}
|
|
340
442
|
/>
|
|
@@ -342,6 +444,7 @@ export const ContractSwitcher = ({
|
|
|
342
444
|
|
|
343
445
|
<div data-fs-contract-switcher-content>
|
|
344
446
|
<ContractSwitcherContent
|
|
447
|
+
labels={labels}
|
|
345
448
|
loading={loading}
|
|
346
449
|
error={error}
|
|
347
450
|
currentContract={currentContract}
|
|
@@ -358,7 +461,7 @@ export const ContractSwitcher = ({
|
|
|
358
461
|
|
|
359
462
|
<footer data-fs-contract-switcher-footer>
|
|
360
463
|
<Button variant="tertiary" onClick={onBack}>
|
|
361
|
-
|
|
464
|
+
{labels.cancelLabel}
|
|
362
465
|
</Button>
|
|
363
466
|
<Button
|
|
364
467
|
variant="primary"
|
|
@@ -366,7 +469,7 @@ export const ContractSwitcher = ({
|
|
|
366
469
|
loading={switching}
|
|
367
470
|
onClick={handleConfirm}
|
|
368
471
|
>
|
|
369
|
-
|
|
472
|
+
{labels.confirmLabel}
|
|
370
473
|
</Button>
|
|
371
474
|
</footer>
|
|
372
475
|
</section>
|