Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions jsapp/js/account/security/email/emailSection.api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fetchDelete, fetchGet, fetchPost } from '#/api'
import type { PaginatedResponse } from '#/dataInterface'
import type { FailResponse, PaginatedResponse } from '#/dataInterface'

export interface EmailResponse {
primary: boolean
Expand All @@ -14,7 +14,7 @@ export async function getUserEmails() {
}

export async function setUserEmail(newEmail: string) {
return fetchPost<EmailResponse>(LIST_URL, { email: newEmail })
return fetchPost<EmailResponse | FailResponse>(LIST_URL, { email: newEmail })
}

/** Removes all unverified/non-primary emails (there should only be one anyway)*/
Expand Down
48 changes: 40 additions & 8 deletions jsapp/js/account/security/email/emailSection.component.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useEffect, useState } from 'react'

import { Group, Text } from '@mantine/core'
import cx from 'classnames'
import securityStyles from '#/account/security/securityRoute.module.scss'
import { MemberRoleEnum } from '#/api/models/memberRoleEnum'
import { useOrganizationAssumed } from '#/api/useOrganizationAssumed'
import Button from '#/components/common/button'
import Icon from '#/components/common/icon'
import TextBox from '#/components/common/textBox'
import type { FailResponse } from '#/dataInterface'
import sessionStore from '#/stores/session'
import { formatTime, notify } from '#/utils'
import { deleteUnverifiedUserEmails, getUserEmails, setUserEmail } from './emailSection.api'
Expand All @@ -18,6 +20,7 @@ interface EmailState {
newEmail: string
refreshedEmail: boolean
refreshedEmailDate: string
fieldErrors: string[]
}

export default function EmailSection() {
Expand All @@ -35,6 +38,7 @@ export default function EmailSection() {
newEmail: initialEmail,
refreshedEmail: false,
refreshedEmailDate: '',
fieldErrors: [],
})

useEffect(() => {
Expand All @@ -47,18 +51,42 @@ export default function EmailSection() {
}, [])

function setNewUserEmail(newEmail: string) {
// Clear errors before making an API call
setEmail({
...email,
fieldErrors: [],
})

setUserEmail(newEmail).then(
() => {
getUserEmails().then((data) => {
(response) => {
if ('primary' in response) {
getUserEmails().then((data) => {
setEmail({
...email,
emails: data.results,
newEmail: '',
})
})
} else {
// If there is no primary email in response, we display an error. This can happen for example when user has
// been created through Django admin without email address.
setEmail({
...email,
emails: data.results,
newEmail: '',
fieldErrors: ['Primary email missing'],
})
})
}
},
() => {
/* Avoid crashing app when 500 error happens */
(err: FailResponse) => {
let errMessages: string[] = []
if (err.responseJSON?.email && typeof err.responseJSON.email === 'string') {
errMessages.push(err.responseJSON.email)
} else if (Array.isArray(err.responseJSON?.email)) {
errMessages = err.responseJSON.email
}
setEmail({
...email,
fieldErrors: errMessages,
})
},
)
}
Expand Down Expand Up @@ -181,7 +209,11 @@ export default function EmailSection() {
handleSubmit()
}}
>
<Button label='Change' size='m' type='primary' onClick={handleSubmit} isDisabled={isSSO} />
<Group gap='sm'>
<Text color='red'>{email.fieldErrors}</Text>

<Button label='Change' size='m' type='primary' onClick={handleSubmit} isDisabled={isSSO} />
</Group>
</form>
</div>
)}
Expand Down