Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part 1: Filter table with search field #68

Merged
merged 9 commits into from
Feb 27, 2024
4 changes: 0 additions & 4 deletions src/components/PageLayout/pagelayout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,4 @@
@media #{variables.$mobile} {
flex-direction: column;
}
}

.tableTitle {
margin: 2.5rem 0;
}
123 changes: 96 additions & 27 deletions src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import styles from './table.module.scss'

import { useEffect, useState } from 'react'
import { useMediaQuery } from 'react-responsive'
import { Text } from '@statisticsnorway/ssb-component-library'
import { Title, Dropdown, Input, Text } from '@statisticsnorway/ssb-component-library'

interface TableProps {
title: string
dropdownAriaLabel?: string
dropdownFilterItems?: Array<object>
columns: TableData['columns']
data: TableData['data']
}
export interface TableData {
columns: {
id: string
Expand All @@ -19,20 +27,26 @@ function conditionalStyling(index: number) {
return (index + 1) % 2 !== 0 ? styles.greenBackground : undefined
}

const NoResultText = () => <p className={styles.noResult}>Fant ingen resultater</p>

const TableMobileView = ({ columns, data }: TableData) => (
<div className={styles.tableContainerMobile}>
{data.map((row, index) => {
return (
<div key={row.id} className={`${styles.tableMobile} ${conditionalStyling(index)}`}>
{columns.map((column, index) => (
<Text small key={column.id}>
{index !== 0 && <b>{column.label}</b>}
{row[column.id]}
</Text>
))}
</div>
)
})}
{data.length ? (
data.map((row, index) => {
return (
<div key={row.id} className={`${styles.tableMobile} ${conditionalStyling(index)}`}>
{columns.map((column, index) => (
<Text small key={column.id}>
{index !== 0 && <b>{column.label}</b>}
{row[column.id]}
</Text>
))}
</div>
)
})
) : (
<NoResultText />
)}
</div>
)

Expand All @@ -47,25 +61,80 @@ const TableDesktopView = ({ columns, data }: TableData) => (
</tr>
</thead>
<tbody>
{data.map((row, index) => {
return (
<tr key={row.id} className={conditionalStyling(index)}>
{columns.map((column) => (
<td key={column.id}>{row[column.id]}</td>
))}
</tr>
)
})}
{data.length ? (
data.map((row, index) => {
return (
<tr key={row.id} className={conditionalStyling(index)}>
{columns.map((column) => (
<td key={column.id}>{row[column.id]}</td>
))}
</tr>
)
})
) : (
<tr>
<td colSpan={columns.length}>
<NoResultText />
</td>
</tr>
)}
</tbody>
</table>
</div>
)

export default function Table({ columns, data }: TableData) {
/* TODO:
* Add alphabetical, numerical etc sorting when row header is clicked
* Consider making table sort more visible
*/
const Table = ({ title, dropdownAriaLabel, dropdownFilterItems, columns, data }: TableProps) => {
const [searchFilterKeyword, setSearchFilterKeyword] = useState('')
const [filteredTableData, setFilteredTableData] = useState(data)

const isOnMobile = useMediaQuery({ query: 'screen and (max-width: 767px)' }) // $mobile variable from ssb-component-library
if (isOnMobile) {
return <TableMobileView columns={columns} data={data} />
} else {
return <TableDesktopView columns={columns} data={data} />

useEffect(() => {
if (searchFilterKeyword !== '') {
const filterTableData = data.filter((row) =>
Object.values(row).toString().toLowerCase().includes(searchFilterKeyword.toLowerCase())
)
setFilteredTableData(filterTableData)
} else {
setFilteredTableData(data) // Reset filter
}
}, [searchFilterKeyword, data])

const handleChange = (value: string) => {
setSearchFilterKeyword(value)
}

return (
<>
<div className={styles.tableTitleContainer}>
{title && (
<Title size={2} className={styles.tableTitleWrapper}>
{title}
</Title>
)}
<div className={styles.tableFilterWrapper}>
{dropdownFilterItems?.length && (
<Dropdown
className={styles.tableFilterDropdown}
ariaLabel={dropdownAriaLabel}
selectedItem={dropdownFilterItems[0]}
items={dropdownFilterItems}
/>
)}
<Input placeholder='Filtrer liste...' value={searchFilterKeyword} handleChange={handleChange} searchField />
</div>
</div>
{isOnMobile ? (
<TableMobileView columns={columns} data={filteredTableData} />
) : (
<TableDesktopView columns={columns} data={filteredTableData} />
)}
</>
)
}

export default Table
51 changes: 51 additions & 0 deletions src/components/Table/table.module.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables;

.tableTitleContainer {
@media #{variables.$desktop} {
display: flex;
flex-wrap: row;
justify-content: space-between;

.tableTitleWrapper {
margin: 2.5rem 0;
}

.tableFilterWrapper {
display: flex;
align-items: center;

.tableFilterDropdown {
margin-right: .5rem;

span {
margin: 0;
}
}
}
}

@media #{variables.$mobile} {
.tableTitleWrapper {
margin: 2.5rem 0 0;
}

.tableFilterWrapper {
margin-bottom: 2rem;

.tableFilterDropdown {
min-width: 100%;
}

> * {
margin: 1rem 0;
}
}
}
}

.tableContainer {
overflow-x: auto;

Expand Down Expand Up @@ -54,4 +97,12 @@

.greenBackground {
background-color: variables.$ssb-green-1;
}

.noResult {
justify-content: center;

@media #{variables.$mobile} {
display: flex;
}
}
33 changes: 21 additions & 12 deletions src/pages/TeamDetail/TeamDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import pageLayoutStyles from '../../components/PageLayout/pagelayout.module.scss'
import styles from './teamDetail.module.scss'

import { useCallback, useContext, useEffect, useState } from 'react'
Expand All @@ -10,7 +9,7 @@ import { DaplaCtrlContext } from '../../provider/DaplaCtrlProvider'
import Table, { TableData } from '../../components/Table/Table'
import { formatDisplayName, getGroupType } from '../../utils/utils'
import { User } from '../../@types/user'
import { Text, Title, Link, Dialog, LeadParagraph } from '@statisticsnorway/ssb-component-library'
import { Text, Link, Dialog, LeadParagraph } from '@statisticsnorway/ssb-component-library'
import PageSkeleton from '../../components/PageSkeleton/PageSkeleton'
import { Skeleton } from '@mui/material'

Expand All @@ -24,12 +23,21 @@ export default function TeamDetail() {
const { teamId } = useParams<{ teamId: string }>()

const prepTeamData = useCallback((response: TeamDetailData): TableData['data'] => {
return response['teamUsers'].teamUsers.map((user) => ({
id: user?.principal_name,
navn: renderUsernameColumn(user),
gruppe: user.groups?.map((group) => getGroupType(group.uniform_name)).join(', '),
epost: user?.principal_name,
}))
return response['teamUsers'].teamUsers.map((user) => {
// Makes data in username column searchable and sortable in table by including these fields
const usernameColumn = {
user: user.display_name,
seksjon: user.section_name,
}

return {
id: user?.principal_name,
...usernameColumn,
navn: renderUsernameColumn(user),
gruppe: user.groups?.map((group) => getGroupType(group.uniform_name)).join(', '),
epost: user?.principal_name,
}
})
}, [])

useEffect(() => {
Expand Down Expand Up @@ -122,10 +130,11 @@ export default function TeamDetail() {
</Text>
<Text medium>{teamDetailData ? teamDetailData['teamUsers'].teamInfo.section_name : ''}</Text>
</LeadParagraph>
<Title size={2} className={pageLayoutStyles.tableTitle}>
Teammedlemmer
</Title>
<Table columns={teamOverviewTableHeaderColumns} data={teamDetailTableData as TableData['data']} />
<Table
title='Teammedlemmer'
columns={teamOverviewTableHeaderColumns}
data={teamDetailTableData as TableData['data']}
/>
</>
)
}
Expand Down
27 changes: 13 additions & 14 deletions src/pages/TeamMembers/TeamMembers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import pageLayoutStyles from '../../components/PageLayout/pagelayout.module.scss'

import { useCallback, useEffect, useState } from 'react'
import { Dialog, Title, Text, Link, Tabs, Divider } from '@statisticsnorway/ssb-component-library'
import { Dialog, Text, Link, Tabs, Divider } from '@statisticsnorway/ssb-component-library'

import { TabProps } from '../../@types/pageTypes'
import PageLayout from '../../components/PageLayout/PageLayout'
Expand All @@ -12,7 +10,7 @@ import { fetchAllTeamMembersData, TeamMembersData, User } from '../../services/t
import { formatDisplayName } from '../../utils/utils'
import { ApiError } from '../../utils/services'

export default function TeamMembers() {
const TeamMembers = () => {
const accessToken = localStorage.getItem('access_token') || ''
const jwt = JSON.parse(atob(accessToken.split('.')[1]))

Expand All @@ -37,7 +35,7 @@ export default function TeamMembers() {
navn: renderUserNameColumn(teamMember),
team: teamMember.teams.length,
data_admin_roller: teamMember.groups.filter((group) => group.uniform_name.endsWith('data-admins')).length,
seksjon: teamMember.section_name,
seksjon: teamMember.section_name, // Makes section name searchable and sortable in table by including the field
seksjonsleder: formatDisplayName(
teamMember.section_manager && teamMember.section_manager.length > 0
? teamMember.section_manager[0].display_name
Expand Down Expand Up @@ -76,7 +74,7 @@ export default function TeamMembers() {
}
}

function renderUserNameColumn(user: User) {
const renderUserNameColumn = (user: User) => {
return (
<>
<span>
Expand All @@ -89,15 +87,15 @@ export default function TeamMembers() {
)
}

function renderErrorAlert() {
const renderErrorAlert = () => {
return (
<Dialog type='warning' title='Could not fetch users'>
{`${error?.code} - ${error?.message}`}
</Dialog>
)
}

function renderContent() {
const renderContent = () => {
if (error) return renderErrorAlert()
if (loading) return <PageSkeleton />

Expand Down Expand Up @@ -132,13 +130,12 @@ export default function TeamMembers() {
]}
/>
<Divider dark />
{/* TODO: Remove Title */}
<Title size={2} className={pageLayoutStyles.tableTitle}>
{teamMembersTableTitle}
</Title>
{teamMembersTableData.length > 0 ? (
//TODO: <Table title={teamMembersTableTitle} columns={teamMembersTableHeaderColumns} data={teamMembersTableData as TableData['data']} />
<Table columns={teamMembersTableHeaderColumns} data={teamMembersTableData as TableData['data']} />
<Table
title={teamMembersTableTitle}
columns={teamMembersTableHeaderColumns}
data={teamMembersTableData as TableData['data']}
/>
) : (
<Dialog type='warning' title='No team members found'>
You are not a manager in any dapla-team
Expand All @@ -151,3 +148,5 @@ export default function TeamMembers() {

return <PageLayout title={'Teammedlemmer'} content={renderContent()} />
}

export default TeamMembers
14 changes: 7 additions & 7 deletions src/pages/TeamOverview/TeamOverview.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import pageLayoutStyles from '../../components/PageLayout/pagelayout.module.scss'

import { useCallback, useEffect, useState } from 'react'
import { Dialog, Title, Text, Link, Tabs, Divider } from '@statisticsnorway/ssb-component-library'
import { Dialog, Text, Link, Tabs, Divider } from '@statisticsnorway/ssb-component-library'

import { TabProps } from '../../@types/pageTypes'
import PageLayout from '../../components/PageLayout/PageLayout'
Expand Down Expand Up @@ -33,6 +31,7 @@ export default function TeamOverview() {

return response[team].teams.map((team) => ({
id: team.uniform_name,
seksjon: team.section_name, // Makes section name searchable and sortable in table by including the field
navn: renderTeamNameColumn(team),
teammedlemmer: team.team_user_count,
ansvarlig: formatDisplayName(team.manager.display_name),
Expand Down Expand Up @@ -124,10 +123,11 @@ export default function TeamOverview() {
]}
/>
<Divider dark />
<Title size={2} className={pageLayoutStyles.tableTitle}>
{teamOverviewTableTitle}
</Title>
<Table columns={teamOverviewTableHeaderColumns} data={teamOverviewTableData as TableData['data']} />
<Table
title={teamOverviewTableTitle}
columns={teamOverviewTableHeaderColumns}
data={teamOverviewTableData as TableData['data']}
/>
</>
)
}
Expand Down
Loading