Skip to content

Commit

Permalink
4032 - Collaborators Grouped UI (#4184)
Browse files Browse the repository at this point in the history
* 4032 - Ui Collaborators grouped

* 4032 - Collaborators Grouped UI
  • Loading branch information
minotogna authored Dec 16, 2024
1 parent 95493a7 commit 7ea5a9d
Show file tree
Hide file tree
Showing 21 changed files with 243 additions and 85 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
"ts-node-dev": "^2.0.0",
"tsc-alias": "^1.8.6",
"turndown": "^7.1.1",
"typescript": "^4.6.3",
"typescript": "^5.7.2",
"webpack": "^5.71.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const useOnChange = (user: User): Returned => {
return userRole
})

const params = { assessmentName, cycleName, roles, userId: user.id }
const params = { assessmentName, cycleName, roles, userUuid: user.uuid }
dispatch(UserManagementActions.updateUserRoles(params))
},
[assessmentName, countryIso, cycle, cycleName, dispatch, user]
Expand Down
6 changes: 6 additions & 0 deletions src/client/components/TablePaginated/Body/Body.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import 'src/client/style/partials';

.table-paginated__groups {
display: grid;
grid-row-gap: $spacing-xs;
}
51 changes: 25 additions & 26 deletions src/client/components/TablePaginated/Body/Body.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import './Body.scss'
import React from 'react'

import classNames from 'classnames'
import { Objects } from 'utils/objects'

import { useTablePaginatedData } from 'client/store/ui/tablePaginated'
import DataColumn from 'client/components/DataGridDeprecated/DataColumn'
import Rows from 'client/components/TablePaginated/Body/Rows'
import RowsGroup from 'client/components/TablePaginated/Body/RowsGroup'
import RowsSkeleton from 'client/components/TablePaginated/Body/RowsSkeleton'
import { Props as BaseProps } from 'client/components/TablePaginated/types'

import { useTablePaginatedBodyData } from './hooks/useTablePaginatedBodyData'

const Body = <Datum extends object>(props: BaseProps<Datum>) => {
const { columns, compareFn, limit, path, wrapCells, skeleton } = props
const { columns, groups, limit, wrapCells, skeleton } = props

const data = useTablePaginatedData<Datum>(path, compareFn)
const data = useTablePaginatedBodyData<Datum>(props)

if (Objects.isNil(data)) {
return <RowsSkeleton columns={columns} limit={limit} skeleton={skeleton} />
}

return (
<>
{data.map((datum, rowIndex) => (
<React.Fragment key={`row_${String(rowIndex)}}`}>
{columns.map((column) => {
const { component: Component, key } = column

if (wrapCells) {
return (
<DataColumn key={key} className={classNames({ withBorder: rowIndex !== 0 })}>
<Component datum={datum} rowIndex={rowIndex} />
</DataColumn>
)
}

return <Component key={key} datum={datum} rowIndex={rowIndex} />
})}
</React.Fragment>
))}
</>
)
if (!Objects.isNil(groups)) {
return (
<div className="table-paginated__groups">
{(data as Array<[PropertyKey, Array<Datum>]>).map(([propertyKey, dataRows]) => (
<RowsGroup
key={propertyKey.toString()}
columns={columns}
data={dataRows}
groups={groups}
propertyKey={propertyKey}
wrapCells={wrapCells}
/>
))}
</div>
)
}

return <Rows columns={columns} data={data as Array<Datum>} wrapCells={wrapCells} />
}

export default Body
34 changes: 34 additions & 0 deletions src/client/components/TablePaginated/Body/Rows/Rows.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'

import classNames from 'classnames'

import DataColumn from 'client/components/DataGridDeprecated/DataColumn'
import { Props as BaseProps } from 'client/components/TablePaginated/types'

type Props<Datum extends object> = Pick<BaseProps<Datum>, 'columns' | 'wrapCells'> & {
data: Array<Datum>
}

const Rows = <Datum extends object>(props: Props<Datum>) => {
const { columns, data, wrapCells } = props

return data.map((datum, rowIndex) => (
<React.Fragment key={`row_${String(rowIndex)}}`}>
{columns.map((column) => {
const { component: Component, key } = column

if (wrapCells) {
return (
<DataColumn key={key} className={classNames({ withBorder: rowIndex !== 0 })}>
<Component datum={datum} rowIndex={rowIndex} />
</DataColumn>
)
}

return <Component key={key} datum={datum} rowIndex={rowIndex} />
})}
</React.Fragment>
))
}

