Skip to content

Commit

Permalink
feat: implement PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzemp committed Jan 13, 2025
1 parent 705528c commit 7c54a40
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 304 deletions.
94 changes: 47 additions & 47 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2025-01-13T15:15:24.364Z\n"
"PO-Revision-Date: 2025-01-13T15:15:24.364Z\n"
"POT-Creation-Date: 2025-01-13T17:35:56.021Z\n"
"PO-Revision-Date: 2025-01-13T17:35:56.021Z\n"

msgid "Never"
msgstr "Never"
Expand Down Expand Up @@ -307,45 +307,6 @@ msgstr "Select profile picture"
msgid "Remove profile picture"
msgstr "Remove profile picture"

msgid "This field is required"
msgstr "This field is required"

msgid "This field should be a URL"
msgstr "This field should be a URL"

msgid "This field should contain a list of URLs"
msgstr "This field should contain a list of URLs"

msgid "This field should be a number"
msgstr "This field should be a number"

msgid "This field should be a positive number"
msgstr "This field should be a positive number"

msgid "This field should be an email"
msgstr "This field should be an email"

msgid "Please enter a valid international phone number (+0123456789)"
msgstr "Please enter a valid international phone number (+0123456789)"

msgid "Yes"
msgstr "Yes"

msgid "No"
msgstr "No"

msgid "No value"
msgstr "No value"

msgid "Use system default"
msgstr "Use system default"

msgid "No options"
msgstr "No options"

msgid "System default"
msgstr "System default"

msgid "No email provided"
msgstr "No email provided"

Expand All @@ -367,15 +328,9 @@ msgstr "Are you sure you want to remove your email?"
msgid "Cancel"
msgstr "Cancel"

msgid "Email"
msgstr "Email"

msgid "Change email"
msgstr "Change email"

msgid "There is no email to remove"
msgstr "There is no email to remove"

msgid "If you change your email, you may need to reverify your email."
msgstr "If you change your email, you may need to reverify your email."

Expand All @@ -394,6 +349,51 @@ msgstr "Confirm new email"
msgid "Save"
msgstr "Save"

msgid "Email"
msgstr "Email"

msgid "There is no email to remove"
msgstr "There is no email to remove"

msgid "This field is required"
msgstr "This field is required"

msgid "This field should be a URL"
msgstr "This field should be a URL"

msgid "This field should contain a list of URLs"
msgstr "This field should contain a list of URLs"

msgid "This field should be a number"
msgstr "This field should be a number"

msgid "This field should be a positive number"
msgstr "This field should be a positive number"

msgid "This field should be an email"
msgstr "This field should be an email"

msgid "Please enter a valid international phone number (+0123456789)"
msgstr "Please enter a valid international phone number (+0123456789)"

msgid "Yes"
msgstr "Yes"

msgid "No"
msgstr "No"

msgid "No value"
msgstr "No value"

msgid "Use system default"
msgstr "Use system default"

msgid "No options"
msgstr "No options"

msgid "System default"
msgstr "System default"

msgid "User profile"
msgstr "User profile"

Expand Down
261 changes: 261 additions & 0 deletions src/layout/EmailField.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
import i18n from '@dhis2/d2-i18n'
import {
Button,
ButtonStrip,
email as emailValidator,
InputField,
Modal,
ModalActions,
ModalContent,
ModalTitle,
NoticeBox,
Tooltip,
} from '@dhis2/ui'
import TextField from 'd2-ui/lib/form-fields/TextField'
import PropTypes from 'prop-types'
import React, { useMemo, useState } from 'react'
import styles from './EmailField.component.module.css'
import { VerifyEmail } from './VerifyEmail.component.js'

const TooltipWrapper = ({ disabled, content, children }) => {
if (!disabled) {
return <>{children}</>
}
return <Tooltip content={content}>{children}</Tooltip>
}

TooltipWrapper.propTypes = {
children: PropTypes.node,
content: PropTypes.string,
disabled: PropTypes.bool,
}

const getSaveDisabledContent = ({ newEmail, emailValidationMessage }) => {
if (!newEmail) {
return i18n.t('No email provided')
}
if (emailValidationMessage) {
return i18n.t('Email is invalid')
}
return i18n.t('Emails must match')
}

const RemoveModal = ({
removeModalOpen,
setRemoveModalOpen,
userEmailVerified,
onUpdate,
}) => (
<Modal hide={!removeModalOpen} onClose={() => setRemoveModalOpen(false)}>
<ModalTitle>{i18n.t('Remove email')}</ModalTitle>

<ModalContent>
{userEmailVerified && (
<NoticeBox
className={styles.emailModalItem}
title={i18n.t('Your email is currently verified')}
warning
></NoticeBox>
)}
<div>{i18n.t('Are you sure you want to remove your email?')}</div>
</ModalContent>

<ModalActions>
<ButtonStrip end>
<Button onClick={() => setRemoveModalOpen(false)} secondary>
{i18n.t('Cancel')}
</Button>

<Button
onClick={() => {
onUpdate('')
setRemoveModalOpen(false)
}}
destructive
>
{i18n.t('Remove email')}
</Button>
</ButtonStrip>
</ModalActions>
</Modal>
)

