From 2de059379e42985cad8ce71e3efc00208a524bc3 Mon Sep 17 00:00:00 2001 From: Jonatan Svennberg Date: Wed, 25 Mar 2026 09:11:58 +0100 Subject: [PATCH 1/2] Refactored sidebar collapsible composition (#26914) closes https://linear.app/ghost/issue/BER-3458/clean-up-collapsible-implementation-in-sidebar Extracted reusable sidebar collapsible component matching the existing composition patterns that are used elsewhere in the sidebar. --- .../app-sidebar/nav-content.helpers.test.ts | 15 +- .../layout/app-sidebar/nav-content.helpers.ts | 8 +- .../src/layout/app-sidebar/nav-content.tsx | 232 ++++++++++-------- .../app-sidebar/nav-custom-views.test.tsx | 57 +++++ .../layout/app-sidebar/nav-custom-views.tsx | 21 +- .../layout/app-sidebar/nav-menu-item.test.tsx | 58 +++++ .../src/layout/app-sidebar/nav-menu-item.tsx | 92 +++++++ .../src/layout/app-sidebar/nav-sub-menu.tsx | 22 -- .../app-sidebar/use-custom-sidebar-views.ts | 23 ++ 9 files changed, 384 insertions(+), 144 deletions(-) create mode 100644 apps/admin/src/layout/app-sidebar/nav-custom-views.test.tsx create mode 100644 apps/admin/src/layout/app-sidebar/nav-menu-item.test.tsx delete mode 100644 apps/admin/src/layout/app-sidebar/nav-sub-menu.tsx create mode 100644 apps/admin/src/layout/app-sidebar/use-custom-sidebar-views.ts diff --git a/apps/admin/src/layout/app-sidebar/nav-content.helpers.test.ts b/apps/admin/src/layout/app-sidebar/nav-content.helpers.test.ts index f2111070658..6e6e7df76e2 100644 --- a/apps/admin/src/layout/app-sidebar/nav-content.helpers.test.ts +++ b/apps/admin/src/layout/app-sidebar/nav-content.helpers.test.ts @@ -18,15 +18,27 @@ describe('isMembersNavActive', () => { membersForwardEnabled: false, isOnMembersForward: false, hasActiveMemberView: false, + isMembersExpanded: false, isLegacyMembersRouteActive: true })).toBe(true); }); - it('marks the base Members link inactive when a saved member view is active', () => { + it('marks the base Members link active when a saved member view is active but collapsed', () => { expect(isMembersNavActive({ membersForwardEnabled: true, isOnMembersForward: true, hasActiveMemberView: true, + isMembersExpanded: false, + isLegacyMembersRouteActive: false + })).toBe(true); + }); + + it('marks the base Members link inactive when a saved member view is active and expanded', () => { + expect(isMembersNavActive({ + membersForwardEnabled: true, + isOnMembersForward: true, + hasActiveMemberView: true, + isMembersExpanded: true, isLegacyMembersRouteActive: false })).toBe(false); }); @@ -36,6 +48,7 @@ describe('isMembersNavActive', () => { membersForwardEnabled: true, isOnMembersForward: true, hasActiveMemberView: false, + isMembersExpanded: false, isLegacyMembersRouteActive: false })).toBe(true); }); diff --git a/apps/admin/src/layout/app-sidebar/nav-content.helpers.ts b/apps/admin/src/layout/app-sidebar/nav-content.helpers.ts index 7640284e22a..ba946c9c852 100644 --- a/apps/admin/src/layout/app-sidebar/nav-content.helpers.ts +++ b/apps/admin/src/layout/app-sidebar/nav-content.helpers.ts @@ -7,11 +7,13 @@ export function isMembersNavActive({ membersForwardEnabled, isOnMembersForward, hasActiveMemberView, + isMembersExpanded, isLegacyMembersRouteActive }: { membersForwardEnabled: boolean; isOnMembersForward: boolean; hasActiveMemberView: boolean; + isMembersExpanded: boolean; isLegacyMembersRouteActive: boolean; }): boolean { if (!membersForwardEnabled) { @@ -19,7 +21,11 @@ export function isMembersNavActive({ } if (isOnMembersForward) { - return !hasActiveMemberView; + if (!hasActiveMemberView) { + return true; + } + + return !isMembersExpanded; } return isLegacyMembersRouteActive; diff --git a/apps/admin/src/layout/app-sidebar/nav-content.tsx b/apps/admin/src/layout/app-sidebar/nav-content.tsx index d6afca3599e..cc37303b17f 100644 --- a/apps/admin/src/layout/app-sidebar/nav-content.tsx +++ b/apps/admin/src/layout/app-sidebar/nav-content.tsx @@ -1,7 +1,6 @@ import React from "react" import { - Button, formatNumber, LucideIcon, SidebarGroup, @@ -13,20 +12,71 @@ import { useLocation } from "@tryghost/admin-x-framework"; import { useCurrentUser } from "@tryghost/admin-x-framework/api/current-user"; import { canManageMembers, canManageTags } from "@tryghost/admin-x-framework/api/users"; import { NavMenuItem } from "./nav-menu-item"; -import NavSubMenu from "./nav-sub-menu"; import { useMemberCount } from "./hooks/use-member-count"; import { useNavigationExpanded } from "./hooks/use-navigation-preferences"; import { NavCustomViews } from "./nav-custom-views"; import { NavMemberViews } from "./nav-member-views"; import { useMemberSidebarViews } from "./member-sidebar-views"; import { getMembersNavActiveRoutes, isMembersNavActive } from "./nav-content.helpers"; +import { useCustomSidebarViews } from "./use-custom-sidebar-views"; import { useEmberRouting } from "@/ember-bridge"; import { useFeatureFlag } from "@/hooks/use-feature-flag"; +function PostsNavItemContent({isActive, to}: {isActive: boolean; to: string}) { + return ( + <> + + + Posts + + + + + + ); +} + +function MembersNavItemContent({ + collapsible, + count, + isActive, + to +}: { + collapsible: boolean; + count: number | null | undefined; + isActive: boolean; + to: string; +}) { + return ( + <> + + + Members + + {count != null && ( + {(formatNumber as (value: number) => string)(count)} + )} + + ); +} + function NavContent({ ...props }: React.ComponentProps) { const { data: currentUser } = useCurrentUser(); - const [postsExpanded, setPostsExpanded] = useNavigationExpanded('posts'); + const [savedPostsExpanded, setPostsExpanded] = useNavigationExpanded('posts'); const [savedMembersExpanded, setMembersExpanded] = useNavigationExpanded('members'); + const postCustomViews = useCustomSidebarViews('posts'); const memberViews = useMemberSidebarViews(); const hasMemberViews = memberViews.length > 0; const location = useLocation(); @@ -37,89 +87,76 @@ function NavContent({ ...props }: React.ComponentProps) { const showTags = currentUser && canManageTags(currentUser); const showMembers = currentUser && canManageMembers(currentUser); + const isDraftPostsRouteActive = routing.isRouteActive('posts', {type: 'draft'}); + const isScheduledPostsRouteActive = routing.isRouteActive('posts', {type: 'scheduled'}); + const isPublishedPostsRouteActive = routing.isRouteActive('posts', {type: 'published'}); + const hasActivePostChild = isDraftPostsRouteActive || isScheduledPostsRouteActive || isPublishedPostsRouteActive || postCustomViews.some(view => view.isActive); + const postsExpanded = savedPostsExpanded; const isOnMembersForward = location.pathname === '/members-forward'; const hasActiveMemberView = isOnMembersForward && memberViews.some(view => view.isActive); - const membersExpanded = savedMembersExpanded || hasActiveMemberView; + const membersExpanded = savedMembersExpanded; const membersNavActive = isMembersNavActive({ membersForwardEnabled, isOnMembersForward, hasActiveMemberView, + isMembersExpanded: membersExpanded, isLegacyMembersRouteActive: routing.isRouteActive(getMembersNavActiveRoutes()) }); + const postsRoute = routing.getRouteUrl('posts'); + const isPostsRouteActive = routing.isRouteActive('posts'); + const postsNavActive = isPostsRouteActive || (!postsExpanded && hasActivePostChild); + const membersRoute = membersForwardEnabled ? 'members-forward' : routing.getRouteUrl('members'); return ( - - - - - Posts - - - + + - - + - {/* Posts submenu */} - - - - Drafts - - + + + + Drafts + + - - - Scheduled - - + + + Scheduled + + - - - Published - - + + + Published + + - - + + + ) { {showMembers && ( <> - - {membersForwardEnabled && hasMemberViews && ( - - )} - - - Members - - {memberCount != null && ( - {(formatNumber as (value: number) => string)(memberCount)} - )} - + + + - {membersForwardEnabled && hasMemberViews && ( - - - + + + + + ) : ( + + + )} )} diff --git a/apps/admin/src/layout/app-sidebar/nav-custom-views.test.tsx b/apps/admin/src/layout/app-sidebar/nav-custom-views.test.tsx new file mode 100644 index 00000000000..12ffffb2d23 --- /dev/null +++ b/apps/admin/src/layout/app-sidebar/nav-custom-views.test.tsx @@ -0,0 +1,57 @@ +// @vitest-environment jsdom + +import {describe, expect, it, vi} from 'vitest'; +import {renderHook} from '@testing-library/react'; +import {type SharedView} from './shared-views'; +import {useCustomSidebarViews} from './use-custom-sidebar-views'; + +interface EmberRoutingMock { + getRouteUrl: (route: 'posts' | 'pages', filter: Record) => string; + isRouteActive: (route: 'posts' | 'pages', filter: Record) => boolean; +} + +const {mockUseSharedViews, mockUseEmberRouting} = vi.hoisted(() => ({ + mockUseSharedViews: vi.fn<(route?: string) => SharedView[]>(), + mockUseEmberRouting: vi.fn<() => EmberRoutingMock>() +})); + +vi.mock('./shared-views', () => ({ + useSharedViews: mockUseSharedViews +})); + +vi.mock('./nav-saved-views', () => ({ + NavSavedViews: () => null +})); + +vi.mock('@/ember-bridge', () => ({ + useEmberRouting: mockUseEmberRouting +})); + +describe('useCustomSidebarViews', () => { + it('maps shared views to sidebar views using Ember routing', () => { + mockUseSharedViews.mockReturnValue([ + { + name: 'Drafts by me', + route: 'posts', + color: 'green', + filter: {type: 'draft', author: 'me'} + } + ]); + mockUseEmberRouting.mockReturnValue({ + getRouteUrl: vi.fn(() => 'posts?type=draft&author=me'), + isRouteActive: vi.fn(() => true) + }); + + const {result} = renderHook(() => useCustomSidebarViews('posts')); + + expect(result.current).toEqual([ + { + key: 'posts?type=draft&author=me', + name: 'Drafts by me', + to: 'posts?type=draft&author=me', + isActive: true, + color: 'green' + } + ]); + }); +}); diff --git a/apps/admin/src/layout/app-sidebar/nav-custom-views.tsx b/apps/admin/src/layout/app-sidebar/nav-custom-views.tsx index 8e24b07dd65..155af9da76c 100644 --- a/apps/admin/src/layout/app-sidebar/nav-custom-views.tsx +++ b/apps/admin/src/layout/app-sidebar/nav-custom-views.tsx @@ -1,29 +1,12 @@ -import { useMemo } from 'react'; import { NavSavedViews } from './nav-saved-views'; -import { useSharedViews } from './shared-views'; -import { useEmberRouting } from '@/ember-bridge'; +import { useCustomSidebarViews } from './use-custom-sidebar-views'; interface NavCustomViewsProps { route?: 'posts' | 'pages'; } export function NavCustomViews({ route = 'posts' }: NavCustomViewsProps) { - const routing = useEmberRouting(); - const sharedViews = useSharedViews(route); - - const customViews = useMemo(() => { - return sharedViews.map((view) => { - const to = routing.getRouteUrl(route, view.filter); - - return { - key: to, - name: view.name, - to, - isActive: routing.isRouteActive(route, view.filter), - color: view.color - }; - }); - }, [route, routing, sharedViews]); + const customViews = useCustomSidebarViews(route); return ; } diff --git a/apps/admin/src/layout/app-sidebar/nav-menu-item.test.tsx b/apps/admin/src/layout/app-sidebar/nav-menu-item.test.tsx new file mode 100644 index 00000000000..b9097a44d51 --- /dev/null +++ b/apps/admin/src/layout/app-sidebar/nav-menu-item.test.tsx @@ -0,0 +1,58 @@ +// @vitest-environment jsdom + +import {fireEvent, render, screen} from '@testing-library/react'; +import {describe, expect, it, vi} from 'vitest'; +import {NavMenuItem} from './nav-menu-item'; + +vi.mock('./use-is-active-link', () => ({ + useIsActiveLink: () => false +})); + +describe('NavMenuItem.Collapsible', () => { + it('wires the toggle button and collapsible menu through shared state', () => { + const onExpandedChange = vi.fn(); + + render( + + + Section + + +
Nested item
+
+
+ ); + + const toggle = screen.getByRole('button', {name: 'Toggle test section'}); + expect(toggle.getAttribute('aria-controls')).toBe('test-submenu'); + expect(toggle.getAttribute('aria-expanded')).toBe('true'); + expect(screen.getByText('Nested item').closest('#test-submenu')).not.toBeNull(); + + fireEvent.click(toggle); + + expect(onExpandedChange).toHaveBeenCalledWith(false); + }); + + it('unmounts nested items when collapsed', () => { + render( + + + Section + + +
Nested item
+
+
+ ); + + expect(screen.queryByText('Nested item')).not.toBeInTheDocument(); + }); +}); diff --git a/apps/admin/src/layout/app-sidebar/nav-menu-item.tsx b/apps/admin/src/layout/app-sidebar/nav-menu-item.tsx index 3f3db44d02a..f7e53f6dce9 100644 --- a/apps/admin/src/layout/app-sidebar/nav-menu-item.tsx +++ b/apps/admin/src/layout/app-sidebar/nav-menu-item.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { + Button, + LucideIcon, SidebarMenuButton, SidebarMenuItem, useSidebar @@ -14,6 +16,93 @@ function NavMenuItem({ children, ...props }: React.ComponentProps void | Promise; +} + +const NavMenuCollapsibleContext = React.createContext(null); + +function useNavMenuCollapsibleContext() { + const context = React.useContext(NavMenuCollapsibleContext); + + if (!context) { + throw new Error('NavMenuItem.Collapsible components must be used within NavMenuItem.Collapsible'); + } + + return context; +} + +interface NavMenuCollapsibleProps { + children: React.ReactNode; + expanded: boolean; + id: string; + onExpandedChange: (expanded: boolean) => void | Promise; +} + +function NavMenuCollapsible({children, expanded, id, onExpandedChange}: NavMenuCollapsibleProps) { + const value = { + expanded, + id, + onExpandedChange + }; + + return ( + + {children} + + ); +} + +interface NavMenuCollapsibleItemProps { + ariaLabel: string; + children: React.ReactNode; +} + +function NavMenuCollapsibleItem({ariaLabel, children}: NavMenuCollapsibleItemProps) { + const {expanded, id, onExpandedChange} = useNavMenuCollapsibleContext(); + + return ( + + + {children} + + ); +} + +interface NavMenuCollapsibleMenuProps { + children: React.ReactNode; +} + +function NavMenuCollapsibleMenu({children}: NavMenuCollapsibleMenuProps) { + const {expanded, id} = useNavMenuCollapsibleContext(); + + return ( +
+
+ {expanded ? children : null} +
+
+ ); +} + type NavMenuLinkProps = React.ComponentProps & { to?: string target?: string @@ -99,5 +188,8 @@ function NavMenuButton({ NavMenuItem.Link = NavMenuLink; NavMenuItem.Label = NavMenuLabel; NavMenuItem.Button = NavMenuButton; +NavMenuItem.Collapsible = NavMenuCollapsible; +NavMenuItem.CollapsibleItem = NavMenuCollapsibleItem; +NavMenuItem.CollapsibleMenu = NavMenuCollapsibleMenu; export { NavMenuItem, NavMenuLink, NavMenuLabel, NavMenuButton } diff --git a/apps/admin/src/layout/app-sidebar/nav-sub-menu.tsx b/apps/admin/src/layout/app-sidebar/nav-sub-menu.tsx deleted file mode 100644 index 34d4ae66bd0..00000000000 --- a/apps/admin/src/layout/app-sidebar/nav-sub-menu.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -interface NavSubMenuProps { - isExpanded: boolean; - children: React.ReactNode; - id?: string; -} - -function NavSubMenu({ isExpanded, children, id }: NavSubMenuProps) { - return ( -
-
- {children} -
-
- ); -} - -export default NavSubMenu; diff --git a/apps/admin/src/layout/app-sidebar/use-custom-sidebar-views.ts b/apps/admin/src/layout/app-sidebar/use-custom-sidebar-views.ts new file mode 100644 index 00000000000..13edb3a80d6 --- /dev/null +++ b/apps/admin/src/layout/app-sidebar/use-custom-sidebar-views.ts @@ -0,0 +1,23 @@ +import {useMemo} from 'react'; +import {type NavSavedView} from './nav-saved-views'; +import {useSharedViews} from './shared-views'; +import {useEmberRouting} from '@/ember-bridge'; + +export function useCustomSidebarViews(route: 'posts' | 'pages' = 'posts') { + const routing = useEmberRouting(); + const sharedViews = useSharedViews(route); + + return useMemo(() => { + return sharedViews.map((view) => { + const to = routing.getRouteUrl(route, view.filter); + + return { + key: to, + name: view.name, + to, + isActive: routing.isRouteActive(route, view.filter), + color: view.color + }; + }); + }, [route, routing, sharedViews]); +} From 24ad5110be577af6c77994617b358236a17539b9 Mon Sep 17 00:00:00 2001 From: Jonatan Svennberg Date: Wed, 25 Mar 2026 09:13:50 +0100 Subject: [PATCH 2/2] Fixed members-forward filter gating parity (#26932) closes https://linear.app/ghost/issue/BER-3456/responded-with-feedback-filter-is-missing-in-members-forward The email filter group and `Responded with feedback`filter now follows the same availability rules as in Ember. --- .../members/components/members-filters.tsx | 8 +--- .../members/use-member-filter-fields.test.ts | 39 ++++++++++++++++++- .../views/members/use-member-filter-fields.ts | 25 +++++------- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/apps/posts/src/views/members/components/members-filters.tsx b/apps/posts/src/views/members/components/members-filters.tsx index 3b57b68f6a1..596271bbc24 100644 --- a/apps/posts/src/views/members/components/members-filters.tsx +++ b/apps/posts/src/views/members/components/members-filters.tsx @@ -9,7 +9,6 @@ import { } from '../use-member-filter-fields'; import {getSettingValue, useBrowseSettings} from '@tryghost/admin-x-framework/api/settings'; import {getSiteTimezone} from '@src/utils/get-site-timezone'; -import {useBrowseConfig} from '@tryghost/admin-x-framework/api/config'; import {useBrowseLabels} from '@tryghost/admin-x-framework/api/labels'; import {useBrowseNewsletters} from '@tryghost/admin-x-framework/api/newsletters'; import {useBrowseOffers} from '@tryghost/admin-x-framework/api/offers'; @@ -55,15 +54,13 @@ const MembersFilters: React.FC = ({ const {data: offersData} = useBrowseOffers({}); const {data: newslettersData} = useBrowseNewsletters({searchParams: {limit: '100'}}); const {data: settingsData} = useBrowseSettings({}); - const {data: configData} = useBrowseConfig({}); const settings = settingsData?.settings || []; const paidMembersEnabled = getSettingValue(settings, 'paid_members_enabled') === true; - const emailAnalyticsEnabled = configData?.config?.emailAnalytics === true; + const emailFiltersEnabled = getSettingValue(settings, 'editor_default_email_recipients') !== 'disabled'; const membersTrackSources = getSettingValue(settings, 'members_track_sources') === true; const emailTrackOpens = getSettingValue(settings, 'email_track_opens') === true; const emailTrackClicks = getSettingValue(settings, 'email_track_clicks') === true; - const audienceFeedbackEnabled = configData?.config?.labs?.audienceFeedback === true; const siteTimezone = getSiteTimezone(settings); const labels = labelsData?.labels || []; @@ -102,7 +99,7 @@ const MembersFilters: React.FC = ({ hydratedNewsletterSlugs, hasMultipleTiers, paidMembersEnabled, - emailAnalyticsEnabled, + emailFiltersEnabled, labelsOptions: labels.map(label => ({value: label.slug, label: label.name})), tiersOptions: activePaidTiers.map(tier => ({value: tier.id, label: tier.name})), offers, @@ -117,7 +114,6 @@ const MembersFilters: React.FC = ({ membersTrackSources, emailTrackOpens, emailTrackClicks, - audienceFeedbackEnabled, siteTimezone }); diff --git a/apps/posts/src/views/members/use-member-filter-fields.test.ts b/apps/posts/src/views/members/use-member-filter-fields.test.ts index f9d14a9f2df..f598982720c 100644 --- a/apps/posts/src/views/members/use-member-filter-fields.test.ts +++ b/apps/posts/src/views/members/use-member-filter-fields.test.ts @@ -26,7 +26,7 @@ describe('useMemberFilterFields', () => { labelsOptions: [{value: 'vip', label: 'VIP'}], newsletters: [{slug: 'weekly', name: 'Weekly', status: 'active'}], paidMembersEnabled: true, - emailAnalyticsEnabled: true, + emailFiltersEnabled: true, postResourceOptions: [{value: 'post_1', label: 'Welcome'}], onPostResourceSearchChange: vi.fn(), postResourceSearchValue: 'wel', @@ -39,7 +39,6 @@ describe('useMemberFilterFields', () => { membersTrackSources: true, emailTrackOpens: true, emailTrackClicks: true, - audienceFeedbackEnabled: true, siteTimezone: 'UTC' })); @@ -72,6 +71,42 @@ describe('useMemberFilterFields', () => { }); }); + it('shows the Email group when email sending is enabled', () => { + const {result} = renderHook(() => useMemberFilterFields({ + emailFiltersEnabled: true, + siteTimezone: 'UTC' + })); + + const emailGroup = result.current.find(group => group.group === 'Email'); + + expect(emailGroup?.fields.map(field => field.key)).toEqual([ + 'email_count', + 'email_opened_count', + 'emails.post_id', + 'newsletter_feedback' + ]); + }); + + it('keeps the feedback filter visible without a separate feature flag', () => { + const {result} = renderHook(() => useMemberFilterFields({ + emailFiltersEnabled: true, + emailResourceOptions: [{value: 'email_1', label: 'Launch'}], + onEmailResourceSearchChange: vi.fn(), + emailResourceSearchValue: 'lau', + emailResourceLoading: false, + siteTimezone: 'UTC' + })); + + const emailFields = result.current.find(group => group.group === 'Email')?.fields ?? []; + const feedbackField = emailFields.find(field => field.key === 'newsletter_feedback'); + + expect(feedbackField).toMatchObject({ + options: [{value: 'email_1', label: 'Launch'}], + searchValue: 'lau', + isLoading: false + }); + }); + it('hydrates newsletter pattern fields with runtime labels', () => { const {result} = renderHook(() => useMemberFilterFields({ newsletters: [ diff --git a/apps/posts/src/views/members/use-member-filter-fields.ts b/apps/posts/src/views/members/use-member-filter-fields.ts index 5f1f36f38dd..196fe6db918 100644 --- a/apps/posts/src/views/members/use-member-filter-fields.ts +++ b/apps/posts/src/views/members/use-member-filter-fields.ts @@ -12,7 +12,7 @@ interface UseMemberFilterFieldsOptions { hydratedNewsletterSlugs?: string[]; hasMultipleTiers?: boolean; paidMembersEnabled?: boolean; - emailAnalyticsEnabled?: boolean; + emailFiltersEnabled?: boolean; postResourceOptions?: FilterOption[]; onPostResourceSearchChange?: (search: string) => void; postResourceSearchValue?: string; @@ -25,7 +25,6 @@ interface UseMemberFilterFieldsOptions { membersTrackSources?: boolean; emailTrackOpens?: boolean; emailTrackClicks?: boolean; - audienceFeedbackEnabled?: boolean; siteTimezone?: string; } @@ -295,7 +294,7 @@ export function useMemberFilterFields({ hydratedNewsletterSlugs = [], hasMultipleTiers = false, paidMembersEnabled = false, - emailAnalyticsEnabled = false, + emailFiltersEnabled = false, postResourceOptions = [], onPostResourceSearchChange, postResourceSearchValue, @@ -308,7 +307,6 @@ export function useMemberFilterFields({ membersTrackSources = false, emailTrackOpens = false, emailTrackClicks = false, - audienceFeedbackEnabled = false, siteTimezone = 'UTC' }: UseMemberFilterFieldsOptions): FilterFieldGroup[] { return useMemo(() => { @@ -430,7 +428,7 @@ export function useMemberFilterFields({ groups.push({group: 'Subscription', fields: subscriptionFields}); } - if (emailAnalyticsEnabled) { + if (emailFiltersEnabled) { const emailFields: FilterFieldConfig[] = [ createFieldConfig('email_count', {}, NUMBER_OPERATOR_LABELS), createFieldConfig('email_opened_count', {}, NUMBER_OPERATOR_LABELS) @@ -465,22 +463,19 @@ export function useMemberFilterFields({ ))); } - if (audienceFeedbackEnabled) { - emailFields.push(createFieldConfig('newsletter_feedback', createSearchableFieldOverrides( - emailResourceOptions, - onEmailResourceSearchChange, - emailResourceSearchValue, - emailResourceLoading - ))); - } + emailFields.push(createFieldConfig('newsletter_feedback', createSearchableFieldOverrides( + emailResourceOptions, + onEmailResourceSearchChange, + emailResourceSearchValue, + emailResourceLoading + ))); groups.push({group: 'Email', fields: emailFields}); } return groups; }, [ - audienceFeedbackEnabled, - emailAnalyticsEnabled, + emailFiltersEnabled, emailResourceLoading, emailResourceOptions, emailResourceSearchValue,