export default Rows
1 change: 1 addition & 0 deletions src/client/components/TablePaginated/Body/Rows/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Rows'
31 changes: 31 additions & 0 deletions src/client/components/TablePaginated/Body/RowsGroup/RowsGroup.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@import 'src/client/style/partials';

button.rows-group__header.inverse {
background-color: $ui-bg-light;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: 1px solid transparent;
border-left: 1px solid $ui-border;
border-right: 1px solid $ui-border;
border-top: 1px solid $ui-border;

&.collapsed {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom: 1px solid $ui-border;

svg {
transform: rotate(-90deg);
}
}
}

.rows-group__rows {
background-color: $ui-bg-light;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
border: 1px solid $ui-border;
margin-top: -1px;
padding: $spacing-xxs;
}
41 changes: 41 additions & 0 deletions src/client/components/TablePaginated/Body/RowsGroup/RowsGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import './RowsGroup.scss'
import React, { useCallback, useState } from 'react'

import classNames from 'classnames'

import Button, { ButtonSize, ButtonType } from 'client/components/Buttons/Button'
import Rows from 'client/components/TablePaginated/Body/Rows'
import { Props as BaseProps } from 'client/components/TablePaginated/types'

type Props<Datum extends object> = Pick<BaseProps<Datum>, 'columns' | 'groups' | 'wrapCells'> & {
data: Array<Datum>
propertyKey: PropertyKey
}

const RowsGroup = <Datum extends object>(props: Props<Datum>) => {
const { columns, data, groups, propertyKey, wrapCells } = props

const [collapsed, setCollapsed] = useState<boolean>(false)
const toggleView = useCallback(() => setCollapsed((prevState) => !prevState), [])

return (
<div>
<Button
className={classNames('rows-group__header', { collapsed })}
iconName="small-down"
inverse
label={`${groups.headerLabel(propertyKey)} (${data.length})`}
onClick={toggleView}
size={ButtonSize.m}
type={ButtonType.black}
/>
{!collapsed && (
<div className="rows-group__rows">
<Rows columns={columns} data={data} wrapCells={wrapCells} />
</div>
)}
</div>
)
}

export default RowsGroup
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './RowsGroup'
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Objects } from 'utils/objects'

import { useTablePaginatedData } from 'client/store/ui/tablePaginated'
import { Props as BaseProps } from 'client/components/TablePaginated/types'

type Returned<Datum extends object> = Array<Datum> | Array<[PropertyKey, Array<Datum>]> | undefined

export const useTablePaginatedBodyData = <Datum extends object>(props: BaseProps<Datum>): Returned<Datum> => {
const { compareFn, groups, path } = props

const data = useTablePaginatedData<Datum>(path, compareFn)

if (Objects.isNil(data) || Objects.isNil(groups)) {
return data
}

return Object.entries(Object.groupBy(data ?? [], groups.keySelector))
}
36 changes: 13 additions & 23 deletions src/client/components/TablePaginated/TablePaginated.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import React, { HTMLAttributes, useMemo, useRef } from 'react'
import Skeleton from 'react-loading-skeleton'

import classNames from 'classnames'
import { Objects } from 'utils/objects'

import { useTablePaginatedCount, useTablePaginatedData, useTablePaginatedPage } from 'client/store/ui/tablePaginated'
import { useOnUpdate } from 'client/hooks'
import { useTablePaginatedCount } from 'client/store/ui/tablePaginated'
import DataGrid from 'client/components/DataGridDeprecated'
import { PaginatorProps } from 'client/components/Paginator'
import Filters from 'client/components/TablePaginated/Filters/Filters'
Expand All @@ -15,6 +13,7 @@ import ExportButton from './ExportButton/ExportButton'
import { useFetchData } from './hooks/useFetchData'
import { useInitTablePaginated } from './hooks/useInitTablePaginated'
import { useResetOnUnmount } from './hooks/useResetOnUnmount'
import { useScrollToTopOnPageUpdate } from './hooks/useScrollToTopOnPageUpdate'
import Body from './Body'
import Count from './Count'
import DefaultEmptyList from './DefaultEmptyList'
Expand All @@ -33,31 +32,24 @@ type Props<Datum extends object> = Pick<HTMLAttributes<HTMLDivElement>, 'classNa
}

