Add basic error handling

This commit is contained in:
adam-skowronek 2023-01-11 23:27:02 +01:00
parent 6be66634f3
commit 3be0d04f28
5 changed files with 166 additions and 46 deletions

View File

@ -1,4 +1,4 @@
import React from 'react' import React, { useState } from 'react'
import { QueryClient, QueryClientProvider } from 'react-query' import { QueryClient, QueryClientProvider } from 'react-query'
import { Navigate, Route, Routes } from 'react-router-dom' import { Navigate, Route, Routes } from 'react-router-dom'
import './App.css' import './App.css'
@ -28,6 +28,9 @@ import GradeCard from './views/GradeCard'
import Group from './views/coordinator/Group' import Group from './views/coordinator/Group'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import WorkloadStatistics from './views/coordinator/WorkloadStatistics' import WorkloadStatistics from './views/coordinator/WorkloadStatistics'
import { MainContext } from './context/MainContext'
import WithAxios from './context/WithAxios'
import BaseModal from './components/BaseModal'
require('dayjs/locale/pl') require('dayjs/locale/pl')
dayjs.locale('pl') dayjs.locale('pl')
@ -41,53 +44,60 @@ const queryClient = new QueryClient({
}) })
function App() { function App() {
const [isModalOpen, setIsModalOpen] = useState(false)
return ( return (
<div> <div>
<QueryClientProvider client={queryClient}> <MainContext.Provider value={{ isModalOpen, setIsModalOpen }}>
<Routes> <WithAxios>
<Route index element={<Login />} /> <QueryClientProvider client={queryClient}>
<Route path="coordinator" element={<Coordinator />}> <Routes>
<Route index element={<Home />} /> <Route index element={<Login />} />
<Route path="groups" element={<CoordinatorGroups />} /> <Route path="coordinator" element={<Coordinator />}>
<Route path="groups/:id" element={<Group />} /> <Route index element={<Home />} />
<Route path="students" element={<Students />} /> <Route path="groups" element={<CoordinatorGroups />} />
<Route path="leaders" element={<Leaders />} /> <Route path="groups/:id" element={<Group />} />
<Route path="add-student" element={<AddStudent />} /> <Route path="students" element={<Students />} />
<Route path="add-group" element={<AddGroup />} /> <Route path="leaders" element={<Leaders />} />
<Route path="add-leader" element={<AddLeader />} /> <Route path="add-student" element={<AddStudent />} />
<Route path="schedule" element={<Schedules />} /> <Route path="add-group" element={<AddGroup />} />
<Route path="schedule/:id" element={<Schedule />} /> <Route path="add-leader" element={<AddLeader />} />
<Route <Route path="schedule" element={<Schedules />} />
path="supervisors_availability" <Route path="schedule/:id" element={<Schedule />} />
element={<SupervisorAvailabilities />} <Route
/> path="supervisors_availability"
<Route path="groups/:id/grade-card" element={<GradeCard />} /> element={<SupervisorAvailabilities />}
<Route />
path="supervisors_availability/:id" <Route path="groups/:id/grade-card" element={<GradeCard />} />
element={<AvailabilitySchedule />} <Route
/> path="supervisors_availability/:id"
<Route element={<AvailabilitySchedule />}
path="schedule/:id/workload" />
element={<WorkloadStatistics />} <Route
/> path="schedule/:id/workload"
</Route> element={<WorkloadStatistics />}
<Route path="student" element={<Student />}> />
<Route index element={<Navigate to="enrollment" />} /> </Route>
<Route path="enrollment" element={<Enrollment />} /> <Route path="student" element={<Student />}>
<Route path="schedule" element={<StudentSchedules />} /> <Route index element={<Navigate to="enrollment" />} />
<Route path="schedule/:id" element={<StudentSchedule />} /> <Route path="enrollment" element={<Enrollment />} />
</Route> <Route path="schedule" element={<StudentSchedules />} />
<Route path="supervisor" element={<Supervisor />}> <Route path="schedule/:id" element={<StudentSchedule />} />
<Route index element={<Navigate to="groups" />} /> </Route>
<Route path="groups" element={<SupervisorGroups />} /> <Route path="supervisor" element={<Supervisor />}>
<Route path="groups/:id" element={<Group />} /> <Route index element={<Navigate to="groups" />} />
<Route path="groups/:id/grade-card" element={<GradeCard />} /> <Route path="groups" element={<SupervisorGroups />} />
<Route path="schedule" element={<SupervisorSchedules />} /> <Route path="groups/:id" element={<Group />} />
<Route path="schedule/:id" element={<SupervisorSchedule />} /> <Route path="groups/:id/grade-card" element={<GradeCard />} />
<Route path="add-group" element={<AddGroup />} /> <Route path="schedule" element={<SupervisorSchedules />} />
</Route> <Route path="schedule/:id" element={<SupervisorSchedule />} />
</Routes> <Route path="add-group" element={<AddGroup />} />
</QueryClientProvider> </Route>
</Routes>
</QueryClientProvider>
<BaseModal isOpen={isModalOpen} />
</WithAxios>
</MainContext.Provider>
</div> </div>
) )
} }