RemoveModal.propTypes = {
removeModalOpen: PropTypes.bool,
setRemoveModalOpen: PropTypes.func,
userEmailVerified: PropTypes.bool,
onUpdate: PropTypes.func,
}

const EmailModal = ({
emailModalOpen,
setEmailModalOpen,
userEmailVerified,
userEmail,
onUpdate,
}) => {
const [newEmail, setNewEmail] = useState()
const [newEmailConfirm, setNewEmailConfirm] = useState()
const [newEmailConfirmTouched, setNewEmailConfirmTouched] = useState(false)
const emailValidationMessage = useMemo(
() => emailValidator(newEmail),
[newEmail]
)
const emailsMatch = newEmail === newEmailConfirm
const saveDisabled =
!newEmail || Boolean(emailValidationMessage) || !emailsMatch
const saveDisabledContent = getSaveDisabledContent({
newEmail,
emailValidationMessage,
})

return (
<Modal
hide={!emailModalOpen}
onClose={() => {
setEmailModalOpen(false)
}}
>
<ModalTitle>{i18n.t('Change email')}</ModalTitle>

<ModalContent>
{userEmailVerified && (
<NoticeBox
className={styles.emailModalItem}
title={i18n.t('Your email is currently verified')}
warning
>
{i18n.t(
'If you change your email, you may need to reverify your email.'
)}
</NoticeBox>
)}

<InputField
label={i18n.t('Current email')}
value={
userEmail?.trim() !== ''
? userEmail
: i18n.t('no current email')
}
type="email"
disabled
className={styles.emailModalItem}
/>
<InputField
label={i18n.t('Enter new email')}
value={newEmail}
type="email"
error={Boolean(emailValidationMessage)}
validationText={emailValidationMessage}
onChange={(newValue) => setNewEmail(newValue.value)}
className={styles.emailModalItem}
/>

<InputField
label={i18n.t('Confirm new email')}
value={newEmailConfirm}
type="email"
error={newEmailConfirmTouched && !emailsMatch}
validationText={
emailsMatch || !newEmailConfirmTouched
? undefined
: i18n.t('Emails must match')
}
onChange={(newValue) => {
setNewEmailConfirmTouched(true)
setNewEmailConfirm(newValue.value)
}}
className={styles.emailModalItem}
/>
</ModalContent>

<ModalActions>
<ButtonStrip end>
<Button onClick={() => setEmailModalOpen(false)} secondary>
{i18n.t('Cancel')}
</Button>

<TooltipWrapper
disabled={saveDisabled}
content={saveDisabledContent}
>
<Button
onClick={() => {
onUpdate(newEmail)
setEmailModalOpen(false)
}}
primary
disabled={saveDisabled}
>
{i18n.t('Save')}
</Button>
</TooltipWrapper>
</ButtonStrip>
</ModalActions>
</Modal>
)
}

EmailModal.propTypes = {
emailModalOpen: PropTypes.bool,
setEmailModalOpen: PropTypes.func,
userEmail: PropTypes.string,
userEmailVerified: PropTypes.bool,
onUpdate: PropTypes.func,
}

export function EmailField({ userEmail, userEmailVerified, onUpdate }) {
const [emailModalOpen, setEmailModalOpen] = useState()
const [removeModalOpen, setRemoveModalOpen] = useState()

return (
<div className={styles.emailModalContainer}>
<TextField
value={userEmail}
disabled
floatingLabelText={i18n.t('Email')}
style={{ width: '100%' }}
/>
<div className={styles.buttonContainer}>
<VerifyEmail userEmail={userEmail} />
<Button secondary onClick={() => setEmailModalOpen(true)}>
{i18n.t('Change email')}
</Button>
<TooltipWrapper
disabled={!userEmail || userEmail?.trim() === ''}
content={i18n.t('There is no email to remove')}
>
<Button
destructive
onClick={() => setRemoveModalOpen(true)}
disabled={!userEmail || userEmail?.trim() === ''}
>
{i18n.t('Remove email')}
</Button>
</TooltipWrapper>
</div>
{emailModalOpen && (
<EmailModal
emailModalOpen={emailModalOpen}
setEmailModalOpen={setEmailModalOpen}
userEmailVerified={userEmailVerified}
userEmail={userEmail}
onUpdate={onUpdate}
/>
)}
<RemoveModal
removeModalOpen={removeModalOpen}
setRemoveModalOpen={setRemoveModalOpen}
userEmailVerified={userEmailVerified}
onUpdate={onUpdate}
/>
</div>
)
}

EmailField.propTypes = {
userEmail: PropTypes.string,
userEmailVerified: PropTypes.bool,
onUpdate: PropTypes.func,
}
File renamed without changes.
Loading

0 comments on commit 7c54a40

Please sign in to comment.