timetable-app

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

commit 8cc5f679a14c03431f3ad105d7a37f96f2eb9060
parent b17b0efb37d9ed9de4ece0eb1d587998474b5c12
Author: Yuukin256 <Yuukin256@gmail.com>
Date:   Thu, 10 Nov 2022 00:10:08 +0900

データフェッチに時間がかかった場合のみ読み込み画面表示

Diffstat:
Asrc/hooks/useDebouncedValue.ts | 18++++++++++++++++++
Msrc/hooks/useRegisterDayTimetable.ts | 6+++++-
Msrc/pages/console/standard.tsx | 11++++++++---
Msrc/pages/console/timetable.tsx | 14+++++++++-----
Myarn.lock | 11+----------
5 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/src/hooks/useDebouncedValue.ts b/src/hooks/useDebouncedValue.ts @@ -0,0 +1,18 @@ +import { useState } from 'react'; +import { useDebounce } from 'react-use'; + +const useDebouncedValue = <T>(val: T, delay?: number) => { + const [debouncedValue, setDebouncedValue] = useState<T>(); + + useDebounce( + () => { + setDebouncedValue(val); + }, + delay ?? 2000, + [val] + ); + + return debouncedValue; +}; + +export default useDebouncedValue; diff --git a/src/hooks/useRegisterDayTimetable.ts b/src/hooks/useRegisterDayTimetable.ts @@ -69,13 +69,17 @@ const useRegisterDayTimetable = (): Result => { enqueueSnackbar('正常に保存されました', { variant: 'success', autoHideDuration: 2000 }); queryClient.invalidateQueries(apiClient.timetables._grade(grade)._date(date.toJSON()).$path()); }, - onError: () => enqueueSnackbar('エラーが発生しました', { variant: 'error', autoHideDuration: 6000 }), + onError: () => { + enqueueSnackbar('エラーが発生しました', { variant: 'error', autoHideDuration: 6000 }); + }, } ); const submit = () => { if (grade) { dayTimetableMutation.mutate({ grade, date, body: timetable }); + } else { + enqueueSnackbar('学年を選択してください', { variant: 'error', autoHideDuration: 6000 }); } }; diff --git a/src/pages/console/standard.tsx b/src/pages/console/standard.tsx @@ -7,6 +7,7 @@ import Breadcrumbs from '@mui/material/Breadcrumbs'; import CircularProgress from '@mui/material/CircularProgress'; import Container from '@mui/material/Container'; import FormControl from '@mui/material/FormControl'; +import FormHelperText from '@mui/material/FormHelperText'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Paper from '@mui/material/Paper'; @@ -21,6 +22,7 @@ import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import Link from 'components/common/Link'; +import useDebouncedValue from 'hooks/useDebouncedValue'; import useRegisterStandardTimetable from 'hooks/useRegisterStandardTimetable'; import type { NextPage } from 'next'; @@ -145,9 +147,11 @@ const Page: NextPage = () => { const { loading, sending, classes, classId, setClassId, standard, setStandard, submit } = useRegisterStandardTimetable(); + const debouncedLoading = useDebouncedValue(loading, 1000); + return ( <Container maxWidth='lg' component={Box} py={2}> - <Backdrop open={loading}> + <Backdrop open={loading && !!debouncedLoading}> <CircularProgress color='inherit' /> </Backdrop> @@ -163,8 +167,8 @@ const Page: NextPage = () => { </Typography> </Breadcrumbs> - <Box width='7rem' m={4}> - <FormControl fullWidth disabled={loading}> + <Box width='8rem' m={4}> + <FormControl fullWidth required disabled={loading} error={typeof classId === 'undefined'}> <InputLabel>クラス</InputLabel> <Select value={classId ?? ''} label='クラス' onChange={(e) => setClassId(e.target.value as number)}> {classes.map((c) => ( @@ -173,6 +177,7 @@ const Page: NextPage = () => { </MenuItem> ))} </Select> + {typeof classId === 'undefined' && <FormHelperText>選択してください</FormHelperText>} </FormControl> </Box> diff --git a/src/pages/console/timetable.tsx b/src/pages/console/timetable.tsx @@ -12,6 +12,7 @@ import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import Container from '@mui/material/Container'; import FormControl from '@mui/material/FormControl'; +import FormHelperText from '@mui/material/FormHelperText'; import IconButton from '@mui/material/IconButton'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; @@ -29,6 +30,7 @@ import { ABSTRACT_LESSON_NAME_MAP_EN_TO_JA, ABSTRACT_LESSON_NAME_MAP_JA_TO_EN, } from 'constant'; +import useDebouncedValue from 'hooks/useDebouncedValue'; import useRegisterDayTimetable from 'hooks/useRegisterDayTimetable'; import { dateToPlainDate, plainDateToDate } from 'utils'; @@ -72,11 +74,12 @@ const Page: NextPage = () => { submit, } = useRegisterDayTimetable(); + const debouncedLoading = useDebouncedValue(loading, 1000); + // TODO: Temporal をそのまま扱える Adapter を用意する? - // TODO: データフェッチに一定以上の時間がかかった場合のみ進捗表示を出す return ( <Container maxWidth='lg' component={Box} py={2}> - <Backdrop open={loading}> + <Backdrop open={loading && !!debouncedLoading}> <CircularProgress color='inherit' /> </Backdrop> @@ -93,8 +96,8 @@ const Page: NextPage = () => { </Breadcrumbs> <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 2, sm: 8 }} m={4}> - <Box width='7rem'> - <FormControl fullWidth required disabled={loading} size='small'> + <Box width='8rem'> + <FormControl fullWidth required disabled={loading} size='small' error={typeof grade === 'undefined'}> <InputLabel>学年</InputLabel> <Select value={grade ?? ''} label='学年' onChange={(e) => setGrade(e.target.value as number)}> {grades.map((g) => ( @@ -103,10 +106,11 @@ const Page: NextPage = () => { </MenuItem> ))} </Select> + {typeof grade === 'undefined' && <FormHelperText>選択してください</FormHelperText>} </FormControl> </Box> - <Stack direction='row' spacing={1}> + <Stack direction='row' spacing={1} alignItems='flex-start'> <IconButton onClick={() => setDate((old) => old.subtract({ days: 1 }))}> <ChevronLeftIcon /> </IconButton> diff --git a/yarn.lock b/yarn.lock @@ -96,16 +96,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2": - version: 7.20.0 - resolution: "@babel/runtime@npm:7.20.0" - dependencies: - regenerator-runtime: ^0.13.10 - checksum: 637fca51db34f3a59d329b7e0d01163769fe94915fdb04e4ac4ba62de9f1ca637ce3a564fe3b0166ccdd7f02f14b6a5707ee3e550b3e01c72327c6620d8e6a8b - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.19.0, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2": +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.19.0, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2": version: 7.20.1 resolution: "@babel/runtime@npm:7.20.1" dependencies: