Skip to content

Commit ba95a62

Browse files
authored
refactor: use swr to fetch data (#117)
1 parent e8cb8f7 commit ba95a62

File tree

38 files changed

+1421
-1054
lines changed

38 files changed

+1421
-1054
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"react-router-dom": "6.9.0",
3131
"react-use": "17.4.0",
3232
"sonner": "^0.3.0",
33+
"swr": "^2.1.3",
3334
"valtio": "^1.10.3",
3435
"vditor": "^3.9.1"
3536
},

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,33 @@
11
import clsx from "clsx";
2-
import { useEffect, useState } from "react";
32
import { Sidebar } from "./components/widgets/Sidebar";
43
import { AppRouter } from "./router/router";
5-
import { apiClient } from "./utils/request";
6-
import { Loading } from "./components/universal/Loading";
7-
import { useNavigate } from "react-router-dom";
84
import { useSnapshot } from "valtio";
9-
import { app, server } from "./states/app";
10-
import { jump } from "@utils/path";
11-
import { toast, Toaster } from "sonner";
5+
import { app } from "./states/app";
6+
import useSWR from "swr";
7+
import { InternelServerErrorPage } from "@pages/InternelServerErrorPage";
8+
import { useAppCheck } from "@hooks/useAppCheck";
129

1310
function App() {
1411
const appSnapshot = useSnapshot(app);
15-
const [loading, setLoading] = useState(true);
16-
const navigate = useNavigate();
1712

18-
useEffect(() => {
19-
apiClient("/ping")
20-
.then(() => {})
21-
.catch(() => {
22-
if (window.location.pathname != jump("/status")) {
23-
toast.error("无法与后端通信,请检查服务状态");
24-
navigate(jump("/status"));
13+
const { error: gatewayError } = useSWR("/ping");
14+
15+
if (gatewayError) {
16+
return (
17+
<InternelServerErrorPage
18+
title={"Mog Gateway 错误"}
19+
description={
20+
"控制台似乎无法连接到 Mog 网关层,请检查 Mog 网关层的运行状态。"
2521
}
26-
return;
27-
})
28-
.then(() => {
29-
apiClient("/user/ping").then(() => {
30-
apiClient("/user/check")
31-
.then(() => {
32-
(window.location.pathname == jump("/") ||
33-
window.location.pathname == jump("/login") ||
34-
window.location.pathname == jump("/register")) &&
35-
navigate(jump("/dashboard"));
36-
app.authenticated = true;
37-
app.showSidebar = true;
38-
})
39-
.catch(() => {
40-
console.log(11)
41-
window.location.pathname != jump("/login") &&
42-
window.location.pathname != jump("/register") &&
43-
window.location.pathname != jump("/status") &&
44-
navigate(jump("/login"));
45-
});
46-
}).catch(() => {
47-
if (window.location.pathname != jump("/status")) {
48-
toast.error("无法与后端通信,请检查服务状态");
49-
navigate(jump("/status"));
50-
}
51-
return;
52-
})
53-
apiClient("/category").then((res) => {
54-
server.categories = res.data;
55-
});
56-
apiClient("/category?type=Tag").then((res) => {
57-
server.tags = res.data;
58-
});
59-
})
60-
.finally(() => {
61-
setTimeout(() => {
62-
setLoading(false);
63-
}, 1000);
64-
});
65-
}, []);
22+
/>
23+
);
24+
}
6625

26+
useAppCheck();
27+
6728
return (
6829
<>
69-
<Toaster />
70-
<Loading loading={loading} />
71-
<div className={clsx("app", "loading", !loading && "loaded")}>
30+
<div className={clsx("app")}>
7231
{appSnapshot.showSidebar && <Sidebar />}
7332
<div className="inner">
7433
<AppRouter />

src/components/universal/CheckBox/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const CheckBox = (props: CheckBoxProps) => {
5050
onChange={handleChange}
5151
{...rest}
5252
/>
53-
<span className={styles.check}></span>
53+
<span className={styles.check} />
5454
<span className={styles.name}>{item.name}</span>
5555
</label>
5656
))}

src/components/universal/Collapse/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Disclosure } from "@headlessui/react"
2-
import { PropsWithChildren } from "react"
2+
import type { PropsWithChildren } from "react"
33
import styles from "./index.module.css"
44

