@@ -23,16 +23,23 @@ import {
23
23
CheckboxRoot ,
24
24
Heading ,
25
25
IconButton ,
26
+ RadioGroupItem ,
27
+ RadioGroupItemControl ,
28
+ RadioGroupItemHiddenInput ,
29
+ RadioGroupItemText ,
30
+ RadioGroupLabel ,
31
+ RadioGroupRoot ,
26
32
Spinner ,
27
33
Text ,
28
34
} from "@ndla/primitives" ;
29
35
import { styled } from "@ndla/styled-system/jsx" ;
30
36
import { FilterContainer } from "./FilterContainer" ;
37
+ import { RESOURCE_NODE_TYPE , TOPIC_NODE_TYPE } from "./searchUtils" ;
31
38
import {
32
- GQLResourceTypeDefinition ,
33
39
GQLResourceTypeFilter_BucketResultFragment ,
34
40
GQLResourceTypeFilter_ResourceTypeDefinitionFragment ,
35
41
} from "../../graphqlTypes" ;
42
+ import { useLtiContext } from "../../LtiContext" ;
36
43
import { useStableSearchParams } from "../../util/useStableSearchParams" ;
37
44
38
45
const DELIMITER = "//" ;
@@ -74,9 +81,30 @@ const StyledAccordionItemContent = styled(AccordionItemContent, {
74
81
} ,
75
82
} ) ;
76
83
84
+ const RadioButtonWrapper = styled ( "div" , {
85
+ base : {
86
+ display : "flex" ,
87
+ gap : "small" ,
88
+ flexWrap : "wrap" ,
89
+ } ,
90
+ } ) ;
91
+
92
+ const StyledRadioGroupRoot = styled ( RadioGroupRoot , {
93
+ base : {
94
+ _horizontal : {
95
+ flexDirection : "column" ,
96
+ } ,
97
+ } ,
98
+ } ) ;
99
+
100
+ const NODE_TYPES = [ RESOURCE_NODE_TYPE , TOPIC_NODE_TYPE ] ;
101
+
77
102
export const ResourceTypeFilter = ( { bucketResult, resourceTypes : resourceTypesProp , resourceTypesLoading } : Props ) => {
78
103
const [ searchParams , setSearchParams ] = useStableSearchParams ( ) ;
79
104
const { t } = useTranslation ( ) ;
105
+ const isLti = useLtiContext ( ) ;
106
+
107
+ const nodeType = useMemo ( ( ) => searchParams . get ( "type" ) ?? RESOURCE_NODE_TYPE , [ searchParams ] ) ;
80
108
81
109
const keyedBucketResult = useMemo ( ( ) => {
82
110
return bucketResult . reduce < Record < string , number > > ( ( acc , curr ) => {
@@ -86,20 +114,15 @@ export const ResourceTypeFilter = ({ bucketResult, resourceTypes: resourceTypesP
86
114
} , [ bucketResult ] ) ;
87
115
88
116
const resourceTypes = useMemo ( ( ) => {
89
- const types = resourceTypesProp ;
90
- const topicArticleType : GQLResourceTypeDefinition = {
91
- id : "topic-article" ,
92
- name : t ( "contentTypes.topic-article" ) ,
93
- } ;
94
- return [ topicArticleType ] . concat ( types ) . map ( ( type ) => ( {
117
+ return resourceTypesProp . map ( ( type ) => ( {
95
118
...type ,
96
119
id : type . id . replace ( "urn:resourcetype:" , "" ) ,
97
120
subtypes : type . subtypes ?. map ( ( subtype ) => ( {
98
121
...subtype ,
99
122
id : subtype . id . replace ( "urn:resourcetype:" , "" ) ,
100
123
} ) ) ,
101
124
} ) ) ;
102
- } , [ resourceTypesProp , t ] ) ;
125
+ } , [ resourceTypesProp ] ) ;
103
126
104
127
const currentResourceTypeIds = useMemo ( ( ) => searchParams . get ( "resourceTypes" ) ?. split ( "," ) ?? [ ] , [ searchParams ] ) ;
105
128
@@ -129,25 +152,109 @@ export const ResourceTypeFilter = ({ bucketResult, resourceTypes: resourceTypesP
129
152
[ currentResourceTypeIds , resourceTypes , setSearchParams ] ,
130
153
) ;
131
154
155
+ const onChangeNodeType = useCallback (
156
+ ( id : string ) => {
157
+ setSearchParams ( { resourceTypes : null , type : id === RESOURCE_NODE_TYPE ? null : id } ) ;
158
+ } ,
159
+ [ setSearchParams ] ,
160
+ ) ;
161
+
132
162
return (
133
163
< FilterContainer >
134
164
< Heading textStyle = "label.medium" fontWeight = "bold" asChild consumeCss >
135
165
< h3 > { t ( "searchPage.resourceTypeFilter.title" ) } </ h3 >
136
166
</ Heading >
137
- { resourceTypesLoading ? (
138
- < Spinner />
139
- ) : (
140
- < StyledAccordionRoot variant = "clean" multiple >
141
- { resourceTypes ?. map ( ( resourceType ) =>
142
- resourceType . subtypes ?. length ? (
143
- < AccordionItem key = { resourceType . id } value = { resourceType . id } >
144
- < FilterWrapper >
167
+ { ! isLti && (
168
+ < StyledRadioGroupRoot
169
+ orientation = "horizontal"
170
+ value = { nodeType }
171
+ onValueChange = { ( details ) => onChangeNodeType ( details . value ) }
172
+ >
173
+ < RadioGroupLabel textStyle = "label.small" > { t ( "searchPage.resourceTypeFilter.radioLabel" ) } </ RadioGroupLabel >
174
+ < RadioButtonWrapper >
175
+ { NODE_TYPES . map ( ( type ) => (
176
+ < RadioGroupItem key = { type } value = { type } >
177
+ < RadioGroupItemControl />
178
+ < RadioGroupItemText > { t ( `searchPage.resourceTypeFilter.${ type } Label` ) } </ RadioGroupItemText >
179
+ < RadioGroupItemHiddenInput />
180
+ </ RadioGroupItem >
181
+ ) ) }
182
+ </ RadioButtonWrapper >
183
+ </ StyledRadioGroupRoot >
184
+ ) }
185
+ < div hidden = { nodeType !== RESOURCE_NODE_TYPE } >
186
+ { resourceTypesLoading ? (
187
+ < Spinner />
188
+ ) : (
189
+ < StyledAccordionRoot variant = "clean" multiple >
190
+ { resourceTypes ?. map ( ( resourceType ) =>
191
+ resourceType . subtypes ?. length ? (
192
+ < AccordionItem key = { resourceType . id } value = { resourceType . id } >
193
+ < FilterWrapper >
194
+ < CheckboxRoot
195
+ value = { resourceType . id }
196
+ checked = {
197
+ currentResourceTypeIds . includes ( resourceType . id ) ||
198
+ resourceType . subtypes . some ( ( s ) => currentResourceTypeIds . includes ( s . id ) )
199
+ }
200
+ onCheckedChange = { ( details ) => onToggleResourceType ( resourceType . id , details . checked === true ) }
201
+ >
202
+ < CheckboxControl >
203
+ < CheckboxIndicator asChild >
204
+ < CheckLine />
205
+ </ CheckboxIndicator >
206
+ </ CheckboxControl >
207
+ < CheckboxLabel > { resourceType . name } </ CheckboxLabel >
208
+ < CheckboxHiddenInput />
209
+ </ CheckboxRoot >
210
+ < AccordionItemTrigger asChild >
211
+ < IconButton
212
+ variant = "tertiary"
213
+ size = "small"
214
+ aria-label = { t ( "searchPage.resourceTypeFilter.showSubtypes" , { parent : resourceType . name } ) }
215
+ title = { t ( "searchPage.resourceTypeFilter.showSubtypes" , { parent : resourceType . name } ) }
216
+ >
217
+ < AccordionItemIndicator asChild >
218
+ < ArrowDownShortLine size = "medium" />
219
+ </ AccordionItemIndicator >
220
+ </ IconButton >
221
+ </ AccordionItemTrigger >
222
+ </ FilterWrapper >
223
+ < StyledAccordionItemContent >
224
+ { resourceType . subtypes . map ( ( subtype ) => (
225
+ < FilterWrapper key = { subtype . id } >
226
+ < CheckboxRoot
227
+ value = { subtype . id }
228
+ checked = { currentResourceTypeIds . includes ( subtype . id ) }
229
+ onCheckedChange = { ( details ) =>
230
+ onToggleResourceType (
231
+ `${ resourceType . id } ${ DELIMITER } ${ subtype . id } ` ,
232
+ details . checked === true ,
233
+ )
234
+ }
235
+ >
236
+ < CheckboxControl >
237
+ < CheckboxIndicator asChild >
238
+ < CheckLine />
239
+ </ CheckboxIndicator >
240
+ </ CheckboxControl >
241
+ < CheckboxLabel > { subtype . name } </ CheckboxLabel >
242
+ < CheckboxHiddenInput />
243
+ </ CheckboxRoot >
244
+ { keyedBucketResult [ subtype . id ] != null && (
245
+ < Text asChild consumeCss color = "text.subtle" textStyle = "label.medium" >
246
+ < span > { keyedBucketResult [ subtype . id ] } </ span >
247
+ </ Text >
248
+ ) }
249
+ </ FilterWrapper >
250
+ ) ) }
251
+ </ StyledAccordionItemContent >
252
+ </ AccordionItem >
253
+ ) : (
254
+ < FilterWrapper key = { resourceType . id } >
145
255
< CheckboxRoot
146
256
value = { resourceType . id }
147
- checked = {
148
- currentResourceTypeIds . includes ( resourceType . id ) ||
149
- resourceType . subtypes . some ( ( s ) => currentResourceTypeIds . includes ( s . id ) )
150
- }
257
+ checked = { currentResourceTypeIds . includes ( resourceType . id ) }
151
258
onCheckedChange = { ( details ) => onToggleResourceType ( resourceType . id , details . checked === true ) }
152
259
>
153
260
< CheckboxControl >
@@ -158,71 +265,17 @@ export const ResourceTypeFilter = ({ bucketResult, resourceTypes: resourceTypesP
158
265
< CheckboxLabel > { resourceType . name } </ CheckboxLabel >
159
266
< CheckboxHiddenInput />
160
267
</ CheckboxRoot >
161
- < AccordionItemTrigger asChild >
162
- < IconButton
163
- variant = "tertiary"
164
- size = "small"
165
- aria-label = { t ( "searchPage.resourceTypeFilter.showSubtypes" , { parent : resourceType . name } ) }
166
- title = { t ( "searchPage.resourceTypeFilter.showSubtypes" , { parent : resourceType . name } ) }
167
- >
168
- < AccordionItemIndicator asChild >
169
- < ArrowDownShortLine size = "medium" />
170
- </ AccordionItemIndicator >
171
- </ IconButton >
172
- </ AccordionItemTrigger >
268
+ { keyedBucketResult [ resourceType . id ] != null && (
269
+ < TopLevelCountText asChild consumeCss color = "text.subtle" textStyle = "label.medium" >
270
+ < span > { keyedBucketResult [ resourceType . id ] } </ span >
271
+ </ TopLevelCountText >
272
+ ) }
173
273
</ FilterWrapper >
174
- < StyledAccordionItemContent >
175
- { resourceType . subtypes . map ( ( subtype ) => (
176
- < FilterWrapper key = { subtype . id } >
177
- < CheckboxRoot
178
- value = { subtype . id }
179
- checked = { currentResourceTypeIds . includes ( subtype . id ) }
180
- onCheckedChange = { ( details ) =>
181
- onToggleResourceType ( `${ resourceType . id } ${ DELIMITER } ${ subtype . id } ` , details . checked === true )
182
- }
183
- >
184
- < CheckboxControl >
185
- < CheckboxIndicator asChild >
186
- < CheckLine />
187
- </ CheckboxIndicator >
188
- </ CheckboxControl >
189
- < CheckboxLabel > { subtype . name } </ CheckboxLabel >
190
- < CheckboxHiddenInput />
191
- </ CheckboxRoot >
192
- { keyedBucketResult [ subtype . id ] != null && (
193
- < Text asChild consumeCss color = "text.subtle" textStyle = "label.medium" >
194
- < span > { keyedBucketResult [ subtype . id ] } </ span >
195
- </ Text >
196
- ) }
197
- </ FilterWrapper >
198
- ) ) }
199
- </ StyledAccordionItemContent >
200
- </ AccordionItem >
201
- ) : (
202
- < FilterWrapper key = { resourceType . id } >
203
- < CheckboxRoot
204
- value = { resourceType . id }
205
- checked = { currentResourceTypeIds . includes ( resourceType . id ) }
206
- onCheckedChange = { ( details ) => onToggleResourceType ( resourceType . id , details . checked === true ) }
207
- >
208
- < CheckboxControl >
209
- < CheckboxIndicator asChild >
210
- < CheckLine />
211
- </ CheckboxIndicator >
212
- </ CheckboxControl >
213
- < CheckboxLabel > { resourceType . name } </ CheckboxLabel >
214
- < CheckboxHiddenInput />
215
- </ CheckboxRoot >
216
- { keyedBucketResult [ resourceType . id ] != null && (
217
- < TopLevelCountText asChild consumeCss color = "text.subtle" textStyle = "label.medium" >
218
- < span > { keyedBucketResult [ resourceType . id ] } </ span >
219
- </ TopLevelCountText >
220
- ) }
221
- </ FilterWrapper >
222
- ) ,
223
- ) }
224
- </ StyledAccordionRoot >
225
- ) }
274
+ ) ,
275
+ ) }
276
+ </ StyledAccordionRoot >
277
+ ) }
278
+ </ div >
226
279
</ FilterContainer >
227
280
) ;
228
281
} ;
0 commit comments