Lesson.tsx (3518B)
1 import { useDisclosure } from '@mantine/hooks'; 2 import CommentIcon from '@mui/icons-material/CommentOutlined'; 3 import { Button } from '@mui/material'; 4 import { alpha, styled } from '@mui/material/styles'; 5 import { useAtomValue } from 'jotai'; 6 7 import useMySubject from 'client/hooks/useMySubject'; 8 9 import { gradeClassAtom } from '../../atoms'; 10 import useNote from '../../hooks/useNote'; 11 import useSpecialChange from '../../hooks/useSpecialChange'; 12 13 import BasisChip from './BasisChip'; 14 import DetailDialog from './DetailDialog'; 15 16 import type { Basis } from '../../types'; 17 import type { Course, DayPeriodJa, GradeClass, SchoolTime } from 'common/types'; 18 19 const ListItem = styled('li')(({ theme }) => ({ 20 marginBottom: theme.spacing(1), 21 '&:last-child': { marginBottom: 0 }, 22 })); 23 24 const PeriodSpan = styled('span')({ 25 display: 'inline-block', 26 width: '1em', 27 }); 28 const LessonSpan = styled('span')({ 29 display: 'inline-block', 30 whiteSpace: 'nowrap', 31 flexGrow: 1, 32 overflowX: 'hidden', 33 textOverflow: 'ellipsis', 34 }); 35 36 type LessonNameWithMySubjectProps = { 37 subjects: readonly string[]; 38 gradeClass: GradeClass; 39 dayPeriod: DayPeriodJa; 40 }; 41 42 function LessonNameWithMySubject({ 43 gradeClass, 44 dayPeriod, 45 subjects, 46 }: LessonNameWithMySubjectProps) { 47 const [mySubject] = useMySubject({ gradeClass, dayPeriod }); 48 return <>{mySubject ?? subjects.join('/')}</>; 49 } 50 51 type Props = { 52 date: Date; 53 period: SchoolTime; 54 courses: Course[]; 55 basis: Basis | null; 56 }; 57 58 // TODO: refactor 59 export default function Lesson({ date, period, courses, basis }: Props) { 60 const gradeClass = useAtomValue(gradeClassAtom); 61 const [open, handlers] = useDisclosure(false); 62 63 const shortNames = courses.map((c) => c.shortName); 64 65 const [specialChangeSubject] = useSpecialChange({ 66 gradeClass, 67 date, 68 period, 69 }); 70 const [note] = useNote({ gradeClass, date, period }); 71 72 return ( 73 <ListItem> 74 <Button 75 sx={(theme) => ({ 76 [theme.breakpoints.up('xs')]: { fontSize: 24, px: 1 }, 77 [theme.breakpoints.up('sm')]: { fontSize: 28, px: 2 }, 78 padding: 0, 79 textAlign: 'left', 80 fontWeight: 'unset', 81 color: 'unset', 82 [theme.getColorSchemeSelector('light')]: { 83 backgroundColor: courses.length 84 ? alpha(theme.palette.primary.light, 0.15) 85 : 'inherit', 86 }, 87 [theme.getColorSchemeSelector('dark')]: { 88 backgroundColor: courses.length 89 ? alpha(theme.palette.primary.dark, 0.4) 90 : 'inherit', 91 }, 92 width: '100%', 93 textTransform: 'none', 94 flexDirection: 'row', 95 alignItems: 'center', 96 gap: 1, 97 overflow: 'clip', 98 })} 99 variant='text' 100 onClick={handlers.open} 101 > 102 <PeriodSpan>{period}.</PeriodSpan> 103 <LessonSpan> 104 {(() => { 105 if (specialChangeSubject) { 106 return specialChangeSubject; 107 } else if (gradeClass && basis?.type === 'dayPeriod') { 108 return ( 109 <LessonNameWithMySubject 110 dayPeriod={basis.dayPeriod} 111 gradeClass={gradeClass} 112 subjects={shortNames} 113 /> 114 ); 115 } else { 116 return shortNames.join('/'); 117 } 118 })()} 119 </LessonSpan> 120 121 {note !== '' && <CommentIcon fontSize='small' />} 122 123 {specialChangeSubject ? ( 124 <BasisChip data={{ type: 'temporary' }} date={date} period={period} /> 125 ) : ( 126 basis && <BasisChip data={basis} date={date} period={period} /> 127 )} 128 </Button> 129 130 <DetailDialog 131 open={open} 132 handleClose={handlers.close} 133 date={date} 134 period={period} 135 courses={courses} 136 basis={basis} 137 /> 138 </ListItem> 139 ); 140 }