55
interface ICollapse {

src/components/universal/Radio/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const Radio = (props: RadioProps) => {
4646
onChange={handleChange}
4747
{...rest}
4848
/>
49-
<span className={styles.check}></span>
49+
<span className={styles.check} />
5050
<span className={styles.name}>{item.name}</span>
5151
</label>
5252
))}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
.button {
3+
background: var(--secondary-color);
4+
border: none;
5+
border-radius: 5px;
6+
padding: 10px 20px;
7+
font-size: 0.8rem;
8+
font-weight: 600;
9+
cursor: pointer;
10+
transition: background 0.2s ease;
11+
margin: 0 10px;
12+
margin-bottom: -10px;
13+
animation: fadeIn 0.5s ease;
14+
position: relative;
15+
}
16+
17+
.button[data-label]:after {
18+
content: attr(data-label);
19+
opacity: 0;
20+
position: absolute;
21+
top: 100%;
22+
margin-top: 5px;
23+
left: 50%;
24+
transform: translateX(-50%);
25+
background: var(--tertiary-color);
26+
color: var(--primary-color);
27+
padding: 5px 10px;
28+
border-radius: 5px;
29+
font-size: 0.8rem;
30+
font-weight: 600;
31+
white-space: nowrap;
32+
transition: opacity 0.2s ease;
33+
}
34+
35+
.button[data-label]:hover:after {
36+
opacity: 1;
37+
}
38+
39+
@keyframes fadeIn {
40+
0% {
41+
opacity: 0;
42+
}
43+
100% {
44+
opacity: 1;
45+
}
46+
}
47+
48+
.select, .button:hover {
49+
background: var(--primary-color);
50+
}
51+
52+
.select:hover {
53+
background-color: var(--background-color-primary);
54+
}
55+
56+
.confrim {
57+
background: red !important;
58+
color: #fff;
59+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { Clear, Delete, Edit } from "@icon-park/react"
2+
import clsx from "clsx"
3+
import styles from "./index.module.css"
4+
5+
interface ActionButtonsProps {
6+
selectedClassName: string
7+
setSelect: (value: React.SetStateAction<any>) => void
8+
selected: any[]
9+
editAction: (event: React.MouseEvent<HTMLButtonElement>) => void
10+
deleteFunction: (e) => void
11+
}
12+
13+
export const ActionButtons = (props: ActionButtonsProps) => {
14+
const { selectedClassName, setSelect, selected, editAction, deleteFunction } = props
15+
16+
const RemoveButton = () => {
17+
return (
18+
<ActionButton
19+
icon={<Clear />}
20+
label="取消选择"
21+
action={() => {
22+
setSelect([])
23+
const items = document.querySelectorAll(".item")
24+
items.forEach((item) => {
25+
item.classList.remove(selectedClassName)
26+
})
27+
}}
28+
/>
29+
)
30+
}
31+
32+
const DeleteButton = () => {
33+
return (
34+
<ActionButton
35+
icon={<Delete />}
36+
label="删除"
37+
action={(e) => {
38+
deleteFunction(e)
39+
setSelect([]);
40+
document
41+
.querySelectorAll(`.${selectedClassName}`)
42+
.forEach((item) => {
43+
item.remove();
44+
});
45+
}}
46+
className={styles.delete}
47+
doubleConfirm
48+
doubleConfirmLabel="确认删除?"
49+
/>
50+
)
51+
}
52+
53+
const EditButton = () => {
54+
return (
55+
<ActionButton
56+
icon={<Edit />}
57+
label="编辑"
58+
action={editAction}
59+
/>
60+
)
61+
}
62+
63+
return (
64+
<>
65+
{selected.length ? <RemoveButton /> : null}
66+
{selected.length ? <DeleteButton /> : null}
67+
{selected.length === 1 ? <EditButton /> : null}
68+
</>
69+
)
70+
}
71+
72+
interface ActionButtonProps {
73+
icon: React.ReactNode
74+
label: string
75+
action: (event: React.MouseEvent<HTMLButtonElement>) => void
76+
className?: string
77+
doubleConfirm?: boolean
78+
doubleConfirmLabel?: string
79+
}
80+
81+
export const ActionButton = (props: ActionButtonProps) => {
82+
const { icon, label, action, className, doubleConfirm, doubleConfirmLabel } = props
83+
84+
return (
85+
<button className={clsx(styles["button"], className)} onClick={(e) => {
86+
if (doubleConfirm) {
87+
if (
88+
e.currentTarget.classList.contains(styles.confrim)
89+
) {
90+
action(e)
91+
} else {
92+
e.currentTarget.classList.add(styles.confrim);
93+
if (doubleConfirmLabel) e.currentTarget.setAttribute("data-label", doubleConfirmLabel)
94+
}
95+
} else {
96+
action(e)
97+
}
98+
}} data-label={label}>
99+
{icon}
100+
</button>
101+
)
102+
}

src/components/widgets/Sidebar/index.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
MenuFoldOne,
1111
MenuUnfoldOne,
1212
OpenDoor,
13-
Page,
1413
Setting,
1514
Theme,
1615
} from "@icon-park/react";
@@ -29,6 +28,8 @@ import { useNavigate } from "react-router-dom";
2928
import { apiClient } from "@utils/request";
3029
import { removeCookie } from "@utils/cookie";
3130
import { jump } from "@utils/path";
31+
import { mutate } from "swr";
32+
import { toast } from "sonner";
3233

3334
const Links = () => {
3435
const authenticated = useSnapshot(app).authenticated;
@@ -49,12 +50,6 @@ const Links = () => {
4950
})}
5051
>
5152
<SidebarItem icon={HomeTwo({})} title="仪表盘" href={jump("/dashboard")} />
52-
<SidebarItem
53-
icon={Page({})}
54-
title="前往站点"
55-
href={"https://github.com"}
56-
outside
57-
/>
5853
<Space height={20} />
5954
<SidebarItem icon={Editor({})} title="文章" href={jump("/posts")} />
6055
<SidebarItem
@@ -92,6 +87,8 @@ const Links = () => {
9287
removeCookie("token")
9388
app.authenticated = false;
9489
navigate(jump("/login"))
90+
mutate("/user/check")
91+
toast("退出成功")
9592
}).catch((e) => {
9693
console.log(e)
9794
})

src/constants/services.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export const MOG_OFFICIAL_SERVICES = [
2+
{
3+
name: "核心网关层",
4+
url: "",
5+
},
6+
{
7+
name: "用户服务",
8+
url: "user",
9+
},
10+
{
11+
name: "文章服务",
12+
url: "post",
13+
},
14+
{
15+
name: "页面服务",
16+
url: "page",
17+
},
18+
{
19+
name: "分类服务",
20+
url: "category",
21+
},
22+
{
23+
name: "评论服务",
24+
url: "comments",
25+
},
26+
{
27+
name: "友链服务",
28+
url: "friends",
29+
},
30+
{
31+
name: "通知服务",
32+
url: "notification",
33+
},
34+
{
35+
name: "主题服务",
36+
url: "themes",
37+
}
38+
];

0 commit comments

Comments
 (0)