ConnectedApps.tsx raw
1 import { CableIcon, TrashIcon } from "lucide-react";
2 import { useRef, useState } from "react";
3 import { CustomPagination } from "src/components/CustomPagination";
4 import EmptyState from "src/components/EmptyState";
5 import Loading from "src/components/Loading";
6 import ResponsiveLinkButton from "src/components/ResponsiveLinkButton";
7 import AlbyConnectionCard from "src/components/connections/AlbyConnectionCard";
8 import AppCard from "src/components/connections/AppCard";
9 import {
10 ALBY_ACCOUNT_APP_NAME,
11 LIST_APPS_LIMIT,
12 SUBWALLET_APPSTORE_APP_ID,
13 } from "src/constants";
14 import { useApps } from "src/hooks/useApps";
15 import { useInfo } from "src/hooks/useInfo";
16 import { useUnusedApps } from "src/hooks/useUnusedApps";
17 import { ListAppsResponse } from "src/types";
18
19 // display previous page while next page is loading
20 let prevAppsData: ListAppsResponse | undefined;
21
22 function ConnectedApps() {
23 const { data: info } = useInfo();
24 const [page, setPage] = useState(1);
25 const { data: appsData } = useApps(LIST_APPS_LIMIT, page, {
26 subWallets: false,
27 });
28 const appsListRef = useRef<HTMLDivElement>(null);
29 const handlePageChange = (page: number) => {
30 setPage(page);
31 appsListRef.current?.scrollIntoView({
32 behavior: "smooth",
33 block: "start",
34 });
35 };
36
37 const unusedApps = useUnusedApps();
38
39 if ((!prevAppsData && !appsData) || !unusedApps || !info) {
40 return <Loading />;
41 }
42 if (appsData) {
43 // eslint-disable-next-line react-hooks/globals
44 prevAppsData = appsData;
45 }
46 const { apps, totalCount } = appsData || prevAppsData!;
47
48 const otherApps = apps
49 .filter((app) => app.name !== ALBY_ACCOUNT_APP_NAME)
50 .filter(
51 (app) => app.metadata?.app_store_app_id !== SUBWALLET_APPSTORE_APP_ID
52 );
53
54 return (
55 <>
56 <div className="flex flex-col flex-1">
57 <div className="flex justify-between items-center">
58 <div className="flex-1">
59 <h1 className="text-xl lg:text-2xl font-semibold">
60 Connected Apps
61 </h1>
62 </div>
63 <div className="flex gap-3 h-full">
64 <>
65 {!!unusedApps.length && (
66 <ResponsiveLinkButton
67 to="/apps/cleanup"
68 icon={TrashIcon}
69 text="Cleanup Unused"
70 variant="outline"
71 />
72 )}
73 </>
74 </div>
75 </div>
76 </div>
77
78 {info.albyAccountConnected && (
79 <div className="mt-6">
80 <AlbyConnectionCard />
81 </div>
82 )}
83
84 <div className="mt-6" />
85
86 {!otherApps.length && (
87 <EmptyState
88 icon={CableIcon}
89 title="Connect Your First App"
90 description="Connect your app of choice, fine-tune permissions and enjoy a seamless and secure wallet experience."
91 variant="dashed"
92 buttonText="See Recommended Apps"
93 buttonLink="/apps?tab=app-store"
94 />
95 )}
96
97 {otherApps.length > 0 && (
98 <div
99 ref={appsListRef}
100 className="grid grid-cols-1 lg:grid-cols-2 gap-3 items-stretch"
101 >
102 {otherApps.map((app, index) => (
103 <AppCard key={index} app={app} />
104 ))}
105 </div>
106 )}
107
108 <CustomPagination
109 limit={LIST_APPS_LIMIT}
110 totalCount={totalCount}
111 page={page}
112 handlePageChange={handlePageChange}
113 />
114 </>
115 );
116 }
117
118 export default ConnectedApps;
119