[Ooditable] reusable "copy studentnumbers" button

+ add to progress tab
This commit is contained in:
joonas-a
2026-09-22 13:45:22 +03:00
parent 7a8e258b7c
commit 0ee5b514f6
5 changed files with 56 additions and 97 deletions
@@ -0,0 +1,43 @@
import Box from '@mui/material/Box'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import Tooltip from '@mui/material/Tooltip'
import { Table } from '@tanstack/react-table'
import { handleClipboardCopy } from '@/components/OodiTable/utils'
import { useStatusNotification } from '@/components/StatusNotification/Context'
import { ContentCopyIcon } from '@/theme'
/** To be paired with Class stats student tables */
export const CopyStudentNumbersHeader = <TData,>({
table,
getStudentNumber,
label = 'Student number',
}: {
table: Table<TData>
getStudentNumber: (row: TData) => string | null | undefined
label?: string
}) => {
const { setStatusNotification, closeNotification } = useStatusNotification()
const allStudentNumbers = table
.getFilteredRowModel()
.rows.map(row => getStudentNumber(row.original))
.filter((studentNumber): studentNumber is string => !!studentNumber)
const copyText = `Copied ${allStudentNumbers.length} student numbers`
return (
<Stack direction="row" spacing={1} sx={{ verticalAlign: 'middle' }}>
<Box sx={{ alignSelf: 'center' }}>{label}</Box>
<Tooltip title="Copy all student numbers to clipboard">
<IconButton
onClick={event =>
void handleClipboardCopy(event, allStudentNumbers, copyText, setStatusNotification, closeNotification)
}
>
<ContentCopyIcon color="action" />
</IconButton>
</Tooltip>
</Stack>
)
}
@@ -1,19 +1,13 @@
import Box from '@mui/material/Box'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import { useTheme } from '@mui/material/styles'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import { ColumnDef, createColumnHelper } from '@tanstack/react-table'
import { useMemo } from 'react'
import { StudentInfoItem } from '@/components/common/StudentInfoItem'
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
import { handleClipboardCopy } from '@/components/OodiTable/utils'
import { CopyStudentNumbersHeader } from '@/components/OodiTable/common/CopyStudentNumbersHeader'
import { Courses, CourseTabModule, CourseTabStudent } from '@/components/PopulationComponents/Students/Table/CoursesTab'
import { useStatusNotification } from '@/components/StatusNotification/Context'
import { DateFormat } from '@/constants/date'
import { CheckIcon, ContentCopyIcon, CropSquareIcon, RemoveIcon, SwapHorizIcon } from '@/theme'
import { CheckIcon, CropSquareIcon, RemoveIcon, SwapHorizIcon } from '@/theme'
import { formatDate, isWithinSixMonths } from '@/util/timeAndDate'
import { CreditTypeCode } from '@oodikone/shared/types'
@@ -29,38 +23,11 @@ const getSortingValue = (course: Courses['number'] | undefined) => {
export const useGetColumnDefinitions = (modules: Map<string, CourseTabModule>): ColumnDef<CourseTabStudent, any>[] => {
const { getTextIn } = useLanguage()
const theme = useTheme()
const { setStatusNotification, closeNotification } = useStatusNotification()
return useMemo(() => {
return [
// Static columns
columnHelper.accessor('studentNumber', {
header: ({ table }) => {
const allStudentNumbers = table
.getFilteredRowModel()
.rows.map(row => row.original.studentNumber)
.filter(Boolean)
const copyText = `Copied ${allStudentNumbers.length} student numbers`
return (
<Stack direction="row" spacing={1} sx={{ verticalAlign: 'middle' }}>
<Box sx={{ alignSelf: 'center' }}>Student number</Box>
<Tooltip title="Copy all student numbers to system clipboard">
<IconButton
onClick={event =>
void handleClipboardCopy(
event,
allStudentNumbers,
copyText,
setStatusNotification,
closeNotification
)
}
>
<ContentCopyIcon color="action" />
</IconButton>
</Tooltip>
</Stack>
)
},
header: ({ table }) => <CopyStudentNumbersHeader getStudentNumber={row => row.studentNumber} table={table} />,
cell: cell => {
const studentNumber = cell.getValue()
if (studentNumber === 'Hidden') return studentNumber
@@ -1,6 +1,4 @@
import Box from '@mui/material/Box'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import Tooltip from '@mui/material/Tooltip'
import type { ColumnDef } from '@tanstack/react-table'
@@ -13,12 +11,11 @@ import { TableHeaderWithTooltip } from '@/components/common/TableHeaderWithToolt
import { creditDateFilter } from '@/components/FilterView/filters'
import { useFilters } from '@/components/FilterView/useFilters'
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
import { handleClipboardCopy } from '@/components/OodiTable/utils'
import { CopyStudentNumbersHeader } from '@/components/OodiTable/common/CopyStudentNumbersHeader'
import { FormattedStudentData } from '@/components/PopulationComponents/Students/Table/GeneralTab'
import { joinProgrammes } from '@/components/PopulationComponents/Students/Table/GeneralTab/util'
import { useStatusNotification } from '@/components/StatusNotification/Context'
import { DateFormat } from '@/constants/date'
import { CheckIcon, ContentCopyIcon } from '@/theme'
import { CheckIcon } from '@/theme'
import { formatDate } from '@/util/timeAndDate'
const columnHelper = createColumnHelper<FormattedStudentData>()
@@ -40,36 +37,12 @@ export const useGetColumnDefinitions = ({
}: GeneralTabColDefProps): ColumnDef<FormattedStudentData, any>[] => {
const { getTextIn } = useLanguage()
const { useFilterSelector } = useFilters()
const { setStatusNotification, closeNotification } = useStatusNotification()
const creditDateFilterOptions = useFilterSelector(creditDateFilter.selectors.selectOptions(undefined))
return useMemo(
() => [
columnHelper.accessor('studentNumber', {
header: ({ table }) => {
const allStudentNumbers = table.getFilteredRowModel().rows.map(row => row.original.studentNumber)
const copyText = `Copied ${allStudentNumbers.length} student numbers`
return (
<Stack direction="row" spacing={1} sx={{ verticalAlign: 'middle' }}>
<Box sx={{ alignSelf: 'center' }}>Student number</Box>
<Tooltip title="Copy all student numbers to clipboard">
<IconButton
onClick={event =>
void handleClipboardCopy(
event,
allStudentNumbers,
copyText,
setStatusNotification,
closeNotification
)
}
>
<ContentCopyIcon color="action" />
</IconButton>
</Tooltip>
</Stack>
)
},
header: ({ table }) => <CopyStudentNumbersHeader getStudentNumber={row => row.studentNumber} table={table} />,
cell: cell => {
const studentNumber = cell.getValue()
if (studentNumber === 'Hidden') return studentNumber
@@ -1,6 +1,4 @@
import Box from '@mui/material/Box'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import { useTheme } from '@mui/material/styles'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
@@ -11,11 +9,10 @@ import { StudentInfoItem } from '@/components/common/StudentInfoItem'
import { StudentNameVisibilityToggle, useStudentNameVisibility } from '@/components/common/StudentNameVisibilityToggle'
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
import { OodiTable } from '@/components/OodiTable'
import { CopyStudentNumbersHeader } from '@/components/OodiTable/common/CopyStudentNumbersHeader'
import { OodiTableExcelExport } from '@/components/OodiTable/excelExport'
import { handleClipboardCopy } from '@/components/OodiTable/utils'
import type { FormattedModules, ModuleTabStudent } from '@/components/PopulationComponents/Students/Table/ModulesTab'
import { useStatusNotification } from '@/components/StatusNotification/Context'
import { CheckIcon, ContentCopyIcon, CropSquareIcon } from '@/theme'
import { CheckIcon, CropSquareIcon } from '@/theme'
const getModuleIfExists = (student: ModuleTabStudent, moduleCode: string) =>
student.studyModulesInHOPS.find(studyModule => studyModule.code === moduleCode) ?? null
@@ -32,35 +29,11 @@ export const ModulesTab = ({
const { getTextIn } = useLanguage()
const { visible: namesVisible } = useStudentNameVisibility()
const theme = useTheme()
const { setStatusNotification, closeNotification } = useStatusNotification()
const ooditableStaticColumns = useMemo(
() => [
ooditableColumnHelper.accessor('studentNumber', {
header: ({ table }) => {
const allStudentNumbers = table.getFilteredRowModel().rows.map(row => row.original.studentNumber)
const copyText = `Copied ${allStudentNumbers.length} student numbers`
return (
<Stack direction="row" spacing={1} sx={{ verticalAlign: 'middle' }}>
<Box sx={{ alignSelf: 'center' }}>Student number</Box>
<Tooltip title="Copy all student numbers to clipboard">
<IconButton
onClick={event =>
void handleClipboardCopy(
event,
allStudentNumbers,
copyText,
setStatusNotification,
closeNotification
)
}
>
<ContentCopyIcon color="action" />
</IconButton>
</Tooltip>
</Stack>
)
},
header: ({ table }) => <CopyStudentNumbersHeader getStudentNumber={row => row.studentNumber} table={table} />,
cell: cell => <StudentInfoItem sisPersonId={cell.row.original.sisPersonID} studentNumber={cell.getValue()} />,
filterFn: (row, columnId, filterValue) => {
const value: string = row.getValue(columnId)
@@ -13,6 +13,7 @@ import { StudentInfoItem } from '@/components/common/StudentInfoItem'
import { StudentNameVisibilityToggle, useStudentNameVisibility } from '@/components/common/StudentNameVisibilityToggle'
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
import { OodiTable } from '@/components/OodiTable'
import { CopyStudentNumbersHeader } from '@/components/OodiTable/common/CopyStudentNumbersHeader'
import { OodiTableExcelExport } from '@/components/OodiTable/excelExport'
import { TableInfo } from '@/components/PopulationComponents/Students/Table/ProgressTab/info'
import { DateFormat } from '@/constants/date'
@@ -541,7 +542,9 @@ export const ProgressTable = ({
header: 'Student',
columns: [
columnHelper.accessor('studentNumber', {
header: 'Student number',
header: ({ table }) => (
<CopyStudentNumbersHeader getStudentNumber={row => row.studentNumber} table={table} />
),
cell: ({ row }) => (
<StudentInfoItem sisPersonId={row.original.sis_person_id} studentNumber={row.original.studentNumber} />
),