From 7e655d513c10d32af331c3f01bbe08e558e65fa6 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 4 May 2022 18:53:43 +0200 Subject: [PATCH] change(ui) - userlist form --- .../app/components/Client/Users/UsersView.tsx | 48 +++++++++++++++++-- .../Users/components/UserForm/UserForm.tsx | 14 ++++-- .../components/UserSearch/UserSearch.tsx | 2 +- .../components/DefaultTimezone.tsx | 1 - frontend/app/mstore/types/role.ts | 2 +- frontend/app/mstore/types/user.ts | 20 ++++++-- frontend/app/mstore/userStore.ts | 30 +++++++----- frontend/app/services/UserService.ts | 10 ++-- 8 files changed, 95 insertions(+), 32 deletions(-) diff --git a/frontend/app/components/Client/Users/UsersView.tsx b/frontend/app/components/Client/Users/UsersView.tsx index 5b207a468..7d4029b5f 100644 --- a/frontend/app/components/Client/Users/UsersView.tsx +++ b/frontend/app/components/Client/Users/UsersView.tsx @@ -1,14 +1,32 @@ import React, { useEffect } from 'react'; import UserList from './components/UserList'; -import { PageTitle } from 'UI'; +import { PageTitle, Popup, IconButton } from 'UI'; import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; import UserSearch from './components/UserSearch'; +import { useModal } from 'App/components/Modal'; +import UserForm from './components/UserForm'; +import { connect } from 'react-redux'; -function UsersView(props) { +interface Props { + account: any; + isEnterprise: boolean; +} +function UsersView(props: Props) { + const { account, isEnterprise } = props; const { userStore, roleStore } = useStore(); const userCount = useObserver(() => userStore.list.length); const roles = useObserver(() => roleStore.list); + const { showModal } = useModal(); + + const isAdmin = account.admin || account.superAdmin; + // const canAddUsers = isAdmin && userCount !== 0; // TODO fetch limits and disable button if limit reached + + const editHandler = (user = null) => { + userStore.initUser(user).then(() => { + showModal(, { right: true }); + }); + } useEffect(() => { if (roles.length === 0) { @@ -22,7 +40,26 @@ function UsersView(props) { Team {userCount}} actionButton={( -
test
+ + editHandler(null) } + /> + + } + // disabled={ canAddUsers } + // content={ `${ !canAddUsers ? (!isAdmin ? PERMISSION_WARNING : LIMIT_WARNING) : 'Add team member' }` } + size="tiny" + inverted + position="top left" + /> )} />
@@ -34,4 +71,7 @@ function UsersView(props) { ); } -export default UsersView; \ No newline at end of file +export default connect(state => ({ + account: state.getIn([ 'user', 'account' ]), + isEnterprise: state.getIn([ 'user', 'client', 'edition' ]) === 'ee', +}))(UsersView); \ No newline at end of file diff --git a/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx b/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx index b47a38d50..489f27881 100644 --- a/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx +++ b/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx @@ -1,9 +1,10 @@ import React from 'react'; -import { Input, CopyButton, Button, Select } from 'UI' +import { Input, CopyButton, Button } from 'UI' import cn from 'classnames'; import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; import { useModal } from 'App/components/Modal'; +import Select from 'Shared/Select'; interface Props { isSmtp?: boolean; @@ -16,18 +17,21 @@ function UserForm(props: Props) { const { userStore, roleStore } = useStore(); const user: any = useObserver(() => userStore.instance); const roles = useObserver(() => roleStore.list.map(r => ({ label: r.name, value: r.roleId }))); - console.log('roles', roles) const onChangeCheckbox = (e: any) => { user.updateKey('isAdmin', !user.isAdmin); } const onSave = () => { + userStore.saveUser(user).then(() => { + hideModal(); + }); } const write = ({ target: { name, value } }) => { user.updateKey(name, value); } + return useObserver(() => (
@@ -87,8 +91,8 @@ function UserForm(props: Props) { selection options={ roles } name="roleId" - value={ user.roleId } - onChange={ write } + defaultValue={ user.roleId } + onChange={({ value }) => user.updateKey('roleId', value)} className="block" />
@@ -111,7 +115,7 @@ function UserForm(props: Props) { onClick={ hideModal } outline > - { 'Cancel' } + { 'Cancel' }
{ !user.isJoined && user.invitationLink && diff --git a/frontend/app/components/Client/Users/components/UserSearch/UserSearch.tsx b/frontend/app/components/Client/Users/components/UserSearch/UserSearch.tsx index 3b2f5d754..cc78476d8 100644 --- a/frontend/app/components/Client/Users/components/UserSearch/UserSearch.tsx +++ b/frontend/app/components/Client/Users/components/UserSearch/UserSearch.tsx @@ -25,7 +25,7 @@ function UserSearch(props) { value={query} name="searchQuery" className="bg-white p-2 border border-gray-light rounded w-full pl-10" - placeholder="Filter by Name, Project" + placeholder="Filter by Name, Role" onChange={write} />
diff --git a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx index e7af914d4..efb91fed9 100644 --- a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx +++ b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx @@ -16,7 +16,6 @@ function DefaultTimezone(props) { const { settingsStore } = useStore(); const [timezone, setTimezone] = React.useState(settingsStore.sessionSettings.timezone); const sessionSettings = useObserver(() => settingsStore.sessionSettings) - console.log('timezone', timezone) return ( <> diff --git a/frontend/app/mstore/types/role.ts b/frontend/app/mstore/types/role.ts index 189984e0f..e8204ef22 100644 --- a/frontend/app/mstore/types/role.ts +++ b/frontend/app/mstore/types/role.ts @@ -25,7 +25,7 @@ export default class Role implements IRole { fromJson(json: any) { runInAction(() => { - this.roleId = json.id; + this.roleId = json.roleId; this.name = json.name; this.description = json.description; }) diff --git a/frontend/app/mstore/types/user.ts b/frontend/app/mstore/types/user.ts index 557beb794..c8b9dcdd6 100644 --- a/frontend/app/mstore/types/user.ts +++ b/frontend/app/mstore/types/user.ts @@ -1,6 +1,6 @@ import { runInAction, makeAutoObservable, observable } from 'mobx' import { DateTime } from 'luxon'; -import { validateEmail } from 'App/validate'; +import { validateEmail, validateName } from 'App/validate'; export interface IUser { userId: string @@ -16,6 +16,7 @@ export interface IUser { fromJson(json: any): IUser toJson(): any + toSave(): any } export default class User implements IUser { @@ -55,7 +56,7 @@ export default class User implements IUser { fromJson(json: any) { runInAction(() => { - this.userId = json.id; + this.userId = json.userId || json.id; // TODO api returning id this.name = json.name; this.email = json.email; this.createdAt = json.createdAt && DateTime.fromISO(json.createdAt || 0) @@ -72,15 +73,26 @@ export default class User implements IUser { toJson() { return { + userId: this.userId, + name: this.name, email: this.email, - isAdmin: this.isAdmin, + admin: this.isAdmin, isSuperAdmin: this.isSuperAdmin, roleId: this.roleId, } } + toSave() { + return { + name: this.name, + email: this.email, + admin: this.isAdmin, + roleId: this.roleId, + } + } + valid() { - return validateEmail(this.email) && !!this.roleId; + return validateName(this.name, { empty: false }) && validateEmail(this.email) && !!this.roleId; } exists() { diff --git a/frontend/app/mstore/userStore.ts b/frontend/app/mstore/userStore.ts index 33e2e9754..640c8910b 100644 --- a/frontend/app/mstore/userStore.ts +++ b/frontend/app/mstore/userStore.ts @@ -1,15 +1,18 @@ import { makeAutoObservable, observable, action } from "mobx" import User, { IUser } from "./types/user"; import { userService } from "App/services"; +import { toast } from 'react-toastify'; export default class UserStore { list: IUser[] = []; instance: IUser|null = null; - loading: boolean = false; page: number = 1; pageSize: number = 10; searchQuery: string = ""; + loading: boolean = false; + saving: boolean = false; + constructor() { makeAutoObservable(this, { instance: observable, @@ -22,7 +25,7 @@ export default class UserStore { initUser(user?: any ): Promise { return new Promise((resolve, reject) => { if (user) { - this.instance = user; + this.instance = new User().fromJson(user.toJson()); } else { this.instance = new User(); } @@ -38,8 +41,11 @@ export default class UserStore { } } - updateUser(user: any) { - Object.assign(this.instance, user); + updateUser(user: IUser) { + const index = this.list.findIndex(u => u.userId === user.userId); + if (index > -1) { + this.list[index] = user; + } } fetchUser(userId: string): Promise { @@ -75,22 +81,24 @@ export default class UserStore { } saveUser(user: IUser): Promise { - this.loading = true; + this.saving = true; const wasCreating = !user.userId; return new Promise((resolve, reject) => { - userService.save(user) - .then(response => { + userService.save(user).then(response => { + const newUser = new User().fromJson(response); if (wasCreating) { - this.list.push(new User().fromJson(response.data)); + this.list.push(new User().fromJson(newUser)); + toast.success('User created successfully'); } else { - this.updateUser(response.data); + this.updateUser(newUser); + toast.success('User updated successfully'); } resolve(response); }).catch(error => { - this.loading = false; + this.saving = false; reject(error); }).finally(() => { - this.loading = false; + this.saving = false; }); }); } diff --git a/frontend/app/services/UserService.ts b/frontend/app/services/UserService.ts index ac65a9647..4715f2e13 100644 --- a/frontend/app/services/UserService.ts +++ b/frontend/app/services/UserService.ts @@ -24,14 +24,14 @@ export default class UserService { .then(response => response.data || {}); } - save(user: IUser) { - const data = user.toJson(); + save(user: IUser): Promise { + const data = user.toSave(); if (user.userId) { - return this.client.put('/users/' + user.userId, data) + return this.client.put('/client/members/' + user.userId, data) .then(response => response.json()) - .then(response => response.data || {}); + .then(response => response.data || {}) } else { - return this.client.post('/users', data) + return this.client.post('/client/members', data) .then(response => response.json()) .then(response => response.data || {}); }