mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-12 15:13:49 -05:00
refactor: better data fetching (#100)
This commit is contained in:
@@ -4,11 +4,12 @@ import Statistic from "./components/Statistic";
|
|||||||
import Image from "./components/Image";
|
import Image from "./components/Image";
|
||||||
import { LastChecked } from "./components/LastChecked";
|
import { LastChecked } from "./components/LastChecked";
|
||||||
import Loading from "./components/Loading";
|
import Loading from "./components/Loading";
|
||||||
import { Data } from "./types";
|
|
||||||
import { theme } from "./theme";
|
import { theme } from "./theme";
|
||||||
import RefreshButton from "./components/RefreshButton";
|
import RefreshButton from "./components/RefreshButton";
|
||||||
import Search from "./components/Search";
|
import Search from "./components/Search";
|
||||||
import { Server } from "./components/Server";
|
import { Server } from "./components/Server";
|
||||||
|
import { useData } from "./hooks/use-data";
|
||||||
|
import DataLoadingError from "./components/DataLoadingError";
|
||||||
|
|
||||||
const SORT_ORDER = [
|
const SORT_ORDER = [
|
||||||
"monitored_images",
|
"monitored_images",
|
||||||
@@ -22,10 +23,11 @@ const SORT_ORDER = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [data, setData] = useState<Data | null>(null);
|
const { data, isLoading, isError } = useData();
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
if (!data) return <Loading onLoad={setData} />;
|
if (isLoading) return <Loading />;
|
||||||
|
if (isError || !data) return <DataLoadingError />;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex min-h-screen justify-center bg-white dark:bg-${theme}-950`}
|
className={`flex min-h-screen justify-center bg-white dark:bg-${theme}-950`}
|
||||||
|
|||||||
30
web/src/components/DataLoadingError.tsx
Normal file
30
web/src/components/DataLoadingError.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import Logo from "./Logo";
|
||||||
|
import { theme } from "../theme";
|
||||||
|
|
||||||
|
const DataLoadingError = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`flex min-h-screen justify-center bg-${theme}-50 dark:bg-${theme}-950`}
|
||||||
|
>
|
||||||
|
<div className="absolute mx-auto h-full w-full max-w-[80rem] overflow-hidden px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="mx-auto my-8 flex h-full max-w-[48rem] flex-col">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<h1 className="text-5xl font-bold lg:text-6xl dark:text-white">
|
||||||
|
Cup
|
||||||
|
</h1>
|
||||||
|
<Logo />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`flex h-full flex-col items-center justify-center gap-1 text-${theme}-500 dark:text-${theme}-400`}
|
||||||
|
>
|
||||||
|
<div className="mb-8 flex gap-1">
|
||||||
|
An error occurred, please try again.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DataLoadingError;
|
||||||
@@ -1,18 +1,8 @@
|
|||||||
import { Data } from "../types";
|
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { LoaderCircle } from "lucide-react";
|
import { LoaderCircle } from "lucide-react";
|
||||||
|
|
||||||
export default function Loading({ onLoad }: { onLoad: (data: Data) => void }) {
|
export default function Loading() {
|
||||||
fetch(
|
|
||||||
process.env.NODE_ENV === "production"
|
|
||||||
? "./api/v3/json"
|
|
||||||
: `http://${window.location.hostname}:8000/api/v3/json`,
|
|
||||||
).then((response) =>
|
|
||||||
response.json().then((data) => {
|
|
||||||
onLoad(data as Data);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex min-h-screen justify-center bg-${theme}-50 dark:bg-${theme}-950`}
|
className={`flex min-h-screen justify-center bg-${theme}-50 dark:bg-${theme}-950`}
|
||||||
|
|||||||
40
web/src/hooks/use-data.tsx
Normal file
40
web/src/hooks/use-data.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import type { Data } from "../types";
|
||||||
|
|
||||||
|
export const useData = () => {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isError, setIsError] = useState(false);
|
||||||
|
const [data, setData] = useState<Data | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoading || isError || !!data) return;
|
||||||
|
setIsLoading(true);
|
||||||
|
setIsError(false);
|
||||||
|
setData(null);
|
||||||
|
fetch(
|
||||||
|
process.env.NODE_ENV === "production"
|
||||||
|
? "./api/v3/json"
|
||||||
|
: `http://${window.location.hostname}:8000/api/v3/json`,
|
||||||
|
)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.ok) return response.json();
|
||||||
|
throw new Error("Failed to fetch data");
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setData(data as Data);
|
||||||
|
})
|
||||||
|
.catch((error: unknown) => {
|
||||||
|
setIsError(true);
|
||||||
|
console.error(error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}, [data, isError, isLoading]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user