add tanstack/react-query
This commit is contained in:
Generated
+27
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
|
"@tanstack/react-query": "^5.90.11",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"jose": "^6.1.2",
|
"jose": "^6.1.2",
|
||||||
"next": "16.0.3",
|
"next": "16.0.3",
|
||||||
@@ -1884,6 +1885,32 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/query-core": {
|
||||||
|
"version": "5.90.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.11.tgz",
|
||||||
|
"integrity": "sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/react-query": {
|
||||||
|
"version": "5.90.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.11.tgz",
|
||||||
|
"integrity": "sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "5.90.11"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.1",
|
"version": "0.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||||
|
|||||||
+2
-1
@@ -5,11 +5,12 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 2999",
|
"dev": "next dev -p 2999",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start -p 2999",
|
||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
|
"@tanstack/react-query": "^5.90.11",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"jose": "^6.1.2",
|
"jose": "^6.1.2",
|
||||||
"next": "16.0.3",
|
"next": "16.0.3",
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import { SignupFormSchema, loginFormSchema } from '@/app/lib/definitions';
|
import { SignupFormSchema, loginFormSchema } from '@/app/lib/definitions';
|
||||||
import { createSession, deleteSession, getSessionToken } from '@/app/lib/session';
|
import { createSession, deleteSession, getSessionData } from '@/app/lib/session';
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
export async function logout() {
|
export async function logout() {
|
||||||
const token = await getSessionToken();
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fetch('http://localhost:8080/api/auth/logout', {
|
await fetch('http://localhost/api/auth/logout', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -39,7 +39,7 @@ export async function authorization(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { email, password } = validatedFields.data;
|
const { email, password } = validatedFields.data;
|
||||||
const response = await fetch('http://localhost:8080/api/auth/login', {
|
const response = await fetch('http://localhost/api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: email,
|
email: email,
|
||||||
@@ -52,7 +52,7 @@ export async function authorization(
|
|||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
await createSession(parsed.token);
|
await createSession(parsed.token, parsed.email);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Something went wrong. from server');
|
throw new Error('Something went wrong. from server');
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ export async function registration(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { full_name, email, password } = validatedFields.data;
|
const { full_name, email, password } = validatedFields.data;
|
||||||
const response = await fetch('http://localhost:8080/api/auth/register', {
|
const response = await fetch('http://localhost/api/auth/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ fullName: full_name, email, password }),
|
body: JSON.stringify({ fullName: full_name, email, password }),
|
||||||
headers: {
|
headers: {
|
||||||
@@ -107,7 +107,7 @@ export async function registration(
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
await createSession(parsed.token);
|
await createSession(parsed.token, email);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Something went wrong. from server');
|
throw new Error('Something went wrong. from server');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { createContext, useContext, ReactNode } from 'react'
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
family: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DataContextType {
|
|
||||||
dataContext: Data | null
|
|
||||||
isLoading: boolean
|
|
||||||
error: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataContext = createContext<DataContextType | undefined>(undefined)
|
|
||||||
|
|
||||||
export function DataProvider({
|
|
||||||
children,
|
|
||||||
dataContext
|
|
||||||
}: {
|
|
||||||
children: ReactNode
|
|
||||||
dataContext: any
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<DataContext.Provider value={{
|
|
||||||
dataContext,
|
|
||||||
isLoading: false,
|
|
||||||
error: null
|
|
||||||
}}>
|
|
||||||
{children}
|
|
||||||
</DataContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDataContext() {
|
|
||||||
const context = useContext(DataContext)
|
|
||||||
if (context === undefined) {
|
|
||||||
throw new Error('useDataContext must be used within a DataProvider')
|
|
||||||
}
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Providers from './providers/providers'
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import "./styles/globals.css";
|
import "./styles/globals.css";
|
||||||
import "./styles/global-styles.scss"
|
import "./styles/global-styles.scss"
|
||||||
@@ -15,7 +16,9 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<body className={``}>
|
<body className={``}>
|
||||||
|
<Providers>
|
||||||
{children}
|
{children}
|
||||||
|
</Providers>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
+13
-14
@@ -1,4 +1,5 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
import { getSessionData } from '@/app/lib/session';
|
||||||
|
|
||||||
const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/';
|
const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/';
|
||||||
const ALL = 'all'
|
const ALL = 'all'
|
||||||
@@ -25,26 +26,24 @@ export async function fetchFruit(id: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function testConnect() {
|
export async function getUserData() {
|
||||||
|
const userEmail = await getSessionData('email');
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('http://localhost:8080/api/auth/register', {
|
const response = await fetch(`http://localhost/api/user?email=${userEmail}`, {
|
||||||
method: 'POST',
|
method: 'GET',
|
||||||
body: JSON.stringify({
|
|
||||||
"fullName": "Vladislav Sergevich",
|
|
||||||
"email": "s2@e.ru",
|
|
||||||
"password": "1121231412"
|
|
||||||
}),
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json",
|
||||||
|
"Authorization": `Bearer ${token}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let parsed = await response.json();
|
if (response.ok) {
|
||||||
|
return await response.json();
|
||||||
return parsed;
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
console.error('error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,9 +25,13 @@ export async function decrypt(session: string | undefined = '') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createSession(token: string) {
|
export async function createSession(token: string, email: string) {
|
||||||
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
||||||
const session = await encrypt({ token, expiresAt });
|
const session = await encrypt({
|
||||||
|
token,
|
||||||
|
email,
|
||||||
|
expiresAt
|
||||||
|
});
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
|
|
||||||
cookieStore.set('session', session, {
|
cookieStore.set('session', session, {
|
||||||
@@ -39,7 +43,7 @@ export async function createSession(token: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSessionToken(): Promise<string | null> {
|
export async function getSessionData(type: 'token' | 'email'): Promise<string | null> {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const sessionCookie = cookieStore.get('session')?.value;
|
const sessionCookie = cookieStore.get('session')?.value;
|
||||||
|
|
||||||
@@ -49,15 +53,14 @@ export async function getSessionToken(): Promise<string | null> {
|
|||||||
|
|
||||||
const payload = await decrypt(sessionCookie);
|
const payload = await decrypt(sessionCookie);
|
||||||
|
|
||||||
if (payload && typeof payload === 'object' && 'token' in payload) {
|
if (payload && typeof payload === 'object' && type in payload) {
|
||||||
return payload.token as string;
|
return payload[type] as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function deleteSession() {
|
export async function deleteSession() {
|
||||||
const cookieStore = await cookies()
|
const cookieStore = await cookies()
|
||||||
cookieStore.delete('session')
|
cookieStore.delete('session')
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ export default function Home() {
|
|||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<div className={styles.intro}>
|
<div className={styles.intro}>
|
||||||
Home page11
|
Home page
|
||||||
</div>
|
</div>
|
||||||
<Link key={'dashboard'}
|
<Link key={'dashboard'}
|
||||||
href={'/pages/dashboard'}
|
href={'/pages/dashboard'}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
import Test from '@/app/ui/test';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'emptypage',
|
title: 'emptypage',
|
||||||
@@ -11,6 +12,9 @@ export default function Home() {
|
|||||||
<div>
|
<div>
|
||||||
emptypage
|
emptypage
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Test />
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
import NavLinks from '@/app/ui/nav-links'
|
import NavLinks from '@/app/ui/nav-links'
|
||||||
import styles from '@/app/page.module.scss'
|
import styles from '@/app/page.module.scss'
|
||||||
import HeaderPanel from '../ui/header/headerPanel';
|
import HeaderPanel from '../ui/header/headerPanel';
|
||||||
import { DataProvider } from '@/app/context/data-context';
|
import { getQueryClient } from '@/app/providers/getQueryClient';
|
||||||
import { fetchFruit } from '@/app/lib/action';
|
import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
|
||||||
import { getSessionToken } from '@/app/lib/session';
|
import { getUserData } from '@/app/lib/action';
|
||||||
|
|
||||||
export default async function Layout({ children }: { children: React.ReactNode }) {
|
export default async function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const queryClient = getQueryClient();
|
||||||
|
|
||||||
const fruitsData = await fetchFruit(100);
|
await Promise.all([
|
||||||
const token = await getSessionToken();
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ['userData'],
|
||||||
|
queryFn: () => getUserData()
|
||||||
|
})
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataProvider dataContext={fruitsData}>
|
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
|
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||||
<NavLinks />
|
<NavLinks />
|
||||||
<div className={`${styles.mainContainter}`}>
|
<div className={`${styles.mainContainter}`}>
|
||||||
<HeaderPanel />
|
<HeaderPanel />
|
||||||
@@ -20,7 +25,7 @@ export default async function Layout({ children }: { children: React.ReactNode }
|
|||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
</HydrationBoundary>
|
||||||
</div>
|
</div>
|
||||||
</DataProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { QueryClient } from '@tanstack/react-query'
|
||||||
|
import { cache } from 'react'
|
||||||
|
|
||||||
|
const getQueryClientDefaultConfig = () => ({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
retry: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export function makeQueryClient() {
|
||||||
|
return new QueryClient(getQueryClientDefaultConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getQueryClient = cache(() => {
|
||||||
|
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return new QueryClient(getQueryClientDefaultConfig())
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
if (!globalThis.__APP_QUERY_CLIENT__) {
|
||||||
|
// @ts-ignore
|
||||||
|
globalThis.__APP_QUERY_CLIENT__ = makeQueryClient()
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis.__APP_QUERY_CLIENT__
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {
|
||||||
|
isServer,
|
||||||
|
QueryClient,
|
||||||
|
QueryClientProvider,
|
||||||
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
|
export function makeQueryClient() {
|
||||||
|
return new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: 60 * 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let browserQueryClient: QueryClient | undefined = undefined
|
||||||
|
|
||||||
|
function getQueryClient() {
|
||||||
|
if (isServer) {
|
||||||
|
return makeQueryClient()
|
||||||
|
} else {
|
||||||
|
if (!browserQueryClient) browserQueryClient = makeQueryClient()
|
||||||
|
return browserQueryClient
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Providers({ children }: { children: React.ReactNode }) {
|
||||||
|
const queryClient = getQueryClient();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { testConnect } from '@/app/lib/action';
|
|
||||||
|
|
||||||
async function clickHandler() {
|
async function clickHandler() {
|
||||||
testConnect();
|
console.log('click')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ButtonTest() {
|
export default function ButtonTest() {
|
||||||
|
|||||||
@@ -3,12 +3,23 @@
|
|||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import { useClickOutside } from '@/app/hooks/useClickOutside';
|
import { useClickOutside } from '@/app/hooks/useClickOutside';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useDataContext } from '@/app/context/data-context';
|
import { getUserData } from '@/app/lib/action';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
export default function UserMenuButton() {
|
export default function UserMenuButton() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const menuRef = useRef<HTMLDivElement | null>(null);
|
const menuRef = useRef<HTMLDivElement | null>(null);
|
||||||
const { dataContext } = useDataContext()
|
const {
|
||||||
|
data: userData,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ['userData'],
|
||||||
|
queryFn: () => {
|
||||||
|
return getUserData();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
useClickOutside(menuRef, () => {
|
useClickOutside(menuRef, () => {
|
||||||
@@ -17,7 +28,6 @@ export default function UserMenuButton() {
|
|||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
console.log(dataContext);
|
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
} else {
|
} else {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
@@ -30,18 +40,29 @@ export default function UserMenuButton() {
|
|||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
ref={menuRef}
|
ref={menuRef}
|
||||||
>
|
>
|
||||||
<div className="user-avatar" id="user-menu-btn" title="Валерка">
|
<div
|
||||||
User
|
className="user-avatar"
|
||||||
|
id="user-menu-btn"
|
||||||
|
title={userData?.fullName ? userData.fullName : ''}
|
||||||
|
>
|
||||||
|
{userData?.fullName ? userData.fullName : ''}
|
||||||
</div>
|
</div>
|
||||||
<div className={`user-dropdown ${isOpen ? 'show' : ''}`} id="user-dropdown">
|
<div className={`user-dropdown ${isOpen ? 'show' : ''}`} id="user-dropdown">
|
||||||
<div className="user-info-header">
|
<div className="user-info-header">
|
||||||
<div className="user-avatar-large">User</div>
|
<div className="user-avatar-large">
|
||||||
|
{userData?.fullName ? userData.fullName : ''}
|
||||||
|
</div>
|
||||||
<div className="user-details">
|
<div className="user-details">
|
||||||
<div className="user-name">Валерка</div>
|
<div className="user-name">
|
||||||
<div className="user-email">va@no-copy.ru</div>
|
{userData?.fullName ? userData.fullName : ''}
|
||||||
|
</div>
|
||||||
|
<div className="user-email">
|
||||||
|
{userData?.email ? userData.email : ''}
|
||||||
|
</div>
|
||||||
<div className="user-subscription">
|
<div className="user-subscription">
|
||||||
<span className="subscription-badge">
|
<span className="subscription-badge">
|
||||||
СТАРТ</span>
|
{userData?.subscriptionType ? userData.subscriptionType : ''}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { getUserData } from '@/app/lib/action';
|
||||||
|
|
||||||
|
export default function HomePage() {
|
||||||
|
const {
|
||||||
|
data: userData,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ['userData'],
|
||||||
|
queryFn: () => {
|
||||||
|
return getUserData();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isLoading) return <div>Loading...</div>;
|
||||||
|
if (isError) return <div>Error: {error.message}</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>user email</h1>
|
||||||
|
<span>
|
||||||
|
{userData.email}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user