From c72b7dd03453aa01c1e61f13b9bfaeb76d2a7b69 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:20:00 -0300 Subject: [PATCH 01/35] feat: add condition that doesn't allow the user remove the admin role from the last admin --- packages/api/src/user/controllers.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/api/src/user/controllers.ts b/packages/api/src/user/controllers.ts index 5f3e2cb04..733b75602 100644 --- a/packages/api/src/user/controllers.ts +++ b/packages/api/src/user/controllers.ts @@ -118,7 +118,6 @@ const addRole = async ( user.nonce = undefined; await user.save(); } - const userWithDetails = await findUser(id); res.status(200).json(userTransformer(res, userWithDetails)); }; @@ -137,6 +136,12 @@ const removeRole = async ( const { role } = req.body; if (!role) throw new BadRequestError('Role is required'); + if (role === UserRole.ADMIN) { + const allAdmins = await UserModel.find({ roles: { $in: ['ADMIN'] } }); + if (allAdmins.length <= 1) { + throw new BadRequestError("You can't remove the last admin!"); + } + } const roleIndex = user.roles.indexOf(role); From 328be65158fc7eb6e7d3841e40ed2e1a97203fd5 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:20:38 -0300 Subject: [PATCH 02/35] feat: added selector for all admins and for all forwarders users --- packages/frontend/src/model/users.ts | 88 ++++++++++++++++++---------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/packages/frontend/src/model/users.ts b/packages/frontend/src/model/users.ts index a16385774..1f526afa8 100644 --- a/packages/frontend/src/model/users.ts +++ b/packages/frontend/src/model/users.ts @@ -44,6 +44,17 @@ export const AllUsers = atom({ default: undefined, }); +export const AllAdminUsers = selector({ + key: 'AllAdminUsers', + get: ({ get }) => { + const users = get(AllUsers); + if (users) { + return users.filter((user) => user.roles.includes(UserRole.ADMIN)); + } + return undefined; + }, +}); + export const AllQuantifierUsers = selector({ key: 'AllQuantifierUsers', get: ({ get }) => { @@ -55,6 +66,17 @@ export const AllQuantifierUsers = selector({ }, }); +export const AllForwarderUsers = selector({ + key: 'AllForwarderUsers', + get: ({ get }) => { + const users = get(AllUsers); + if (users) { + return users.filter((user) => user.roles.includes(UserRole.FORWARDER)); + } + return undefined; + }, +}); + export const useAllUsersQuery = (): AxiosResponse => { const allUsersQueryResponse = useAuthApiQuery(AllUsersQuery); const [allUsers, setAllUsers] = useRecoilState(AllUsers); @@ -72,19 +94,23 @@ export const useAllUsersQuery = (): AxiosResponse => { return allUsersQueryResponse; }; -type SingleUserParams = { +/** + * Types for `useParams()` + */ +export type SingleUserParams = { userId: string | undefined; }; + export const SingleUser = selectorFamily({ key: 'SingleUser', get: (params: SingleUserParams) => - ({ get }): UserDto | undefined => { - const { userId } = params; - const allUsers = get(AllUsers); - if (!allUsers) return undefined; - return allUsers.filter((user) => user._id === userId)[0]; - }, + ({ get }): UserDto | undefined => { + const { userId } = params; + const allUsers = get(AllUsers); + if (!allUsers) return undefined; + return allUsers.filter((user) => user._id === userId)[0]; + }, }); type SingleUserByReceiverIdParams = { @@ -94,15 +120,15 @@ export const SingleUserByReceiverId = selectorFamily({ key: 'SingleUserByReceiverId', get: (params: SingleUserByReceiverIdParams) => - ({ get }): UserDto | undefined => { - const { receiverId } = params; - const allUsers = get(AllUsers); - if (!allUsers) return undefined; - return allUsers.find((user) => { - if (!user.accounts) return false; - return user.accounts.find((account) => account._id === receiverId); - }); - }, + ({ get }): UserDto | undefined => { + const { receiverId } = params; + const allUsers = get(AllUsers); + if (!allUsers) return undefined; + return allUsers.find((user) => { + if (!user.accounts) return false; + return user.accounts.find((account) => account._id === receiverId); + }); + }, }); const stringToNumber = (s: string): number => { @@ -121,22 +147,22 @@ export const PseudonymForUser = selectorFamily({ key: 'PseudonymForUser', get: (params: PseudonymForUserParams) => - ({ get }): string => { - const { periodId, userId } = params; - const allPeriods = get(AllPeriods); - if (!allPeriods) return 'Loading…'; - const periodIndex = allPeriods.findIndex((p) => p._id === periodId); - - if (userId && periodIndex > -1) { - const u = stringToNumber(userId); - const p = stringToNumber(periodId); - const n = pseudonymNouns[(u + p) % pseudonymNouns.length]; - const a = psudonymAdjectives[(u + p) % psudonymAdjectives.length]; - return `${a} ${n}`; - } + ({ get }): string => { + const { periodId, userId } = params; + const allPeriods = get(AllPeriods); + if (!allPeriods) return 'Loading…'; + const periodIndex = allPeriods.findIndex((p) => p._id === periodId); + + if (userId && periodIndex > -1) { + const u = stringToNumber(userId); + const p = stringToNumber(periodId); + const n = pseudonymNouns[(u + p) % pseudonymNouns.length]; + const a = psudonymAdjectives[(u + p) % psudonymAdjectives.length]; + return `${a} ${n}`; + } - return 'Unknown user'; - }, + return 'Unknown user'; + }, }); export const AddUserRoleApiResponse = atom< From b0728ae7569836d1ccc66d1181e45c0df29d79da Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:21:36 -0300 Subject: [PATCH 03/35] fix: removed unused stuff and added new users table --- .../frontend/src/pages/Users/UsersPage.tsx | 52 ++----------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/packages/frontend/src/pages/Users/UsersPage.tsx b/packages/frontend/src/pages/Users/UsersPage.tsx index e95e0e085..226eaad0b 100644 --- a/packages/frontend/src/pages/Users/UsersPage.tsx +++ b/packages/frontend/src/pages/Users/UsersPage.tsx @@ -1,58 +1,14 @@ import BreadCrumb from '@/components/BreadCrumb'; -import { useAdminUsers } from '@/model/users'; -import PoolAddDialog from '@/pages/Users/components/AddDialog'; -import { faPlus, faUserFriends } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserRole } from 'api/dist/user/types'; -import React from 'react'; +import { faUserFriends } from '@fortawesome/free-solid-svg-icons'; +import UsersStatistics from './components/UsersStatistics'; import UsersTable from './components/UsersTable'; -const AddRoleButton = (): JSX.Element => { - const [isOpen, setIsOpen] = React.useState(false); - const { addRole } = useAdminUsers(); - - const handleAddQuantifierClick = (): void => { - setIsOpen(true); - }; - - const handleQuantifierAdded = (id: string): void => { - void addRole(id, UserRole.QUANTIFIER); - }; - - return ( - - ); -}; - const UsersPage = (): JSX.Element => { return (
- - + +
-
- - - -
From 7e1b1c609a9608fb5aca0b22b2a084d77817f08b Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:21:58 -0300 Subject: [PATCH 04/35] fix: removed unused files --- .../src/pages/Users/components/AddDialog.tsx | 153 ------------------ .../pages/Users/components/DeleteDialog.tsx | 68 -------- 2 files changed, 221 deletions(-) delete mode 100644 packages/frontend/src/pages/Users/components/AddDialog.tsx delete mode 100644 packages/frontend/src/pages/Users/components/DeleteDialog.tsx diff --git a/packages/frontend/src/pages/Users/components/AddDialog.tsx b/packages/frontend/src/pages/Users/components/AddDialog.tsx deleted file mode 100644 index 10d93bd1c..000000000 --- a/packages/frontend/src/pages/Users/components/AddDialog.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { AllUsers } from '@/model/users'; -import { classNames } from '@/utils/index'; -import { getUsername } from '@/utils/users'; -import { faTimes, faUser } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserDto, UserRole } from 'api/dist/user/types'; -import { useCombobox } from 'downshift'; -import React from 'react'; -import { useRecoilValue } from 'recoil'; - -interface UserAutosuggestProps { - onClose(): void; - onQuantifierAdded(id: string): void; -} - -const UserAutosuggest = ({ - onQuantifierAdded, - onClose, -}: UserAutosuggestProps): JSX.Element => { - const allUsers = useRecoilValue(AllUsers); - - const DropdownCombobox = (): JSX.Element => { - const [inputItems, setInputItems] = React.useState( - allUsers ? allUsers : ([] as UserDto[]) - ); - const { - isOpen, - getMenuProps, - getInputProps, - getComboboxProps, - highlightedIndex, - getItemProps, - } = useCombobox({ - items: inputItems, - onInputValueChange: ({ inputValue }) => { - if (allUsers) { - setInputItems( - allUsers.filter((user) => { - if (!inputValue) return false; - if (user.roles.includes(UserRole.QUANTIFIER)) return false; - if (user._id?.includes(inputValue.toLowerCase())) return true; - if ( - user.ethereumAddress && - user.ethereumAddress.length > 0 && - user.ethereumAddress - .toLowerCase() - .includes(inputValue.toLowerCase()) - ) - return true; - if ( - user.accounts?.find((account) => - account.name.toLowerCase().includes(inputValue.toLowerCase()) - ? true - : false - ) - ) - return true; - return false; - }) - ); - } - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onSelectedItemChange: (data: any) => { - const selectedItem = data.selectedItem as UserDto; - if (selectedItem._id) { - onQuantifierAdded(selectedItem._id); - } - onClose(); - }, - }); - return ( -
-
-
-
- - - -
- -
-
-
    0 ? '' : 'hidden', - 'absolute bg-white border w-80 mt-[1px]' - )} - {...getMenuProps()} - > - {isOpen && - inputItems.map((item, index) => ( -
  • - {getUsername(item)} -
  • - ))} -
-
- ); - }; - return ; -}; - -interface PoolAddDialogProps { - onClose(): void; - onQuantifierAdded(id: string): void; -} -const PoolAddDialog = ({ - onClose, - onQuantifierAdded, -}: PoolAddDialogProps): JSX.Element => { - return ( -
- -
-
- -
-
-
- -
- - Add a member to the Quantifier Pool - -
- -
-
-
-
- ); -}; - -export default PoolAddDialog; diff --git a/packages/frontend/src/pages/Users/components/DeleteDialog.tsx b/packages/frontend/src/pages/Users/components/DeleteDialog.tsx deleted file mode 100644 index 35f473787..000000000 --- a/packages/frontend/src/pages/Users/components/DeleteDialog.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { getUsername } from '@/utils/users'; -import { - faTimes, - faTimesCircle, - faUser, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserDto } from 'api/dist/user/types'; - -interface PoolDeleteDialogProps { - onClose(): void; - onQuantifierRemoved(id: string): void; - quantifier: UserDto | undefined; -} -const PoolDeleteDialog = ({ - onClose, - onQuantifierRemoved, - quantifier, -}: PoolDeleteDialogProps): JSX.Element | null => { - if (quantifier) { - return ( -
- -
-
- -
-
-
- -
- - Removing 1 member from Quantifier Pool - -
- {getUsername(quantifier)} -
-
- -
-
-
-
- ); - } else { - return null; - } -}; - -export default PoolDeleteDialog; From 98e3f9cddff069ee4e7e7e1130727f49f7e5ecfd Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:22:51 -0300 Subject: [PATCH 05/35] feat: added new users table --- .../src/pages/Users/components/RoleBadge.tsx | 13 + .../Users/components/UsersStatistics.tsx | 29 +++ .../src/pages/Users/components/UsersTable.tsx | 244 ++++++++++-------- .../Users/components/UsersTableHeader.tsx | 13 + .../Users/components/UsersTablePagination.tsx | 62 +++++ .../pages/Users/components/UsersTableRow.tsx | 37 +++ 6 files changed, 295 insertions(+), 103 deletions(-) create mode 100644 packages/frontend/src/pages/Users/components/RoleBadge.tsx create mode 100644 packages/frontend/src/pages/Users/components/UsersStatistics.tsx create mode 100644 packages/frontend/src/pages/Users/components/UsersTableHeader.tsx create mode 100644 packages/frontend/src/pages/Users/components/UsersTablePagination.tsx create mode 100644 packages/frontend/src/pages/Users/components/UsersTableRow.tsx diff --git a/packages/frontend/src/pages/Users/components/RoleBadge.tsx b/packages/frontend/src/pages/Users/components/RoleBadge.tsx new file mode 100644 index 000000000..1083b007e --- /dev/null +++ b/packages/frontend/src/pages/Users/components/RoleBadge.tsx @@ -0,0 +1,13 @@ +interface IRoleBadge { + label: string; +} + +const RoleBadge = ({ label }: IRoleBadge): JSX.Element => { + return ( +
+ {label} +
+ ); +}; + +export default RoleBadge; diff --git a/packages/frontend/src/pages/Users/components/UsersStatistics.tsx b/packages/frontend/src/pages/Users/components/UsersStatistics.tsx new file mode 100644 index 000000000..d0c00e054 --- /dev/null +++ b/packages/frontend/src/pages/Users/components/UsersStatistics.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useRecoilValue } from 'recoil'; +import { + AllAdminUsers, + AllForwarderUsers, + AllQuantifierUsers, + AllUsers, +} from '@/model/users'; + +const UsersStatistics = (): JSX.Element => { + const allAdminUsers = useRecoilValue(AllAdminUsers); + const allForwarderUsers = useRecoilValue(AllForwarderUsers); + const allQuantifierUsers = useRecoilValue(AllQuantifierUsers); + const allUsers = useRecoilValue(AllUsers); + + return ( +
+
+ User statistics +
+
Activated users: {allUsers?.length}
+
Admins: {allAdminUsers?.length}
+
Forwarders: {allForwarderUsers?.length}
+
Quantifiers: {allQuantifierUsers?.length}
+
+ ); +}; + +export default UsersStatistics; diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 6cbb42907..9f2f49834 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -1,121 +1,159 @@ -import { UserAvatar } from '@/components/user/UserAvatar'; -import { AllQuantifierUsers, useAdminUsers } from '@/model/users'; -import { shortenEthAddress } from '@/utils/index'; +import { + AllAdminUsers, + AllForwarderUsers, + AllQuantifierUsers, + AllUsers, +} from '@/model/users'; import { getUsername } from '@/utils/users'; -import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserDto, UserRole } from 'api/dist/user/types'; import React from 'react'; -import { TableOptions, useTable } from 'react-table'; import { useRecoilValue } from 'recoil'; -import PoolDeleteDialog from './DeleteDialog'; +import { UserDto, UserRole } from 'api/dist/user/types'; +import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import UsersTableRow from './UsersTableRow'; +import UsersTableHeader from './UsersTableHeader'; +import UsersTablePagination from './UsersTablePagination'; + +const roleOptions = [ + { name: 'All users', value: UserRole.USER }, + { name: 'Admins', value: UserRole.ADMIN }, + { name: 'Forwarders', value: UserRole.FORWARDER }, + { name: 'Quantifiers', value: UserRole.QUANTIFIER }, +]; const UsersTable = (): JSX.Element => { + const allAdminUsers = useRecoilValue(AllAdminUsers); + const allForwarderUsers = useRecoilValue(AllForwarderUsers); const allQuantifierUsers = useRecoilValue(AllQuantifierUsers); - const { removeRole } = useAdminUsers(); - - const deleteDialogRef = React.useRef(null); - - const [isOpen, setIsOpen] = React.useState(false); - const [selectedQuantifier, setSelectedQuantifier] = React.useState(); - - const columns = React.useMemo( - () => [ - { - Header: 'Id', - accessor: '_id', - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Cell: (data: any): JSX.Element => { - return ( -
-
- -
-
- {data.row.original.accounts?.length > 0 ? ( -
{getUsername(data.row.original)}
- ) : ( - '' - )} - {shortenEthAddress(data.row.original.ethereumAddress)} -
-
- ); - }, - }, - ], - [] + const allUsers = useRecoilValue(AllUsers); + const [tableData, setTableData] = React.useState(); + const [selectedRole, setSelectedRole] = React.useState( + UserRole.USER ); + const [filter, setFilter] = React.useState(''); + const [filterType, setFilterType] = React.useState('user'); + const [page, setPage] = React.useState(1); + const [lastPage, setLastPage] = React.useState(0); - const options = { - columns, - data: allQuantifierUsers ? allQuantifierUsers : [], - } as TableOptions<{}>; - const tableInstance = useTable(options); + React.useEffect(() => { + if (allUsers) { + setTableData(allUsers); + } + }, [allUsers]); - const { getTableProps, getTableBodyProps, rows, prepareRow } = tableInstance; + React.useEffect(() => { + if (filter && tableData) { + let filteredData: UserDto[]; + if (filterType === 'user') { + filteredData = tableData.filter((user) => { + const username = getUsername(user)?.toLowerCase(); + if (username?.includes(filter.toLocaleLowerCase())) { + return user; + } + }); + } else { + filteredData = tableData.filter((user) => { + if ( + user.ethereumAddress?.toLocaleLowerCase() === + filter.toLocaleLowerCase() + ) { + return user; + } + }); + } + setTableData(filteredData); + } + }, [filterType, filter]); - if (!allQuantifierUsers) - return
There are no users in the Quantifier pool.
; + React.useEffect(() => { + switch (selectedRole) { + case UserRole.USER: + setTableData(allUsers); + break; + case UserRole.ADMIN: + setTableData(allAdminUsers); + break; + case UserRole.FORWARDER: + setTableData(allForwarderUsers); + break; + case UserRole.QUANTIFIER: + setTableData(allQuantifierUsers); + break; + } + setFilter(''); + }, [selectedRole]); - const handleDeleteQuantifierClick = (quantifier: UserDto): void => { - setSelectedQuantifier(quantifier); - setIsOpen(true); - }; + React.useEffect(() => { + if (tableData) { + setPage(1); - const removeQuantifier = (id: string): void => { - void removeRole(id, UserRole.QUANTIFIER); - }; + if (tableData.length % 5 === 0) { + setLastPage(Math.trunc(tableData.length / 5)); + } else { + setLastPage(Math.trunc(tableData.length / 5) + 1); + } + } + }, [tableData]); return ( - - - {rows.map((row) => { - prepareRow(row); - return ( - // eslint-disable-next-line react/jsx-key - - {row.cells.map((cell) => { - // eslint-disable-next-line react/jsx-key - return ; - })} - - - ); - })} - - {isOpen ? ( - setIsOpen(false)} - className="fixed inset-0 z-10 overflow-y-auto" - initialFocus={deleteDialogRef} +
+
+ +
+ +
+
-
{cell.render('Cell')} - -
+ + + + + +
+ + + +
+ + {tableData?.map((row, index) => { + if (Math.trunc(index / 5) + 1 === page) { + return ; + } + })} + + + ); }; diff --git a/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx b/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx new file mode 100644 index 000000000..0ab0b6ac4 --- /dev/null +++ b/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx @@ -0,0 +1,13 @@ +interface IUsersTableHeader { + label: string; +} + +const UsersTableHeader = ({ label }: IUsersTableHeader): JSX.Element => { + return ( +
+ {label} +
+ ); +}; + +export default UsersTableHeader; diff --git a/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx b/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx new file mode 100644 index 000000000..cd295e0b7 --- /dev/null +++ b/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { + faAngleLeft, + faAngleRight, + faAnglesLeft, + faAnglesRight, +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +interface IUsersTablePagination { + lastPage: number; + page: number; + setPage: React.Dispatch>; +} + +const UsersTablePagination = ({ + lastPage, + page, + setPage, +}: IUsersTablePagination): JSX.Element => { + return ( +
+ setPage(1)} + /> + + setPage((previousPage) => + previousPage === 1 ? previousPage : previousPage - 1 + ) + } + /> + + setPage((previousPage) => + previousPage === lastPage ? lastPage : previousPage + 1 + ) + } + /> + setPage(lastPage)} + /> + + Page {page} of {lastPage} + +
+ ); +}; + +export default UsersTablePagination; diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx new file mode 100644 index 000000000..5ebe7521c --- /dev/null +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -0,0 +1,37 @@ +import { useHistory } from 'react-router-dom'; +import { UserDto, UserRole } from 'api/dist/user/types'; +import RoleBadge from './RoleBadge'; +import { UserAvatar } from '@/components/user/UserAvatar'; +import { shortenEthAddress } from '@/utils/index'; +import { getUsername } from '@/utils/users'; + +interface IUsersTableRow { + data: UserDto; +} + +const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element => { + const history = useHistory(); + return ( +
history.push(`pool/${data._id}`)} + > +
+ + + {shortenEthAddress(data.ethereumAddress!)} + +
+
{getUsername(data)}
+
+ {data.roles.map((role, index) => { + if (role !== UserRole.USER) { + return ; + } + })} +
+
+ ); +}; + +export default UsersTableRow; From dd53b4f050ae1b33fed5c507ed62b115790b7b3c Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:23:13 -0300 Subject: [PATCH 06/35] feat: added new page that display info of specific user --- .../src/navigation/AuthenticatedRoutes.tsx | 9 +- .../src/pages/UserDetails/UserDetailsPage.tsx | 88 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx diff --git a/packages/frontend/src/navigation/AuthenticatedRoutes.tsx b/packages/frontend/src/navigation/AuthenticatedRoutes.tsx index 9c7c185ec..30e19f741 100644 --- a/packages/frontend/src/navigation/AuthenticatedRoutes.tsx +++ b/packages/frontend/src/navigation/AuthenticatedRoutes.tsx @@ -9,6 +9,9 @@ import { useRecoilValue } from 'recoil'; import AuthenticatedLayout from '../layouts/AuthenticatedLayout'; const MyPraisePage = React.lazy(() => import('@/pages/MyPraise/MyPraisePage')); +const UserDetailsPage = React.lazy( + () => import('@/pages/UserDetails/UserDetailsPage') +); const UsersPage = React.lazy(() => import('@/pages/Users/UsersPage')); const PeriodsPage = React.lazy(() => import('@/pages/Periods/PeriodsPage')); @@ -78,10 +81,14 @@ const Routes = (): JSX.Element => { - + + + + + diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx new file mode 100644 index 000000000..15d7f824b --- /dev/null +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -0,0 +1,88 @@ +import { faUserGroup } from '@fortawesome/free-solid-svg-icons'; +import BreadCrumb from '@/components/BreadCrumb'; +import BackLink from '@/navigation/BackLink'; +import { SingleUser, SingleUserParams, useAdminUsers } from '@/model/users'; +import { useRecoilValue } from 'recoil'; +import { useParams } from 'react-router-dom'; +import { formatIsoDateUTC } from '@/utils/date'; +import { shortenEthAddress } from '@/utils/index'; +import { UserDto, UserRole } from 'api/dist/user/types'; +import { toast } from 'react-hot-toast'; + +const roles = [UserRole.ADMIN, UserRole.FORWARDER, UserRole.QUANTIFIER]; + +const UserDetailsPage = (): JSX.Element => { + const { userId } = useParams(); + const user = useRecoilValue(SingleUser({ userId })); + const { addRole, removeRole } = useAdminUsers(); + + const handleRole = (role: UserRole, user: UserDto): void => { + let resp; + const isRemove = user.roles.includes(role); + async (): Promise => { + if (isRemove) { + resp = await removeRole(user._id, role); + } else { + resp = await addRole(user._id, role); + } + if (resp?.status === 200) { + toast.success(`Role ${isRemove ? 'removed' : 'added'} successfully!`); + } + }; + }; + + return ( +
+ + +
+ User identity + {!!user && ( + <> + + {shortenEthAddress(user.ethereumAddress || '')} + + Created: {formatIsoDateUTC(user.createdAt)} + Last updated: {formatIsoDateUTC(user.updatedAt)} + + )} +
+
+ Linked Discord identities + {user?.accounts?.map((account, index) => ( + <> + User account #{index + 1} + {account.name} + Discord User ID: {account.user} + Created: {formatIsoDateUTC(account.createdAt)} + Last updated: {formatIsoDateUTC(account.updatedAt)} + + ))} +
+
+ Roles +
+ {!!user && + roles.map((role) => ( +
handleRole(role, user)} + > + handleRole(role, user)} + /> + {role} +
+ ))} +
+
+
+ ); +}; + +export default UserDetailsPage; From ac99dbe30f5906b2dad07b10ce45f878bf66caf1 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 12 May 2022 16:40:08 -0300 Subject: [PATCH 07/35] hotfix: eslint error --- packages/frontend/src/model/users.ts | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/frontend/src/model/users.ts b/packages/frontend/src/model/users.ts index 1f526afa8..d90ee5d8a 100644 --- a/packages/frontend/src/model/users.ts +++ b/packages/frontend/src/model/users.ts @@ -105,12 +105,12 @@ export const SingleUser = selectorFamily({ key: 'SingleUser', get: (params: SingleUserParams) => - ({ get }): UserDto | undefined => { - const { userId } = params; - const allUsers = get(AllUsers); - if (!allUsers) return undefined; - return allUsers.filter((user) => user._id === userId)[0]; - }, + ({ get }): UserDto | undefined => { + const { userId } = params; + const allUsers = get(AllUsers); + if (!allUsers) return undefined; + return allUsers.filter((user) => user._id === userId)[0]; + }, }); type SingleUserByReceiverIdParams = { @@ -120,15 +120,15 @@ export const SingleUserByReceiverId = selectorFamily({ key: 'SingleUserByReceiverId', get: (params: SingleUserByReceiverIdParams) => - ({ get }): UserDto | undefined => { - const { receiverId } = params; - const allUsers = get(AllUsers); - if (!allUsers) return undefined; - return allUsers.find((user) => { - if (!user.accounts) return false; - return user.accounts.find((account) => account._id === receiverId); - }); - }, + ({ get }): UserDto | undefined => { + const { receiverId } = params; + const allUsers = get(AllUsers); + if (!allUsers) return undefined; + return allUsers.find((user) => { + if (!user.accounts) return false; + return user.accounts.find((account) => account._id === receiverId); + }); + }, }); const stringToNumber = (s: string): number => { @@ -147,22 +147,22 @@ export const PseudonymForUser = selectorFamily({ key: 'PseudonymForUser', get: (params: PseudonymForUserParams) => - ({ get }): string => { - const { periodId, userId } = params; - const allPeriods = get(AllPeriods); - if (!allPeriods) return 'Loading…'; - const periodIndex = allPeriods.findIndex((p) => p._id === periodId); + ({ get }): string => { + const { periodId, userId } = params; + const allPeriods = get(AllPeriods); + if (!allPeriods) return 'Loading…'; + const periodIndex = allPeriods.findIndex((p) => p._id === periodId); - if (userId && periodIndex > -1) { - const u = stringToNumber(userId); - const p = stringToNumber(periodId); - const n = pseudonymNouns[(u + p) % pseudonymNouns.length]; - const a = psudonymAdjectives[(u + p) % psudonymAdjectives.length]; - return `${a} ${n}`; - } + if (userId && periodIndex > -1) { + const u = stringToNumber(userId); + const p = stringToNumber(periodId); + const n = pseudonymNouns[(u + p) % pseudonymNouns.length]; + const a = psudonymAdjectives[(u + p) % psudonymAdjectives.length]; + return `${a} ${n}`; + } - return 'Unknown user'; - }, + return 'Unknown user'; + }, }); export const AddUserRoleApiResponse = atom< From 1ece64336a7bf47535de80876913edc61b1b9512 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 15:03:50 -0300 Subject: [PATCH 08/35] hotfix: change URL from pool to users --- packages/frontend/src/navigation/AuthenticatedRoutes.tsx | 4 ++-- packages/frontend/src/navigation/Nav.tsx | 2 +- packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx | 2 +- .../frontend/src/pages/Users/components/UsersTableRow.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/navigation/AuthenticatedRoutes.tsx b/packages/frontend/src/navigation/AuthenticatedRoutes.tsx index 30e19f741..4a9250c3a 100644 --- a/packages/frontend/src/navigation/AuthenticatedRoutes.tsx +++ b/packages/frontend/src/navigation/AuthenticatedRoutes.tsx @@ -81,11 +81,11 @@ const Routes = (): JSX.Element => { - + - + diff --git a/packages/frontend/src/navigation/Nav.tsx b/packages/frontend/src/navigation/Nav.tsx index cb27027f5..41613dcb6 100644 --- a/packages/frontend/src/navigation/Nav.tsx +++ b/packages/frontend/src/navigation/Nav.tsx @@ -50,7 +50,7 @@ export default function Nav(): JSX.Element { { return (
- +
User identity {!!user && ( diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index 5ebe7521c..478aa364b 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -14,7 +14,7 @@ const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element => { return (
history.push(`pool/${data._id}`)} + onClick={(): void => history.push(`users/${data._id}`)} >
From 539384799d540815280caacf9bcceed9f0a19d57 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 15:17:49 -0300 Subject: [PATCH 09/35] hotfix: fix user check and removed the span tags --- .../src/pages/UserDetails/UserDetailsPage.tsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index 850a5db4b..8b9826afd 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -30,32 +30,34 @@ const UserDetailsPage = (): JSX.Element => { } }; }; - + if (!user) return <>; return (
User identity - {!!user && ( - <> - - {shortenEthAddress(user.ethereumAddress || '')} - - Created: {formatIsoDateUTC(user.createdAt)} - Last updated: {formatIsoDateUTC(user.updatedAt)} - - )} + + {shortenEthAddress(user.ethereumAddress || '')} + +
+ Created: {formatIsoDateUTC(user.createdAt)} +
+ Last updated: {formatIsoDateUTC(user.updatedAt)} +
- Linked Discord identities + Linked Discord identity {user?.accounts?.map((account, index) => ( <> - User account #{index + 1} {account.name} - Discord User ID: {account.user} - Created: {formatIsoDateUTC(account.createdAt)} - Last updated: {formatIsoDateUTC(account.updatedAt)} +
+ Discord User ID: {account.user} +
+ Created: {formatIsoDateUTC(account.createdAt)} +
+ Last updated: {formatIsoDateUTC(account.updatedAt)} +
))}
From fb6e83e0bad6870414602569db778bc3ca1528f4 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 16:36:10 -0300 Subject: [PATCH 10/35] style: added opacity if role is not added --- ...snames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip | Bin 0 -> 9515 bytes packages/frontend/package.json | 1 + .../src/pages/UserDetails/UserDetailsPage.tsx | 74 +++++++++++------- yarn.lock | 8 ++ 4 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 .yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip diff --git a/.yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip b/.yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip new file mode 100644 index 0000000000000000000000000000000000000000..1fe04174bf5ef85ed9391678fe854bd2eba604bb GIT binary patch literal 9515 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 { const user = useRecoilValue(SingleUser({ userId })); const { addRole, removeRole } = useAdminUsers(); - const handleRole = (role: UserRole, user: UserDto): void => { + const handleRole = async (role: UserRole, user: UserDto): Promise => { let resp; const isRemove = user.roles.includes(role); - async (): Promise => { - if (isRemove) { - resp = await removeRole(user._id, role); - } else { - resp = await addRole(user._id, role); - } - if (resp?.status === 200) { - toast.success(`Role ${isRemove ? 'removed' : 'added'} successfully!`); - } - }; + if (isRemove) { + resp = await removeRole(user._id, role); + } else { + resp = await addRole(user._id, role); + } + if (resp?.status === 200) { + toast.success(`Role ${isRemove ? 'removed' : 'added'} successfully!`); + } }; + if (!user) return <>; + return (
@@ -48,7 +50,7 @@ const UserDetailsPage = (): JSX.Element => {
Linked Discord identity - {user?.accounts?.map((account, index) => ( + {user?.accounts?.map((account) => ( <> {account.name}
@@ -64,23 +66,37 @@ const UserDetailsPage = (): JSX.Element => {
Roles
- {!!user && - roles.map((role) => ( -
handleRole(role, user)} - > - handleRole(role, user)} - /> - {role} -
- ))} + {roles.map((role) => ( +
=> handleRole(role, user)} + > + + +
+ ))}
diff --git a/yarn.lock b/yarn.lock index d55b7ee02..e60aff086 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6011,6 +6011,13 @@ __metadata: languageName: node linkType: hard +"classnames@npm:^2.3.1": + version: 2.3.1 + resolution: "classnames@npm:2.3.1" + checksum: 14db8889d56c267a591f08b0834989fe542d47fac659af5a539e110cc4266694e8de86e4e3bbd271157dbd831361310a8293e0167141e80b0f03a0f175c80960 + languageName: node + linkType: hard + "clean-css@npm:^5.2.2": version: 5.2.4 resolution: "clean-css@npm:5.2.4" @@ -9086,6 +9093,7 @@ __metadata: autoprefixer: ^9.8.6 axios: ^0.22.0 axios-auth-refresh: ^3.2.2 + classnames: ^2.3.1 craco-alias: ^3.0.1 date-fns: ^2.25.0 date-fns-tz: ^1.3.3 From f178a8c463561d2f49cc0e5646b23bc6009eaa0c Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 16:40:20 -0300 Subject: [PATCH 11/35] hotfix: substitute roleBadge by InlineLabel component --- .../src/pages/Users/components/RoleBadge.tsx | 13 ------------- .../src/pages/Users/components/UsersTableRow.tsx | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 packages/frontend/src/pages/Users/components/RoleBadge.tsx diff --git a/packages/frontend/src/pages/Users/components/RoleBadge.tsx b/packages/frontend/src/pages/Users/components/RoleBadge.tsx deleted file mode 100644 index 1083b007e..000000000 --- a/packages/frontend/src/pages/Users/components/RoleBadge.tsx +++ /dev/null @@ -1,13 +0,0 @@ -interface IRoleBadge { - label: string; -} - -const RoleBadge = ({ label }: IRoleBadge): JSX.Element => { - return ( -
- {label} -
- ); -}; - -export default RoleBadge; diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index 478aa364b..6c0c0302e 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -1,6 +1,6 @@ import { useHistory } from 'react-router-dom'; import { UserDto, UserRole } from 'api/dist/user/types'; -import RoleBadge from './RoleBadge'; +import { InlineLabel } from '@/components/InlineLabel'; import { UserAvatar } from '@/components/user/UserAvatar'; import { shortenEthAddress } from '@/utils/index'; import { getUsername } from '@/utils/users'; @@ -26,7 +26,7 @@ const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element => {
{data.roles.map((role, index) => { if (role !== UserRole.USER) { - return ; + return ; } })}
From 289a8831db89e84e8fd92a9d727580d389540289 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 16:42:15 -0300 Subject: [PATCH 12/35] hotfix: space between arrows --- .../pages/Users/components/UsersTablePagination.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx b/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx index cd295e0b7..636223bc3 100644 --- a/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTablePagination.tsx @@ -19,16 +19,16 @@ const UsersTablePagination = ({ setPage, }: IUsersTablePagination): JSX.Element => { return ( -
+
setPage(1)} /> setPage((previousPage) => @@ -38,7 +38,7 @@ const UsersTablePagination = ({ /> setPage((previousPage) => @@ -48,7 +48,7 @@ const UsersTablePagination = ({ /> setPage(lastPage)} /> From 5f6537f4420378651ea3752a240a31d3ea7b127c Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Thu, 19 May 2022 16:43:49 -0300 Subject: [PATCH 13/35] hotfix: removed table header component --- .../src/pages/Users/components/UsersTable.tsx | 13 +++++++++---- .../src/pages/Users/components/UsersTableHeader.tsx | 13 ------------- 2 files changed, 9 insertions(+), 17 deletions(-) delete mode 100644 packages/frontend/src/pages/Users/components/UsersTableHeader.tsx diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 9f2f49834..39c59df87 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -11,7 +11,6 @@ import { UserDto, UserRole } from 'api/dist/user/types'; import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import UsersTableRow from './UsersTableRow'; -import UsersTableHeader from './UsersTableHeader'; import UsersTablePagination from './UsersTablePagination'; const roleOptions = [ @@ -141,9 +140,15 @@ const UsersTable = (): JSX.Element => {
- - - +
+ User +
+
+ Discord +
+
+ Roles +
{tableData?.map((row, index) => { diff --git a/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx b/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx deleted file mode 100644 index 0ab0b6ac4..000000000 --- a/packages/frontend/src/pages/Users/components/UsersTableHeader.tsx +++ /dev/null @@ -1,13 +0,0 @@ -interface IUsersTableHeader { - label: string; -} - -const UsersTableHeader = ({ label }: IUsersTableHeader): JSX.Element => { - return ( -
- {label} -
- ); -}; - -export default UsersTableHeader; From d4a4850d138fcc3ddd4d065e9636d6cbd497afc7 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Fri, 20 May 2022 15:48:34 -0300 Subject: [PATCH 14/35] fix: remove select from search bar and fix the wrong behavior --- .../src/pages/Users/components/UsersTable.tsx | 58 +++++++------------ 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 39c59df87..903876d05 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -30,7 +30,6 @@ const UsersTable = (): JSX.Element => { UserRole.USER ); const [filter, setFilter] = React.useState(''); - const [filterType, setFilterType] = React.useState('user'); const [page, setPage] = React.useState(1); const [lastPage, setLastPage] = React.useState(0); @@ -40,30 +39,6 @@ const UsersTable = (): JSX.Element => { } }, [allUsers]); - React.useEffect(() => { - if (filter && tableData) { - let filteredData: UserDto[]; - if (filterType === 'user') { - filteredData = tableData.filter((user) => { - const username = getUsername(user)?.toLowerCase(); - if (username?.includes(filter.toLocaleLowerCase())) { - return user; - } - }); - } else { - filteredData = tableData.filter((user) => { - if ( - user.ethereumAddress?.toLocaleLowerCase() === - filter.toLocaleLowerCase() - ) { - return user; - } - }); - } - setTableData(filteredData); - } - }, [filterType, filter]); - React.useEffect(() => { switch (selectedRole) { case UserRole.USER: @@ -80,7 +55,13 @@ const UsersTable = (): JSX.Element => { break; } setFilter(''); - }, [selectedRole]); + }, [ + selectedRole, + allUsers, + allAdminUsers, + allForwarderUsers, + allQuantifierUsers, + ]); React.useEffect(() => { if (tableData) { @@ -94,6 +75,19 @@ const UsersTable = (): JSX.Element => { } }, [tableData]); + const applyFilter = (data: UserDto[] | undefined): UserDto[] => { + if (!data) return []; + const filteredData = data.filter((user: UserDto) => { + const username = getUsername(user)?.toLowerCase(); + const userAddress = user.ethereumAddress?.toLowerCase(); + const filterData = filter.toLocaleLowerCase(); + if (username?.includes(filterData) || userAddress?.includes(filterData)) { + return user; + } + }); + return filteredData; + }; + return (
@@ -127,16 +121,6 @@ const UsersTable = (): JSX.Element => { } /> -
-
@@ -151,7 +135,7 @@ const UsersTable = (): JSX.Element => {
- {tableData?.map((row, index) => { + {applyFilter(tableData).map((row, index) => { if (Math.trunc(index / 5) + 1 === page) { return ; } From 5864448b1b9c3a7477ce85f5c2fe537be6ed75c2 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 11:20:06 -0400 Subject: [PATCH 15/35] chore(frontend): delete no longer used components AddDialog & DeleteDialog --- .../src/pages/Users/components/AddDialog.tsx | 152 ------------------ .../pages/Users/components/DeleteDialog.tsx | 67 -------- 2 files changed, 219 deletions(-) delete mode 100644 packages/frontend/src/pages/Users/components/AddDialog.tsx delete mode 100644 packages/frontend/src/pages/Users/components/DeleteDialog.tsx diff --git a/packages/frontend/src/pages/Users/components/AddDialog.tsx b/packages/frontend/src/pages/Users/components/AddDialog.tsx deleted file mode 100644 index c6240f0ae..000000000 --- a/packages/frontend/src/pages/Users/components/AddDialog.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { AllUsers } from '@/model/users'; -import { classNames } from '@/utils/index'; -import { faTimes, faUser } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserDto, UserRole } from 'api/dist/user/types'; -import { useCombobox } from 'downshift'; -import React from 'react'; -import { useRecoilValue } from 'recoil'; - -interface UserAutosuggestProps { - onClose(): void; - onQuantifierAdded(id: string): void; -} - -const UserAutosuggest = ({ - onQuantifierAdded, - onClose, -}: UserAutosuggestProps): JSX.Element => { - const allUsers = useRecoilValue(AllUsers); - - const DropdownCombobox = (): JSX.Element => { - const [inputItems, setInputItems] = React.useState( - allUsers ? allUsers : ([] as UserDto[]) - ); - const { - isOpen, - getMenuProps, - getInputProps, - getComboboxProps, - highlightedIndex, - getItemProps, - } = useCombobox({ - items: inputItems, - onInputValueChange: ({ inputValue }) => { - if (allUsers) { - setInputItems( - allUsers.filter((user) => { - if (!inputValue) return false; - if (user.roles.includes(UserRole.QUANTIFIER)) return false; - if (user._id?.includes(inputValue.toLowerCase())) return true; - if ( - user.ethereumAddress && - user.ethereumAddress.length > 0 && - user.ethereumAddress - .toLowerCase() - .includes(inputValue.toLowerCase()) - ) - return true; - if ( - user.accounts?.find((account) => - account.name.toLowerCase().includes(inputValue.toLowerCase()) - ? true - : false - ) - ) - return true; - return false; - }) - ); - } - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onSelectedItemChange: (data: any) => { - const selectedItem = data.selectedItem as UserDto; - if (selectedItem._id) { - onQuantifierAdded(selectedItem._id); - } - onClose(); - }, - }); - return ( -
-
-
-
- - - -
- -
-
-
    0 ? '' : 'hidden', - 'absolute bg-white border w-80 mt-[1px]' - )} - {...getMenuProps()} - > - {isOpen && - inputItems.map((item, index) => ( -
  • - {item.nameRealized} -
  • - ))} -
-
- ); - }; - return ; -}; - -interface PoolAddDialogProps { - onClose(): void; - onQuantifierAdded(id: string): void; -} -const PoolAddDialog = ({ - onClose, - onQuantifierAdded, -}: PoolAddDialogProps): JSX.Element => { - return ( -
- -
-
- -
-
-
- -
- - Add a member to the Quantifier Pool - -
- -
-
-
-
- ); -}; - -export default PoolAddDialog; diff --git a/packages/frontend/src/pages/Users/components/DeleteDialog.tsx b/packages/frontend/src/pages/Users/components/DeleteDialog.tsx deleted file mode 100644 index a0e5b3623..000000000 --- a/packages/frontend/src/pages/Users/components/DeleteDialog.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { - faTimes, - faTimesCircle, - faUser, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog } from '@headlessui/react'; -import { UserDto } from 'api/dist/user/types'; - -interface PoolDeleteDialogProps { - onClose(): void; - onQuantifierRemoved(id: string): void; - quantifier: UserDto | undefined; -} -const PoolDeleteDialog = ({ - onClose, - onQuantifierRemoved, - quantifier, -}: PoolDeleteDialogProps): JSX.Element | null => { - if (quantifier) { - return ( -
- -
-
- -
-
-
- -
- - Removing 1 member from Quantifier Pool - -
- {quantifier.nameRealized} -
-
- -
-
-
-
- ); - } else { - return null; - } -}; - -export default PoolDeleteDialog; From 544a2baeb01e5eebf2fc67b9b21a8de2b6955ae0 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 11:23:34 -0400 Subject: [PATCH 16/35] feat(frontend): rename 'Quantifier Pool' nav item to 'Users' --- packages/frontend/src/navigation/Nav.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/frontend/src/navigation/Nav.tsx b/packages/frontend/src/navigation/Nav.tsx index 5ee12d3ad..995a6a30d 100644 --- a/packages/frontend/src/navigation/Nav.tsx +++ b/packages/frontend/src/navigation/Nav.tsx @@ -49,11 +49,7 @@ export default function Nav(): JSX.Element { to="/mypraise" /> - + Date: Mon, 23 May 2022 11:37:55 -0400 Subject: [PATCH 17/35] refactor(frontend): call promise function with void to avoid needing to ignore eslint rule no-misused-promises --- packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index f52c6b56a..93f67bcc1 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ import { faUserGroup } from '@fortawesome/free-solid-svg-icons'; import classnames from 'classnames'; import BreadCrumb from '@/components/BreadCrumb'; @@ -83,7 +82,7 @@ const UserDetailsPage = (): JSX.Element => { ['opacity-60']: !user.roles.includes(role), } )} - onClick={async (): Promise => handleRole(role, user)} + onClick={(): void => void handleRole(role, user)} > Date: Mon, 23 May 2022 11:40:08 -0400 Subject: [PATCH 18/35] refactor(frontend): instead of returing empty JSX element when required data is missing, return null --- packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index 93f67bcc1..05b3d8ae0 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -12,7 +12,7 @@ import { toast } from 'react-hot-toast'; const roles = [UserRole.ADMIN, UserRole.FORWARDER, UserRole.QUANTIFIER]; -const UserDetailsPage = (): JSX.Element => { +const UserDetailsPage = (): JSX.Element | null => { const { userId } = useParams(); const user = useRecoilValue(SingleUser({ userId })); const { addRole, removeRole } = useAdminUsers(); @@ -30,7 +30,7 @@ const UserDetailsPage = (): JSX.Element => { } }; - if (!user) return <>; + if (!user) return null; return (
From 12139b49be95c61380ffbe1d8bc0293f766a5c16 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 11:49:43 -0400 Subject: [PATCH 19/35] refactor(frontend): remove additional dependency 'classnames' -- the core functionality of which is implemented in a helper util --- ...snames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip | Bin 9515 -> 0 bytes packages/frontend/package.json | 1 - .../src/pages/UserDetails/UserDetailsPage.tsx | 19 ++++-------------- yarn.lock | 8 -------- 4 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 .yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip diff --git a/.yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip b/.yarn/cache/classnames-npm-2.3.1-f2ae0a8d3c-14db8889d5.zip deleted file mode 100644 index 1fe04174bf5ef85ed9391678fe854bd2eba604bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9515 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 { {roles.map((role) => (
void handleRole(role, user)} > diff --git a/yarn.lock b/yarn.lock index 93fcc8078..db02fdfae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5952,13 +5952,6 @@ __metadata: languageName: node linkType: hard -"classnames@npm:^2.3.1": - version: 2.3.1 - resolution: "classnames@npm:2.3.1" - checksum: 14db8889d56c267a591f08b0834989fe542d47fac659af5a539e110cc4266694e8de86e4e3bbd271157dbd831361310a8293e0167141e80b0f03a0f175c80960 - languageName: node - linkType: hard - "clean-css@npm:^5.2.2": version: 5.2.4 resolution: "clean-css@npm:5.2.4" @@ -8897,7 +8890,6 @@ __metadata: autoprefixer: ^9.8.6 axios: ^0.22.0 axios-auth-refresh: ^3.2.2 - classnames: ^2.3.1 craco-alias: ^3.0.1 date-fns: ^2.25.0 date-fns-tz: ^1.3.3 From d5157813b70b9486f877b124edd1864f7a6ecaf0 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 11:53:48 -0400 Subject: [PATCH 20/35] refactor(frontend): remove non-null assertion within component render -- instead return null if component does not have all needed data --- .../frontend/src/pages/Users/components/UsersTableRow.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index 6c0c0302e..fb068d530 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -9,8 +9,11 @@ interface IUsersTableRow { data: UserDto; } -const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element => { +const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element | null => { const history = useHistory(); + + if (!data.ethereumAddress) return null; + return (
{
- {shortenEthAddress(data.ethereumAddress!)} + {shortenEthAddress(data.ethereumAddress)}
{getUsername(data)}
From 463893507330619556e4c72bb2bc52fdc40362cf Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 13:36:33 -0400 Subject: [PATCH 21/35] refactor(frontend): replace usage of getUsername with user.nameRealized (reflect changes in #365), switch to using shortenEthAddress implementation from api. --- .../src/pages/UserDetails/UserDetailsPage.tsx | 3 ++- .../src/pages/Users/components/UsersTable.tsx | 10 +++++----- .../src/pages/Users/components/UsersTableRow.tsx | 13 +++++++------ packages/frontend/src/utils/users.ts | 16 ---------------- 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index 7df8fcb59..50e6528e5 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -1,3 +1,4 @@ +import { shortenEthAddress } from 'api/dist/user/utils'; import { faUserGroup } from '@fortawesome/free-solid-svg-icons'; import BreadCrumb from '@/components/BreadCrumb'; import BackLink from '@/navigation/BackLink'; @@ -5,7 +6,7 @@ import { SingleUser, SingleUserParams, useAdminUsers } from '@/model/users'; import { useRecoilValue } from 'recoil'; import { useParams } from 'react-router-dom'; import { formatIsoDateUTC } from '@/utils/date'; -import { shortenEthAddress, classNames } from '@/utils/index'; +import { classNames } from '@/utils/index'; import { UserDto, UserRole } from 'api/dist/user/types'; import { toast } from 'react-hot-toast'; diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 903876d05..5ee224304 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -4,7 +4,6 @@ import { AllQuantifierUsers, AllUsers, } from '@/model/users'; -import { getUsername } from '@/utils/users'; import React from 'react'; import { useRecoilValue } from 'recoil'; import { UserDto, UserRole } from 'api/dist/user/types'; @@ -78,12 +77,13 @@ const UsersTable = (): JSX.Element => { const applyFilter = (data: UserDto[] | undefined): UserDto[] => { if (!data) return []; const filteredData = data.filter((user: UserDto) => { - const username = getUsername(user)?.toLowerCase(); const userAddress = user.ethereumAddress?.toLowerCase(); const filterData = filter.toLocaleLowerCase(); - if (username?.includes(filterData) || userAddress?.includes(filterData)) { - return user; - } + + return ( + user.nameRealized.includes(filterData) || + userAddress?.includes(filterData) + ); }); return filteredData; }; diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index fb068d530..bdc07cef5 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -1,9 +1,8 @@ +import { shortenEthAddress } from 'api/dist/user/utils'; import { useHistory } from 'react-router-dom'; import { UserDto, UserRole } from 'api/dist/user/types'; import { InlineLabel } from '@/components/InlineLabel'; import { UserAvatar } from '@/components/user/UserAvatar'; -import { shortenEthAddress } from '@/utils/index'; -import { getUsername } from '@/utils/users'; interface IUsersTableRow { data: UserDto; @@ -14,6 +13,8 @@ const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element | null => { if (!data.ethereumAddress) return null; + const shortEthAddress = shortenEthAddress(data.ethereumAddress); + return (
{ >
- - {shortenEthAddress(data.ethereumAddress)} - + {shortEthAddress} +
+
+ {shortEthAddress !== data.nameRealized ? data.nameRealized : '-'}
-
{getUsername(data)}
{data.roles.map((role, index) => { if (role !== UserRole.USER) { diff --git a/packages/frontend/src/utils/users.ts b/packages/frontend/src/utils/users.ts index f12b6de42..e7c733468 100644 --- a/packages/frontend/src/utils/users.ts +++ b/packages/frontend/src/utils/users.ts @@ -1,19 +1,3 @@ -import { UserDto } from 'api/dist/user/types'; -import { shortenEthAddress } from '.'; - -export const getUsername = (user: UserDto): string | undefined => { - let username = ''; - if (Array.isArray(user.accounts) && user.accounts.length > 0) { - for (const account of user.accounts) { - username = account.name; - // Prefer DISCORD over others - if (account.platform === 'DISCORD') break; - } - } else if (username === '' && user.ethereumAddress) - return shortenEthAddress(user.ethereumAddress)?.toString(); - return username; -}; - export const psudonymAdjectives = [ 'Red', 'Green', From 564b0b0515daff550206d19e59002ac7b176fef2 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 13:42:52 -0400 Subject: [PATCH 22/35] fix(frontend): ensure non-selected roles are more transparent, decrease opacity slightly to reflect mockup --- packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index 50e6528e5..ce22988fd 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -70,7 +70,7 @@ const UserDetailsPage = (): JSX.Element | null => { key={role} className={classNames( 'flex gap-2 justify-center items-center py-2 px-3 rounded-md cursor-pointer bg-black', - user.roles.includes(role) ? 'opacity-60' : '' + user.roles.includes(role) ? '' : 'opacity-50' )} onClick={(): void => void handleRole(role, user)} > From 1f0b8ca92c6e3a976908a01d71cf20abf78b0776 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 13:50:34 -0400 Subject: [PATCH 23/35] refactor(frontend): move conditional outside of function parameters --- packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx index ce22988fd..c0ea8b25c 100644 --- a/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx +++ b/packages/frontend/src/pages/UserDetails/UserDetailsPage.tsx @@ -39,7 +39,7 @@ const UserDetailsPage = (): JSX.Element | null => {
User identity - {shortenEthAddress(user.ethereumAddress || '')} + {user.ethereumAddress && shortenEthAddress(user.ethereumAddress)}
Created: {formatIsoDateUTC(user.createdAt)} From 42b5ac0c25af1de173c0b42fbd7676d934eb77b7 Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 14:03:47 -0400 Subject: [PATCH 24/35] refactor(frontend): modify InlineLabel so it cannot break to a new line mid-word --- packages/frontend/src/components/InlineLabel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/InlineLabel.tsx b/packages/frontend/src/components/InlineLabel.tsx index 73dded2e5..b1f316c33 100644 --- a/packages/frontend/src/components/InlineLabel.tsx +++ b/packages/frontend/src/components/InlineLabel.tsx @@ -20,7 +20,7 @@ export const InlineLabel = ({ onClick={onClick} className={classNames( className, - 'h-6 pl-1 pr-1 mr-1 text-xs text-white no-underline bg-gray-800 py-[1px] rounded', + 'inline-block pl-1 pr-1 mr-1 text-xs text-white no-underline bg-gray-800 py-[1px] rounded break-normal', onClick ? 'cursor-pointer' : '' )} title={title} From 9037f4cd4be247fbb6f8edd0cc499d1cb64b7b1a Mon Sep 17 00:00:00 2001 From: Matt Gabrenya Date: Mon, 23 May 2022 14:25:38 -0400 Subject: [PATCH 25/35] fix(frontend): ensure users are filtered by name lowercased --- packages/frontend/src/pages/Users/components/UsersTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 5ee224304..a7e0346e3 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -81,7 +81,7 @@ const UsersTable = (): JSX.Element => { const filterData = filter.toLocaleLowerCase(); return ( - user.nameRealized.includes(filterData) || + user.nameRealized.toLowerCase().includes(filterData) || userAddress?.includes(filterData) ); }); From 65542e6e3d35deaaabaf55c93f8e70eac0aa79bd Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Wed, 1 Jun 2022 11:00:41 -0300 Subject: [PATCH 26/35] wip: fix search on table --- .../src/pages/Users/components/UsersTable.tsx | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index a7e0346e3..36c69f3fa 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -32,6 +32,25 @@ const UsersTable = (): JSX.Element => { const [page, setPage] = React.useState(1); const [lastPage, setLastPage] = React.useState(0); + const applyFilter = React.useCallback( + (data: UserDto[] | undefined): UserDto[] => { + if (!data) return []; + const filteredData = data.filter((user: UserDto) => { + const userAddress = user.ethereumAddress?.toLowerCase(); + const filterData = filter.toLocaleLowerCase(); + + return ( + user.nameRealized.toLowerCase().includes(filterData) || + userAddress?.includes(filterData) + ); + }); + + return filteredData; + }, + + [filter] + ); + React.useEffect(() => { if (allUsers) { setTableData(allUsers); @@ -65,28 +84,15 @@ const UsersTable = (): JSX.Element => { React.useEffect(() => { if (tableData) { setPage(1); + const filteredData = applyFilter(tableData); - if (tableData.length % 5 === 0) { - setLastPage(Math.trunc(tableData.length / 5)); + if (filteredData.length % 5 === 0) { + setLastPage(Math.trunc(filteredData.length / 5)); } else { - setLastPage(Math.trunc(tableData.length / 5) + 1); + setLastPage(Math.trunc(filteredData.length / 5) + 1); } } - }, [tableData]); - - const applyFilter = (data: UserDto[] | undefined): UserDto[] => { - if (!data) return []; - const filteredData = data.filter((user: UserDto) => { - const userAddress = user.ethereumAddress?.toLowerCase(); - const filterData = filter.toLocaleLowerCase(); - - return ( - user.nameRealized.toLowerCase().includes(filterData) || - userAddress?.includes(filterData) - ); - }); - return filteredData; - }; + }, [tableData, filter, applyFilter]); return (
@@ -140,8 +146,12 @@ const UsersTable = (): JSX.Element => { return ; } })} + -
); }; From 999898c60415ad79b48b616681b8b8d2edf009f1 Mon Sep 17 00:00:00 2001 From: Pedro Kretzschmar Date: Wed, 1 Jun 2022 17:57:07 -0300 Subject: [PATCH 27/35] fix: users table responsivity --- .../src/pages/Users/components/UsersTable.tsx | 12 ++++++------ .../src/pages/Users/components/UsersTableRow.tsx | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 36c69f3fa..b719b0d12 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -95,8 +95,8 @@ const UsersTable = (): JSX.Element => { }, [tableData, filter, applyFilter]); return ( -
-
+ <> +
): void => setFilter(event.target.value) @@ -142,7 +144,7 @@ const UsersTable = (): JSX.Element => {
{applyFilter(tableData).map((row, index) => { - if (Math.trunc(index / 5) + 1 === page) { + if (Math.trunc(index / USERS_PER_PAGE) + 1 === page) { return ; } })} From ea0b36f919d2699a9a57f9b2272270c7533ec56a Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 3 Jun 2022 10:51:36 +0200 Subject: [PATCH 31/35] Fix: prevent word break in label --- packages/frontend/src/components/InlineLabel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/InlineLabel.tsx b/packages/frontend/src/components/InlineLabel.tsx index 0243e623a..d999b3e73 100644 --- a/packages/frontend/src/components/InlineLabel.tsx +++ b/packages/frontend/src/components/InlineLabel.tsx @@ -22,7 +22,7 @@ export const InlineLabel = ({ onClick={onClick} className={classNames( className, - 'h-6 pl-1 pr-1 mr-1 text-xs text-white no-underline bg-gray-800 py-[1px] rounded', + 'h-6 pl-1 pr-1 mr-1 whitespace-nowrap text-xs text-white no-underline bg-gray-800 py-[1px] rounded', onClick ? 'cursor-pointer' : '' )} > From fae3ddab05a40297af63c29baf3403b252cb897e Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 3 Jun 2022 12:52:26 +0200 Subject: [PATCH 32/35] Fix: Paddings etc --- .../src/pages/Users/components/UsersTable.tsx | 2 +- .../pages/Users/components/UsersTableRow.tsx | 34 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 265057ec7..24886a9d5 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -131,7 +131,7 @@ const UsersTable = (): JSX.Element => {
-
+
User
diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index b96147cda..0e86fb5f3 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -17,22 +17,28 @@ const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element | null => { return (
history.push(`users/${data._id}`)} > -
- - {shortEthAddress} -
-
- {shortEthAddress !== data.nameRealized ? data.nameRealized : '-'} -
-
- {data.roles.map((role, index) => { - if (role !== UserRole.USER) { - return ; - } - })} +
+
+
+ +
+
+ {shortEthAddress} +
+
+
+ {shortEthAddress !== data.nameRealized ? data.nameRealized : '-'} +
+
+ {data.roles.map((role, index) => { + if (role !== UserRole.USER) { + return ; + } + })} +
); From f79e05b7ac3a53c5900c9e46281b6216b26f0f24 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 3 Jun 2022 12:56:17 +0200 Subject: [PATCH 33/35] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1825c5155..178236753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Convert the Quantifier Pool screen to a User Admin screen #320 #395 + ### Fixed ## [0.7.0] - 2022-05-31 From 60c076b8aa6d8cb521eec48be0f445ce6114123b Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 3 Jun 2022 13:06:19 +0200 Subject: [PATCH 34/35] Fix: Reactive layout --- .../src/pages/Users/components/UsersTable.tsx | 7 ++----- .../src/pages/Users/components/UsersTableRow.tsx | 14 +++++++------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 24886a9d5..1bb91b65f 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -132,13 +132,10 @@ const UsersTable = (): JSX.Element => {
-
+
User
-
- Discord -
-
+
Roles
diff --git a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx index 0e86fb5f3..5b50c3765 100644 --- a/packages/frontend/src/pages/Users/components/UsersTableRow.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTableRow.tsx @@ -21,18 +21,18 @@ const UsersTableRow = ({ data }: IUsersTableRow): JSX.Element | null => { onClick={(): void => history.push(`users/${data._id}`)} >
-
+
-
- {shortEthAddress} +
+
+ {shortEthAddress !== data.nameRealized ? data.nameRealized : '-'} +
+
{shortEthAddress}
-
- {shortEthAddress !== data.nameRealized ? data.nameRealized : '-'} -
-
+
{data.roles.map((role, index) => { if (role !== UserRole.USER) { return ; From 103bec830b8d5c9a769d6ee72770fad74162817f Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 3 Jun 2022 13:10:03 +0200 Subject: [PATCH 35/35] Fix: Paddings --- packages/frontend/src/pages/Users/components/UsersTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/Users/components/UsersTable.tsx b/packages/frontend/src/pages/Users/components/UsersTable.tsx index 1bb91b65f..3ef153a13 100644 --- a/packages/frontend/src/pages/Users/components/UsersTable.tsx +++ b/packages/frontend/src/pages/Users/components/UsersTable.tsx @@ -98,7 +98,7 @@ const UsersTable = (): JSX.Element => { return ( <> -
+