-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement the overview table of the Shifts tool
- Loading branch information
Showing
10 changed files
with
491 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2024 Peter Beverloo & AnimeCon. All rights reserved. | ||
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | ||
|
||
import Collapse from '@mui/material/Collapse'; | ||
|
||
import { Section, type SectionProps } from './Section'; | ||
|
||
/** | ||
* Props accepted by the <CollapsableSection> component, that are directly owned by the component. | ||
*/ | ||
export type CollapsableSectionProps = SectionProps & { | ||
/** | ||
* Whether the section should be transitioned in. | ||
*/ | ||
in?: boolean; | ||
} | ||
|
||
/** | ||
* The <CollapsableSection> component represents a visually separated section of a page in the | ||
* administration area that, unlike <Section>, can be hidden and shown dynamically. The component | ||
* is designed to be compatible with server-side rendering. | ||
*/ | ||
export function CollapsableSection(props: React.PropsWithChildren<CollapsableSectionProps>) { | ||
const { in: transitionedIn, ...sectionProps } = props; | ||
|
||
return ( | ||
<Collapse in={transitionedIn} sx={{ '&.MuiCollapse-hidden': { marginBottom: -2 } }}> | ||
<Section {...sectionProps} /> | ||
</Collapse> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright 2024 Peter Beverloo & AnimeCon. All rights reserved. | ||
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | ||
|
||
import SentimentDissatisfiedIcon from '@mui/icons-material/SentimentDissatisfied'; | ||
import SentimentSatisfiedAltIcon from '@mui/icons-material/SentimentSatisfiedAlt'; | ||
import SentimentSatisfiedIcon from '@mui/icons-material/SentimentSatisfied'; | ||
import SentimentVeryDissatisfiedIcon from '@mui/icons-material/SentimentVeryDissatisfied'; | ||
import SentimentVerySatisfiedIcon from '@mui/icons-material/SentimentVerySatisfied'; | ||
import Tooltip from '@mui/material/Tooltip'; | ||
|
||
/** | ||
* Props accepted by the <ExcitementIcon> component. | ||
*/ | ||
export interface ExcitementIconProps { | ||
/** | ||
* The excitement level, must be between 0 and 1. | ||
*/ | ||
excitement: number; | ||
} | ||
|
||
/** | ||
* The <ExcitementIcon> component returns an appropriate component visualising the excitement that | ||
* is indicated in the given `props`. | ||
*/ | ||
export function ExcitementIcon(props: ExcitementIconProps) { | ||
const { excitement } = props; | ||
if (excitement <= 0.2) { | ||
return ( | ||
<Tooltip title="This is a really boring shift"> | ||
<SentimentVeryDissatisfiedIcon fontSize="small" color="error" /> | ||
</Tooltip> | ||
); | ||
} else if (excitement <= 0.4) { | ||
return ( | ||
<Tooltip title="This is a boring shift"> | ||
<SentimentDissatisfiedIcon fontSize="small" color="error" /> | ||
</Tooltip> | ||
); | ||
} else if (excitement <= 0.6) { | ||
return ( | ||
<Tooltip title="This is a dull shift"> | ||
<SentimentSatisfiedIcon fontSize="small" color="warning" /> | ||
</Tooltip> | ||
); | ||
} else if (excitement <= 0.8) { | ||
return ( | ||
<Tooltip title="This is a nice shift"> | ||
<SentimentSatisfiedAltIcon fontSize="small" color="success" /> | ||
</Tooltip> | ||
); | ||
} else { | ||
return ( | ||
<Tooltip title="This is a great shift"> | ||
<SentimentVerySatisfiedIcon fontSize="small" color="success" /> | ||
</Tooltip> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// Copyright 2024 Peter Beverloo & AnimeCon. All rights reserved. | ||
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | ||
|
||
'use client'; | ||
|
||
import Link from 'next/link'; | ||
|
||
import { default as MuiLink } from '@mui/material/Link'; | ||
import NewReleasesIcon from '@mui/icons-material/NewReleases'; | ||
import SentimentSatisfiedAltIcon from '@mui/icons-material/SentimentSatisfiedAlt'; | ||
import Tooltip from '@mui/material/Tooltip'; | ||
import Typography from '@mui/material/Typography'; | ||
|
||
import type { EventShiftContext, EventShiftRowModel } from '@app/api/admin/event/shifts/[[...id]]/route'; | ||
import { ExcitementIcon } from '@app/admin/components/ExcitementIcon'; | ||
import { RemoteDataTable, type RemoteDataTableColumn } from '@app/admin/components/RemoteDataTable'; | ||
|
||
/** | ||
* Formats the given number of `minutes` to a HH:MM string. | ||
*/ | ||
function formatMinutes(minutes: number): string { | ||
const hours = Math.floor(minutes / 60); | ||
const remainingMinutes = minutes - hours * 60; | ||
|
||
return remainingMinutes ? `${hours}:${('00' + remainingMinutes).substr(-2)}` | ||
: `${hours}`; | ||
} | ||
|
||
/** | ||
* Props accepted by the <ShiftTable> component. | ||
*/ | ||
export type ShiftTableProps = EventShiftContext['context'] & { | ||
/** | ||
* Whether the shift table should be shown in read only mode. | ||
*/ | ||
readOnly?: boolean; | ||
}; | ||
|
||
/** | ||
* The <ShiftTable> component is a Data Table that allows rows to be shown and deleted, which | ||
* displays the shifts that exist for a particular { event, team } pair. | ||
*/ | ||
export function ShiftTable(props: ShiftTableProps) { | ||
const { readOnly, ...context } = props; | ||
|
||
const deleteColumn: RemoteDataTableColumn<EventShiftRowModel>[] = []; | ||
if (!readOnly) { | ||
deleteColumn.push({ | ||
field: 'id', | ||
headerName: /* empty= */ '', | ||
sortable: false, | ||
width: 50, | ||
}); | ||
} | ||
|
||
const columns: RemoteDataTableColumn<EventShiftRowModel>[] = [ | ||
...deleteColumn, | ||
{ | ||
field: 'name', | ||
headerName: 'Shift', | ||
flex: 1, | ||
|
||
renderCell: params => | ||
<MuiLink component={Link} href={`./shifts/${params.row.id}`}> | ||
{params.value} | ||
</MuiLink>, | ||
}, | ||
{ | ||
field: 'hours', | ||
headerName: 'Scheduled', | ||
flex: 1, | ||
|
||
renderCell: params => { | ||
if (!params.value) { | ||
return ( | ||
<Typography variant="body2" sx={{ color: 'text.disabled' }}> | ||
… | ||
</Typography> | ||
); | ||
} | ||
|
||
return <>{formatMinutes(params.value)} hours</>; | ||
}, | ||
}, | ||
{ | ||
field: 'activityId', | ||
headerAlign: 'center', | ||
headerName: /* empty= */ '', | ||
sortable: false, | ||
align: 'center', | ||
width: 50, | ||
|
||
renderHeader: params => | ||
<Tooltip title="Initiative or program?"> | ||
<NewReleasesIcon fontSize="small" color="primary" /> | ||
</Tooltip>, | ||
|
||
renderCell: params => { | ||
if (!params.value) { | ||
return ( | ||
<Tooltip title="(our initiative)"> | ||
<NewReleasesIcon fontSize="small" color="disabled" /> | ||
</Tooltip> | ||
); | ||
} | ||
|
||
const href = `../program/activities/${params.row.activityId}`; | ||
return ( | ||
<Tooltip title={params.row.activityName}> | ||
<MuiLink component={Link} href={href} sx={{ pt: '5px' }}> | ||
<NewReleasesIcon fontSize="small" color="success" /> | ||
</MuiLink> | ||
</Tooltip> | ||
); | ||
} | ||
}, | ||
{ | ||
field: 'excitement', | ||
headerAlign: 'center', | ||
headerName: /* empty= */ '', | ||
sortable: false, | ||
align: 'center', | ||
width: 50, | ||
|
||
renderHeader: params => | ||
<Tooltip title="Volunteer sentiment"> | ||
<SentimentSatisfiedAltIcon fontSize="small" color="primary" /> | ||
</Tooltip>, | ||
|
||
renderCell: params => | ||
<ExcitementIcon excitement={params.value} />, | ||
} | ||
]; | ||
|
||
return ( | ||
<RemoteDataTable columns={columns} endpoint="/api/admin/event/shifts" context={context} | ||
defaultSort={{ field: 'id', sort: 'asc' }} subject="shift" | ||
enableDelete={!readOnly} pageSize={100} disableFooter /> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.