Skip to content

Commit 108e7e3

Browse files
authored
Implement navigate to 404 error page when accessing non-existent URL in workspaceSlug (#244)
* Add 404 NotFound Page * Add query error exception handling condition * Navigate to page 404 according to error conditions * Fix to Specify specific error code * Add error and loading conditions * Move to Global Logic of axios Error status * Remove Logic of Axios Error * Comment to change it to navigate * Move File hooks to utils * Fix: CustomNavigate * Revert "Fix: CustomNavigate" This reverts commit 3a48e1e. * Fix customNavigate to window.location.href * Remove customNavigate * Rebase: Code Conflict
1 parent 6b26087 commit 108e7e3

File tree

6 files changed

+95
-6
lines changed

6 files changed

+95
-6
lines changed

frontend/src/App.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import AuthProvider from "./providers/AuthProvider";
2222
import { useErrorHandler } from "./hooks/useErrorHandler";
2323
import * as Sentry from "@sentry/react";
2424
import { useGetSettingsQuery } from "./hooks/api/settings";
25+
import { isAxios404Error, isAxios500Error } from "./utils/axios.default";
2526

2627
if (import.meta.env.PROD) {
2728
Sentry.init({
@@ -76,7 +77,15 @@ function App() {
7677
const queryClient = useMemo(() => {
7778
return new QueryClient({
7879
queryCache: new QueryCache({
79-
onError: handleError,
80+
onError: (error) => {
81+
if (isAxios404Error(error)) {
82+
window.location.href = "/404";
83+
} else if (isAxios500Error(error)) {
84+
window.location.href = "/404";
85+
} else {
86+
handleError(error);
87+
}
88+
},
8089
}),
8190
defaultOptions: {
8291
mutations: {

frontend/src/pages/error/index.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Box, Typography, Button } from "@mui/material";
2+
import { useNavigate } from "react-router-dom";
3+
4+
const NotFound = () => {
5+
const navigate = useNavigate();
6+
7+
const handleGoHome = () => {
8+
navigate("/");
9+
};
10+
11+
return (
12+
<Box
13+
sx={{
14+
display: "flex",
15+
flexDirection: "column",
16+
justifyContent: "center",
17+
alignItems: "center",
18+
height: "100vh",
19+
width: "100vw",
20+
textAlign: "center",
21+
bgcolor: "background.default",
22+
color: "text.primary",
23+
p: 3,
24+
}}
25+
>
26+
<Typography variant="h1" component="h1" gutterBottom>
27+
404
28+
</Typography>
29+
<Typography variant="h5" component="p" gutterBottom>
30+
Page Not Found
31+
</Typography>
32+
<Typography variant="body1" component="p" gutterBottom>
33+
The page you are looking for does not exist.
34+
</Typography>
35+
<Button variant="contained" color="primary" onClick={handleGoHome} sx={{ mt: 2 }}>
36+
Go to Home
37+
</Button>
38+
</Box>
39+
);
40+
};
41+
42+
export default NotFound;

frontend/src/pages/workspace/Index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
useGetWorkspaceDocumentListQuery,
55
} from "../../hooks/api/workspaceDocument";
66
import { useGetWorkspaceQuery } from "../../hooks/api/workspace";
7-
import { Box, Button, CircularProgress, Grid, Stack, Typography } from "@mui/material";
7+
import { Backdrop, Box, Button, CircularProgress, Grid, Stack, Typography } from "@mui/material";
88
import DocumentCard from "../../components/cards/DocumentCard";
99
import { useMemo, useState } from "react";
1010
import { Document } from "../../hooks/api/types/document.d";
@@ -15,7 +15,8 @@ import AddIcon from "@mui/icons-material/Add";
1515
function WorkspaceIndex() {
1616
const params = useParams();
1717
const navigate = useNavigate();
18-
const { data: workspace } = useGetWorkspaceQuery(params.workspaceSlug);
18+
const { data: workspace, isLoading } = useGetWorkspaceQuery(params.workspaceSlug);
19+
1920
const {
2021
data: documentPageList,
2122
fetchNextPage,
@@ -31,6 +32,14 @@ function WorkspaceIndex() {
3132
);
3233
}, [documentPageList?.pages]);
3334

35+
if (isLoading) {
36+
return (
37+
<Backdrop open>
38+
<CircularProgress color="inherit" />
39+
</Backdrop>
40+
);
41+
}
42+
3443
const handleCreateDocumentModalOpen = () => {
3544
setCreateDocumentModalOpen((prev) => !prev);
3645
};

frontend/src/pages/workspace/document/Index.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect } from "react";
22
import { setClient, setDoc } from "../../../store/editorSlice";
33
import { useDispatch, useSelector } from "react-redux";
4-
import { Box } from "@mui/material";
4+
import { Backdrop, Box, CircularProgress } from "@mui/material";
55
import { useParams } from "react-router-dom";
66
import { selectUser } from "../../../store/userSlice";
77
import { useGetDocumentQuery } from "../../../hooks/api/workspaceDocument";
@@ -14,10 +14,16 @@ import { selectSetting } from "../../../store/settingSlice";
1414
function DocumentIndex() {
1515
const dispatch = useDispatch();
1616
const params = useParams();
17+
1718
const userStore = useSelector(selectUser);
1819
const settingStore = useSelector(selectSetting);
19-
const { data: workspace } = useGetWorkspaceQuery(params.workspaceSlug);
20-
const { data: document } = useGetDocumentQuery(workspace?.id, params.documentId);
20+
const { data: workspace, isLoading: isWorkspaceLoading } = useGetWorkspaceQuery(
21+
params.workspaceSlug
22+
);
23+
const { data: document, isLoading: isDocumentLoading } = useGetDocumentQuery(
24+
workspace?.id,
25+
params.documentId
26+
);
2127
const { doc, client } = useYorkieDocument(document?.yorkieDocumentId, userStore.data?.nickname);
2228

2329
useEffect(() => {
@@ -32,6 +38,14 @@ function DocumentIndex() {
3238
};
3339
}, [dispatch, client, doc]);
3440

41+
if (isDocumentLoading || isWorkspaceLoading) {
42+
return (
43+
<Backdrop open>
44+
<CircularProgress color="inherit" />
45+
</Backdrop>
46+
);
47+
}
48+
3549
return (
3650
<Box height="calc(100% - 64px)">
3751
<DocumentView />

frontend/src/routes.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import DocumentIndex from "./pages/workspace/document/Index";
1111
import DocumentShareIndex from "./pages/workspace/document/share/Index";
1212
import JoinIndex from "./pages/workspace/join/Index";
1313
import MemberIndex from "./pages/workspace/member/Index";
14+
import NotFound from "./pages/error";
1415
import ProfileIndex from "./pages/settings/profile/Index";
1516
import SettingLayout from "./components/layouts/SettingLayout";
1617

@@ -85,6 +86,11 @@ const codePairRoutes: Array<CodePairRoute> = [
8586
accessType: AccessType.PRIVATE,
8687
element: <JoinIndex />,
8788
},
89+
{
90+
path: "/404",
91+
accessType: AccessType.PUBLIC,
92+
element: <NotFound />,
93+
},
8894
{
8995
path: "settings/profile",
9096
accessType: AccessType.PRIVATE,

frontend/src/utils/axios.default.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { AxiosError } from "axios";
2+
3+
export const isAxios404Error = (error: unknown): boolean => {
4+
return error instanceof AxiosError && error.response?.status === 404;
5+
};
6+
7+
export const isAxios500Error = (error: unknown): boolean => {
8+
return error instanceof AxiosError && error.response?.status === 500;
9+
};

0 commit comments

Comments
 (0)