- Install @tanstack/react-query with exponential backoff retry config - Create QueryClientProvider and custom hooks for listings, analytics, payments, and subscription API calls - Migrate 5 dashboard pages from useState/useEffect to React Query hooks - Add dark mode CSS variables and ThemeProvider with localStorage persistence - Add theme toggle button in dashboard header (sun/moon icon) - Enhance error boundaries with auto-retry, retry count, and loading state Co-Authored-By: Paperclip <noreply@paperclip.ing>
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
import type { Metadata, Viewport } from 'next';
|
|
import { AuthProvider } from '@/components/providers/auth-provider';
|
|
import { QueryProvider } from '@/components/providers/query-provider';
|
|
import { ThemeProvider } from '@/components/providers/theme-provider';
|
|
import './globals.css';
|
|
|
|
const siteUrl = process.env['NEXT_PUBLIC_SITE_URL'] || 'https://goodgo.vn';
|
|
|
|
export const viewport: Viewport = {
|
|
width: 'device-width',
|
|
initialScale: 1,
|
|
themeColor: '#15803d',
|
|
};
|
|
|
|
export const metadata: Metadata = {
|
|
metadataBase: new URL(siteUrl),
|
|
title: {
|
|
default: 'GoodGo \u2014 N\u1ec1n t\u1ea3ng B\u1ea5t \u0111\u1ed9ng s\u1ea3n Vi\u1ec7t Nam',
|
|
template: '%s | GoodGo',
|
|
},
|
|
description:
|
|
'GoodGo \u2014 n\u1ec1n t\u1ea3ng b\u1ea5t \u0111\u1ed9ng s\u1ea3n th\u00f4ng minh t\u1ea1i Vi\u1ec7t Nam. Mua b\u00e1n, cho thu\u00ea nh\u00e0 \u0111\u1ea5t d\u1ec5 d\u00e0ng v\u1edbi h\u01a1n 10,000+ tin \u0111\u0103ng tr\u00ean to\u00e0n qu\u1ed1c.',
|
|
keywords: [
|
|
'b\u1ea5t \u0111\u1ed9ng s\u1ea3n',
|
|
'mua b\u00e1n nh\u00e0 \u0111\u1ea5t',
|
|
'cho thu\u00ea nh\u00e0',
|
|
'goodgo',
|
|
'nh\u00e0 \u0111\u1ea5t vi\u1ec7t nam',
|
|
'chung c\u01b0',
|
|
'bi\u1ec7t th\u1ef1',
|
|
'nh\u00e0 ph\u1ed1',
|
|
'\u0111\u1ea5t n\u1ec1n',
|
|
],
|
|
authors: [{ name: 'GoodGo' }],
|
|
creator: 'GoodGo',
|
|
openGraph: {
|
|
type: 'website',
|
|
locale: 'vi_VN',
|
|
url: siteUrl,
|
|
siteName: 'GoodGo',
|
|
title: 'GoodGo \u2014 N\u1ec1n t\u1ea3ng B\u1ea5t \u0111\u1ed9ng s\u1ea3n Vi\u1ec7t Nam',
|
|
description:
|
|
'Mua b\u00e1n, cho thu\u00ea b\u1ea5t \u0111\u1ed9ng s\u1ea3n d\u1ec5 d\u00e0ng v\u1edbi GoodGo \u2014 n\u1ec1n t\u1ea3ng th\u00f4ng minh, uy t\u00edn h\u00e0ng \u0111\u1ea7u Vi\u1ec7t Nam.',
|
|
images: [
|
|
{
|
|
url: '/og-image.png',
|
|
width: 1200,
|
|
height: 630,
|
|
alt: 'GoodGo \u2014 N\u1ec1n t\u1ea3ng B\u1ea5t \u0111\u1ed9ng s\u1ea3n Vi\u1ec7t Nam',
|
|
},
|
|
],
|
|
},
|
|
twitter: {
|
|
card: 'summary_large_image',
|
|
title: 'GoodGo \u2014 N\u1ec1n t\u1ea3ng B\u1ea5t \u0111\u1ed9ng s\u1ea3n Vi\u1ec7t Nam',
|
|
description:
|
|
'Mua b\u00e1n, cho thu\u00ea b\u1ea5t \u0111\u1ed9ng s\u1ea3n d\u1ec5 d\u00e0ng v\u1edbi GoodGo.',
|
|
images: ['/og-image.png'],
|
|
},
|
|
robots: {
|
|
index: true,
|
|
follow: true,
|
|
googleBot: {
|
|
index: true,
|
|
follow: true,
|
|
'max-video-preview': -1,
|
|
'max-image-preview': 'large',
|
|
'max-snippet': -1,
|
|
},
|
|
},
|
|
};
|
|
|
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html lang="vi" suppressHydrationWarning>
|
|
<body>
|
|
<a
|
|
href="#main-content"
|
|
className="fixed left-2 top-2 z-[100] -translate-y-16 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-lg transition-transform focus:translate-y-0"
|
|
>
|
|
Chuyển đến nội dung chính
|
|
</a>
|
|
<ThemeProvider>
|
|
<QueryProvider>
|
|
<AuthProvider>{children}</AuthProvider>
|
|
</QueryProvider>
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|