@@ -3,6 +3,9 @@ import React, { useContext, useMemo } from 'react';
33import { FeedSettingsEditContext } from '../FeedSettingsEditContext' ;
44import useFeedSettings from '../../../../hooks/useFeedSettings' ;
55import { useAdvancedSettings } from '../../../../hooks/feed/useAdvancedSettings' ;
6+ import { useConditionalFeature , useToastNotification } from '../../../../hooks' ;
7+ import { useLogContext } from '../../../../contexts/LogContext' ;
8+ import { useSettingsContext } from '../../../../contexts/SettingsContext' ;
69import {
710 getAdvancedContentTypes ,
811 getContentCurationList ,
@@ -14,21 +17,33 @@ import {
1417 TypographyType ,
1518} from '../../../typography/Typography' ;
1619import { FilterCheckbox } from '../../../fields/FilterCheckbox' ;
20+ import { Switch } from '../../../fields/Switch' ;
1721import { FeedType } from '../../../../graphql/feed' ;
22+ import { featureNoAiFeed } from '../../../../lib/featureManagement' ;
23+ import { SidebarSettingsFlags } from '../../../../graphql/settings' ;
24+ import { labels } from '../../../../lib/labels' ;
25+ import { LogEvent , Origin , TargetId } from '../../../../lib/log' ;
1826
1927export const TOGGLEABLE_TYPES = [ 'Videos' , 'Polls' , 'Social' ] ;
2028const CUSTOM_FEEDS_ONLY = [ 'Article' ] ;
2129const ADVANCED_SETTINGS_KEY = 'advancedSettings' ;
2230
2331export const FeedSettingsContentPreferencesSection = ( ) : ReactElement => {
2432 const { feed, editFeedSettings } = useContext ( FeedSettingsEditContext ) ;
33+ const { flags, updateFlag } = useSettingsContext ( ) ;
34+ const { displayToast } = useToastNotification ( ) ;
35+ const { logEvent } = useLogContext ( ) ;
2536 const { advancedSettings } = useFeedSettings ( { feedId : feed ?. id } ) ;
2637 const {
2738 selectedSettings,
2839 onToggleSettings,
2940 checkSourceBlocked,
3041 onToggleSource,
3142 } = useAdvancedSettings ( { feedId : feed ?. id } ) ;
43+ const { value : isNoAiFeatureEnabled } = useConditionalFeature ( {
44+ feature : featureNoAiFeed ,
45+ shouldEvaluate : feed ?. type === FeedType . Main ,
46+ } ) ;
3247 const toggleableTypes = useMemo (
3348 ( ) =>
3449 getAdvancedContentTypes (
@@ -63,7 +78,12 @@ export const FeedSettingsContentPreferencesSection = (): ReactElement => {
6378 </ Typography >
6479 </ div >
6580 < div className = "flex flex-col" >
66- { toggleableTypes . map ( ( { id, title, defaultEnabledState } ) => {
81+ { toggleableTypes . map ( ( setting ) => {
82+ if ( ! setting ) {
83+ return null ;
84+ }
85+
86+ const { id, title, defaultEnabledState } = setting ;
6787 const isDisabled =
6888 CUSTOM_FEEDS_ONLY . includes ( title ) &&
6989 feed ?. type !== FeedType . Custom ;
@@ -93,6 +113,47 @@ export const FeedSettingsContentPreferencesSection = (): ReactElement => {
93113 } ) }
94114 </ div >
95115 </ div >
116+ { feed ?. type === FeedType . Main && isNoAiFeatureEnabled && (
117+ < div className = "flex flex-col gap-4" >
118+ < div className = "flex flex-col gap-1" >
119+ < Typography bold type = { TypographyType . Body } >
120+ No AI mode
121+ </ Typography >
122+ < Typography
123+ type = { TypographyType . Callout }
124+ color = { TypographyColor . Tertiary }
125+ >
126+ Keep AI topics filtered out across My Feed. You can hide the
127+ homepage toggle once this is set.
128+ </ Typography >
129+ </ div >
130+ < Switch
131+ inputId = "no-ai-feed-preference-switch"
132+ name = "no_ai_feed_preference"
133+ compact = { false }
134+ checked = { flags ?. noAiFeedEnabled ?? false }
135+ onClick = { ( ) => {
136+ const newState = ! ( flags ?. noAiFeedEnabled ?? false ) ;
137+
138+ editFeedSettings ( ( ) =>
139+ updateFlag ( SidebarSettingsFlags . NoAiFeedEnabled , newState ) ,
140+ ) ;
141+ displayToast (
142+ newState ? labels . feed . noAi . hidden : labels . feed . noAi . visible ,
143+ ) ;
144+ logEvent ( {
145+ event_name : LogEvent . ToggleNoAiFeed ,
146+ target_id : newState ? TargetId . On : TargetId . Off ,
147+ extra : JSON . stringify ( {
148+ origin : Origin . Settings ,
149+ } ) ,
150+ } ) ;
151+ } }
152+ >
153+ Keep AI topics filtered out
154+ </ Switch >
155+ </ div >
156+ ) }
96157 < div className = "flex flex-col gap-4" >
97158 < div className = "flex flex-col gap-1" >
98159 < Typography bold type = { TypographyType . Body } >
@@ -105,20 +166,28 @@ export const FeedSettingsContentPreferencesSection = (): ReactElement => {
105166 Pick the categories of content you'd like to see in your feed.
106167 </ Typography >
107168 </ div >
108- { contentSourceList ?. map ( ( { id, title, description, options } ) => (
109- < FilterCheckbox
110- key = { id }
111- name = { `${ ADVANCED_SETTINGS_KEY } -${ id } ` }
112- checked = { ! checkSourceBlocked ( options . source ) }
113- description = { description }
114- onToggleCallback = { ( ) =>
115- editFeedSettings ( ( ) => onToggleSource ( options . source ) )
116- }
117- descriptionClassName = "text-text-tertiary"
118- >
119- < Typography bold > { title } </ Typography >
120- </ FilterCheckbox >
121- ) ) }
169+ { contentSourceList ?. map ( ( { id, title, description, options } ) => {
170+ if ( ! options ?. source ) {
171+ return null ;
172+ }
173+
174+ const { source } = options ;
175+
176+ return (
177+ < FilterCheckbox
178+ key = { id }
179+ name = { `${ ADVANCED_SETTINGS_KEY } -${ id } ` }
180+ checked = { ! checkSourceBlocked ( source ) }
181+ description = { description }
182+ onToggleCallback = { ( ) =>
183+ editFeedSettings ( ( ) => onToggleSource ( source ) )
184+ }
185+ descriptionClassName = "text-text-tertiary"
186+ >
187+ < Typography bold > { title } </ Typography >
188+ </ FilterCheckbox >
189+ ) ;
190+ } ) }
122191 { contentCurationList ?. map (
123192 ( { id, title, description, defaultEnabledState } ) => (
124193 < FilterCheckbox
0 commit comments