Add QueryClientProvider for react-query support
Integrate react-query by adding `QueryClientProvider` to the application. This involves updating dependencies, wrapping existing providers with `QueryProvider`, and refactoring the `account-info` module to utilize new hooks and APIs.
This commit is contained in:
parent
a75a87f683
commit
ea7ab60e5c
@ -41,6 +41,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.0",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.4",
|
"@radix-ui/react-tooltip": "^1.1.4",
|
||||||
|
"@tanstack/react-query": "^5.60.2",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
|
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@ -95,6 +95,9 @@ importers:
|
|||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: ^1.1.4
|
specifier: ^1.1.4
|
||||||
version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@tanstack/react-query':
|
||||||
|
specifier: ^5.60.2
|
||||||
|
version: 5.60.2(react@18.3.1)
|
||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.20.5
|
specifier: ^8.20.5
|
||||||
version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -1246,6 +1249,14 @@ packages:
|
|||||||
'@swc/helpers@0.5.5':
|
'@swc/helpers@0.5.5':
|
||||||
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.59.20':
|
||||||
|
resolution: {integrity: sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.60.2':
|
||||||
|
resolution: {integrity: sha512-JhpJNxIAPuE0YCpP1Py4zAsgx+zY0V531McRMtQbwVlJF8+mlZwcOPrzGmPV248K8IP+mPbsfxXToVNMNwjUcw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18 || ^19
|
||||||
|
|
||||||
'@tanstack/react-table@8.20.5':
|
'@tanstack/react-table@8.20.5':
|
||||||
resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==}
|
resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -3850,6 +3861,13 @@ snapshots:
|
|||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
tslib: 2.6.3
|
tslib: 2.6.3
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.59.20': {}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.60.2(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/query-core': 5.59.20
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
'@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
'@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tanstack/table-core': 8.20.5
|
'@tanstack/table-core': 8.20.5
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -9,30 +10,55 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import type { IUserData, IUserWallet } from "@/interfaces/userdata.interface";
|
import type { IUserData, IUserWallet } from "@/interfaces/userdata.interface";
|
||||||
|
|
||||||
import { CopyButton } from "@/components/ui/copy-button";
|
import { CopyButton } from "@/components/ui/copy-button";
|
||||||
import {
|
import type {
|
||||||
type ICryptoInUserWalletInfo,
|
ICryptoInUserWalletInfo,
|
||||||
ICryptoInWalletInfo,
|
|
||||||
} from "@/interfaces/crypto.interface";
|
} from "@/interfaces/crypto.interface";
|
||||||
import { doDisconnect, getWallet } from "@/services/account.handler";
|
|
||||||
import { Bitcoin, Fingerprint, Key, Landmark, Unplug, User, Wallet } from "lucide-react";
|
import { Bitcoin, Fingerprint, Key, Landmark, Unplug, User, Wallet } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useCallback, useMemo } from "react";
|
||||||
|
import { EReturnState, type IStandardisedReturn } from "@/interfaces/general.interface";
|
||||||
|
import type { IApiUserAssetsRes } from "@/interfaces/api.interface";
|
||||||
|
import ApiRequest from "@/services/apiRequest";
|
||||||
|
|
||||||
export function AccountInfo({
|
export function doDisconnect() {
|
||||||
userData,
|
if (typeof window !== "undefined") {
|
||||||
setUserData,
|
window.localStorage.removeItem("sub");
|
||||||
isDisconnected,
|
//Redirect to homepage
|
||||||
}: {
|
window.location.href = "/";
|
||||||
userData: IUserData;
|
return true;
|
||||||
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>;
|
}
|
||||||
isDisconnected: boolean;
|
console.log("Whut ? Why trying to remove an item from the localStorage when running in SSR ?");
|
||||||
}) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getWallet(): Promise<IStandardisedReturn<IApiUserAssetsRes>> {
|
||||||
|
try {
|
||||||
|
const ReqRes =
|
||||||
|
await ApiRequest.authenticated.get.json<IStandardisedReturn<IApiUserAssetsRes>>(
|
||||||
|
"user/my-assets"
|
||||||
|
);
|
||||||
|
console.log(ReqRes.data);
|
||||||
|
|
||||||
|
if (ReqRes.status !== 200) {
|
||||||
|
return {
|
||||||
|
state: EReturnState.clientError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
state: EReturnState.done,
|
||||||
|
resolved: ReqRes.data,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
state: EReturnState.serverError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function useWallet(userData: IUserData, setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>) {
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -40,10 +66,8 @@ export function AccountInfo({
|
|||||||
getWallet().then((res) => {
|
getWallet().then((res) => {
|
||||||
const wallet: IUserWallet = {
|
const wallet: IUserWallet = {
|
||||||
uat: Date.now(),
|
uat: Date.now(),
|
||||||
update_interval: 30_000,
|
update_interval: 30000,
|
||||||
owned_cryptos:
|
owned_cryptos: res.resolved?.UserHasCrypto?.map((el): ICryptoInUserWalletInfo => ({
|
||||||
res.resolved?.UserHasCrypto?.map((el): ICryptoInUserWalletInfo => {
|
|
||||||
return {
|
|
||||||
id: el.Crypto.id,
|
id: el.Crypto.id,
|
||||||
name: el.Crypto.name,
|
name: el.Crypto.name,
|
||||||
value: el.Crypto.value,
|
value: el.Crypto.value,
|
||||||
@ -52,40 +76,70 @@ export function AccountInfo({
|
|||||||
owned_amount: el.amount,
|
owned_amount: el.amount,
|
||||||
created_at: el.Crypto.created_at,
|
created_at: el.Crypto.created_at,
|
||||||
updated_at: el.Crypto.updated_at,
|
updated_at: el.Crypto.updated_at,
|
||||||
};
|
})) || [],
|
||||||
}) || [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
delete res.resolved?.UserHasCrypto;
|
delete res.resolved?.UserHasCrypto;
|
||||||
//@ts-ignore
|
setUserData((prev) => ({
|
||||||
setUserData({
|
...prev,
|
||||||
...userData,
|
|
||||||
...res.resolved,
|
...res.resolved,
|
||||||
wallet: wallet,
|
wallet,
|
||||||
});
|
}) as unknown as IUserData);
|
||||||
console.log(userData);
|
console.log(userData);
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isLoaded, userData, setUserData]);
|
}, [isLoaded, userData, setUserData]);
|
||||||
|
|
||||||
|
return isLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AccountInfo({
|
||||||
|
userData,
|
||||||
|
setUserData,
|
||||||
|
isDisconnected,
|
||||||
|
}: {
|
||||||
|
userData: IUserData;
|
||||||
|
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>;
|
||||||
|
isDisconnected: boolean;
|
||||||
|
}) {
|
||||||
|
const isLoaded = useWallet(userData, setUserData);
|
||||||
|
|
||||||
|
const walletInfo = useMemo(() => (
|
||||||
|
<div className={"flex flex-col md:flex-row gap-2 justify-center md:justify-evenly items-start md:items-center w-full"}>
|
||||||
|
<div className={"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"}>
|
||||||
|
<Landmark />
|
||||||
|
<p className={"rounded bg-accent text-accent-foreground p-1"}>{userData.dollarAvailables} $</p>
|
||||||
|
</div>
|
||||||
|
<div className={"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"}>
|
||||||
|
<Bitcoin />
|
||||||
|
<p className={"rounded bg-accent text-accent-foreground p-1"}>{`You currently have ${userData.wallet.owned_cryptos.length} crypto(s)`}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
), [userData.dollarAvailables, userData.wallet.owned_cryptos.length]);
|
||||||
|
|
||||||
|
const userInfo = useMemo(() => (
|
||||||
|
<div className={"flex flex-col gap-3 justify-center items-start mx-auto mt-4"}>
|
||||||
|
<div className={"flex flex-row text-nowrap flex-nowrap gap-1 text-primary"}>
|
||||||
|
<Fingerprint />
|
||||||
|
<h2>Your identity</h2>
|
||||||
|
</div>
|
||||||
|
<div className={"font-light text-xs md:text-sm flex flex-row items-center justify-start gap-1 bg-accent p-2 rounded"}>
|
||||||
|
<p>{userData.id}</p>
|
||||||
|
<CopyButton value={userData.id} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
), [userData.id]);
|
||||||
|
|
||||||
if (isDisconnected) {
|
if (isDisconnected) {
|
||||||
return (
|
return (
|
||||||
<div className={"flex flex-col justify-center items-center h-10 p-2 text-xs mt-2"}>
|
<div className={"flex flex-col justify-center items-center h-10 p-2 text-xs mt-2"}>
|
||||||
<div
|
<div className={"flex flex-row justify-center items-center gap-1 text-destructive to-red-900 animate-pulse"}>
|
||||||
className={
|
|
||||||
"flex flex-row justify-center items-center gap-1 text-destructive to-red-900 animate-pulse"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Unplug className={"w-4"} />
|
<Unplug className={"w-4"} />
|
||||||
<p>Disconnected</p>
|
<p>Disconnected</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Link
|
<Link href={"/auth"} className={"hover:text-primary flex justify-evenly items-center gap-1 p-1 text-nowrap"}>
|
||||||
href={"/auth"}
|
|
||||||
className={
|
|
||||||
"hover:text-primary flex justify-evenly items-center gap-1 p-1 text-nowrap"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Key className={"w-3"} /> Link account
|
<Key className={"w-3"} /> Link account
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -107,50 +161,8 @@ export function AccountInfo({
|
|||||||
<DialogDescription>{userData.pseudo}</DialogDescription>
|
<DialogDescription>{userData.pseudo}</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className={"flex flex-col items-center justify-center w-full"}>
|
<div className={"flex flex-col items-center justify-center w-full"}>
|
||||||
<div className={"flex flex-col justify-evenly items-center gap-2"}>
|
{walletInfo}
|
||||||
<div
|
{userInfo}
|
||||||
className={
|
|
||||||
"flex flex-col md:flex-row gap-2 justify-center md:justify-evenly items-start md:items-center w-full"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Landmark />
|
|
||||||
<p className={"rounded bg-accent text-accent-foreground p-1"}>
|
|
||||||
{userData.dollarAvailables} $
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Bitcoin />
|
|
||||||
<p className={"rounded bg-accent text-accent-foreground p-1"}>
|
|
||||||
{`You currently have ${userData.wallet.owned_cryptos.length} crypto(s)`}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={"flex flex-col gap-3 justify-center items-start mx-auto mt-4"}
|
|
||||||
>
|
|
||||||
<div className={"flex flex-row text-nowrap flex-nowrap gap-1 text-primary"}>
|
|
||||||
<Fingerprint />
|
|
||||||
<h2>Your identity</h2>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"font-light text-xs md:text-sm flex flex-row items-center justify-start gap-1 bg-accent p-2 rounded"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<p>{userData.id}</p>
|
|
||||||
<CopyButton value={userData.id} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant={"secondary"} className={"gap-2 px-2"} asChild>
|
<Button variant={"secondary"} className={"gap-2 px-2"} asChild>
|
||||||
@ -159,11 +171,7 @@ export function AccountInfo({
|
|||||||
<p>My wallet</p>
|
<p>My wallet</p>
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button variant={"destructive"} className={"gap-2 px-2 mb-2"} onClick={() => doDisconnect()}>
|
||||||
variant={"destructive"}
|
|
||||||
className={"gap-2 px-2 mb-2"}
|
|
||||||
onClick={() => doDisconnect()}
|
|
||||||
>
|
|
||||||
<Unplug />
|
<Unplug />
|
||||||
<p>Disconnect</p>
|
<p>Disconnect</p>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -4,11 +4,16 @@ import { Header } from "@/components/header";
|
|||||||
import { ThemeProvider } from "@/components/providers/theme-provider";
|
import { ThemeProvider } from "@/components/providers/theme-provider";
|
||||||
import { UserDataProvider } from "@/components/providers/userdata-provider";
|
import { UserDataProvider } from "@/components/providers/userdata-provider";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
import {QueryProvider} from "@/components/providers/query-provider";
|
||||||
|
|
||||||
export function Providers({ children }: { children: React.ReactNode }) {
|
export function Providers({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||||
<UserDataProvider>{children}</UserDataProvider>
|
<QueryProvider>
|
||||||
|
<UserDataProvider>
|
||||||
|
{children}
|
||||||
|
</UserDataProvider>
|
||||||
|
</QueryProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
13
src/components/providers/query-provider.tsx
Normal file
13
src/components/providers/query-provider.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client"
|
||||||
|
import type {ReactNode} from "react";
|
||||||
|
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
||||||
|
|
||||||
|
|
||||||
|
interface QueryProviderProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
export function QueryProvider({ children }: QueryProviderProps) {
|
||||||
|
return (<QueryClientProvider client={new QueryClient()}>
|
||||||
|
{ children }
|
||||||
|
</QueryClientProvider>)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user