refactor: modularize ServerListClient with utility functions and components

This commit is contained in:
hamster1963 2025-02-06 00:26:20 +08:00
parent 1713189333
commit 07afc44eb7

View File

@ -20,6 +20,77 @@ const ServerGlobal = dynamic(() => import("./Global"), {
loading: () => <GlobalLoading />,
})
const sortServersByDisplayIndex = (servers: any[]) => {
return servers.sort((a, b) => {
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0)
return displayIndexDiff !== 0 ? displayIndexDiff : a.id - b.id
})
}
const filterServersByStatus = (servers: any[], status: string) => {
return status === "all"
? servers
: servers.filter((server) => [status].includes(server.online_status ? "online" : "offline"))
}
const filterServersByTag = (servers: any[], tag: string, defaultTag: string) => {
return tag === defaultTag ? servers : servers.filter((server) => server.tag === tag)
}
const sortServersByNetwork = (servers: any[]) => {
return [...servers].sort((a, b) => {
if (!a.online_status && b.online_status) return 1
if (a.online_status && !b.online_status) return -1
if (!a.online_status && !b.online_status) return 0
return b.status.NetInSpeed + b.status.NetOutSpeed - (a.status.NetInSpeed + a.status.NetOutSpeed)
})
}
const getTagCounts = (servers: any[]) => {
return servers.reduce((acc: Record<string, number>, server) => {
if (server.tag) {
acc[server.tag] = (acc[server.tag] || 0) + 1
}
return acc
}, {})
}
const LoadingState = ({ t }: { t: any }) => (
<div className="flex flex-col items-center min-h-96 justify-center ">
<div className="font-semibold flex items-center gap-2 text-sm">
<Loader visible={true} />
{t("connecting")}...
</div>
</div>
)
const ErrorState = ({ error, t }: { error: Error; t: any }) => (
<div className="flex flex-col items-center justify-center">
<p className="text-sm font-medium opacity-40">{error.message}</p>
<p className="text-sm font-medium opacity-40">{t("error_message")}</p>
</div>
)
const ServerList = ({ servers, inline, containerRef }: { servers: any[]; inline: string; containerRef: any }) => {
if (inline === "1") {
return (
<section ref={containerRef} className="flex flex-col gap-2 overflow-x-scroll scrollbar-hidden">
{servers.map((serverInfo) => (
<ServerCardInline key={serverInfo.id} serverInfo={serverInfo} />
))}
</section>
)
}
return (
<section ref={containerRef} className="grid grid-cols-1 gap-2 md:grid-cols-2">
{servers.map((serverInfo) => (
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
))}
</section>
)
}
export default function ServerListClient() {
const { status } = useStatus()
const { filter } = useFilter()
@ -36,12 +107,9 @@ export default function ServerListClient() {
if (inlineState !== null) {
setInline(inlineState)
}
}, [])
useEffect(() => {
const savedTag = sessionStorage.getItem("selectedTag") || defaultTag
setTag(savedTag)
restoreScrollPosition()
}, [])
@ -71,73 +139,30 @@ export default function ServerListClient() {
const { data, error } = useServerData()
if (error)
return (
<div className="flex flex-col items-center justify-center">
<p className="text-sm font-medium opacity-40">{error.message}</p>
<p className="text-sm font-medium opacity-40">{t("error_message")}</p>
</div>
)
if (!data?.result)
return (
<div className="flex flex-col items-center min-h-96 justify-center ">
<div className="font-semibold flex items-center gap-2 text-sm">
<Loader visible={true} />
{t("connecting")}...
</div>
</div>
)
if (error) return <ErrorState error={error} t={t} />
if (!data?.result) return <LoadingState t={t} />
const { result } = data
const sortedServers = result.sort((a, b) => {
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0)
if (displayIndexDiff !== 0) return displayIndexDiff
return a.id - b.id
})
const filteredServersByStatus =
status === "all"
? sortedServers
: sortedServers.filter((server) =>
[status].includes(server.online_status ? "online" : "offline"),
)
const sortedServers = sortServersByDisplayIndex(result)
const filteredServersByStatus = filterServersByStatus(sortedServers, status)
const allTag = filteredServersByStatus.map((server) => server.tag).filter(Boolean)
const uniqueTags = [...new Set(allTag)]
uniqueTags.unshift(defaultTag)
const filteredServers =
tag === defaultTag
? filteredServersByStatus
: filteredServersByStatus.filter((server) => server.tag === tag)
let filteredServers = filterServersByTag(filteredServersByStatus, tag, defaultTag)
if (filter) {
filteredServers.sort((a, b) => {
if (!a.online_status && b.online_status) return 1
if (a.online_status && !b.online_status) return -1
if (!a.online_status && !b.online_status) return 0
return (
b.status.NetInSpeed + b.status.NetOutSpeed - (a.status.NetInSpeed + a.status.NetOutSpeed)
)
})
filteredServers = sortServersByNetwork(filteredServers)
}
const tagCountMap: Record<string, number> = {}
for (const server of filteredServersByStatus) {
if (server.tag) {
tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1
}
}
const tagCountMap = getTagCounts(filteredServersByStatus)
return (
<>
<section className="flex items-center gap-2 w-full overflow-hidden">
<button
type="button"
onClick={() => {
setShowMap(!showMap)
}}
onClick={() => setShowMap(!showMap)}
className={cn(
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)]",
{
@ -150,11 +175,12 @@ export default function ServerListClient() {
<button
type="button"
onClick={() => {
setInline(inline === "0" ? "1" : "0")
localStorage.setItem("inline", inline === "0" ? "1" : "0")
const newInline = inline === "0" ? "1" : "0"
setInline(newInline)
localStorage.setItem("inline", newInline)
}}
className={cn(
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)] ",
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)]",
{
"shadow-[inset_0_1px_0_rgba(0,0,0,0.2)] bg-blue-500": inline === "1",
},
@ -172,24 +198,7 @@ export default function ServerListClient() {
)}
</section>
{showMap && <ServerGlobal />}
{inline === "1" && (
<section
ref={containerRef}
className="flex flex-col gap-2 overflow-x-scroll scrollbar-hidden"
>
{filteredServers.map((serverInfo) => (
<ServerCardInline key={serverInfo.id} serverInfo={serverInfo} />
))}
</section>
)}
{inline === "0" && (
<section ref={containerRef} className="grid grid-cols-1 gap-2 md:grid-cols-2">
{filteredServers.map((serverInfo) => (
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
))}
</section>
)}
<ServerList servers={filteredServers} inline={inline} containerRef={containerRef} />
</>
)
}