Skip to content

Commit 0831970

Browse files
Copilotdkhalife
andauthored
Move notification settings draft from React state to Redux (#204)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: dkhalife <[email protected]>
1 parent 9ca89c2 commit 0831970

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

src/store/userSlice.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export interface UserState {
1212
status: SyncState
1313
lastFetched: number | null
1414
error: string | null
15+
draftNotificationSettings: {
16+
provider: NotificationType
17+
triggers: NotificationTriggerOptions
18+
}
1519
}
1620

1721
const initialState: UserState = {
@@ -31,6 +35,16 @@ const initialState: UserState = {
3135
status: 'loading',
3236
lastFetched: null,
3337
error: null,
38+
draftNotificationSettings: {
39+
provider: {
40+
provider: 'none'
41+
},
42+
triggers: {
43+
pre_due: false,
44+
due_date: false,
45+
overdue: false,
46+
},
47+
},
3448
}
3549

3650
export const fetchUser = createAsyncThunk('user/fetchUser', async () => {
@@ -55,6 +69,19 @@ const userSlice = createSlice({
5569
) {
5670
state.profile.notifications.provider = action.payload.provider
5771
state.profile.notifications.triggers = action.payload.triggers
72+
// Keep draft in sync when updated via websocket
73+
state.draftNotificationSettings.provider = action.payload.provider
74+
state.draftNotificationSettings.triggers = action.payload.triggers
75+
},
76+
setNotificationSettingsDraft(
77+
state,
78+
action: PayloadAction<{
79+
provider: NotificationType
80+
triggers: NotificationTriggerOptions
81+
}>,
82+
) {
83+
state.draftNotificationSettings.provider = action.payload.provider
84+
state.draftNotificationSettings.triggers = action.payload.triggers
5885
},
5986
},
6087
extraReducers: builder => {
@@ -68,6 +95,9 @@ const userSlice = createSlice({
6895
state.profile = action.payload
6996
state.lastFetched = Date.now()
7097
state.error = null
98+
// Initialize draft with the fetched profile's notification settings
99+
state.draftNotificationSettings.provider = action.payload.notifications.provider
100+
state.draftNotificationSettings.triggers = action.payload.notifications.triggers
71101
})
72102
.addCase(fetchUser.rejected, (state, action) => {
73103
state.status = 'failed'
@@ -96,6 +126,8 @@ const userSlice = createSlice({
96126
},
97127
})
98128

129+
export const { setNotificationSettingsDraft } = userSlice.actions
130+
99131
export const userReducer = userSlice.reducer
100132

101133
const { notificationSettingsUpdated } = userSlice.actions

src/views/Notifications/NotificationOptions.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export class NotificationOptions extends React.Component<
3333
}
3434
}
3535

36+
componentDidUpdate(prevProps: NotificationOptionsProps) {
37+
if (prevProps.notification !== this.props.notification) {
38+
this.setState({
39+
notification: this.props.notification,
40+
})
41+
}
42+
}
43+
3644
private onNotificationOptionChange = (item: NotificationTriggerOption) => {
3745
const { notification } = this.state
3846

src/views/Notifications/NotificationSettings.tsx

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,19 @@ import {
2222
} from '@/models/notifications'
2323
import { RootState, AppDispatch } from '@/store/store'
2424
import { connect } from 'react-redux'
25-
import { updateNotificationSettings } from '@/store/userSlice'
25+
import { updateNotificationSettings, setNotificationSettingsDraft } from '@/store/userSlice'
2626

2727
type NotificationSettingProps = {
28-
initialType: NotificationType
29-
initialOptions: NotificationTriggerOptions
28+
draftType: NotificationType
29+
draftOptions: NotificationTriggerOptions
3030

31+
setNotificationSettingsDraft: (provider: NotificationType, triggers: NotificationTriggerOptions) => void
3132
updateNotificationSettings: (type: NotificationType, options: NotificationTriggerOptions) => Promise<any>
3233
}
3334

3435
interface NotificationSettingState {
3536
saved: boolean
36-
type: NotificationType
3737
error: string
38-
options: NotificationTriggerOptions
3938
}
4039

4140
class NotificationSettingsImpl extends React.Component<
@@ -48,8 +47,6 @@ class NotificationSettingsImpl extends React.Component<
4847
this.state = {
4948
saved: true,
5049
error: '',
51-
type: props.initialType,
52-
options: props.initialOptions,
5350
}
5451
}
5552

@@ -60,9 +57,9 @@ class NotificationSettingsImpl extends React.Component<
6057
const provider = option as NotificationProvider
6158
const type = getDefaultTypeForProvider(provider)
6259

60+
this.props.setNotificationSettingsDraft(type, this.props.draftOptions)
6361
this.setState({
6462
saved: false,
65-
type,
6663
})
6764
}
6865

@@ -71,56 +68,65 @@ class NotificationSettingsImpl extends React.Component<
7168
option: SelectValue<string, false>,
7269
) => {
7370
const method = option as WebhookMethod
74-
const type = this.state.type as NotificationTypeWebhook
71+
const type = this.props.draftType as NotificationTypeWebhook
7572

76-
this.setState({
77-
saved: false,
78-
type: {
73+
this.props.setNotificationSettingsDraft(
74+
{
7975
...type,
8076
method,
8177
},
78+
this.props.draftOptions
79+
)
80+
this.setState({
81+
saved: false,
8282
})
8383
}
8484

8585
private onURLChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
8686
const url = e.target.value
8787

88-
const type = this.state.type as
88+
const type = this.props.draftType as
8989
| NotificationTypeWebhook
9090
| NotificationTypeGotify
9191

92-
this.setState({
93-
saved: false,
94-
type: {
92+
this.props.setNotificationSettingsDraft(
93+
{
9594
...type,
9695
url,
9796
},
97+
this.props.draftOptions
98+
)
99+
this.setState({
100+
saved: false,
98101
})
99102
}
100103

101104
private onGotifyTokenChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
102105
const token = e.target.value
103106

104-
const type = this.state.type as NotificationTypeGotify
107+
const type = this.props.draftType as NotificationTypeGotify
105108

106-
this.setState({
107-
saved: false,
108-
type: {
109+
this.props.setNotificationSettingsDraft(
110+
{
109111
...type,
110112
token,
111113
},
114+
this.props.draftOptions
115+
)
116+
this.setState({
117+
saved: false,
112118
})
113119
}
114120

115121
private onTriggersChanged = (options: NotificationTriggerOptions) => {
122+
this.props.setNotificationSettingsDraft(this.props.draftType, options)
116123
this.setState({
117124
saved: false,
118-
options,
119125
})
120126
}
121127

122128
private onSaveClicked = async () => {
123-
const { type, options } = this.state
129+
const { draftType: type, draftOptions: options } = this.props
124130
if (type.provider === 'webhook') {
125131
const isValidURL = type.url.match(/^https?:\/\/[^\s/$.?#].[^\s]*$/i)
126132
if (!isValidURL) {
@@ -152,7 +158,8 @@ class NotificationSettingsImpl extends React.Component<
152158
}
153159

154160
render(): React.ReactNode {
155-
const { error, type, options, saved } = this.state
161+
const { error, saved } = this.state
162+
const { draftType: type, draftOptions: options } = this.props
156163

157164
const placeholderURL =
158165
type.provider === 'webhook'
@@ -254,15 +261,15 @@ class NotificationSettingsImpl extends React.Component<
254261
}
255262

256263
const mapStateToProps = (state: RootState) => {
257-
const userNotifications = state.user.profile.notifications
258-
259264
return {
260-
initialType: userNotifications.provider,
261-
initialOptions: userNotifications.triggers,
265+
draftType: state.user.draftNotificationSettings.provider,
266+
draftOptions: state.user.draftNotificationSettings.triggers,
262267
}
263268
}
264269

265270
const mapDispatchToProps = (dispatch: AppDispatch) => ({
271+
setNotificationSettingsDraft: (provider: NotificationType, triggers: NotificationTriggerOptions) =>
272+
dispatch(setNotificationSettingsDraft({ provider, triggers })),
266273
updateNotificationSettings: (type: NotificationType, options: NotificationTriggerOptions) =>
267274
dispatch(updateNotificationSettings({ type, options })),
268275
})

0 commit comments

Comments
 (0)