-
+
OK
-
+
diff --git a/website/src/Dialog/MessageDialog.js b/website/src/Modal/MessageModal.js
similarity index 93%
rename from website/src/Dialog/MessageDialog.js
rename to website/src/Modal/MessageModal.js
index d9aa17b..5b144e4 100644
--- a/website/src/Dialog/MessageDialog.js
+++ b/website/src/Modal/MessageModal.js
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Modal, Button, Icon, Column, Text } from 'ui'
-export class MessageDialog extends React.Component {
+export class MessageModal extends React.Component {
static propTypes = {
open: PropTypes.bool,
title: PropTypes.string.isRequired,
diff --git a/website/src/Dialog/WaitDialog.js b/website/src/Modal/WaitModal.js
similarity index 87%
rename from website/src/Dialog/WaitDialog.js
rename to website/src/Modal/WaitModal.js
index 027611e..5a3cd57 100644
--- a/website/src/Dialog/WaitDialog.js
+++ b/website/src/Modal/WaitModal.js
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Dimmer, Loader, Text } from 'ui'
-export class WaitDialog extends React.Component {
+export class WaitModal extends React.Component {
static propTypes = {
message: PropTypes.string.isRequired
}
diff --git a/website/src/Dialog/YesNoMessageDialog.js b/website/src/Modal/YesNoMessageModal.js
similarity index 95%
rename from website/src/Dialog/YesNoMessageDialog.js
rename to website/src/Modal/YesNoMessageModal.js
index e1cf7ad..8da4b00 100644
--- a/website/src/Dialog/YesNoMessageDialog.js
+++ b/website/src/Modal/YesNoMessageModal.js
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Modal, Button, Column, Text, Icon } from 'ui'
-export class YesNoMessageDialog extends React.Component {
+export class YesNoMessageModal extends React.Component {
static propTypes = {
open: PropTypes.bool,
title: PropTypes.string.isRequired,
diff --git a/website/src/Modal/index.js b/website/src/Modal/index.js
new file mode 100644
index 0000000..d2ffcfe
--- /dev/null
+++ b/website/src/Modal/index.js
@@ -0,0 +1,5 @@
+export { WaitModal } from './WaitModal'
+export { YesNoMessageModal } from './YesNoMessageModal'
+export { MessageModal } from './MessageModal'
+export { ChangePasswordModal } from './ChangePasswordModal'
+export { ChangeEmailModal } from './ChangeEmailModal'
diff --git a/website/src/Profile/Profile.js b/website/src/Profile/Profile.js
index d8453f7..76ccf45 100644
--- a/website/src/Profile/Profile.js
+++ b/website/src/Profile/Profile.js
@@ -1,7 +1,7 @@
import React from 'react'
import { ProfileForm } from './ProfileForm'
import { Constants, api } from '../helpers'
-import { WaitDialog, MessageDialog, ChangePasswordDialog, ChangeEmailDialog } from '../Dialog'
+import { WaitModal, MessageModal, ChangePasswordModal, ChangeEmailModal } from '../Modal'
import { autoBind } from 'auto-bind2'
export class Profile extends React.Component {
@@ -11,11 +11,11 @@ export class Profile extends React.Component {
const user = api.loggedInUser
this.state = {
- messageDialog: null,
- waitDialog: null,
- changePasswordDialog: null,
- changeEmailDialog: null,
- progressDialog: null,
+ messageModal: null,
+ waitModal: null,
+ changePasswordModal: null,
+ changeEmailModal: null,
+ progressModal: null,
uploadPercent: 0,
user,
userImageUrl: api.makeImageUrl(user.imageId, Constants.bigUserImageSize)
@@ -35,32 +35,32 @@ export class Profile extends React.Component {
}
handleSaved(user) {
- this.setState({ waitDialog: { message: 'Updating Profile' } })
+ this.setState({ waitModal: { message: 'Updating Profile' } })
api.updateUser(user).then((updatedUser) => {
this.setState({
- waitDialog: null,
+ waitModal: null,
user: updatedUser
})
}).catch((error) => {
this.setState({
- waitDialog: null,
- messageDialog: { title: 'Update Error...', message: `Unable to save the profile changes. ${error.message}` }
+ waitModal: null,
+ messageModal: { title: 'Update Error...', message: `Unable to save the profile changes. ${error.message}` }
})
})
}
- handleMessageDialogDismiss() {
- this.setState({ messageDialog: null })
+ handleMessageModalDismiss() {
+ this.setState({ messageModal: null })
}
handleChangePassword() {
- this.setState({ changePasswordDialog: true })
+ this.setState({ changePasswordModal: true })
}
handleSelectImage(file) {
- this.setState({ progressDialog: { message: `Uploading image '${file.name}'...`, file }, uploadPercent: 0 })
+ this.setState({ progressModal: { message: `Uploading image '${file.name}'...`, file }, uploadPercent: 0 })
api.upload(file, this.handleProgress).then((uploadData) => {
- this.setState({ progressDialog: null })
+ this.setState({ progressModal: null })
return api.setUserImage({
_id: api.loggedInUser._id,
imageId: uploadData.assetId,
@@ -70,14 +70,14 @@ export class Profile extends React.Component {
}).catch((error) => {
// TODO: if the upload succeeds but the setUserImage fails, delete the uploaded image
this.setState({
- progressDialog: null,
- messageDialog: { title: 'Upload Error...', message: `Unable to upload the file. ${error.message}` }
+ progressModal: null,
+ messageModal: { title: 'Upload Error...', message: `Unable to upload the file. ${error.message}` }
})
})
}
handleProgress(uploadData) {
- if (this.state.progressDialog) {
+ if (this.state.progressModal) {
this.setState({ uploadPercent: Math.round(uploadData.uploadedChunks / uploadData.numberOfChunks * 100) })
return true
} else {
@@ -86,22 +86,22 @@ export class Profile extends React.Component {
}
handleUploadCancel(result) {
- this.setState({ progressDialog: null })
+ this.setState({ progressModal: null })
}
handleChangePasswordDismiss(passwords) {
- this.setState({ changePasswordDialog: false })
+ this.setState({ changePasswordModal: false })
if (passwords) {
this.setState({
- waitDialog: { message: 'Changing Password' }
+ waitModal: { message: 'Changing Password' }
})
api.changePassword(passwords).then(() => {
- this.setState({ waitDialog: false })
+ this.setState({ waitModal: false })
}).catch((error) => {
this.setState({
- waitDialog: false,
- messageDialog: {
+ waitModal: false,
+ messageModal: {
title: 'Changing Password Error',
message: `Unable to change password. ${error.message}.`
}
@@ -111,21 +111,21 @@ export class Profile extends React.Component {
}
handleChangeEmail() {
- this.setState({ changeEmailDialog: {} })
+ this.setState({ changeEmailModal: {} })
}
handleChangeEmailDismiss(newEmail) {
- this.setState({ changeEmailDialog: null })
+ this.setState({ changeEmailModal: null })
if (!newEmail) {
return
}
this.setState({
- waitDialog: { message: 'Requesting Email Change...' }
+ waitModal: { message: 'Requesting Email Change...' }
})
api.sendConfirmEmail({ newEmail }).then(() => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: false,
title: 'Email Change Requested...',
message: `An email has been sent to '${newEmail}' with a link that you need to click on to finish changing your email.`
@@ -134,8 +134,8 @@ export class Profile extends React.Component {
}).catch((error) => {
this.setState({
error: true,
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Email Change Error...',
message: `Unable to request email change. ${error ? error.message : ''}`
@@ -155,16 +155,16 @@ export class Profile extends React.Component {
onChangeEmail={this.handleChangeEmail}
userImageUrl={this.state.userImageUrl} />
-
+
-
+
-
+
-
+
)
}
diff --git a/website/src/Profile/ProfileForm.js b/website/src/Profile/ProfileForm.js
index 4488a83..2cf6431 100644
--- a/website/src/Profile/ProfileForm.js
+++ b/website/src/Profile/ProfileForm.js
@@ -1,8 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
-import { Column, Button } from 'ui'
+import { Column, Button, BoundInput, BoundButton } from 'ui'
import { regExpPattern } from 'regexp-pattern'
-import { Validator, ValidatedInput, ValidatedButton } from '../Validated'
+import { FormBinder } from 'react-form-binder'
export class ProfileForm extends React.Component {
static propTypes = {
@@ -13,7 +13,7 @@ export class ProfileForm extends React.Component {
onChangeEmail: PropTypes.func
}
- static validations = {
+ static bindings = {
email: {
isValid: (r, v) => (v !== ''),
isDisabled: (r) => (!!r._id)
@@ -68,16 +68,16 @@ export class ProfileForm extends React.Component {
this.handleSubmit = this.handleSubmit.bind(this)
this.state = {
- validator: new Validator(
- this.props.user, ProfileForm.validations, this.props.onModifiedChanged)
+ binder: new FormBinder(
+ this.props.user, ProfileForm.bindings, this.props.onModifiedChanged)
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.user !== this.props.user) {
this.setState({
- validator: new Validator(
- nextProps.user, ProfileForm.validations, nextProps.onModifiedChanged)
+ binder: new FormBinder(
+ nextProps.user, ProfileForm.bindings, nextProps.onModifiedChanged)
})
}
}
@@ -85,7 +85,7 @@ export class ProfileForm extends React.Component {
handleSubmit(e) {
e.preventDefault()
- let obj = this.state.validator.getValues()
+ let obj = this.state.binder.getValues()
if (obj && this.props.onSaved) {
this.props.onSaved(obj)
@@ -97,16 +97,16 @@ export class ProfileForm extends React.Component {
diff --git a/website/src/Users/UserForm.js b/website/src/Users/UserForm.js
index 7cefaf7..919b8c3 100644
--- a/website/src/Users/UserForm.js
+++ b/website/src/Users/UserForm.js
@@ -1,23 +1,22 @@
import React from 'react'
import PropTypes from 'prop-types'
-import { autoBind } from 'auto-bind2'
+import { reactAutoBind } from 'auto-bind2'
import { regExpPattern } from 'regexp-pattern'
-import { ValidatedEmailIcon } from './ValidatedEmailIcon'
import { Constants, api } from '../helpers'
-import { Validator, ValidatedInput, ValidatedButton, ValidatedCheckbox } from '../Validated'
-import { Column } from 'ui'
+import { Column, BoundInput, BoundButton, BoundCheckbox, BoundEmailIcon } from 'ui'
+import { FormBinder } from 'react-form-binder'
export class UserForm extends React.Component {
static propTypes = {
user: PropTypes.object,
onSave: PropTypes.func,
onRemove: PropTypes.func,
- onModifiedChanged: PropTypes.func,
+ onAnyModified: PropTypes.func,
onChangeEmail: PropTypes.func,
onResendEmail: PropTypes.func
}
- static validations = {
+ static bindings = {
email: {
isValid: (r, v) => (regExpPattern.email.test(v)),
isDisabled: (r) => (!!r._id)
@@ -35,45 +34,6 @@ export class UserForm extends React.Component {
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)
@@ -94,43 +54,40 @@ export class UserForm extends React.Component {
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')))
+ reactAutoBind(this)
this.state = {
- validator: new Validator(this.props.user, UserForm.validations, this.props.onModifiedChanged)
+ binder: new FormBinder(this.props.user, UserForm.bindings, this.props.onAnyModified)
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.user !== this.props.user) {
this.setState({
- validator: new Validator(nextProps.user, UserForm.validations, nextProps.onModifiedChanged)
+ binder: new FormBinder(nextProps.user, UserForm.bindings, nextProps.onAnyModified)
})
}
}
handleSubmit(e) {
e.preventDefault()
- let obj = this.state.validator.getValues()
+ let obj = this.state.binder.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)
+ const { user, onAnyModified } = this.props
+
+ this.setState({ binder: new FormBinder(user, UserForm.bindings, onAnyModified) })
+
+ if (onAnyModified) {
+ onAnyModified(false)
+ }
}
handleChangeEmail() {
@@ -146,37 +103,37 @@ export class UserForm extends React.Component {
diff --git a/website/src/Users/UserForm.scss b/website/src/Users/UserForm.scss
deleted file mode 100644
index e898c8a..0000000
--- a/website/src/Users/UserForm.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.user-form {
- text-align: left;
- margin: 3em auto 4em auto;
-}
-
-.user-form > .fields {
- margin-bottom: 1.5em !important;
-}
diff --git a/website/src/Users/UserList.js b/website/src/Users/UserList.js
index 78d9e74..5ae66b4 100644
--- a/website/src/Users/UserList.js
+++ b/website/src/Users/UserList.js
@@ -2,7 +2,6 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Dropdown, List, Icon, Button, Image } from 'ui'
import { Constants, api } from '../helpers'
-import './UserList.scss'
const selectionOptions = Constants.accessLevels.concat([{ value: 'all', text: 'All Levels' }])
diff --git a/website/src/Users/UserList.scss b/website/src/Users/UserList.scss
deleted file mode 100644
index 1e6e129..0000000
--- a/website/src/Users/UserList.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-.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%;
-}
diff --git a/website/src/Users/Users.js b/website/src/Users/Users.js
index fe28110..bd0f80c 100644
--- a/website/src/Users/Users.js
+++ b/website/src/Users/Users.js
@@ -5,7 +5,7 @@ import { UserForm } from './UserForm'
import { UserFormPlaceholder } from './UserFormPlaceholder'
import { api } from '../helpers'
import { Row } from 'ui'
-import { YesNoMessageDialog, MessageDialog, ChangeEmailDialog, WaitDialog } from '../Dialog'
+import { YesNoMessageModal, MessageModal, ChangeEmailModal, WaitModal } from '../Modal'
export class Users extends React.Component {
constructor() {
@@ -14,10 +14,10 @@ export class Users extends React.Component {
this.state = {
selectedUser: null,
users: [],
- yesNoDialog: null,
- messageDialog: null,
- waitDialog: null,
- changeEmailDialog: null
+ yesNoModal: null,
+ messageModal: null,
+ waitModal: null,
+ changeEmailModal: null
}
}
@@ -27,7 +27,7 @@ export class Users extends React.Component {
this.setState({ users: list.items })
}).catch((error) => {
this.setState({
- messageDialog: {
+ messageModal: {
error: true,
title: 'User List Error',
message: `Unable to get the list of users. ${error.message}`
@@ -50,10 +50,10 @@ export class Users extends React.Component {
if (this.state.modified) {
this.nextSelectedUser = user
this.setState({
- yesNoDialog: {
+ yesNoModal: {
title: 'User Modified',
message: 'This user has been modified. Are you sure you would like to navigate away?',
- onDismiss: this.handleModifiedDialogDismiss
+ onDismiss: this.handleModifiedModalDismiss
}
})
} else {
@@ -64,18 +64,18 @@ export class Users extends React.Component {
handleSave(user) {
if (user._id) {
- this.setState({ waitDialog: { message: 'Updating User' } })
+ this.setState({ waitModal: { message: 'Updating User' } })
api.updateUser(user).then((updatedUser) => {
this.setState({
- waitDialog: null,
+ waitModal: null,
users: this.state.users.map((user) => (user._id === updatedUser._id ? updatedUser : user)),
modified: false,
selectedUser: updatedUser
})
}).catch((error) => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Update Error',
message: `Unable to save the user changes. ${error.message}`
@@ -83,18 +83,18 @@ export class Users extends React.Component {
})
})
} else {
- this.setState({ waitDialog: { message: 'Creating User' } })
+ this.setState({ waitModal: { message: 'Creating User' } })
api.createUser(user).then((createdUser) => {
this.setState({
- waitDialog: false,
+ waitModal: false,
users: this.state.users.map((user) => (!user._id ? createdUser : user)),
modified: false,
selectedUser: createdUser
})
}).catch((error) => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Create Error',
message: `Unable to create the user. ${error.message}`
@@ -105,17 +105,17 @@ export class Users extends React.Component {
}
handleChangeEmail() {
- this.setState({ changeEmailDialog: {} })
+ this.setState({ changeEmailModal: {} })
}
handleResendEmail() {
this.setState({
- waitDialog: { message: 'Resending Email...' }
+ waitModal: { message: 'Resending Email...' }
})
api.sendConfirmEmail({ existingEmail: this.state.selectedUser.email }).then(() => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
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.`
@@ -124,8 +124,8 @@ export class Users extends React.Component {
}).catch((error) => {
this.setState({
error: true,
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Email Change Error...',
message: `Unable to request email change. ${error ? error.message : ''}`
@@ -135,17 +135,17 @@ export class Users extends React.Component {
}
handleChangeEmailDismiss(newEmail) {
- this.setState({ changeEmailDialog: null })
+ this.setState({ changeEmailModal: null })
if (!newEmail) {
return
}
this.setState({
- waitDialog: { message: 'Requesting Email Change...' }
+ waitModal: { message: 'Requesting Email Change...' }
})
api.sendConfirmEmail({ existingEmail: this.state.selectedUser.email, newEmail }).then(() => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
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.`
@@ -154,8 +154,8 @@ export class Users extends React.Component {
}).catch((error) => {
this.setState({
error: true,
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Email Change Error...',
message: `Unable to request email change. ${error ? error.message : ''}`
@@ -166,32 +166,32 @@ export class Users extends React.Component {
handleRemove() {
this.setState({
- yesNoDialog: {
+ yesNoModal: {
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
+ onDismiss: this.handleRemoveModalDismiss
}
})
}
- handleRemoveDialogDismiss(yes) {
+ handleRemoveModalDismiss(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' } })
+ this.setState({ waitModal: { message: 'Removing User' } })
api.deleteUser(selectedUserId).then(() => {
this.setState({
- waitDialog: null,
+ waitModal: null,
users: [...this.state.users.slice(0, selectedIndex), ...this.state.users.slice(selectedIndex + 1)],
selectedUser: null
})
}).catch((error) => {
this.setState({
- waitDialog: null,
- messageDialog: {
+ waitModal: null,
+ messageModal: {
error: true,
title: 'Remove Error',
message: `Unable to remove the user. ${error.message}`
@@ -202,11 +202,11 @@ export class Users extends React.Component {
}
this.setState({
- yesNoDialog: null
+ yesNoModal: null
})
}
- handleModifiedDialogDismiss(yes) {
+ handleModifiedModalDismiss(yes) {
if (yes) {
this.setState({
selectedUser: this.nextSelectedUser,
@@ -217,12 +217,12 @@ export class Users extends React.Component {
}
this.setState({
- yesNoDialog: null
+ yesNoModal: null
})
}
- handleMessageDialogDismiss() {
- this.setState({ messageDialog: null })
+ handleMessageModalDismiss() {
+ this.setState({ messageModal: null })
}
handleModifiedChanged(modified) {
@@ -260,21 +260,21 @@ export class Users extends React.Component {
-
+
-
+
-
+
-
+
)
}
diff --git a/website/src/Validated/ValidatedActionsButton.js b/website/src/Validated/ValidatedActionsButton.js
deleted file mode 100644
index 5918108..0000000
--- a/website/src/Validated/ValidatedActionsButton.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { Button } from 'ui'
-
-export class ValidatedActionsButton extends React.Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- size: PropTypes.string,
- validator: PropTypes.object.isRequired,
- primary: PropTypes.bool,
- submit: PropTypes.bool,
- color: PropTypes.string,
- form: PropTypes.string,
- children: PropTypes.node
- }
-
- constructor(props) {
- super(props)
- this.updateValue = this.updateValue.bind(this)
-
- let { name, validator } = this.props
-
- validator.addListener(name, this.updateValue)
- this.state = validator.getField(name)
- }
-
- updateValue(name) {
- this.setState(this.props.validator.getField(name))
- }
-
- componentWillUnmount() {
- this.props.validator.removeListener(this.props.name, this.updateValue)
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.props.validator.removeListener(this.props.name, this.updateValue)
- nextProps.validator.addListener(nextProps.name, this.updateValue)
- this.setState(nextProps.validator.getField(nextProps.name))
- }
- }
-
- render() {
- const { children, size, color, primary, submit, name, form } = this.props
-
- if (this.state.visible) {
- return (
-
- )
- } else {
- return null
- }
- }
-}
diff --git a/website/src/Validated/ValidatedCheckbox.js b/website/src/Validated/ValidatedCheckbox.js
deleted file mode 100644
index ba96ec5..0000000
--- a/website/src/Validated/ValidatedCheckbox.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { Checkbox } from 'ui'
-
-// This is an example of a validated component with a value that can change itself, that cannot ever be invalid.
-
-export class ValidatedCheckbox extends React.Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- label: PropTypes.string,
- validator: PropTypes.object.isRequired,
- }
-
- constructor(props) {
- super(props)
-
- this.state = props.validator.getField(props.name)
- this.handleChange = this.handleChange.bind(this)
- }
-
- handleChange(e, data) {
- const { validator, name } = this.props
- const state = validator.getField(name)
-
- if (!state.readOnly && !state.disabled) {
- this.setState(validator.updateValue(name, data.checked))
- }
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.setState(nextProps.validator.getField(nextProps.name))
- }
- }
-
- render() {
- return (
-
- )
- }
-}
diff --git a/website/src/Validated/ValidatedContainer.js b/website/src/Validated/ValidatedContainer.js
deleted file mode 100644
index 3e71fcf..0000000
--- a/website/src/Validated/ValidatedContainer.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-export class ValidatedContainer extends React.Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- validator: PropTypes.object.isRequired,
- children: PropTypes.oneOfType([
- PropTypes.array,
- PropTypes.object
- ])
- }
-
- constructor(props) {
- super(props)
- this.updateValue = this.updateValue.bind(this)
-
- let { name, validator } = this.props
-
- validator.addListener(name, this.updateValue)
- this.state = validator.getField(name)
- }
-
- updateValue(name) {
- this.setState(this.props.validator.getField(name))
- }
-
- componentWillUnmount() {
- this.props.validator.removeListener(this.props.name, this.updateValue)
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.props.validator.removeListener(this.props.name, this.updateValue)
- nextProps.validator.addListener(nextProps.name, this.updateValue)
- this.setState(nextProps.validator.getField(nextProps.name))
- }
- }
-
- render() {
- if (this.state.visible) {
- return (
-
- {this.props.children}
-
- )
- } else {
- return null
- }
- }
-}
diff --git a/website/src/Validated/ValidatedDropdown.js b/website/src/Validated/ValidatedDropdown.js
deleted file mode 100644
index 5968daf..0000000
--- a/website/src/Validated/ValidatedDropdown.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { Dropdown, Text } from 'ui'
-
-export class ValidatedDropdown extends React.Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- label: PropTypes.string,
- width: PropTypes.number,
- placeholder: PropTypes.string,
- options: PropTypes.array,
- message: PropTypes.string.isRequired,
- validator: PropTypes.object.isRequired,
- searchable: PropTypes.bool
- }
-
- constructor(props) {
- super(props)
-
- this.state = props.validator.getField(props.name)
- this.handleChange = this.handleChange.bind(this)
- }
-
- handleChange(e, data) {
- const { validator, name } = this.props
-
- this.setState(validator.updateValue(name, data.value))
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.setState(nextProps.validator.getField(nextProps.name))
- }
- }
-
- render() {
- return (
-
-
-
- {this.props.message}
-
- )
- }
-}
diff --git a/website/src/Validated/Validator.js b/website/src/Validated/Validator.js
deleted file mode 100644
index a0b0d61..0000000
--- a/website/src/Validated/Validator.js
+++ /dev/null
@@ -1,188 +0,0 @@
-import EventEmitter from 'eventemitter3'
-
-const any = function(obj, pred) {
- for (let name in obj) {
- if (pred(obj[name])) {
- return true
- }
- }
- return false
-}
-
-export class Validator extends EventEmitter {
- constructor(originalObj, validations, onModifiedChanged) {
- super()
- this.updateValue = this.updateValue.bind(this)
-
- this._id = originalObj._id
- this.onModifiedChanged = onModifiedChanged
- this.fields = {}
- this.nonValueFields = {}
-
- for (let name in validations) {
- let validation = validations[name]
- let field = {
- isDisabled: this.normalize(validation.isDisabled, false),
- isReadOnly: this.normalize(validation.isReadOnly, false),
- isVisible: this.normalize(validation.isVisible, true),
- nonValue: validation.nonValue || false
- }
-
- if (field.nonValue) {
- field.disabled = field.isDisabled(this)
- field.readOnly = field.isReadOnly(this)
- field.visible = field.isVisible(this)
- this.nonValueFields[name] = field
- } else {
- field.alwaysGet = validation.alwaysGet
- field.isValid = this.normalize(validation.isValid, true)
- field.initValue = (validation.initValue === undefined ? '' : validation.initValue)
- field.originalValue = Validator.getObjectValue(originalObj, name)
- this.updateFieldValue(field, field.originalValue || field.initValue)
- this.fields[name] = field
- }
- }
-
- this.updateNonValueFields()
- }
-
- normalize(obj, def) {
- return obj ? ((obj.constructor === Function) ? obj : () => (!!obj)) : () => (def)
- }
-
- static stateSafeField(field) {
- return {
- value: field.value,
- modified: field.modified,
- valid: field.valid,
- disabled: field.disabled,
- readOnly: field.readOnly,
- visible: field.visible
- }
- }
-
- updateValue(name, newValue) {
- let lastAnyModified = this.anyModified
- let field = this.fields[name]
-
- if (field) {
- this.updateFieldValue(field, newValue)
- this.updateNonValueFields()
- if (lastAnyModified !== this.anyModified && this.onModifiedChanged) {
- this.onModifiedChanged(this.anyModified)
- }
- }
-
- return Validator.stateSafeField(field)
- }
-
- updateFieldValue(field, newValue) {
- field.value = newValue
- field.disabled = field.isDisabled(this)
- field.readOnly = field.isReadOnly(this)
- field.visible = field.isVisible(this)
- field.valid = field.isValid(this, newValue)
- field.modified =
- field.originalValue !== undefined ? (field.originalValue !== newValue) : (newValue !== field.initValue)
-
- this.anyModified = field.modified || any(this.fields, (field) => (field.modified))
- this.allValid = !field.valid ? false : !any(this.fields, (field) => (!field.valid))
- }
-
- updateNonValueFields() {
- for (let name in this.nonValueFields) {
- let field = this.nonValueFields[name]
- let disabled = field.isDisabled(this)
- let readOnly = field.isReadOnly(this)
- let visible = field.isVisible(this)
- let b = (disabled !== field.disabled || readOnly !== field.readOnly || visible !== field.visible)
-
- field.disabled = disabled
- field.readOnly = readOnly
- field.visible = visible
-
- if (b) {
- this.emit(name, name)
- }
- }
- }
-
- getField(name) {
- let field = this.fields[name] || this.nonValueFields[name]
-
- if (!field) {
- throw new Error(`Field '${name}' does not have a validation entry`)
- }
-
- return Validator.stateSafeField(field)
- }
-
- getValues() {
- // Generate an object that has the modified and alwaysGet fields
- let obj = {}
-
- if (!this.anyModified && !this.allValid) {
- return obj
- }
-
- // Will have an _id if updating
- if (this._id) {
- obj._id = this._id
- }
-
- for (let name in this.fields) {
- let field = this.fields[name]
-
- if (field.alwaysGet || (!field.nonValue && field.modified)) {
- let value = field.value
- if (value && value.constructor === 'String') {
- value = value.trim()
- }
- Validator.setObjectValue(obj, name, value)
- }
- }
-
- return obj
- }
-
- getOriginalValues() {
- // Generate an object that has the original values of all fields
- let obj = {}
-
- if (this._id) {
- obj._id = this._id
- }
-
- for (let name in this.fields) {
- let field = this.fields[name]
-
- if (field.originalValue !== undefined) {
- Validator.setObjectValue(obj, name, field.originalValue)
- }
- }
-
- return obj
- }
-
- static getObjectValue(obj, name) {
- name.split('.').forEach((namePart) => {
- if (obj) {
- obj = obj[namePart]
- }
- })
- return obj
- }
-
- static setObjectValue(obj, name, value) {
- name.split('.').forEach((namePart, i, nameParts) => {
- if (i < nameParts.length - 1) {
- if (!obj[namePart]) {
- obj[namePart] = {}
- }
- obj = obj[namePart]
- } else {
- obj[namePart] = value
- }
- })
- }
-}
diff --git a/website/src/Validated/index.js b/website/src/Validated/index.js
deleted file mode 100644
index 7386654..0000000
--- a/website/src/Validated/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export { Validator } from './Validator'
-export { ValidatedInput } from './ValidatedInput'
-export { ValidatedButton } from './ValidatedButton'
-export { ValidatedActionsButton } from './ValidatedActionsButton'
-export { ValidatedDropdown } from './ValidatedDropdown'
-export { ValidatedCheckbox } from './ValidatedCheckbox'
-export { ValidatedContainer } from './ValidatedContainer'
diff --git a/website/src/assets/icons/logout.svg b/website/src/assets/icons/logout.svg
index ab6bfca..f431a20 100644
--- a/website/src/assets/icons/logout.svg
+++ b/website/src/assets/icons/logout.svg
@@ -1,54 +1,9 @@
-
-
-
+
+
diff --git a/website/src/assets/icons/placeholder.svg b/website/src/assets/icons/placeholder.svg
new file mode 100644
index 0000000..db1f6ad
--- /dev/null
+++ b/website/src/assets/icons/placeholder.svg
@@ -0,0 +1,9 @@
+
+
diff --git a/website/src/assets/icons/profile.svg b/website/src/assets/icons/profile.svg
new file mode 100644
index 0000000..8fe66d7
--- /dev/null
+++ b/website/src/assets/icons/profile.svg
@@ -0,0 +1,9 @@
+
+
diff --git a/website/src/assets/icons/shapes.svg b/website/src/assets/icons/shapes.svg
deleted file mode 100644
index f6b16b6..0000000
--- a/website/src/assets/icons/shapes.svg
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
diff --git a/website/src/Validated/ValidatedButton.js b/website/src/ui/BoundButton.js
similarity index 59%
rename from website/src/Validated/ValidatedButton.js
rename to website/src/ui/BoundButton.js
index 3242a4f..10b4c96 100644
--- a/website/src/Validated/ValidatedButton.js
+++ b/website/src/ui/BoundButton.js
@@ -1,15 +1,16 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Button } from 'ui'
+import { reactAutoBind } from 'auto-bind2'
-export class ValidatedButton extends React.Component {
+export default class BoundButton extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string,
width: PropTypes.number,
size: PropTypes.string,
content: PropTypes.string,
- validator: PropTypes.object.isRequired,
+ binder: PropTypes.object.isRequired,
submit: PropTypes.bool,
color: PropTypes.string,
onClick: PropTypes.func
@@ -17,27 +18,27 @@ export class ValidatedButton extends React.Component {
constructor(props) {
super(props)
- this.updateValue = this.updateValue.bind(this)
+ reactAutoBind(this)
- let { name, validator } = this.props
+ let { name, binder } = this.props
- validator.addListener(name, this.updateValue)
- this.state = validator.getField(name)
+ binder.addListener(name, this.updateValue)
+ this.state = binder.getFieldState(name)
}
updateValue(name) {
- this.setState(this.props.validator.getField(name))
+ this.setState(this.props.binder.getFieldState(name))
}
componentWillUnmount() {
- this.props.validator.removeListener(this.props.name, this.updateValue)
+ this.props.binder.removeListener(this.props.name, this.updateValue)
}
componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.props.validator.removeListener(this.props.name, this.updateValue)
- nextProps.validator.addListener(nextProps.name, this.updateValue)
- this.setState(nextProps.validator.getField(nextProps.name))
+ if (nextProps.binder !== this.props.binder) {
+ this.props.binder.removeListener(this.props.name, this.updateValue)
+ nextProps.binder.addListener(nextProps.name, this.updateValue)
+ this.setState(nextProps.binder.getFieldState(nextProps.name))
}
}
diff --git a/website/src/ui/BoundCheckbox.js b/website/src/ui/BoundCheckbox.js
new file mode 100644
index 0000000..d091f6d
--- /dev/null
+++ b/website/src/ui/BoundCheckbox.js
@@ -0,0 +1,39 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { Checkbox } from 'ui'
+import { reactAutoBind } from 'auto-bind2'
+
+export default class BoundCheckbox extends React.Component {
+ static propTypes = {
+ name: PropTypes.string.isRequired,
+ label: PropTypes.string,
+ binder: PropTypes.object.isRequired,
+ }
+
+ constructor(props) {
+ super(props)
+ reactAutoBind(this)
+ this.state = props.binder.getFieldState(props.name)
+ }
+
+ handleChange(e, data) {
+ const { binder, name } = this.props
+ const state = binder.getFieldState(name)
+
+ if (!state.readOnly && !state.disabled) {
+ this.setState(binder.updateFieldValue(name, data.checked))
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.binder !== this.props.binder) {
+ this.setState(nextProps.binder.getFieldState(nextProps.name))
+ }
+ }
+
+ render() {
+ return (
+
+ )
+ }
+}
diff --git a/website/src/Users/ValidatedEmailIcon.js b/website/src/ui/BoundEmailIcon.js
similarity index 56%
rename from website/src/Users/ValidatedEmailIcon.js
rename to website/src/ui/BoundEmailIcon.js
index feff83f..775211c 100644
--- a/website/src/Users/ValidatedEmailIcon.js
+++ b/website/src/ui/BoundEmailIcon.js
@@ -2,24 +2,22 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Text, Button, Icon } from 'ui'
-// This is a validated component with a value that cannot change itself and is specialized
-
-export class ValidatedEmailIcon extends React.Component {
+export default class BoundEmailIcon extends React.Component {
static propTypes = {
name: PropTypes.string,
- validator: PropTypes.object,
+ binder: PropTypes.object,
width: PropTypes.number,
onClick: PropTypes.func
}
constructor(props) {
super(props)
- this.state = props.validator.getField('emailValidated')
+ this.state = props.binder.getField('emailValidated')
}
componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.setState(nextProps.validator.getField(nextProps.name))
+ if (nextProps.binder !== this.props.binder) {
+ this.setState(nextProps.binder.getField(nextProps.name))
}
}
@@ -28,14 +26,14 @@ export class ValidatedEmailIcon extends React.Component {
return (
-
+
)
} else {
return (
-
)
diff --git a/website/src/Validated/ValidatedInput.js b/website/src/ui/BoundInput.js
similarity index 62%
rename from website/src/Validated/ValidatedInput.js
rename to website/src/ui/BoundInput.js
index d40b4b7..eb7745f 100644
--- a/website/src/Validated/ValidatedInput.js
+++ b/website/src/ui/BoundInput.js
@@ -1,38 +1,36 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Input, Text } from 'ui'
+import { reactAutoBind } from 'auto-bind2'
-// This is an example of a validated component with a value that changes itself
-
-export class ValidatedInput extends React.Component {
+export default class BoundInput extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
message: PropTypes.string,
label: PropTypes.string,
- validator: PropTypes.object.isRequired,
+ binder: PropTypes.object.isRequired,
password: PropTypes.bool,
placeholder: PropTypes.string
}
constructor(props) {
super(props)
-
- this.state = props.validator.getField(props.name)
- this.handleChange = this.handleChange.bind(this)
+ reactAutoBind(this)
+ this.state = props.binder.getFieldState(props.name)
}
handleChange(e, data) {
- const { validator, name } = this.props
- const state = validator.getField(name)
+ const { binder, name } = this.props
+ const state = binder.getFieldState(name)
if (!state.readOnly && !state.disabled) {
- this.setState(validator.updateValue(name, data.value))
+ this.setState(binder.updateFieldValue(name, data.value))
}
}
componentWillReceiveProps(nextProps) {
- if (nextProps.validator !== this.props.validator) {
- this.setState(nextProps.validator.getField(nextProps.name))
+ if (nextProps.binder !== this.props.binder) {
+ this.setState(nextProps.binder.getFieldState(nextProps.name))
}
}
diff --git a/website/src/ui/Box.js b/website/src/ui/Box.js
index c73bbe7..d696035 100644
--- a/website/src/ui/Box.js
+++ b/website/src/ui/Box.js
@@ -18,6 +18,7 @@ class Box extends Component {
return (
{children}
diff --git a/website/src/ui/Checkbox.js b/website/src/ui/Checkbox.js
index 4db2b76..1d3d72b 100644
--- a/website/src/ui/Checkbox.js
+++ b/website/src/ui/Checkbox.js
@@ -31,9 +31,9 @@ class Checkbox extends Component {
{this.props.label}
diff --git a/website/src/ui/Column.js b/website/src/ui/Column.js
index d244695..b6d6ed6 100644
--- a/website/src/ui/Column.js
+++ b/website/src/ui/Column.js
@@ -12,7 +12,7 @@ class Column extends Component {
const { children, minHeight } = this.props
return (
- {children}
+ {children}
)
}
}
@@ -21,15 +21,21 @@ Column.Item = Radium(class StackLayoutItem extends Component {
static propTypes = {
children: PropTypes.node,
minHeight: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ height: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ paddingTop: PropTypes.number,
+ paddingBottom: PropTypes.number,
+ padding: PropTypes.number,
grow: PropTypes.bool
}
render() {
- const { children, grow, minHeight } = this.props
+ const { children, grow, height, minHeight, padding, paddingTop, paddingBottom } = this.props
const flexGrow = grow ? 1 : null
return (
- {children}
+
+ {children}
+
)
}
})
diff --git a/website/src/ui/HeaderButton.js b/website/src/ui/HeaderButton.js
new file mode 100644
index 0000000..8e80808
--- /dev/null
+++ b/website/src/ui/HeaderButton.js
@@ -0,0 +1,25 @@
+import Radium from 'radium'
+import PropTypes from 'prop-types'
+import React, { Component } from 'react'
+import style from './HeaderButton.style'
+import { Icon } from 'ui'
+
+class HeaderButton extends Component {
+ static propTypes = {
+ icon: PropTypes.string,
+ onClick: PropTypes.func,
+ size: PropTypes.number
+ }
+
+ render() {
+ const { onClick, icon, size } = this.props
+
+ return (
+
+ )
+ }
+}
+
+export default Radium(HeaderButton)
diff --git a/website/src/ui/HeaderButton.style.js b/website/src/ui/HeaderButton.style.js
new file mode 100644
index 0000000..21bd69f
--- /dev/null
+++ b/website/src/ui/HeaderButton.style.js
@@ -0,0 +1,15 @@
+import { colorInfo } from './style'
+
+export default {
+ base: {
+ background: colorInfo.headerButtonBackground,
+ verticalAlign: 'middle',
+ borderWidth: 0,
+ padding: '0 0 0 0',
+ outline: 'none',
+
+ ':hover': {
+ background: colorInfo.headerButtonBackgroundHover,
+ }
+ }
+}
diff --git a/website/src/ui/Icon.js b/website/src/ui/Icon.js
index d1d7777..fc8f09e 100644
--- a/website/src/ui/Icon.js
+++ b/website/src/ui/Icon.js
@@ -1,28 +1,32 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import { sizeInfo } from './style'
-// See https://www.flaticon.com/packs/web-button-compilation for more icons
+// See https://www.flaticon.com/packs/free-basic-ui-elements
export default class Icon extends Component {
static propTypes = {
name: PropTypes.string.isRequired,
size: PropTypes.number,
- margin: PropTypes.number
}
static defaultProps = {
- size: 50,
- margin: 5,
- name: 'shapes'
+ size: 50
}
static svgs = {
logout: require('icons/logout.svg'),
- shapes: require('icons/shapes.svg')
+ profile: require('icons/profile.svg'),
+ placeholder: require('icons/placeholder.svg'),
}
render() {
- return
+ let { size, name } = this.props
+ let source = Icon.svgs[name] || Icon.svgs['placeholder']
+ const margin = sizeInfo.iconMargin
+
+ size -= margin * 2
+
+ return
}
}
diff --git a/website/src/ui/Image.js b/website/src/ui/Image.js
index 5d347b9..3523980 100644
--- a/website/src/ui/Image.js
+++ b/website/src/ui/Image.js
@@ -1,18 +1,24 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
+import { sizeInfo } from './style'
class Image extends Component {
static propTypes = {
source: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
- margin: PropTypes.number
}
render() {
+ let { source, width, height } = this.props
+ const margin = sizeInfo.imageMargin
+
+ width = width ? (width - margin * 2) : null
+ height = height ? (height - margin * 2) : null
+
return (
-
+
)
}
}
diff --git a/website/src/ui/Row.js b/website/src/ui/Row.js
index a5cca28..63250fb 100644
--- a/website/src/ui/Row.js
+++ b/website/src/ui/Row.js
@@ -12,7 +12,7 @@ class Row extends Component {
const { children, minWidth } = this.props
return (
- {children}
+ {children}
)
}
}
diff --git a/website/src/ui/index.js b/website/src/ui/index.js
index d7fda85..c464e39 100644
--- a/website/src/ui/index.js
+++ b/website/src/ui/index.js
@@ -1,5 +1,6 @@
export { default as Box } from './Box'
export { default as Button } from './Button'
+export { default as HeaderButton } from './HeaderButton'
export { default as Checkbox } from './Checkbox'
export { default as Input } from './Input'
export { default as Image } from './Image'
@@ -13,3 +14,7 @@ export { default as Dimmer } from './Dimmer'
export { default as Loader } from './Loader'
export { default as Row } from './Row'
export { default as Column } from './Column'
+export { default as BoundButton } from './BoundButton'
+export { default as BoundCheckbox } from './BoundCheckbox'
+export { default as BoundInput } from './BoundInput'
+export { default as BoundEmailIcon } from './BoundEmailIcon'
diff --git a/website/src/ui/style.js b/website/src/ui/style.js
index f392d7e..f0f993a 100644
--- a/website/src/ui/style.js
+++ b/website/src/ui/style.js
@@ -3,7 +3,16 @@ export const colorInfo = {
alertText: '#FF0000',
grayText: '#B0B0B0',
buttonBackground: '#3498DB',
- buttonBackgroundHover: '#3CB0FD'
+ buttonBackgroundHover: '#3CB0FD',
+ headerButtonBackground: '#FAFAFA',
+ headerButtonBackgroundHover: '#DADADA',
+}
+
+export const sizeInfo = {
+ headerHeight: 60,
+ imageMargin: 5, // The margin around images
+ iconMargin: 10, // The margin around icons
+ headerBorderWidth: 1
}
export const fontInfo = {