View File

@ -0,0 +1 @@
<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.13401-7 7s3.134 7 7 7 7-3.13401 7-7-3.134-7-7-7zm-1 2h2v4l-.5 3h-1l-.5-3zm1 8a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#ef2929"/></svg>

After

Width:  |  Height:  |  Size: 240 B

View File

@ -0,0 +1,72 @@
import { ReactElement, useContext } from 'react'
import Modal from 'react-modal'
import { MainContext } from '../context/MainContext'
import { ReactComponent as IconRemove } from '../assets/svg/icon-remove.svg'
import { ReactComponent as IconError } from '../assets/svg/icon-error.svg'
export interface ModalData {
title: string
message: string
icon?: ReactElement
}
export interface BaseModalProps {
isOpen: boolean
modalData?: ModalData | null
}
const customStyles = {
overlay: {
backgroundColor: 'rgba(125,125,125, 0.55)',
zIndex: 100,
},
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
padding: '15px',
width: '460px',
height: '250px',
borderRadius: '25px',
backgroundColor: '#f7f7f7',
},
}
const BaseModal = ({ isOpen, modalData }: BaseModalProps) => {
Modal.setAppElement('#root')
const { setIsModalOpen } = useContext(MainContext)
const { icon, message, title } = modalData ?? {}
return (
<>
<Modal
isOpen={isOpen}
style={customStyles}
contentLabel="Info modal"
onRequestClose={() => setIsModalOpen(false)}
>
<div className="flex flex-col p-2">
<button
className="self-end"
onClick={() => {
if (setIsModalOpen) setIsModalOpen(false)
}}
>
<IconRemove />
</button>
<div className="flex justify-center align-center items-center mt-8 flex-col">
<IconError style={{ transform: 'scale(2)' }} />
<h2 className="font-bold text-xl text-center mt-5">
Przepraszamy, wystąpił błąd. <br /> Spróbuj ponownie.
</h2>
</div>
</div>
</Modal>
</>
)
}
export default BaseModal

View File

@ -0,0 +1,8 @@
import React, { Dispatch, SetStateAction } from 'react'
type ContextProps = {
isModalOpen: boolean
setIsModalOpen: Dispatch<SetStateAction<boolean>>
}
export const MainContext = React.createContext<ContextProps>({} as ContextProps)

View File

@ -0,0 +1,29 @@
import { FunctionComponent, useContext, useMemo } from 'react'
import axiosInstance from '../api/axiosInstance'
import { MainContext } from './MainContext'
const WithAxios: FunctionComponent<{ children: React.ReactNode }> = ({
children,
}) => {
const { setIsModalOpen } = useContext(MainContext)
useMemo(() => {
axiosInstance.interceptors.request.use(async (request) => {
return request
})
axiosInstance.interceptors.response.use(
(response) => {
return response
},
(error) => {
setIsModalOpen(false)
if (error.response?.status) {
setIsModalOpen(true)
}
return Promise.reject(error)
},
)
}, [setIsModalOpen])
return <>{children}</>
}
export default WithAxios