Skip to content

Commit b9ed6f6

Browse files
authored
feat: Add redux and API layer support for User Profile (#5023)
1 parent e12345f commit b9ed6f6

File tree

6 files changed

+129
-56
lines changed

6 files changed

+129
-56
lines changed

src/accounts/context/userAccount.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ import {
1515
} from 'src/shared/copy/notifications'
1616

1717
// Utils
18-
import {
19-
getAccounts,
20-
putAccountsDefault,
21-
patchAccount,
22-
} from 'src/client/unityRoutes'
18+
import {getAccounts, patchAccount} from 'src/client/unityRoutes'
2319

2420
// Metrics
2521
import {event} from 'src/cloud/utils/reporting'
@@ -29,6 +25,9 @@ import {isFlagEnabled} from 'src/shared/utils/featureFlag'
2925
import {setMe} from 'src/me/actions/creators'
3026
import {MeState} from 'src/me/reducers'
3127

28+
// API
29+
import {updateDefaultQuartzAccount} from 'src/identity/apis/auth'
30+
3231
export type Props = {
3332
children: JSX.Element
3433
}
@@ -108,14 +107,9 @@ export const UserAccountProvider: FC<Props> = React.memo(({children}) => {
108107
const accountName = getAccountNameById(newDefaultAcctId)
109108

110109
try {
111-
const resp = await putAccountsDefault({data: {id: newDefaultAcctId}})
110+
await updateDefaultQuartzAccount(newDefaultAcctId)
112111
setDefaultAccountId(newDefaultAcctId)
113-
114-
if (resp.status !== 204) {
115-
dispatch(notify(accountDefaultSettingError(accountName)))
116-
} else {
117-
dispatch(notify(accountDefaultSettingSuccess(accountName)))
118-
}
112+
dispatch(notify(accountDefaultSettingSuccess(accountName)))
119113
} catch (error) {
120114
dispatch(notify(accountDefaultSettingError(accountName)))
121115
}

src/identity/apis/auth.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getOrg,
77
getOrgs,
88
putOrgsDefault,
9+
putAccountsDefault,
910
Account,
1011
Identity,
1112
IdentityAccount,
@@ -227,6 +228,23 @@ export const fetchAccountDetails = async (
227228
return accountDetails
228229
}
229230

231+
// change the user's default account
232+
export const updateDefaultQuartzAccount = async (
233+
accountId: number
234+
): Promise<void> => {
235+
const response = await putAccountsDefault({
236+
data: {
237+
id: accountId,
238+
},
239+
})
240+
241+
if (response.status === 500) {
242+
throw new ServerError(response.data.message)
243+
}
244+
245+
// success status code is 204; no data in response.body is expected.
246+
}
247+
230248
// fetch details about user's current organization
231249
export const fetchOrgDetails = async (orgId: string): Promise<Organization> => {
232250
const response = await getOrg({orgId})
@@ -259,7 +277,7 @@ export const fetchQuartzOrgs = async (): Promise<OrganizationSummaries> => {
259277
}
260278

261279
// change default organization for a given account
262-
export const putDefaultQuartzOrg = async (orgId: string) => {
280+
export const updateDefaultQuartzOrg = async (orgId: string) => {
263281
const response = await putOrgsDefault({
264282
data: {
265283
id: orgId,

src/identity/quartzOrganizations/actions/creators/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import {RemoteDataState} from 'src/types'
33

44
export const SET_QUARTZ_ORGANIZATIONS = 'SET_QUARTZ_ORGANIZATIONS'
55
export const SET_QUARTZ_ORGANIZATIONS_STATUS = 'SET_QUARTZ_ORGANIZATIONS_STATUS'
6+
export const SET_QUARTZ_DEFAULT_ORG = 'SET_QUARTZ_DEFAULT_ORG'
67

78
export type Actions =
9+
| ReturnType<typeof setQuartzDefaultOrg>
810
| ReturnType<typeof setQuartzOrganizations>
911
| ReturnType<typeof setQuartzOrganizationsStatus>
1012

@@ -21,3 +23,13 @@ export const setQuartzOrganizationsStatus = (status: RemoteDataState) =>
2123
type: SET_QUARTZ_ORGANIZATIONS_STATUS,
2224
status: status,
2325
} as const)
26+
27+
export const setQuartzDefaultOrg = (
28+
oldDefaultOrgId: string,
29+
newDefaultOrgId: string
30+
) =>
31+
({
32+
type: SET_QUARTZ_DEFAULT_ORG,
33+
oldDefaultOrgId: oldDefaultOrgId,
34+
newDefaultOrgId: newDefaultOrgId,
35+
} as const)

src/identity/quartzOrganizations/actions/thunks/index.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import {Dispatch} from 'react'
22

33
// API
4-
import {fetchQuartzOrgs} from 'src/identity/apis/auth'
4+
import {fetchQuartzOrgs, updateDefaultQuartzOrg} from 'src/identity/apis/auth'
55

66
// Actions
77
import {
88
Actions as QuartzOrganizationActions,
9+
setQuartzDefaultOrg,
910
setQuartzOrganizations,
1011
setQuartzOrganizationsStatus,
1112
} from 'src/identity/quartzOrganizations/actions/creators'
1213
import {PublishNotificationAction} from 'src/shared/actions/notifications'
1314

1415
// Types
1516
import {RemoteDataState} from 'src/types'
17+
import {OrganizationSummaries} from 'src/client/unityRoutes'
18+
1619
type Actions = QuartzOrganizationActions | PublishNotificationAction
20+
type DefaultOrg = OrganizationSummaries[number]
1721

1822
// Notifications
1923
import {notify} from 'src/shared/actions/notifications'
@@ -33,3 +37,21 @@ export const getQuartzOrganizationsThunk = () => async (
3337
dispatch(notify(updateQuartzOrganizationsFailed()))
3438
}
3539
}
40+
41+
export const updateDefaultOrgThunk = (
42+
oldDefaultOrg: DefaultOrg,
43+
newDefaultOrg: DefaultOrg
44+
) => async (dispatch: Dispatch<Actions>) => {
45+
try {
46+
dispatch(setQuartzOrganizationsStatus(RemoteDataState.Loading))
47+
48+
await updateDefaultQuartzOrg(newDefaultOrg.id)
49+
50+
dispatch(setQuartzDefaultOrg(oldDefaultOrg.id, newDefaultOrg.id))
51+
52+
dispatch(setQuartzOrganizationsStatus(RemoteDataState.Done))
53+
} catch (err) {
54+
dispatch(setQuartzOrganizationsStatus(RemoteDataState.Error))
55+
throw Error(err)
56+
}
57+
}

src/identity/quartzOrganizations/reducers/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Actions,
44
SET_QUARTZ_ORGANIZATIONS,
55
SET_QUARTZ_ORGANIZATIONS_STATUS,
6+
SET_QUARTZ_DEFAULT_ORG,
67
} from 'src/identity/quartzOrganizations/actions/creators'
78
import {emptyOrg} from 'src/identity/components/GlobalHeader/DefaultEntities'
89
import produce from 'immer'
@@ -24,5 +25,22 @@ export default (state = initialState, action: Actions): QuartzOrganizations =>
2425
draftState.status = action.status
2526
return
2627
}
28+
29+
case SET_QUARTZ_DEFAULT_ORG: {
30+
const {oldDefaultOrgId, newDefaultOrgId} = action
31+
32+
if (oldDefaultOrgId !== newDefaultOrgId) {
33+
draftState.orgs.forEach(org => {
34+
if (org.id === oldDefaultOrgId) {
35+
org.isDefault = false
36+
}
37+
38+
if (org.id === newDefaultOrgId) {
39+
org.isDefault = true
40+
}
41+
})
42+
}
43+
return
44+
}
2745
}
2846
})

src/shared/copy/notifications/categories/accounts-users-orgs.ts

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,23 @@ import {
44
defaultSuccessNotification,
55
} from 'src/shared/copy/notifications'
66

7+
export const accountDefaultSettingError = (
8+
accountName: string
9+
): Notification => ({
10+
...defaultErrorNotification,
11+
message: `Account "${accountName}" was not set as the default account. The default is unchanged.`,
12+
})
13+
714
export const accountDefaultSettingSuccess = (
815
accountName: string
916
): Notification => ({
1017
...defaultSuccessNotification,
1118
message: `Account "${accountName}" was successfully set as the default account`,
1219
})
1320

14-
export const accountDefaultSettingError = (
15-
accountName: string
16-
): Notification => ({
21+
export const accountRenameError = (accountName: string): Notification => ({
1722
...defaultErrorNotification,
18-
message: `Account "${accountName}" was not set as the default account; the default is unchanged`,
23+
message: `Account "${accountName}" was not renamed; the rename update failed`,
1924
})
2025

2126
export const accountRenameSuccess = (
@@ -26,105 +31,104 @@ export const accountRenameSuccess = (
2631
message: `Account "${oldAccountName}" was successfully renamed to "${newAccountName}"`,
2732
})
2833

29-
export const accountRenameError = (accountName: string): Notification => ({
34+
export const inviteFailed = (): Notification => ({
3035
...defaultErrorNotification,
31-
message: `Account "${accountName}" was not renamed; the rename update failed`,
36+
message: `invite failed`,
3237
})
3338

34-
export const orgCreateSuccess = (): Notification => ({
35-
...defaultSuccessNotification,
36-
message: 'Organization was successfully created',
39+
export const invitationResentFailed = (): Notification => ({
40+
...defaultErrorNotification,
41+
message: `Error sending invitation`,
3742
})
3843

39-
export const orgCreateFailed = (): Notification => ({
40-
...defaultErrorNotification,
41-
message: 'Failed to create organization',
44+
export const invitationResentSuccessful = (): Notification => ({
45+
...defaultSuccessNotification,
46+
message: `Invitation Re-sent`,
4247
})
4348

44-
export const orgEditSuccess = (): Notification => ({
49+
export const inviteSent = (): Notification => ({
4550
...defaultSuccessNotification,
46-
message: 'Organization was successfully updated',
51+
message: `Invitation Sent`,
4752
})
4853

49-
export const orgEditFailed = (): Notification => ({
54+
export const invitationWithdrawnFailed = (): Notification => ({
5055
...defaultErrorNotification,
51-
message: 'Failed to update organization',
56+
message: `Error withdrawing invite, try again`,
5257
})
5358

54-
export const orgRenameSuccess = (orgName: string): Notification => ({
59+
export const invitationWithdrawnSuccessful = (): Notification => ({
5560
...defaultSuccessNotification,
56-
message: `Organization was successfully renamed "${orgName}"`,
61+
message: `Invitation Withdrawn`,
5762
})
5863

59-
export const orgRenameFailed = (orgName): Notification => ({
64+
export const memberAddFailed = (message: string): Notification => ({
6065
...defaultErrorNotification,
61-
message: `Failed to update organization "${orgName}"`,
66+
message: `Failed to add members: "${message}"`,
6267
})
6368

6469
export const memberAddSuccess = (username: string): Notification => ({
6570
...defaultSuccessNotification,
6671
message: `Member "${username}" was added successfully`,
6772
})
6873

69-
export const memberAddFailed = (message: string): Notification => ({
74+
export const memberRemoveFailed = (message: string): Notification => ({
7075
...defaultErrorNotification,
71-
message: `Failed to add members: "${message}"`,
76+
message: `Failed to remove members: "${message}"`,
7277
})
7378

7479
export const memberRemoveSuccess = (memberName: string): Notification => ({
7580
...defaultSuccessNotification,
7681
message: `Member "${memberName}" was removed successfully`,
7782
})
7883

79-
export const memberRemoveFailed = (message: string): Notification => ({
84+
export const orgCreateFailed = (): Notification => ({
8085
...defaultErrorNotification,
81-
message: `Failed to remove members: "${message}"`,
86+
message: 'Failed to create organization',
8287
})
8388

84-
/* USERS NOTIFICATIONS */
85-
export const inviteSent = (): Notification => ({
89+
export const orgCreateSuccess = (): Notification => ({
8690
...defaultSuccessNotification,
87-
message: `Invitation Sent`,
91+
message: 'Organization was successfully created',
8892
})
8993

90-
export const inviteFailed = (): Notification => ({
94+
export const orgDefaultSettingError = (orgName: string): Notification => ({
9195
...defaultErrorNotification,
92-
message: `invite failed`,
96+
message: `Organization "${orgName}" could not be set as the default organization. Please try again.`,
9397
})
9498

95-
export const invitationResentSuccessful = (): Notification => ({
99+
export const orgDefaultSettingSuccess = (orgName: string): Notification => ({
96100
...defaultSuccessNotification,
97-
message: `Invitation Re-sent`,
101+
message: `Organization "${orgName}" was successfully set as the default organization`,
98102
})
99103

100-
export const invitationResentFailed = (): Notification => ({
104+
export const orgEditFailed = (): Notification => ({
101105
...defaultErrorNotification,
102-
message: `Error sending invitation`,
106+
message: 'Failed to update organization',
103107
})
104108

105-
export const invitationWithdrawnSuccessful = (): Notification => ({
109+
export const orgEditSuccess = (): Notification => ({
106110
...defaultSuccessNotification,
107-
message: `Invitation Withdrawn`,
111+
message: 'Organization was successfully updated',
108112
})
109113

110-
export const invitationWithdrawnFailed = (): Notification => ({
114+
export const orgRenameFailed = (orgName): Notification => ({
111115
...defaultErrorNotification,
112-
message: `Error withdrawing invite, try again`,
116+
message: `Failed to update organization "${orgName}"`,
113117
})
114118

115-
export const removeUserSuccessful = (): Notification => ({
119+
export const orgRenameSuccess = (orgName: string): Notification => ({
116120
...defaultSuccessNotification,
117-
message: `User Removed`,
121+
message: `Organization was successfully renamed "${orgName}"`,
118122
})
119123

120124
export const removeUserFailed = (): Notification => ({
121125
...defaultErrorNotification,
122126
message: `Error removing user, try again`,
123127
})
124128

125-
export const updateIdentityFailed = (): Notification => ({
126-
...defaultErrorNotification,
127-
message: 'Error retrieving user identity. Please refresh this page.',
129+
export const removeUserSuccessful = (): Notification => ({
130+
...defaultSuccessNotification,
131+
message: `User Removed`,
128132
})
129133

130134
export const updateBillingFailed = (): Notification => ({
@@ -133,6 +137,11 @@ export const updateBillingFailed = (): Notification => ({
133137
'Error retrieving account billing provider. Please refresh this page.',
134138
})
135139

140+
export const updateIdentityFailed = (): Notification => ({
141+
...defaultErrorNotification,
142+
message: 'Error retrieving user identity. Please refresh this page.',
143+
})
144+
136145
export const updateOrgFailed = (): Notification => ({
137146
...defaultErrorNotification,
138147
message:

0 commit comments

Comments
 (0)