Skip to content

Commit 1b5e7b0

Browse files
committed
Changed multiple active subscriptions filter to a Yes/No select
ref https://linear.app/ghost/issue/BER-3720/cleanupimprove-multi-sub-filter-implementation Matches the established Yes/No pattern used by the comments moderation "Reported" filter instead of introducing a one-off boolean toggle. The field is now a select with Yes/No options, so its predicates carry string values like every other select filter, the chip reads "Multiple active subscriptions is Yes" rather than an unlabelled switch, and the bespoke 'boolean' ui type added to the shared filter framework is no longer needed.
1 parent 445d376 commit 1b5e7b0

5 files changed

Lines changed: 30 additions & 20 deletions

File tree

apps/posts/src/views/filters/filter-types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface FilterField {
2424
parseKeys?: readonly string[];
2525
ui: {
2626
label: string;
27-
type: 'text' | 'select' | 'multiselect' | 'date' | 'number' | 'boolean' | 'custom';
27+
type: 'text' | 'select' | 'multiselect' | 'date' | 'number' | 'custom';
2828
[key: string]: unknown;
2929
};
3030
options?: Array<{value: string; label: string}>;

apps/posts/src/views/members/hooks/use-members-filter-state.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('useMembersFilterState', () => {
7979
id: 'count.active_stripe_customers:1',
8080
field: 'count.active_stripe_customers',
8181
operator: 'is',
82-
values: [true]
82+
values: ['true']
8383
}
8484
]);
8585
expect(result.current.query).toBe('filter=count.active_stripe_customers%3A%3E1');
@@ -108,7 +108,7 @@ describe('useMembersFilterState', () => {
108108
id: 'count.active_stripe_customers:1',
109109
field: 'count.active_stripe_customers',
110110
operator: 'is',
111-
values: [false]
111+
values: ['false']
112112
}
113113
]);
114114
expect(result.current.query).toBe('filter=count.active_stripe_customers%3A%3C2');

apps/posts/src/views/members/member-fields.test.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,44 +148,45 @@ describe('multipleActiveSubscriptionsCodec', () => {
148148
timezone: 'UTC'
149149
};
150150

151-
it('serializes the boolean predicate to count comparisons', () => {
151+
it('serializes the Yes/No predicate to count comparisons', () => {
152152
const predicate: FilterPredicate = {
153153
id: '1',
154154
field: 'count.active_stripe_customers',
155155
operator: 'is',
156-
values: [true]
156+
values: ['true']
157157
};
158158

159159
expect(field.codec.serialize(predicate, context)).toEqual([
160160
'count.active_stripe_customers:>1'
161161
]);
162-
expect(field.codec.serialize({...predicate, values: [false]}, context)).toEqual([
162+
expect(field.codec.serialize({...predicate, values: ['false']}, context)).toEqual([
163163
'count.active_stripe_customers:<2'
164164
]);
165165
});
166166

167-
it('rejects non-boolean values and other operators', () => {
167+
it('rejects unknown values and other operators', () => {
168168
const predicate: FilterPredicate = {
169169
id: '1',
170170
field: 'count.active_stripe_customers',
171171
operator: 'is',
172-
values: [1]
172+
values: [true]
173173
};
174174

175175
expect(field.codec.serialize(predicate, context)).toBeNull();
176-
expect(field.codec.serialize({...predicate, operator: 'is-greater', values: [true]}, context)).toBeNull();
176+
expect(field.codec.serialize({...predicate, values: [1]}, context)).toBeNull();
177+
expect(field.codec.serialize({...predicate, operator: 'is-greater', values: ['true']}, context)).toBeNull();
177178
});
178179

179180
it('parses only the comparisons it serializes', () => {
180181
expect(field.codec.parse({'count.active_stripe_customers': {$gt: 1}}, context)).toEqual({
181182
field: 'count.active_stripe_customers',
182183
operator: 'is',
183-
values: [true]
184+
values: ['true']
184185
});
185186
expect(field.codec.parse({'count.active_stripe_customers': {$lt: 2}}, context)).toEqual({
186187
field: 'count.active_stripe_customers',
187188
operator: 'is',
188-
values: [false]
189+
values: ['false']
189190
});
190191
expect(field.codec.parse({'count.active_stripe_customers': {$gt: 2}}, context)).toBeNull();
191192
expect(field.codec.parse({'count.active_stripe_customers': 1}, context)).toBeNull();

apps/posts/src/views/members/member-fields.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,30 +105,32 @@ const multipleActiveSubscriptionsCodec: FilterCodec = {
105105
return {
106106
field: ctx.key,
107107
operator: 'is',
108-
values: [true]
108+
values: ['true']
109109
};
110110
}
111111

112112
if (comparator.operator === '$lt' && comparator.value === 2) {
113113
return {
114114
field: ctx.key,
115115
operator: 'is',
116-
values: [false]
116+
values: ['false']
117117
};
118118
}
119119

120120
return null;
121121
},
122122
serialize(predicate) {
123+
const value = predicate.values[0];
124+
123125
if (predicate.operator !== 'is') {
124126
return null;
125127
}
126128

127-
if (predicate.values[0] === true) {
129+
if (value === 'true') {
128130
return [MULTIPLE_ACTIVE_STRIPE_CUSTOMERS_FILTER];
129131
}
130132

131-
if (predicate.values[0] === false) {
133+
if (value === 'false') {
132134
return [NO_MULTIPLE_ACTIVE_STRIPE_CUSTOMERS_FILTER];
133135
}
134136

@@ -447,10 +449,14 @@ const baseMemberFields = defineFields({
447449
operators: ['is'],
448450
ui: {
449451
label: 'Multiple active subscriptions',
450-
type: 'boolean',
451-
defaultValue: true,
452+
type: 'select',
453+
searchable: false,
452454
hideOperatorSelect: true
453455
},
456+
options: [
457+
{value: 'true', label: 'Yes'},
458+
{value: 'false', label: 'No'}
459+
],
454460
codec: multipleActiveSubscriptionsCodec
455461
}
456462
});

apps/posts/src/views/members/use-member-filter-fields.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,12 @@ describe('useMemberFilterFields', () => {
204204

205205
expect(multipleSubscriptionsField).toMatchObject({
206206
label: 'Multiple active subscriptions',
207-
type: 'boolean',
208-
defaultValue: true,
209-
hideOperatorSelect: true
207+
type: 'select',
208+
hideOperatorSelect: true,
209+
options: [
210+
{value: 'true', label: 'Yes'},
211+
{value: 'false', label: 'No'}
212+
]
210213
});
211214
});
212215

0 commit comments

Comments
 (0)