change(ui) - userlist form

This commit is contained in:
Shekar Siri 2022-05-04 18:53:43 +02:00
parent 5ef382c9b8
commit 7e655d513c
8 changed files with 95 additions and 32 deletions

View file

@ -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(<UserForm />, { right: true });
});
}
useEffect(() => {
if (roles.length === 0) {
@ -22,7 +40,26 @@ function UsersView(props) {
<PageTitle
title={<div>Team <span className="color-gray-medium">{userCount}</span></div>}
actionButton={(
<div className="ml-2">test</div>
<Popup
trigger={
<div>
<IconButton
id="add-button"
// disabled={ !canAddUsers }
circle
icon="plus"
outline
className="ml-3"
onClick={ () => editHandler(null) }
/>
</div>
}
// disabled={ canAddUsers }
// content={ `${ !canAddUsers ? (!isAdmin ? PERMISSION_WARNING : LIMIT_WARNING) : 'Add team member' }` }
size="tiny"
inverted
position="top left"
/>
)}
/>
<div>
@ -34,4 +71,7 @@ function UsersView(props) {
);
}
export default UsersView;
export default connect(state => ({
account: state.getIn([ 'user', 'account' ]),
isEnterprise: state.getIn([ 'user', 'client', 'edition' ]) === 'ee',
}))(UsersView);

View file

@ -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(() => (
<div className="bg-white h-screen p-6" style={{ width: '400px'}}>
<div className="">
@ -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"
/>
</div>
@ -111,7 +115,7 @@ function UserForm(props: Props) {
onClick={ hideModal }
outline
>
{ 'Cancel' }
{ 'Cancel' }
</Button>
</div>
{ !user.isJoined && user.invitationLink &&

View file

@ -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}
/>
</div>

View file

@ -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 (
<>

View file

@ -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;
})

View file

@ -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() {

View file

@ -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<void> {
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<any> {
@ -75,22 +81,24 @@ export default class UserStore {
}
saveUser(user: IUser): Promise<any> {
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;
});
});
}

View file

@ -24,14 +24,14 @@ export default class UserService {
.then(response => response.data || {});
}
save(user: IUser) {
const data = user.toJson();
save(user: IUser): Promise<any> {
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 || {});
}