const TablePaginated = <Datum extends object>(props: Props<Datum>) => {
const { className, gridTemplateColumns } = props // HTMLDivElement Props
const { className, gridTemplateColumns: gridTemplateColumnsProps } = props // HTMLDivElement Props
const { marginPagesDisplayed, pageRangeDisplayed } = props // Paginator Props
const { columns, filters, limit, path } = props // Base Props
const { columns, filters, groups, limit, path } = props // Base Props
const { counter, EmptyListComponent, export: exportTable, header, skeleton, wrapCells, compareFn } = props // Component Props

const divRef = useRef<HTMLDivElement>()

useInitTablePaginated({ filters, path })
useFetchData({ counter, limit, path })
useResetOnUnmount({ path })

useScrollToTopOnPageUpdate({ divRef, path })
const count = useTablePaginatedCount(path)
const data = useTablePaginatedData(path)
const page = useTablePaginatedPage(path)

const gridTemplateColumns = useMemo<string | number>(
() => gridTemplateColumnsProps ?? `repeat(${columns.length}, auto)`,
[columns.length, gridTemplateColumnsProps]
)
const withFilters = useMemo<boolean>(() => filters.filter((filter) => !filter.hidden).length > 0, [filters])
const divRef = useRef<HTMLDivElement>()

// on page update -> scroll on top
useOnUpdate(() => {
if (!Objects.isNil(data)) {
setTimeout(() => {
const opts: ScrollIntoViewOptions = { behavior: 'smooth', block: 'start', inline: 'nearest' }
divRef.current?.parentElement?.parentElement?.scrollIntoView(opts)
})
}
}, [page])

return (
<div ref={divRef} className={classNames('table-paginated', className)}>
Expand All @@ -69,15 +61,13 @@ const TablePaginated = <Datum extends object>(props: Props<Datum>) => {
{withFilters && <Filters filters={filters} path={path} />}
</div>
)}
<DataGrid
className="table-paginated-datagrid"
style={{ gridTemplateColumns: gridTemplateColumns ?? `repeat(${columns.length}, auto)` }}
>
<DataGrid className="table-paginated-datagrid" style={{ gridTemplateColumns }}>
{header && <Header columns={columns} path={path} />}
{count?.total === 0 && <EmptyListComponent />}
<Body
columns={columns}
compareFn={compareFn}
groups={groups}
limit={limit}
path={path}
skeleton={skeleton}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { MutableRefObject } from 'react'

import { Objects } from 'utils/objects'

import { useTablePaginatedData, useTablePaginatedPage } from 'client/store/ui/tablePaginated'
import { useOnUpdate } from 'client/hooks'

type Props = {
divRef: MutableRefObject<HTMLDivElement>
path: string
}

export const useScrollToTopOnPageUpdate = (props: Props): void => {
const { divRef, path } = props

const data = useTablePaginatedData(path)
const page = useTablePaginatedPage(path)

useOnUpdate(() => {
if (!Objects.isNil(data)) {
setTimeout(() => {
const opts: ScrollIntoViewOptions = { behavior: 'smooth', block: 'start', inline: 'nearest' }
divRef.current?.parentElement?.parentElement?.scrollIntoView(opts)
})
}
}, [page])
}
1 change: 1 addition & 0 deletions src/client/components/TablePaginated/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type Props<Datum extends object> = {
columns: Array<Column<Datum>>
compareFn?: TablePaginatedCompareFn<Datum>
filters?: Array<TablePaginatedFilter<TablePaginatedFilterType>>
groups?: { headerLabel: (key: PropertyKey) => string; keySelector: (datum: Datum) => PropertyKey }
limit?: number
path: string
skeleton?: TablePaginatedSkeleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@

.home-user-info {
&.expired {
.home-user-name {
.home-user-name .name {
text-decoration: line-through;
}
}
}

.home-user-name {
font-weight: 700;
margin-top: -6px;
}

.home-user-role {
align-items: center;
display: flex;
gap: 8px;

.role {
color: lighten($text-mute, 10%);
font-size: $font-xs;
text-transform: uppercase;
.name {
font-weight: 700;
}
}

Expand All @@ -33,9 +26,9 @@
border: 1px solid rgba($ui-alert, 0.8);
color: darken($ui-alert, 20%);
display: grid;
font-size: 9px;
font-size: 8px;
font-weight: 600;
height: 18px;
height: 16px;
justify-content: center;
letter-spacing: 0.4px;
line-height: 0;
Expand Down
Loading

0 comments on commit 7ea5a9d

Please sign in to comment.