Skip to content
Snippets Groups Projects
Commit bddb8e29 authored by Andreas Ellewsen's avatar Andreas Ellewsen
Browse files

Merge branch 'GREG-328-frontpage-improvmements' into 'master'

Add sorting for each column on the sponsor frontpage

See merge request !385
parents 5ee7a773 873c28ee
No related branches found
No related tags found
1 merge request!385Add sorting for each column on the sponsor frontpage
Pipeline #179835 passed
......@@ -13,6 +13,7 @@ import {
TableContainer,
TableHead,
TableRow,
TableSortLabel,
TextField,
Typography,
} from '@mui/material'
......@@ -54,6 +55,14 @@ interface FrontPageProps {
loading: boolean
}
type SortDirection = 'desc' | 'asc'
type SortField = 'name' | 'role' | 'status' | 'endDate' | 'department'
interface GuestRole {
guest: Guest
role: Role
}
const StyledTableRow = styled(TableRow)({
borderTop: '0',
borderLeft: '0',
......@@ -172,22 +181,65 @@ const Status = ({ person, role }: StatusProps) => {
}
}
const sortByDate = (
guestRole: { guest: Guest; role: Role }[]
): { guest: Guest; role: Role }[] =>
guestRole.sort(
(a, b) => a.role.end_date.getTime() - b.role.end_date.getTime()
function createGuestsRoles(guests: Guest[]): GuestRole[] {
const guestRoles: GuestRole[] = []
guests.forEach((guest) =>
guest.roles.forEach((role) => {
guestRoles.push({ guest, role })
})
)
return guestRoles
}
function sortByName(
guestA: Guest,
guestB: Guest,
direction: SortDirection
): number {
const firstA = guestA.first.toLowerCase()
const firstB = guestB.first.toLowerCase()
if (firstA < firstB) {
return direction === 'asc' ? -1 : 1
}
if (firstA > firstB) {
return direction === 'asc' ? 1 : -1
}
return 0
}
function sortGuestsByName(guests: Guest[], direction: SortDirection) {
return createGuestsRoles(guests).sort((a, b) =>
sortByName(a.guest, b.guest, direction)
)
}
function sortGuestRolesByEndDate(
guestRole: GuestRole[],
direction: SortDirection
): GuestRole[] {
return guestRole.sort((a, b) => {
const aEndDate = a.role.end_date.getTime()
const bEndDate = b.role.end_date.getTime()
if (aEndDate < bEndDate) {
return direction === 'asc' ? -1 : 1
}
if (aEndDate > bEndDate) {
return direction === 'asc' ? 1 : -1
}
// Secondary sort on guest name, always asc
return sortByName(a.guest, b.guest, 'asc')
})
}
const sortByStatus = (guests: Guest[]): { guest: Guest; role: Role }[] => {
function sortByStatus(guests: Guest[], direction: SortDirection): GuestRole[] {
let activeRoleAndPerson: { guest: Guest; role: Role }[] = []
let expiringRoleAndPerson: { guest: Guest; role: Role }[] = []
let expiredRoleAndPerson: { guest: Guest; role: Role }[] = []
let status
guests.forEach((guest) =>
guest.roles.forEach((role) => {
;[status] = calculateStatus(guest, role)
const [status] = calculateStatus(guest, role)
if (status === 'active') {
activeRoleAndPerson.push({ guest, role })
} else if (status === 'expiring') {
......@@ -198,13 +250,71 @@ const sortByStatus = (guests: Guest[]): { guest: Guest; role: Role }[] => {
})
)
activeRoleAndPerson = sortByDate(activeRoleAndPerson)
expiringRoleAndPerson = sortByDate(expiringRoleAndPerson)
expiredRoleAndPerson = sortByDate(expiredRoleAndPerson)
// Always use 'asc' for secondary sorting
activeRoleAndPerson = sortGuestRolesByEndDate(activeRoleAndPerson, 'asc')
expiringRoleAndPerson = sortGuestRolesByEndDate(expiringRoleAndPerson, 'asc')
expiredRoleAndPerson = sortGuestRolesByEndDate(expiredRoleAndPerson, 'asc')
return expiringRoleAndPerson
if (direction === 'asc') {
return expiringRoleAndPerson
.concat(activeRoleAndPerson)
.concat(expiredRoleAndPerson)
}
return expiredRoleAndPerson
.concat(activeRoleAndPerson)
.concat(expiredRoleAndPerson)
.concat(expiringRoleAndPerson)
}
function sortGuestsByRoleName(guests: Guest[], direction: SortDirection) {
return createGuestsRoles(guests).sort((a, b) => {
const aRoleName = getRoleName(a.role).toLowerCase()
const bRoleName = getRoleName(b.role).toLowerCase()
if (aRoleName < bRoleName) {
return direction === 'asc' ? -1 : 1
}
if (aRoleName > bRoleName) {
return direction === 'asc' ? 1 : -1
}
// Secondary sort on guest name, always asc
return sortByName(a.guest, b.guest, 'asc')
})
}
function sortGuestsByDepartmentName(guests: Guest[], direction: SortDirection) {
return createGuestsRoles(guests).sort((a, b) => {
const aRoleOUName = getRoleOuName(a.role).toLowerCase()
const bRoleOUName = getRoleOuName(b.role).toLowerCase()
if (aRoleOUName < bRoleOUName) {
return direction === 'asc' ? -1 : 1
}
if (aRoleOUName > bRoleOUName) {
return direction === 'asc' ? 1 : -1
}
// Secondary sort on guest name, always asc
return sortByName(a.guest, b.guest, 'asc')
})
}
function sortGuestsAndRoles(
guests: Guest[],
sortField: SortField,
direction: SortDirection
): { guest: Guest; role: Role }[] {
switch (sortField) {
case 'department':
return sortGuestsByDepartmentName(guests, direction)
case 'endDate':
return sortGuestRolesByEndDate(createGuestsRoles(guests), direction)
case 'name':
return sortGuestsByName(guests, direction)
case 'role':
return sortGuestsByRoleName(guests, direction)
case 'status':
return sortByStatus(guests, direction)
default:
// Fallback to original sort
return createGuestsRoles(guests)
}
}
const PersonLine = ({ person, role }: PersonLineProps) => {
......@@ -236,6 +346,17 @@ const PersonLine = ({ person, role }: PersonLineProps) => {
const GuestTable = ({ guests, emptyText, marginWidth }: GuestTableProps) => {
const { t } = useTranslation('common')
const [direction, setDirection] = useState<SortDirection>('asc')
const [orderBy, setOrderBy] = useState<SortField>('status')
const handleRequestSort =
(sortBy: SortField) => (event: React.MouseEvent<unknown>) => {
event.preventDefault()
const isAsc = orderBy === sortBy && direction === 'asc'
setDirection(isAsc ? 'desc' : 'asc')
setOrderBy(sortBy)
}
return (
<TableContainer
component={Paper}
......@@ -248,17 +369,63 @@ const GuestTable = ({ guests, emptyText, marginWidth }: GuestTableProps) => {
<Table sx={{ minWidth: marginWidth }} aria-label="simple table">
<StyledTableHead>
<TableRow>
<StyledTableHeadCell>{t('common:name')}</StyledTableHeadCell>
<StyledTableHeadCell>{t('common:role')}</StyledTableHeadCell>
<StyledTableHeadCell>{t('common:status')}</StyledTableHeadCell>
<StyledTableHeadCell>{t('common:endDate')}</StyledTableHeadCell>
<StyledTableHeadCell>{t('common:department')}</StyledTableHeadCell>
<StyledTableHeadCell>
<TableSortLabel
key="name"
active={orderBy === 'name'}
direction={orderBy === 'name' ? direction : 'asc'}
onClick={handleRequestSort('name')}
>
{t('common:name')}
</TableSortLabel>
</StyledTableHeadCell>
<StyledTableHeadCell>
<TableSortLabel
key="role"
active={orderBy === 'role'}
direction={orderBy === 'role' ? direction : 'asc'}
onClick={handleRequestSort('role')}
>
{t('common:role')}
</TableSortLabel>
</StyledTableHeadCell>
<StyledTableHeadCell>
<TableSortLabel
key="status"
active={orderBy === 'status'}
direction={orderBy === 'status' ? direction : 'asc'}
onClick={handleRequestSort('status')}
>
{t('common:status')}
</TableSortLabel>
</StyledTableHeadCell>
<StyledTableHeadCell>
<TableSortLabel
key="endDate"
active={orderBy === 'endDate'}
direction={orderBy === 'endDate' ? direction : 'asc'}
onClick={handleRequestSort('endDate')}
>
{t('common:endDate')}
</TableSortLabel>
</StyledTableHeadCell>
<StyledTableHeadCell>
<TableSortLabel
key="department"
active={orderBy === 'department'}
direction={orderBy === 'department' ? direction : 'asc'}
onClick={handleRequestSort('department')}
>
{t('common:department')}
</TableSortLabel>
</StyledTableHeadCell>
<StyledTableHeadCell />
</TableRow>
</StyledTableHead>
<TableBody>
{guests.length > 0 ? (
sortByStatus(guests).map((personRole) => (
sortGuestsAndRoles(guests, orderBy, direction).map((personRole) => (
<PersonLine
key={`${personRole.guest.first} ${personRole.guest.last} ${personRole.role.id}`}
role={personRole.role}
......@@ -267,7 +434,7 @@ const GuestTable = ({ guests, emptyText, marginWidth }: GuestTableProps) => {
))
) : (
<StyledTableRow>
<TableCell> {emptyText}</TableCell>
<TableCell>{emptyText}</TableCell>
</StyledTableRow>
)}
</TableBody>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment