Skip to content

Commit a991ea0

Browse files
🔁 refactor: improve DownloadButton data fetching with react-query
Refactored DownloadButton component to use react-query for data fetching, enhancing maintainability and readability. - Introduced react-query's useQuery hook to manage GitHub releases data fetching, resulting in cleaner and more efficient component state management. - Removed manual fetch calls and state management code, simplifying the component logic. - Added error handling and loading states with react-query, improving user experience by providing feedback during data loading and on errors.
1 parent 8bc008a commit a991ea0

2 files changed

Lines changed: 92 additions & 40 deletions

File tree

apps/web/app/(default)/download/DownloadButton.tsx

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { getOS } from "@/app/utils";
44
import { GithubStars } from "@/components/GithubStars";
55
import { useEffect, useState } from "react";
6+
import { useQuery } from "@tanstack/react-query";
67

78
// Define the interface for a GitHub release asset
89
interface ReleaseAsset {
@@ -37,36 +38,40 @@ function getDownloadUrl(os: string, releases: GitHubRelease[]): string | null {
3738
return null;
3839
}
3940

41+
const fetchReleases = async (): Promise<GitHubRelease[]> => {
42+
const response = await fetch(
43+
"https://api.github.com/repos/mangledbottles/screenlink-desktop/releases"
44+
);
45+
return response.json();
46+
};
47+
4048
export const DownloadButton = () => {
4149
const [os, setOs] = useState<string | null>(null);
42-
const [downloadUrl, setDownloadUrl] = useState<string | null>(null);
43-
const [githubRequestFinished, setGithubRequestFinished] = useState(false);
44-
const [releases, setReleases] = useState<GitHubRelease[]>([]);
4550

4651
useEffect(() => {
4752
const updatedOs = getOS();
4853
setOs(updatedOs);
49-
50-
// Fetch the latest releases from GitHub
51-
fetch(
52-
"https://api.github.com/repos/mangledbottles/screenlink-desktop/releases"
53-
)
54-
.then((response) => response.json())
55-
.then((releases: GitHubRelease[]) => {
56-
// Assuming the first release in the array is the latest
57-
const latestRelease = releases[0];
58-
const url = getDownloadUrl(updatedOs, releases);
59-
setReleases(releases);
60-
setDownloadUrl(url);
61-
setGithubRequestFinished(true);
62-
})
63-
.catch((error) => {
64-
console.error("Error fetching releases:", error);
65-
setGithubRequestFinished(true);
66-
});
6754
}, []);
6855

69-
if (githubRequestFinished && !downloadUrl) {
56+
const {
57+
data: releases,
58+
isLoading,
59+
isError,
60+
} = useQuery<GitHubRelease[], Error, GitHubRelease[]>({
61+
queryKey: ["releases"],
62+
queryFn: fetchReleases,
63+
staleTime: 5 * 60 * 1000, // 5 minutes
64+
});
65+
66+
const downloadUrl = releases ? getDownloadUrl(os ?? "", releases) : null;
67+
68+
if (isLoading) {
69+
return (
70+
<span className="animate-pulse inline-flex items-center rounded-md bg-blue-400/10 px-3 py-3 text-2xl font-medium text-blue-400 ring-1 ring-inset ring-blue-400/30 hover:bg-blue-400/20 dark:bg-blue-400/20 dark:text-blue-400 dark:ring-blue-400/20 w-44 h-16 cursor-pointer"></span>
71+
);
72+
}
73+
74+
if (isError || (releases && !downloadUrl)) {
7075
return (
7176
<div className="flex flex-col items-center justify-center h-full">
7277
<p className="max-w-[800px] mb-4 text-white text-center md:text-sm/relaxed lg:text-base/relaxed xl:text-xl/relaxed dark:text-white">
@@ -87,12 +92,7 @@ export const DownloadButton = () => {
8792
<span className="animate-pulse inline-flex items-center rounded-md bg-blue-400/10 px-3 py-3 text-2xl font-medium text-blue-400 ring-1 ring-inset ring-blue-400/30 hover:bg-blue-400/20 dark:bg-blue-400/20 dark:text-blue-400 dark:ring-blue-400/20 w-44 h-16 cursor-pointer"></span>
8893
);
8994

90-
if (!downloadUrl)
91-
return (
92-
<span className="animate-pulse inline-flex items-center rounded-md bg-blue-400/10 px-3 py-3 text-2xl font-medium text-blue-400 ring-1 ring-inset ring-blue-400/30 hover:bg-blue-400/20 dark:bg-blue-400/20 dark:text-blue-400 dark:ring-blue-400/20 w-44 h-16 cursor-pointer"></span>
93-
);
94-
95-
if (os === "macOS") return <MacDownloadButton releases={releases} />;
95+
if (os === "macOS") return <MacDownloadButton releases={releases ?? []} />;
9696

9797
return (
9898
<a

apps/web/yarn.lock

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@
2222
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz"
2323
integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==
2424

25-
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
25+
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
2626
version "7.23.6"
2727
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz"
2828
integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==
2929
dependencies:
3030
regenerator-runtime "^0.14.0"
3131

32+
"@babel/runtime@^7.23.7":
33+
version "7.24.0"
34+
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e"
35+
integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
36+
dependencies:
37+
regenerator-runtime "^0.14.0"
38+
3239
"@babel/types@^7.0.0", "@babel/types@^7.20.7":
3340
version "7.23.9"
3441
resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz"
@@ -45,6 +52,18 @@
4552
dependencies:
4653
tslib "^2.4.0"
4754

55+
"@emotion/is-prop-valid@^0.8.2":
56+
version "0.8.8"
57+
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
58+
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
59+
dependencies:
60+
"@emotion/memoize" "0.7.4"
61+
62+
"@emotion/memoize@0.7.4":
63+
version "0.7.4"
64+
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
65+
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
66+
4867
"@floating-ui/core@^1.4.2":
4968
version "1.5.2"
5069
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz"
@@ -1128,6 +1147,19 @@
11281147
dependencies:
11291148
tslib "^2.4.0"
11301149

1150+
"@tabler/icons-react@^2.47.0":
1151+
version "2.47.0"
1152+
resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-2.47.0.tgz#b704e7ae98f95be8bd6e938b4b2e84cd20b0cf31"
1153+
integrity sha512-iqly2FvCF/qUbgmvS8E40rVeYY7laltc5GUjRxQj59DuX0x/6CpKHTXt86YlI2whg4czvd/c8Ce8YR08uEku0g==
1154+
dependencies:
1155+
"@tabler/icons" "2.47.0"
1156+
prop-types "^15.7.2"
1157+
1158+
"@tabler/icons@2.47.0":
1159+
version "2.47.0"
1160+
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-2.47.0.tgz#c41c680d1947e3ab2d60af3febc4132287c60596"
1161+
integrity sha512-4w5evLh+7FUUiA1GucvGj2ReX2TvOjEr4ejXdwL/bsjoSkof6r1gQmzqI+VHrE2CpJpB3al7bCTulOkFa/RcyA==
1162+
11311163
"@tailwindcss/forms@^0.5.6":
11321164
version "0.5.7"
11331165
resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz"
@@ -1589,6 +1621,11 @@ clsx@2.0.0, clsx@^2.0.0:
15891621
resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz"
15901622
integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==
15911623

1624+
clsx@^2.1.0:
1625+
version "2.1.0"
1626+
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb"
1627+
integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==
1628+
15921629
cmdk@^0.2.0:
15931630
version "0.2.0"
15941631
resolved "https://registry.npmjs.org/cmdk/-/cmdk-0.2.0.tgz"
@@ -1890,9 +1927,9 @@ fastq@^1.6.0:
18901927
dependencies:
18911928
reusify "^1.0.4"
18921929

1893-
fflate@^0.4.1:
1930+
fflate@^0.4.8:
18941931
version "0.4.8"
1895-
resolved "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz"
1932+
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
18961933
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
18971934

18981935
file-system-cache@2.3.0:
@@ -1929,6 +1966,15 @@ fraction.js@^4.3.6:
19291966
resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz"
19301967
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
19311968

1969+
framer-motion@^11.0.8:
1970+
version "11.0.8"
1971+
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.0.8.tgz#8f97a18cbad5858d85b53bc325c40a03d0a5c203"
1972+
integrity sha512-1KSGNuqe1qZkS/SWQlDnqK2VCVzRVEoval379j0FiUBJAZoqgwyvqFkfvJbgW2IPFo4wX16K+M0k5jO23lCIjA==
1973+
dependencies:
1974+
tslib "^2.4.0"
1975+
optionalDependencies:
1976+
"@emotion/is-prop-valid" "^0.8.2"
1977+
19321978
fs-extra@11.1.1:
19331979
version "11.1.1"
19341980
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz"
@@ -2619,11 +2665,12 @@ postcss@^8.4.23:
26192665
source-map-js "^1.0.2"
26202666

26212667
posthog-js@^1.93.3:
2622-
version "1.96.1"
2623-
resolved "https://registry.npmjs.org/posthog-js/-/posthog-js-1.96.1.tgz"
2624-
integrity sha512-kv1vQqYMt2BV3YHS+wxsbGuP+tz+M3y1AzNhz8TfkpY1HT8W/ONT0i0eQpeRr9Y+d4x/fZ6M4cXG5GMvi9lRCA==
2668+
version "1.112.0"
2669+
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.112.0.tgz#691004e7ea839251fd14d31f5a1b54d257c452d5"
2670+
integrity sha512-GQ97lTjlVSTRcXtc9exmNS6PCx3DSmSRMjv4iwCs8+4z6ENx0mJKfiw0VQVsuthNByYXq+nW0Fao36YPl/USRg==
26252671
dependencies:
2626-
fflate "^0.4.1"
2672+
fflate "^0.4.8"
2673+
preact "^10.19.3"
26272674

26282675
posthog-node@^3.1.3:
26292676
version "3.2.0"
@@ -2640,6 +2687,11 @@ preact-render-to-string@^5.1.19:
26402687
dependencies:
26412688
pretty-format "^3.8.0"
26422689

2690+
preact@^10.19.3:
2691+
version "10.19.6"
2692+
resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.6.tgz#66007b67aad4d11899f583df1b0116d94a89b8f5"
2693+
integrity sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==
2694+
26432695
preact@^10.6.3:
26442696
version "10.19.3"
26452697
resolved "https://registry.npmjs.org/preact/-/preact-10.19.3.tgz"
@@ -3074,12 +3126,12 @@ tailwind-merge@^1.14.0:
30743126
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz"
30753127
integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==
30763128

3077-
tailwind-merge@^2.0.0:
3078-
version "2.1.0"
3079-
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.1.0.tgz"
3080-
integrity sha512-l11VvI4nSwW7MtLSLYT4ldidDEUwQAMWuSHk7l4zcXZDgnCRa0V3OdCwFfM7DCzakVXMNRwAeje9maFFXT71dQ==
3129+
tailwind-merge@^2.2.1:
3130+
version "2.2.1"
3131+
resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.2.1.tgz#3f10f296a2dba1d88769de8244fafd95c3324aeb"
3132+
integrity sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==
30813133
dependencies:
3082-
"@babel/runtime" "^7.23.5"
3134+
"@babel/runtime" "^7.23.7"
30833135

30843136
tailwindcss-animate@^1.0.7:
30853137
version "1.0.7"

0 commit comments

Comments
 (0)