diff --git a/jsapp/js/account/security/email/emailSection.api.ts b/jsapp/js/account/security/email/emailSection.api.ts index 1ca9a7fe48..38c78fd520 100644 --- a/jsapp/js/account/security/email/emailSection.api.ts +++ b/jsapp/js/account/security/email/emailSection.api.ts @@ -1,23 +1,27 @@ -import type {PaginatedResponse} from 'js/dataInterface'; -import {fetchGet, fetchPost, fetchDelete} from 'jsapp/js/api'; +import { fetchDelete, fetchGet, fetchPost } from '#/api' +import type { PaginatedResponse } from '#/dataInterface' export interface EmailResponse { - primary: boolean; - email: string; - verified: boolean; + primary: boolean + email: string + verified: boolean } -const LIST_URL = '/me/emails/'; +export interface EmailError { + email: string[] +} + +const LIST_URL = '/me/emails/' export async function getUserEmails() { - return fetchGet>(LIST_URL); + return fetchGet>(LIST_URL) } export async function setUserEmail(newEmail: string) { - return fetchPost(LIST_URL, {email: newEmail}); + return fetchPost(LIST_URL, { email: newEmail }) } /** Removes all unverified/non-primary emails (there should only be one anyway)*/ export async function deleteUnverifiedUserEmails() { - return fetchDelete(LIST_URL); + return fetchDelete(LIST_URL) } diff --git a/jsapp/js/account/security/email/emailSection.component.tsx b/jsapp/js/account/security/email/emailSection.component.tsx index 8569e4cb42..593f422120 100644 --- a/jsapp/js/account/security/email/emailSection.component.tsx +++ b/jsapp/js/account/security/email/emailSection.component.tsx @@ -1,49 +1,63 @@ -import React, {useEffect, useState} from 'react'; -import sessionStore from 'js/stores/session'; -import {deleteUnverifiedUserEmails, EmailResponse} from './emailSection.api'; -import {getUserEmails, setUserEmail} from './emailSection.api'; -import style from './emailSection.module.scss'; -import Button from 'jsapp/js/components/common/button'; -import TextBox from 'jsapp/js/components/common/textBox'; -import Icon from 'jsapp/js/components/common/icon'; -import {formatTime} from 'jsapp/js/utils'; +import React, { useEffect, useState } from 'react' +import Button from '#/components/common/button' +import Icon from '#/components/common/icon' +import TextBox from '#/components/common/textBox' +import sessionStore from '#/stores/session' +import { formatTime } from '#/utils' +import { type EmailResponse, deleteUnverifiedUserEmails } from './emailSection.api' +import { getUserEmails, setUserEmail } from './emailSection.api' +import style from './emailSection.module.scss' interface EmailState { - emails: EmailResponse[]; - newEmail: string; - refreshedEmail: boolean; - refreshedEmailDate: string; + emails: EmailResponse[] + newEmail: string + refreshedEmail: boolean + refreshedEmailDate: string + fieldErrors: string[] } export default function EmailSection() { - const [session] = useState(() => sessionStore); + const [session] = useState(() => sessionStore) const [email, setEmail] = useState({ emails: [], newEmail: '', refreshedEmail: false, refreshedEmailDate: '', - }); + fieldErrors: [], + }) useEffect(() => { getUserEmails().then((data) => { setEmail({ ...email, emails: data.results, - }); - }); - }, []); + }) + }) + }, []) function setNewUserEmail(newEmail: string) { - setUserEmail(newEmail).then(() => { - getUserEmails().then((data) => { + setEmail({ + ...email, + fieldErrors: [], + }) + + setUserEmail(newEmail).then((response) => { + if ('primary' in response) { + getUserEmails().then((data) => { + setEmail({ + ...email, + emails: data.results, + newEmail: '', + }) + }) + } else { setEmail({ ...email, - emails: data.results, - newEmail: '', - }); - }); - }); + fieldErrors: response.email, + }) + } + }) } function deleteNewUserEmail() { @@ -54,16 +68,16 @@ export default function EmailSection() { emails: data.results, newEmail: '', refreshedEmail: false, - }); - }); - }); + }) + }) + }) } function resendNewUserEmail(unverfiedEmail: string) { setEmail({ ...email, refreshedEmail: false, - }); + }) deleteUnverifiedUserEmails().then(() => { setUserEmail(unverfiedEmail).then(() => { @@ -71,20 +85,20 @@ export default function EmailSection() { ...email, refreshedEmail: true, refreshedEmailDate: formatTime(new Date().toUTCString()), - }); - }); - }); + }) + }) + }) } function onTextFieldChange(value: string) { setEmail({ ...email, newEmail: value, - }); + }) } - const currentAccount = session.currentAccount; - const unverifiedEmail = email.emails.find((userEmail) => !userEmail.verified && !userEmail.primary); + const currentAccount = session.currentAccount + const unverifiedEmail = email.emails.find((userEmail) => !userEmail.verified && !userEmail.primary) return (
@@ -93,67 +107,50 @@ export default function EmailSection() {
- {!session.isPending && - session.isInitialLoadComplete && - 'email' in currentAccount && ( -

{currentAccount.email}

- )} - - {unverifiedEmail?.email && - !session.isPending && - session.isInitialLoadComplete && - 'email' in currentAccount && ( - <> -
- -

- - {t('Check your email ##UNVERIFIED_EMAIL##. ').replace( - '##UNVERIFIED_EMAIL##', - unverifiedEmail.email - )} - - - {t( - 'A verification link has been sent to confirm your ownership. Once confirmed, this address will replace ##UNVERIFIED_EMAIL##' - ).replace('##UNVERIFIED_EMAIL##', currentAccount.email)} -

-
- -
-
- - {email.refreshedEmail && - - } - - )} + {!session.isPending && session.isInitialLoadComplete && 'email' in currentAccount && ( +

{currentAccount.email}

+ )} + + {unverifiedEmail?.email && !session.isPending && session.isInitialLoadComplete && 'email' in currentAccount && ( + <> +
+ +

+ + {t('Check your email ##UNVERIFIED_EMAIL##. ').replace('##UNVERIFIED_EMAIL##', unverifiedEmail.email)} + + + {t( + 'A verification link has been sent to confirm your ownership. Once confirmed, this address will replace ##UNVERIFIED_EMAIL##', + ).replace('##UNVERIFIED_EMAIL##', currentAccount.email)} +

+
+ +
+
+ + {email.refreshedEmail && ( + + )} + + )}
{ - e.preventDefault(); - setNewUserEmail(email.newEmail); + e.preventDefault() + setNewUserEmail(email.newEmail) }} > {/*TODO: Move TextBox into a modal--it messes up the flow of the row right now*/} @@ -164,14 +161,18 @@ export default function EmailSection() { onChange={onTextFieldChange.bind(onTextFieldChange)} /> -