Initial commit
This commit is contained in:
230
website/src/Users/UserForm.js
Normal file
230
website/src/Users/UserForm.js
Normal file
@@ -0,0 +1,230 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { autoBind } from 'auto-bind2'
|
||||
import { regExpPattern } from 'regexp-pattern'
|
||||
import { Grid, Form } from 'semantic-ui-react'
|
||||
import './UserForm.scss'
|
||||
import { ValidatedEmailIcon } from './ValidatedEmailIcon'
|
||||
import { Constants, api } from '../helpers'
|
||||
import { Validator, ValidatedInput, ValidatedButton, ValidatedDropdown, ValidatedDatePicker, ValidatedContainer } from '../Validated'
|
||||
|
||||
export class UserForm extends React.Component {
|
||||
static propTypes = {
|
||||
user: PropTypes.object,
|
||||
onSave: PropTypes.func,
|
||||
onRemove: PropTypes.func,
|
||||
onModifiedChanged: PropTypes.func,
|
||||
onChangeEmail: PropTypes.func,
|
||||
onResendEmail: PropTypes.func
|
||||
}
|
||||
|
||||
static validations = {
|
||||
email: {
|
||||
isValid: (r, v) => (regExpPattern.email.test(v)),
|
||||
isDisabled: (r) => (!!r._id)
|
||||
},
|
||||
emailValidated: {
|
||||
isDisabled: (r) => (!!r._id === false)
|
||||
},
|
||||
changeEmail: {
|
||||
nonValue: true,
|
||||
isDisabled: (r) => (!!r._id === false)
|
||||
},
|
||||
firstName: {
|
||||
isValid: (r, v) => (v !== '')
|
||||
},
|
||||
lastName: {
|
||||
isValid: (r, v) => (v !== '')
|
||||
},
|
||||
zip: {
|
||||
isValid: (r, v) => (v === '' || regExpPattern.zip.test(v))
|
||||
},
|
||||
state: {
|
||||
isValid: (r, v) => (v === '' || regExpPattern.state.test(v))
|
||||
},
|
||||
city: {
|
||||
isValid: true
|
||||
},
|
||||
address1: {
|
||||
isValid: true
|
||||
},
|
||||
address2: {
|
||||
isValid: true
|
||||
},
|
||||
homePhone: {
|
||||
isValid: (r, v) => (v === '' || regExpPattern.phone.test(v))
|
||||
},
|
||||
cellPhone: {
|
||||
isValid: (r, v) => (v === '' || regExpPattern.phone.test(v))
|
||||
},
|
||||
dateOfBirth: {
|
||||
isValid: true
|
||||
},
|
||||
dateOfHire: {
|
||||
isValid: true
|
||||
},
|
||||
ssn: {
|
||||
isValid: (r, v) => (v === '' || regExpPattern.ssn.test(v))
|
||||
},
|
||||
numHouseholds: {
|
||||
isValid: true
|
||||
},
|
||||
t12: {
|
||||
isValid: true
|
||||
},
|
||||
aum: {
|
||||
isValid: true
|
||||
},
|
||||
role: {
|
||||
isValid: (r, v) => (v !== ''),
|
||||
isDisabled: (r) => (api.loggedInUser._id === r._id)
|
||||
},
|
||||
project: {
|
||||
isValid: (r, v) => (v !== '' || v === '')
|
||||
},
|
||||
remove: {
|
||||
nonValue: true,
|
||||
isVisible: (r) => (!!r._id),
|
||||
isDisabled: (r) => (api.loggedInUser._id === r._id)
|
||||
},
|
||||
reset: {
|
||||
nonValue: true,
|
||||
isDisabled: (r) => (!r.anyModified)
|
||||
},
|
||||
submit: {
|
||||
nonValue: true,
|
||||
isDisabled: (r) => (!r.anyModified && !r.allValid)
|
||||
},
|
||||
'broker-fields': {
|
||||
nonValue: true,
|
||||
isVisible: (r, v) => (r.getField('role').value === 'broker')
|
||||
},
|
||||
'standard-fields': {
|
||||
nonValue: true,
|
||||
isVisible: (r, v) => (r.getField('role').value !== 'broker')
|
||||
}
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
autoBind(this, (name) => (name.startsWith('handle')))
|
||||
this.state = {
|
||||
validator: new Validator(this.props.user, UserForm.validations, this.props.onModifiedChanged)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.user !== this.props.user) {
|
||||
this.setState({
|
||||
validator: new Validator(nextProps.user, UserForm.validations, nextProps.onModifiedChanged)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault()
|
||||
let obj = this.state.validator.getValues()
|
||||
if (obj) {
|
||||
this.props.onSave(obj)
|
||||
}
|
||||
}
|
||||
|
||||
handleReset() {
|
||||
this.setState({ validator: new Validator(this.props.user, UserForm.validations, this.props.onModifiedChanged) })
|
||||
this.props.onModifiedChanged(false)
|
||||
}
|
||||
|
||||
handleChangeEmail() {
|
||||
this.props.onChangeEmail()
|
||||
}
|
||||
|
||||
handleResendEmail() {
|
||||
this.props.onResendEmail()
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form className='user-form' onSubmit={this.handleSubmit}>
|
||||
<Grid stackable>
|
||||
<Grid.Column width={16}>
|
||||
<Form.Group>
|
||||
<ValidatedDropdown label={'Deighton Access & Security Level'} width={6} selection
|
||||
options={Constants.accessLevels} name='role' message='The user role and security level'
|
||||
placeholder='' validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<ValidatedInput label='First Name' name='firstName'
|
||||
width={8} validator={this.state.validator} />
|
||||
<ValidatedInput label='Last Name' name='lastName'
|
||||
width={8} validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<ValidatedInput label='Email' name='email' width={8} message='Must be a valid email address. Required.'
|
||||
validator={this.state.validator} />
|
||||
<ValidatedEmailIcon name='emailValidated' validator={this.state.validator} width={4}
|
||||
onClick={this.handleResendEmail} />
|
||||
<ValidatedButton width={4} size='medium' content='Change Email' label=' ' name='changeEmail'
|
||||
validator={this.state.validator} onClick={this.handleChangeEmail} />
|
||||
</Form.Group>
|
||||
|
||||
<ValidatedContainer name='standard-fields' validator={this.state.validator}>
|
||||
<Form.Group>
|
||||
<ValidatedInput label='Zip' width={4} name='zip' message='5 Character U.S. Zip Code. Optional.'
|
||||
position='bottom center' validator={this.state.validator} />
|
||||
<ValidatedDropdown label='State' name='state' width={4}
|
||||
placeholder='Select State' options={Constants.stateOptions} validator={this.state.validator} searchable />
|
||||
<ValidatedInput label='City' width={8} type='text' name='city' message='U.S. City. Optional.'
|
||||
validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<ValidatedInput label='Address' width={12} name='address1'
|
||||
validator={this.state.validator} message='Primary Street Address. Optional.' />
|
||||
<ValidatedInput label='Apt. #' width={4} name='address2'
|
||||
validator={this.state.validator} message='Apartment/Unit number. Optional.' />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<ValidatedInput label='Home Phone' width={8} name='homePhone'
|
||||
validator={this.state.validator} message='A valid U.S. phone number. IE: (555)123-4567. Optional.' />
|
||||
<ValidatedInput label='Cell Phone' width={8} name='cellPhone'
|
||||
validator={this.state.validator} message='A valid U.S. phone number. IE: (555)123-4567. Optional.' />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<ValidatedDatePicker label='Date of Birth' width={5} name='dateOfBirth'
|
||||
validator={this.state.validator} />
|
||||
<ValidatedInput label='SSN' width={6} name='ssn'
|
||||
validator={this.state.validator} message='U.S. Social Security Number. IE: 123-45-6789' />
|
||||
<ValidatedDatePicker label='Hire Date' width={5} name='dateOfHire'
|
||||
validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
</ValidatedContainer>
|
||||
|
||||
<ValidatedContainer name='broker-fields' validator={this.state.validator}>
|
||||
<Form.Group>
|
||||
<ValidatedInput label='# Households' width={5} name='numHouseholds'
|
||||
message='Number of households in this brokers account' validator={this.state.validator} />
|
||||
<ValidatedInput label='T-12' width={6} name='t12' message='This brokers T-12 info.'
|
||||
validator={this.state.validator} />
|
||||
<ValidatedInput label='AUM' width={5} name='aum'
|
||||
message='This brokers AUM information.' validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
</ValidatedContainer>
|
||||
|
||||
<Form.Group>
|
||||
<ValidatedButton color='red' width={4} size='medium' content='Remove' label=' ' name='remove'
|
||||
validator={this.state.validator} onClick={this.props.onRemove} />
|
||||
<ValidatedButton width={4} size='medium' content='Reset' label=' ' name='reset'
|
||||
validator={this.state.validator} onClick={this.handleReset} />
|
||||
<Form.Field width={this.state.validator._id ? 8 : 12} />
|
||||
<ValidatedButton primary submit width={4} size='medium'
|
||||
content={this.state.validator._id ? 'Save' : 'Add'} label=' ' name='submit'
|
||||
validator={this.state.validator} />
|
||||
</Form.Group>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
}
|
||||
8
website/src/Users/UserForm.scss
Normal file
8
website/src/Users/UserForm.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
.user-form {
|
||||
text-align: left;
|
||||
margin: 3em auto 4em auto;
|
||||
}
|
||||
|
||||
.user-form > .fields {
|
||||
margin-bottom: 1.5em !important;
|
||||
}
|
||||
9
website/src/Users/UserFormPlaceholder.js
Normal file
9
website/src/Users/UserFormPlaceholder.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import './UserFormPlaceholder.scss'
|
||||
|
||||
export const UserFormPlaceholder = () => (
|
||||
<div className='user-form-placeholder'>
|
||||
<h3>Select a registered user to view details here</h3>
|
||||
<h5>Or 'Add New User'</h5>
|
||||
</div>
|
||||
)
|
||||
7
website/src/Users/UserFormPlaceholder.scss
Normal file
7
website/src/Users/UserFormPlaceholder.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.user-form-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
69
website/src/Users/UserList.js
Normal file
69
website/src/Users/UserList.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Dropdown, List, Icon, Button, Image } from 'semantic-ui-react'
|
||||
import { Constants, api } from '../helpers'
|
||||
import './UserList.scss'
|
||||
|
||||
const selectionOptions = Constants.accessLevels.concat([{ value: 'all', text: 'All Levels' }])
|
||||
|
||||
export class UserList extends React.Component {
|
||||
static propTypes = {
|
||||
users: PropTypes.array,
|
||||
onUserListClick: PropTypes.func,
|
||||
selectedUser: PropTypes.object,
|
||||
selectionModified: PropTypes.bool,
|
||||
onAddNewUser: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: null
|
||||
}
|
||||
this.filterUsers = this.filterUsers.bind(this)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// This ensures that the original list is populated with 'all' by default,
|
||||
// due to the component mounting before users are returned (by api)
|
||||
if (nextProps.users !== this.props.users) {
|
||||
this.setState({ users: nextProps.users })
|
||||
}
|
||||
}
|
||||
|
||||
filterUsers(e, data) {
|
||||
e.preventDefault()
|
||||
let users = this.props.users
|
||||
if (data.value !== 'all') {
|
||||
users = users.filter(user => data.value === user.role)
|
||||
}
|
||||
this.setState({ users })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Dropdown placeholder='All Registered Users' selection fluid
|
||||
options={selectionOptions} onChange={this.filterUsers} />
|
||||
<List className='user-list' size='big' selection verticalAlign='middle'>
|
||||
{
|
||||
this.state.users
|
||||
? this.state.users.map((user, index) =>
|
||||
(<List.Item className='user-list-item' key={user._id || '0'} onClick={this.props.onUserListClick}
|
||||
active={user === this.props.selectedUser} data-index={index}>
|
||||
<Image avatar src={api.makeImageUrl(user.thumbnailImageId, Constants.smallUserImageSize)} />
|
||||
<List.Content>
|
||||
{ user._id ? user.firstName + ' ' + user.lastName : '[New User]' }
|
||||
{ user === this.props.selectedUser && this.props.selectionModified ? <Icon className='user-update'
|
||||
name='edit' /> : null }
|
||||
</List.Content>
|
||||
</List.Item>)
|
||||
)
|
||||
: null
|
||||
}
|
||||
</List>
|
||||
<Button className='add-new-user' content='Add New User' primary onClick={this.props.onAddNewUser} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
21
website/src/Users/UserList.scss
Normal file
21
website/src/Users/UserList.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.user-list {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0.25em !important;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 0.25em 2px Silver;
|
||||
-webkit-box-shadow: 0 0 0.25em 2px Silver;
|
||||
max-height: 60vh;
|
||||
min-height: 60vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.user-list > .item {
|
||||
margin: 5em 0;
|
||||
}
|
||||
|
||||
i.user-update {
|
||||
position: absolute;
|
||||
right: 7.5%;
|
||||
}
|
||||
281
website/src/Users/Users.js
Normal file
281
website/src/Users/Users.js
Normal file
@@ -0,0 +1,281 @@
|
||||
import React from 'react'
|
||||
import { Container, Grid } from 'semantic-ui-react'
|
||||
import { autoBind } from 'auto-bind2'
|
||||
import { UserList } from './UserList'
|
||||
import { UserForm } from './UserForm'
|
||||
import { UserFormPlaceholder } from './UserFormPlaceholder'
|
||||
import { api } from '../helpers'
|
||||
import { YesNoMessageDialog, MessageDialog, ChangeEmailDialog, WaitDialog } from '../Dialog'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor() {
|
||||
super()
|
||||
autoBind(this, (name) => (name.startsWith('handle')))
|
||||
this.state = {
|
||||
selectedUser: null,
|
||||
users: [],
|
||||
yesNoDialog: null,
|
||||
messageDialog: null,
|
||||
waitDialog: null,
|
||||
changeEmailDialog: null
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
api.listUsers().then((list) => {
|
||||
list.items.sort((userA, userB) => (userA.lastName.localeCompare(userB.lastName)))
|
||||
this.setState({ users: list.items })
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'User List Error',
|
||||
message: `Unable to get the list of users. ${error.message}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
removeUnfinishedNewUser() {
|
||||
let users = this.state.users
|
||||
|
||||
if (users.length > 0 && !users[0]._id) {
|
||||
this.setState({ users: this.state.users.slice(1) })
|
||||
}
|
||||
}
|
||||
|
||||
handleUserListClick(e) {
|
||||
let user = this.state.users[Number(e.currentTarget.getAttribute('data-index'))]
|
||||
|
||||
if (this.state.modified) {
|
||||
this.nextSelectedUser = user
|
||||
this.setState({
|
||||
yesNoDialog: {
|
||||
title: 'User Modified',
|
||||
message: 'This user has been modified. Are you sure you would like to navigate away?',
|
||||
onDismiss: this.handleModifiedDialogDismiss
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.setState({ selectedUser: user })
|
||||
this.removeUnfinishedNewUser()
|
||||
}
|
||||
}
|
||||
|
||||
handleSave(user) {
|
||||
if (user._id) {
|
||||
this.setState({ waitDialog: { message: 'Updating User' } })
|
||||
api.updateUser(user).then((updatedUser) => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
users: this.state.users.map((user) => (user._id === updatedUser._id ? updatedUser : user)),
|
||||
modified: false,
|
||||
selectedUser: updatedUser
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'Update Error',
|
||||
message: `Unable to save the user changes. ${error.message}`
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.setState({ waitDialog: { message: 'Creating User' } })
|
||||
api.createUser(user).then((createdUser) => {
|
||||
this.setState({
|
||||
waitDialog: false,
|
||||
users: this.state.users.map((user) => (!user._id ? createdUser : user)),
|
||||
modified: false,
|
||||
selectedUser: createdUser
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'Create Error',
|
||||
message: `Unable to create the user. ${error.message}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleChangeEmail() {
|
||||
this.setState({ changeEmailDialog: {} })
|
||||
}
|
||||
|
||||
handleResendEmail() {
|
||||
this.setState({
|
||||
waitDialog: { message: 'Resending Email...' }
|
||||
})
|
||||
api.sendConfirmEmail({ existingEmail: this.state.selectedUser.email }).then(() => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: false,
|
||||
title: "We've Re-Sent the Email...",
|
||||
message: `An email has been sent to '${this.state.selectedUser.email}'. This user will need to follow that email's included link to verify their account.`
|
||||
}
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
error: true,
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'Email Change Error...',
|
||||
message: `Unable to request email change. ${error ? error.message : ''}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
handleChangeEmailDismiss(newEmail) {
|
||||
this.setState({ changeEmailDialog: null })
|
||||
if (!newEmail) {
|
||||
return
|
||||
}
|
||||
this.setState({
|
||||
waitDialog: { message: 'Requesting Email Change...' }
|
||||
})
|
||||
api.sendConfirmEmail({ existingEmail: this.state.selectedUser.email, newEmail }).then(() => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: false,
|
||||
title: 'Email Change Requested...',
|
||||
message: `An email has been sent to '${newEmail}'. This user will need to follow that email's included link to finish changing their email.`
|
||||
}
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
error: true,
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'Email Change Error...',
|
||||
message: `Unable to request email change. ${error ? error.message : ''}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
handleRemove() {
|
||||
this.setState({
|
||||
yesNoDialog: {
|
||||
title: 'Permanently Delete User?',
|
||||
message: 'You are about to delete this user from the system. This includes references to this user in Projects, Packages, and so on. Are you sure you want to remove this user?',
|
||||
onDismiss: this.handleRemoveDialogDismiss
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleRemoveDialogDismiss(yes) {
|
||||
if (yes) {
|
||||
// TODO: Pass the _id back from the dialog input data
|
||||
const selectedUserId = this.state.selectedUser._id
|
||||
const selectedIndex = this.state.users.findIndex((user) => (user._id === selectedUserId))
|
||||
|
||||
if (selectedIndex >= 0) {
|
||||
this.setState({ waitDialog: { message: 'Removing User' } })
|
||||
api.deleteUser(selectedUserId).then(() => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
users: [...this.state.users.slice(0, selectedIndex), ...this.state.users.slice(selectedIndex + 1)],
|
||||
selectedUser: null
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
waitDialog: null,
|
||||
messageDialog: {
|
||||
error: true,
|
||||
title: 'Remove Error',
|
||||
message: `Unable to remove the user. ${error.message}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
yesNoDialog: null
|
||||
})
|
||||
}
|
||||
|
||||
handleModifiedDialogDismiss(yes) {
|
||||
if (yes) {
|
||||
this.setState({
|
||||
selectedUser: this.nextSelectedUser,
|
||||
modified: false
|
||||
})
|
||||
this.removeUnfinishedNewUser()
|
||||
delete this.nextSelectedUser
|
||||
}
|
||||
|
||||
this.setState({
|
||||
yesNoDialog: null
|
||||
})
|
||||
}
|
||||
|
||||
handleMessageDialogDismiss() {
|
||||
this.setState({ messageDialog: null })
|
||||
}
|
||||
|
||||
handleModifiedChanged(modified) {
|
||||
this.setState({ modified: modified })
|
||||
}
|
||||
|
||||
handleAddNewUser() {
|
||||
let newUser = {}
|
||||
let newUsers = [newUser].concat(this.state.users)
|
||||
this.setState({ users: newUsers, selectedUser: newUser })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container>
|
||||
<div>Users</div>
|
||||
|
||||
<Grid stackable>
|
||||
{/* User List - Displayed on left hand side. */}
|
||||
<Grid.Column width={5}>
|
||||
<UserList users={this.state.users} selectedUser={this.state.selectedUser}
|
||||
selectionModified={this.state.modified} onUserListClick={this.handleUserListClick}
|
||||
onAddNewUser={this.handleAddNewUser} />
|
||||
</Grid.Column>
|
||||
|
||||
{/* User Info - Displayed on right hand side. */}
|
||||
<Grid.Column width={11}>
|
||||
{
|
||||
this.state.selectedUser
|
||||
? <UserForm user={this.state.selectedUser} onSave={this.handleSave}
|
||||
onRemove={this.handleRemove} onModifiedChanged={this.handleModifiedChanged}
|
||||
onChangeEmail={this.handleChangeEmail} onResendEmail={this.handleResendEmail} />
|
||||
: <UserFormPlaceholder />
|
||||
}
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
|
||||
<ChangeEmailDialog open={!!this.state.changeEmailDialog} onDismiss={this.handleChangeEmailDismiss} />
|
||||
|
||||
<YesNoMessageDialog open={!!this.state.yesNoDialog}
|
||||
title={this.state.yesNoDialog ? this.state.yesNoDialog.title : ''}
|
||||
message={this.state.yesNoDialog ? this.state.yesNoDialog.message : ''}
|
||||
onDismiss={this.state.yesNoDialog ? this.state.yesNoDialog.onDismiss : null} />
|
||||
|
||||
<MessageDialog
|
||||
open={!!this.state.messageDialog}
|
||||
error={this.state.messageDialog ? this.state.messageDialog.error : false}
|
||||
title={this.state.messageDialog ? this.state.messageDialog.title : ''}
|
||||
message={this.state.messageDialog ? this.state.messageDialog.message : ''}
|
||||
onDismiss={this.handleMessageDialogDismiss} />
|
||||
|
||||
<WaitDialog active={!!this.state.waitDialog} message={this.state.waitDialog ? this.state.waitDialog.message : ''} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
47
website/src/Users/ValidatedEmailIcon.js
Normal file
47
website/src/Users/ValidatedEmailIcon.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Form, Icon, Popup, Button } from 'semantic-ui-react'
|
||||
import './ValidatedEmailIcon.scss'
|
||||
|
||||
// This is a validated component with a value that cannot change itself and is specialized
|
||||
|
||||
export class ValidatedEmailIcon extends React.Component {
|
||||
static propTypes = {
|
||||
name: PropTypes.string,
|
||||
validator: PropTypes.object,
|
||||
width: PropTypes.number,
|
||||
onClick: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = props.validator.getField('emailValidated')
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.validator !== this.props.validator) {
|
||||
this.setState(nextProps.validator.getField(nextProps.name))
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.value) {
|
||||
return (
|
||||
<Form.Field width={this.props.width}>
|
||||
<label> </label>
|
||||
<Popup content='Email Validated' position='bottom center' hoverable trigger={
|
||||
<Icon name='mail' color='green' size='big' className='mail-validated-icon' />
|
||||
} />
|
||||
</Form.Field>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Form.Field width={this.props.width}>
|
||||
<label> </label>
|
||||
<Button fluid icon='mail outline' color='red' labelPosition='left'
|
||||
content='Resend Email' onClick={this.props.onClick} disabled={this.state.disabled} />
|
||||
</Form.Field>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
website/src/Users/ValidatedEmailIcon.scss
Normal file
3
website/src/Users/ValidatedEmailIcon.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.mail-validated-icon {
|
||||
padding-top: 4px;
|
||||
}
|
||||
1
website/src/Users/index.js
Normal file
1
website/src/Users/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { Users } from './Users'
|
||||
Reference in New Issue
Block a user