Skip to content

Commit 4b7e875

Browse files
committed
[Frontend] Separate filter selector and action types from factory scope
1 parent 35fb70b commit 4b7e875

File tree

1 file changed

+43
-46
lines changed

1 file changed

+43
-46
lines changed

services/frontend/src/components/FilterView/filters/createFilter.ts

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { Student } from '..'
88
import type { FilterContext, FilterViewContextState } from '../context'
99
import type { FilterTrayProps } from '../FilterTray'
1010

11+
type Selector<T, R> = (options: FilterContext['options'], args: T) => R
12+
type Action<P> = (options: FilterContext['options'], payload: P) => void
13+
1114
export type Filter = {
1215
args?: any
1316

@@ -50,7 +53,7 @@ export type Filter = {
5053
*/
5154
render: (props: FilterTrayProps, ctx: FilterContext) => ReactNode
5255

53-
isActive: (opts: FilterContext['options']) => boolean
56+
isActive: Selector<void, boolean>
5457
}
5558

5659
/** TODO: Find acual types */
@@ -59,24 +62,24 @@ type FilterOptions = Filter & {
5962
* Redux selectors.
6063
* `selectOptions` and `isActive` will be overwriten.
6164
*/
62-
selectors?: Record<string, (options: FilterContext['options'], args: any) => any>
65+
selectors?: Record<string, Selector<any, any>>
6366

6467
/**
6568
* By default `setOptions` and `reset` are assigned.
6669
* NOTE: `reset` will set the value to null, this may not be desired!
6770
*/
68-
actions?: Record<string, (options: FilterContext['options'], payload: any) => void>
71+
actions?: Record<string, Action<any>>
6972
}
7073

7174
export type FilterFactory = {
7275
key: string
7376
actions: Record<
7477
string,
75-
<T>(payload: T) => (
78+
<P>(payload: P) => (
7679
view: string,
7780
getContext: FilterViewContextState['getContextByKey']
7881
) => {
79-
payload: T
82+
payload: P
8083
type: string
8184
}
8285
>
@@ -96,58 +99,52 @@ export type FilterFactory = {
9699
* Unlike the name suggests, this function returns a filter factory.
97100
*/
98101
export const createFilter = (options: FilterOptions): FilterFactory => {
99-
const opt_selectors = options.selectors ?? {}
100-
const opt_actions = options.actions ?? {}
102+
const opt_selectors: NonNullable<FilterOptions['selectors']> = Object.assign(options.selectors ?? {}, {
103+
selectOptions: (opts, _) => opts,
104+
isActive: options.isActive,
105+
})
101106

102107
/**
103108
* Selectors are wrapped redux selectors that act on the filter's options.
104109
*/
105-
const selectors = mapValues(
106-
{
107-
...opt_selectors,
108-
selectOptions: (opts, _) => opts,
109-
isActive: options.isActive,
110-
},
111-
([key, selector]) => {
112-
const gift = args => {
113-
const wrapper = (opts: FilterContext['options']) => selector(opts, args)
114-
wrapper.filter = options.key
115-
116-
return wrapper
117-
}
118-
119-
return [key, gift]
110+
const selectors = mapValues(opt_selectors, ([key, selector]) => {
111+
const gift = args => {
112+
const wrapper = (opts: FilterContext['options']) => selector(opts, args)
113+
wrapper.filter = options.key
114+
115+
return wrapper
120116
}
121-
)
117+
118+
return [key, gift]
119+
})
120+
121+
const opt_actions: NonNullable<FilterOptions['actions']> = Object.assign(options.actions ?? {}, {
122+
setOptions: (_, value) => value,
123+
reset: (..._) => null,
124+
})
125+
122126
/**
123127
* Actions are wrapped redux actions that act on the filter's options.
124128
*
125129
* Note that these actions cannot be dispatched using the vanilla redux
126130
* dispatch function. You need to use the dipatch function obtained form
127131
* the useFilterDispatch hook.
128132
*/
129-
const actions = mapValues(
130-
{
131-
setOptions: (_, value) => value,
132-
reset: (..._) => null,
133-
...opt_actions,
134-
},
135-
([key, action]) => {
136-
return [
137-
key,
138-
payload => (view: string, getContext: FilterViewContextState['getContextByKey']) => {
139-
const ctx = getContext(options.key)
140-
141-
return setFilterOptions({
142-
view,
143-
filter: options.key,
144-
action: `${options.key}/${key}`,
145-
options: produce(ctx.options, (draft: FilterContext['options']) => action(draft, payload)),
146-
})
147-
},
148-
]
149-
}
150-
)
133+
const actions = mapValues(opt_actions, ([key, action]) => {
134+
return [
135+
key,
136+
payload => (view: string, getContext: FilterViewContextState['getContextByKey']) => {
137+
const ctx = getContext(options.key)
138+
139+
return setFilterOptions({
140+
view,
141+
filter: options.key,
142+
action: `${options.key}/${key}`,
143+
options: produce(ctx.options, (draft: FilterContext['options']) => action(draft, payload)),
144+
})
145+
},
146+
]
147+
})
151148

152149
/**
153150
* `filter`
@@ -191,7 +188,7 @@ export const createFilter = (options: FilterOptions): FilterFactory => {
191188
* The filter is evaluated over the student list only when this function returns true.
192189
* Activity of the filter is also reflected in the user interface.
193190
*/
194-
const factory = (args?: any): Filter => ({
191+
const factory: FilterFactory = (args?: any): Filter => ({
195192
args,
196193

197194
key: options.key,

0 commit comments

Comments
 (0)