1+ import { usePersistentInMemoryState } from "web/hooks/use-persistent-in-memory-state" ;
2+ import {
3+ notification_destination_types ,
4+ notification_preference ,
5+ notification_preferences
6+ } from "common/user-notification-preferences" ;
7+ import { useCallback } from "react" ;
8+ import { debounce } from "lodash" ;
9+ import { api } from "web/lib/api" ;
10+ import { MultiSelectAnswers } from "web/components/answers/answer-compatibility-question-content" ;
11+ import { usePrivateUser } from "web/hooks/use-user" ;
12+
13+ export const NotificationSettings = ( ) => {
14+ const privateUser = usePrivateUser ( )
15+ if ( ! privateUser ) return null
16+
17+ const [ prefs , setPrefs ] =
18+ usePersistentInMemoryState < notification_preferences > (
19+ privateUser . notificationPreferences ,
20+ 'notification-preferences'
21+ )
22+
23+ const notificationTypes : {
24+ type : notification_preference
25+ question : string
26+ } [ ] = [
27+ {
28+ type : 'new_match' ,
29+ question :
30+ '... matches with you?' ,
31+ } ,
32+ {
33+ type : 'new_message' ,
34+ question : '... sends you a new message?' ,
35+ } ,
36+ // {
37+ // type: 'new_profile_like',
38+ // question: '... likes your profile?',
39+ // },
40+ {
41+ type : 'new_endorsement' ,
42+ question : '... endorses you?' ,
43+ } ,
44+ // {
45+ // type: 'new_profile_ship',
46+ // question: '... ships you?',
47+ // },
48+ {
49+ type : 'tagged_user' ,
50+ question : '... mentions you?' ,
51+ } ,
52+ // {
53+ // type: 'on_new_follow',
54+ // question: '... follows you?',
55+ // },
56+ {
57+ type : 'new_search_alerts' ,
58+ question : 'Alerts from bookmarked searches?' ,
59+ } ,
60+ {
61+ type : 'opt_out_all' ,
62+ question :
63+ 'Opt out of all notifications? (You can always change this later)' ,
64+ } ,
65+ ]
66+
67+ return (
68+ < div className = "mx-auto max-w-2xl" >
69+ < div className = "flex flex-col gap-8 p-4" >
70+ < p className = "text-ink-700 font-medium" > Where do you want to be notified when someone</ p >
71+ { notificationTypes . map ( ( { type, question} ) => (
72+ < NotificationOption
73+ key = { type }
74+ type = { type }
75+ question = { question }
76+ selected = { prefs [ type ] }
77+ onUpdate = { ( selected ) => {
78+ setPrefs ( ( prevPrefs ) => ( { ...prevPrefs , [ type ] : selected } ) )
79+ } }
80+ />
81+ ) ) }
82+ </ div >
83+ </ div >
84+ )
85+ }
86+
87+ const NotificationOption = ( props : {
88+ type : notification_preference
89+ question : string
90+ selected : notification_destination_types [ ]
91+ onUpdate : ( selected : notification_destination_types [ ] ) => void
92+ } ) => {
93+ const { type, question, selected, onUpdate} = props
94+
95+ const getSelectedValues = ( destinations : string [ ] ) => {
96+ const values : number [ ] = [ ]
97+ if ( ( destinations ?? [ ] ) . includes ( 'email' ) ) values . push ( 0 )
98+ if ( ( destinations ?? [ ] ) . includes ( 'browser' ) ) values . push ( 1 )
99+ return values
100+ }
101+
102+ const setValue = async ( value : number [ ] ) => {
103+ const newDestinations : notification_destination_types [ ] = [ ]
104+ if ( value . includes ( 0 ) ) newDestinations . push ( 'email' )
105+ if ( value . includes ( 1 ) ) newDestinations . push ( 'browser' )
106+
107+ onUpdate ( newDestinations )
108+ save ( selected , newDestinations )
109+ }
110+
111+ const save = useCallback (
112+ debounce (
113+ (
114+ oldDestinations : notification_destination_types [ ] ,
115+ newDestinations : notification_destination_types [ ]
116+ ) => {
117+ // for each medium, if it changed, trigger a save
118+ const mediums = [ 'email' , 'browser' ] as const
119+ mediums . forEach ( ( medium ) => {
120+ const wasEnabled = oldDestinations . includes ( medium )
121+ const isEnabled = newDestinations . includes ( medium )
122+ if ( wasEnabled !== isEnabled ) {
123+ api ( 'update-notif-settings' , {
124+ type,
125+ medium,
126+ enabled : isEnabled ,
127+ } )
128+ }
129+ } )
130+ } ,
131+ 500
132+ ) ,
133+ [ ]
134+ )
135+
136+ return (
137+ < div className = "flex flex-col gap-2" >
138+ < div className = "text-ink-700 font-medium" > { question } </ div >
139+ < MultiSelectAnswers
140+ options = { [ 'By email' , 'On notifications page' ] }
141+ values = { getSelectedValues ( selected ) }
142+ setValue = { setValue }
143+ />
144+ </ div >
145+ )
146+ }
0 commit comments