diff --git a/client/src/components/Admin/Users/List/List.css b/client/src/components/Admin/Users/List/List.css index 77a6e02c..13f5e973 100644 --- a/client/src/components/Admin/Users/List/List.css +++ b/client/src/components/Admin/Users/List/List.css @@ -1,32 +1,57 @@ -table.list { - width: 100%; +.table { margin-top: 1rem; - border-collapse: collapse; } -.list th { - border-bottom: 1px solid #9597b1; - font-weight: normal; - padding: 0.25rem 0.25rem; +.center { + display: flex; + justify-content: center; } -.list td { - padding: 0.5rem 0.25rem; - border-bottom: 1px solid #dbdce0; +.tableCell { + display: flex; + align-items: center; + margin-left: 0.25rem; } -.list tr:nth-child(even) td { - background: #f9f9f9; +.action { + display: inline; + font-size: 2rem; + font-weight: bold; + color: #CCC; + padding: 0; + background: none; + border: none; } -.left { - text-align: left; +.action:last-child { + margin-left: 0.5rem; } -.center { - text-align: center; +.action:focus { + outline: none; +} + +.success { + composes: icon success from 'css/flaticon.css'; +} + +.close { + composes: icon close from 'css/flaticon.css'; +} + +.unavailable { + composes: icon lock from 'css/flaticon.css'; +} + +.toggle.success { + color: #258573; +} + +.toggle.close { + color: #c5493c; } -.right { - text-align: right; +.canNotVote { + color: #b73b3b; + font-weight: bold; } diff --git a/client/src/components/Admin/Users/List/Table.js b/client/src/components/Admin/Users/List/Table.js new file mode 100644 index 00000000..d11d4532 --- /dev/null +++ b/client/src/components/Admin/Users/List/Table.js @@ -0,0 +1,51 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { getPermissionDisplay } from 'common/auth/permissions'; +import classNames from 'classnames'; +import moment from 'moment'; +import css from './List.css'; +import { ToggleCanVoteContainer } from '../ToggleCanVote'; + +export const RegisteredIndicator = props => +
{props.value.isRegistered}
; + +RegisteredIndicator.propTypes = { + value: PropTypes.shape({ + registeredDate: PropTypes.string, + isRegistered: PropTypes.bool, + }).isRequired, +}; + +export const PermissionDisplay = props => + getPermissionDisplay(props.value); + +PermissionDisplay.propTypes = { + value: PropTypes.number, +}; + +export const ToggleCanVoteIndicator = (props, toggleCanVote) => + ; + +ToggleCanVoteIndicator.propTypes = { + value: PropTypes.bool.isRequired, + original: PropTypes.shape({ + id: PropTypes.string, + permissions: PropTypes.number, + setPermissions: PropTypes.func.isRequired, + }).isRequired, +}; diff --git a/client/src/components/Admin/Users/List/index.js b/client/src/components/Admin/Users/List/index.js index 356626c7..cb385af7 100644 --- a/client/src/components/Admin/Users/List/index.js +++ b/client/src/components/Admin/Users/List/index.js @@ -4,8 +4,11 @@ import { connect } from 'react-redux'; import Fuse from 'fuse.js'; import { CAN_VOTE } from 'common/auth/permissions'; import { adminToggleCanVote } from 'features/user/actionCreators'; -import { UserContainer } from '../User'; +import ReactTable from 'react-table'; +import 'react-table/react-table.css'; +import classNames from 'classnames'; import css from './List.css'; +import { RegisteredIndicator, PermissionDisplay, ToggleCanVoteIndicator } from './Table'; const UserList = ({ users, toggleCanVote }) => { const userKeys = Object.keys(users); @@ -19,42 +22,62 @@ const UserList = ({ users, toggleCanVote }) => { const usersRegistered = userKeys .filter(u => users[u].completedRegistration) .length; + + const data = [...Object.keys(users) + .map(key => users[key]) + .map(user => ({ + name: user.name, + canVote: user.canVote, + registered: { + registeredDate: user.registered, + isRegistered: user.completedRegistration, + }, + id: user.id, + permissions: user.permissions, + setPermissions: user.setPermissions, + }))]; + + const columns = [{ + Header: `Navn (${totalUsers})`, + accessor: 'name', + }, { + Header: `Registrert (${usersRegistered})`, + accessor: 'registered', + className: css.center, + Cell: RegisteredIndicator, + }, { + Header: `Rettigheter (${usersHasPermsToVote})`, + accessor: 'permissions', + Cell: PermissionDisplay, + }, { + Header: `Stemmeberettigelse (${usersCanVote}/${usersHasPermsToVote})`, + accessor: 'canVote', + className: css.center, + Cell: props => ToggleCanVoteIndicator(props, toggleCanVote), + }]; + return ( - - - - - - - - - - - {Object.keys(users) - .sort((a, b) => users[a].name.localeCompare(users[b].name)) - .map((key) => { - const user = users[key]; - return (); - }, - )} - -
Bruker ({totalUsers}) - Registrert ({usersRegistered}) - - Rettigheter ({usersHasPermsToVote}) - - Stemmeberettigelse ({usersCanVote}/{usersHasPermsToVote}) -
- ); + ({ + className: classNames({ + [css.canNotVote]: !(rowInfo && rowInfo.row.canVote), + }), + })} + getTdProps={() => ({ + className: css.tableCell, + })} + />); }; UserList.propTypes = { diff --git a/client/src/components/Admin/Users/User/User.css b/client/src/components/Admin/Users/ToggleCanVote/ToggleCanVote.css similarity index 83% rename from client/src/components/Admin/Users/User/User.css rename to client/src/components/Admin/Users/ToggleCanVote/ToggleCanVote.css index b649770d..a8030fde 100644 --- a/client/src/components/Admin/Users/User/User.css +++ b/client/src/components/Admin/Users/ToggleCanVote/ToggleCanVote.css @@ -3,14 +3,6 @@ font-weight: bold; } -.left { - composes: left from '../List/List.css'; -} - -.right { - composes: right from '../List/List.css'; -} - .action { display: inline; font-size: 2rem; diff --git a/client/src/components/Admin/Users/ToggleCanVote/index.js b/client/src/components/Admin/Users/ToggleCanVote/index.js new file mode 100644 index 00000000..4cd933f5 --- /dev/null +++ b/client/src/components/Admin/Users/ToggleCanVote/index.js @@ -0,0 +1,98 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import classNames from 'classnames'; +import { CAN_VOTE } from 'common/auth/permissions'; +import { adminSetPermissions } from 'features/user/actionCreators'; +import Button from '../../../Button'; +import Dialog from '../../../Dialog'; +import css from './ToggleCanVote.css'; + +class ToggleCanVote extends React.Component { + constructor(props) { + super(props); + + this.state = { + showToggleCanVoteWarning: false, + }; + } + + canVoteHandler(id, toggleTo) { + this.setState({ showToggleCanVoteWarning: false }); + this.props.setPermissions(id, toggleTo, CAN_VOTE); + } + + render() { + const { id, canVote, permissions, toggleCanVote } = this.props; + + const successToggle = classNames( + css.success, + { [css.toggle]: canVote }, + ); + + const closeToggle = classNames( + css.close, + { [css.toggle]: !canVote }, + ); + + return ( + + this.setState({ showToggleCanVoteWarning: false })} + > +

Dette kan bare gjøres dersom generalforsamlingen vedtar det.

+ + +
+ + + +
+ ); + } +} + +ToggleCanVote.propTypes = { + canVote: PropTypes.bool.isRequired, + id: PropTypes.string.isRequired, + permissions: PropTypes.number.isRequired, + setPermissions: PropTypes.func.isRequired, + toggleCanVote: PropTypes.func.isRequired, +}; + +const mapDispatchToProps = ({ + setPermissions: adminSetPermissions, +}); + +export default ToggleCanVote; +export const ToggleCanVoteContainer = connect( + null, + mapDispatchToProps, +)(ToggleCanVote); diff --git a/client/src/components/Admin/Users/User/index.js b/client/src/components/Admin/Users/User/index.js deleted file mode 100644 index a0660a5a..00000000 --- a/client/src/components/Admin/Users/User/index.js +++ /dev/null @@ -1,122 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import classNames from 'classnames'; -import moment from 'moment'; -import { CAN_VOTE, getPermissionDisplay } from 'common/auth/permissions'; -import { adminSetPermissions } from 'features/user/actionCreators'; -import Button from '../../../Button'; -import Dialog from '../../../Dialog'; -import css from './User.css'; - -class User extends React.Component { - constructor(props) { - super(props); - this.state = { - showToggleCanVoteWarning: false, - }; - } - - canVoteHandler(id, toggleTo) { - this.setState({ showToggleCanVoteWarning: false }); - this.props.setPermissions(id, toggleTo, CAN_VOTE); - } - - render() { - const { id, name, registered, canVote, completedRegistration, permissions, toggleCanVote, - } = this.props; - const userClass = classNames({ - [css.canNotVote]: !canVote, - }); - const registeredDate = moment(registered); - const successToggle = classNames( - css.success, - { [css.toggle]: canVote }, - ); - const closeToggle = classNames( - css.close, - { [css.toggle]: !canVote }, - ); - const permissionLevel = getPermissionDisplay(permissions); - return ( - - {name} - -
{completedRegistration}
- - - {permissionLevel} - - - this.setState({ showToggleCanVoteWarning: false })} - > -

Dette kan bare gjøres dersom generalforsamlingen vedtar det.

- - -
- - - - - ); - } -} - -User.propTypes = { - name: PropTypes.string.isRequired, - canVote: PropTypes.bool.isRequired, - completedRegistration: PropTypes.bool.isRequired, - id: PropTypes.string.isRequired, - permissions: PropTypes.number.isRequired, - registered: PropTypes.string.isRequired, - setPermissions: PropTypes.func.isRequired, - toggleCanVote: PropTypes.func.isRequired, -}; - -const mapDispatchToProps = ({ - setPermissions: adminSetPermissions, -}); - -export default User; -export const UserContainer = connect( - null, - mapDispatchToProps, -)(User); diff --git a/client/src/components/Dialog/Dialog.css b/client/src/components/Dialog/Dialog.css index 2eec7c58..258fdd29 100644 --- a/client/src/components/Dialog/Dialog.css +++ b/client/src/components/Dialog/Dialog.css @@ -9,6 +9,7 @@ .visible { display: block; + z-index: 1; } .backdrop { diff --git a/package.json b/package.json index 25dfc6c2..a47fc429 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-hot-loader": "^3.0.0", "react-redux": "^5.0.2", "react-router-dom": "^4.1.1", + "react-table": "^6.9.2", "redux": "^3.6.0", "redux-logger": "^3.0.1", "redux-persist": "^5.1.0", diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 6e965aa9..d90f5232 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -11,8 +11,24 @@ module.exports = merge.smart(config, { devtool: 'eval-source-map', module: { rules: [ + { + test: /\.css$/, + include: [/node_modules/], + use: [ + { + loader: "style-loader", + }, + { + loader: "css-loader", + options: { + modules: false, + }, + }, + ], + }, { test: /\.css$/, + exclude: [/node_modules/], use: [ { loader: 'style-loader', @@ -23,6 +39,7 @@ module.exports = merge.smart(config, { sourceMap: true, modules: true, localIdentName: '[name]__[local]___[hash:base64:5]', + importLoaders:1, }, }, { diff --git a/yarn.lock b/yarn.lock index 86a02a99..070bc304 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6247,6 +6247,13 @@ react-side-effect@^1.0.2: exenv "^1.2.1" shallowequal "^1.0.1" +react-table@^6.9.2: + version "6.9.2" + resolved "https://registry.yarnpkg.com/react-table/-/react-table-6.9.2.tgz#6a59adfeb8d5deced288241ed1c7847035b5ec5f" + integrity sha512-sTbNHU8Um0xRtmCd1js873HXnXaMWeBwZoiljuj0l1d44eaqjKyYPK/3HCBbJg1yeE2O5pQJ3Km0tlm9niNL9w== + dependencies: + classnames "^2.2.5" + react@^16.0.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"