timetable-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 9927e6c6e7b90ad88523ac21ce5c455283ece926
parent 8c4d81ffc9b526156306079d980f35caa7be085a
Author: Yuukin256 <52195426+Yuukin256@users.noreply.github.com>
Date:   Sat,  1 Jun 2024 21:37:15 +0900

臨時変更情報を入力する機能を追加 (#67)

* useNote フックをdaily機能のhooksフォルタに移動

* 臨時変更を入力できる機能を実装

* 臨時変更登録機能の案内を追加
Diffstat:
Msrc/client/components/SlideFooter/index.tsx | 9++-------
Msrc/client/features/daily/components/Lessons/DetailDialog.tsx | 65+++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/client/features/daily/components/Lessons/Lesson.tsx | 40+++++++++++++++++++++++++++++-----------
Rsrc/client/hooks/useNote.ts -> src/client/features/daily/hooks/useNote.ts | 0
Asrc/client/features/daily/hooks/useSpecialChange.ts | 30++++++++++++++++++++++++++++++
Msrc/client/features/daily/types.ts | 2+-
Msrc/pages/how-to-use.tsx | 10++++++++--
7 files changed, 117 insertions(+), 39 deletions(-)

diff --git a/src/client/components/SlideFooter/index.tsx b/src/client/components/SlideFooter/index.tsx @@ -69,14 +69,9 @@ const prioritySlideData: SlideData[] = [ id: 13, content: ( <> - 新年度開始直後は時間割情報に誤りがある可能性がありますのでご注意ください。誤ったデータにお気づきの際は - <Link href={BUG_REPORT_FORM_URL} target='_blank' rel='noopener'> - 報告フォーム - </Link> - にお願いします。 + 臨時変更の情報を入力する機能を追加しました!登録した臨時変更情報は他の利用者に共有されません。ご要望ありがとうございました。 </> ), - severity: 'warning', }, ]; @@ -135,7 +130,7 @@ const extraSlideData: SlideData[] = [ id: 106, content: ( <> - 各時限の時間割をタップすると、授業場所などの詳細表示が出ます。メモ機能も詳細表示内に移動しました。 + 各時限の時間割をタップすると、授業場所、臨時変更入力機能、メモ機能などが表示されます。 </> ), }, diff --git a/src/client/features/daily/components/Lessons/DetailDialog.tsx b/src/client/features/daily/components/Lessons/DetailDialog.tsx @@ -31,6 +31,8 @@ type Props = { basis: Basis | null; note: string; setNote: (value: string) => void; + specialChangeSubject: string | null; + setSpecialChangeSubject: (value: string) => void; }; export default function DetailDialog({ @@ -42,6 +44,8 @@ export default function DetailDialog({ basis, note, setNote, + specialChangeSubject, + setSpecialChangeSubject, }: Props) { return ( <Dialog open={open} onClose={handleClose}> @@ -65,28 +69,53 @@ export default function DetailDialog({ <DialogContent> <Stack spacing={1}> - {basis?.type === 'dayPeriod' && ( + {basis?.type === 'dayPeriod' && !specialChangeSubject && ( <span>曜日時限: {basis.dayPeriod}</span> )} - <TableContainer component={Paper}> - <Table> - <TableHead> - <TableRow> - <TableCell>科目</TableCell> - <TableCell>場所</TableCell> - </TableRow> - </TableHead> - <TableBody> - {courses.map((course) => ( - <TableRow key={course.shortName}> - <TableCell>{course.name ?? course.shortName}</TableCell> - <TableCell>{course.room}</TableCell> + {!specialChangeSubject && ( + <TableContainer component={Paper}> + <Table> + <TableHead> + <TableRow> + <TableCell>科目</TableCell> + <TableCell>場所</TableCell> </TableRow> - ))} - </TableBody> - </Table> - </TableContainer> + </TableHead> + <TableBody> + {courses.map((course) => ( + <TableRow key={course.shortName}> + <TableCell>{course.name ?? course.shortName}</TableCell> + <TableCell>{course.room}</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </TableContainer> + )} + + <TextField + label='臨時変更' + placeholder='変更後の科目名を入力' + value={specialChangeSubject} + onChange={(e) => setSpecialChangeSubject(e.target.value)} + variant='standard' + fullWidth + multiline + InputProps={{ + endAdornment: ( + <InputAdornment position='end'> + <IconButton + aria-label='臨時変更をクリア' + onClick={() => setSpecialChangeSubject('')} + edge='end' + > + <ClearIcon /> + </IconButton> + </InputAdornment> + ), + }} + /> <TextField label='メモ' diff --git a/src/client/features/daily/components/Lessons/Lesson.tsx b/src/client/features/daily/components/Lessons/Lesson.tsx @@ -5,9 +5,10 @@ import { alpha, styled } from '@mui/material/styles'; import { useAtomValue } from 'jotai'; import useMySubject from 'client/hooks/useMySubject'; -import useNote from 'client/hooks/useNote'; import { gradeClassAtom } from '../../atoms'; +import useNote from '../../hooks/useNote'; +import useSpecialChange from '../../hooks/useSpecialChange'; import BasisChip from './BasisChip'; import DetailDialog from './DetailDialog'; @@ -60,6 +61,11 @@ export default function Lesson({ date, period, courses, basis }: Props) { const shortNames = courses.map((c) => c.shortName); + const [specialChangeSubject, setSpecialChangeSubject] = useSpecialChange({ + gradeClass, + date, + period, + }); const [note, setNote] = useNote({ gradeClass, date, period }); return ( @@ -88,20 +94,30 @@ export default function Lesson({ date, period, courses, basis }: Props) { > <PeriodSpan>{period}.</PeriodSpan> <LessonSpan> - {gradeClass && basis?.type === 'dayPeriod' ? ( - <LessonNameWithMySubject - dayPeriod={basis.dayPeriod} - gradeClass={gradeClass} - subjects={shortNames} - /> - ) : ( - shortNames.join('/') - )} + {(() => { + if (specialChangeSubject) { + return specialChangeSubject; + } else if (gradeClass && basis?.type === 'dayPeriod') { + return ( + <LessonNameWithMySubject + dayPeriod={basis.dayPeriod} + gradeClass={gradeClass} + subjects={shortNames} + /> + ); + } else { + return shortNames.join('/'); + } + })()} </LessonSpan> {note !== '' && <CommentIcon fontSize='small' />} - {basis && <BasisChip data={basis} date={date} period={period} />} + {specialChangeSubject ? ( + <BasisChip data={{ type: 'temporary' }} date={date} period={period} /> + ) : ( + basis && <BasisChip data={basis} date={date} period={period} /> + )} </Button> <DetailDialog @@ -113,6 +129,8 @@ export default function Lesson({ date, period, courses, basis }: Props) { basis={basis} note={note} setNote={setNote} + specialChangeSubject={specialChangeSubject} + setSpecialChangeSubject={setSpecialChangeSubject} /> </ListItem> ); diff --git a/src/client/hooks/useNote.ts b/src/client/features/daily/hooks/useNote.ts diff --git a/src/client/features/daily/hooks/useSpecialChange.ts b/src/client/features/daily/hooks/useSpecialChange.ts @@ -0,0 +1,30 @@ +import { useLocalStorage } from '@mantine/hooks'; + +import formatDate from 'common/utils/formatDate'; + +import type { GradeClass, SchoolTime } from 'common/types'; + +const getStorageKey = (gradeClass: string, date: Date, period: SchoolTime) => { + const dateString = formatDate(date); + return `specialChange_data_${gradeClass}_${dateString}_${period}`; +}; + +type Params = { + gradeClass: GradeClass | null; + date: Date; + period: SchoolTime; +}; + +type Return = [string | null, (value: string) => void]; + +const useSpecialChange = ({ gradeClass, date, period }: Params): Return => { + const [specialChangeSubject, setSpecialChangeSubject] = useLocalStorage< + string | undefined + >({ + key: getStorageKey(gradeClass ?? '', date, period), + getInitialValueInEffect: true, + }); + return [specialChangeSubject ?? null, setSpecialChangeSubject]; +}; + +export default useSpecialChange; diff --git a/src/client/features/daily/types.ts b/src/client/features/daily/types.ts @@ -2,7 +2,7 @@ import type { Course, DayPeriodJa, SchoolPeriod } from 'common/types'; export type Basis = | { type: 'dayPeriod'; dayPeriod: DayPeriodJa } - | { type: 'temporary'; id: number }; + | { type: 'temporary'; id?: number }; export type OnePeriod = { courses: Course[]; basis: Basis }; diff --git a/src/pages/how-to-use.tsx b/src/pages/how-to-use.tsx @@ -57,10 +57,10 @@ const HouToUsePage: NextPage = () => { /> </Box> <p> - 時間割ページでは上の画像のように、クラス別に1日ごとに時間割を表示しています。過去5日間と未来1ヶ月間の時間割を表示します。左右にフリックすることで前後の日付に移動できます。 + 時間割ページでは上の画像のように、クラス別に1日ごとの時間割を表示しています。過去5日間と未来1ヶ月間の時間割を表示します。左右にフリックすることで前後の日付に移動できます。 </p> <p> - 各時限をタップすると、その時間の詳細が開きます。詳細表示では授業場所を確認したり、メモ機能を利用したりできます。臨時変更がある際はメモ機能をお使いください。メモが入力されている場合は{' '} + 各時限をタップすると、その時間の詳細が開きます。詳細表示では授業場所を確認したり、臨時変更情報を登録したり、メモ機能を利用したりできます。臨時変更やメモはブラウザ内に保存され、他の利用者には共有されません。メモが入力されている場合は、科目名の横に{' '} <CommentIcon fontSize='inherit' style={{ verticalAlign: 'text-bottom' }} @@ -72,6 +72,12 @@ const HouToUsePage: NextPage = () => { <Chip component='span' label='金1' size='small' />{' '} のように表示しています。時間割変更がある場合は色が変わって{' '} <Chip component='span' label='金1' size='small' color='warning' />{' '} + <Chip + component='span' + label='臨時' + size='small' + color='warning' + />{' '} のように強調表示されます。 </p> </Box>