Skip to content

Commit c968166

Browse files
committed
refactor: refactor source code
1 parent 029700c commit c968166

File tree

13 files changed

+178
-68
lines changed

13 files changed

+178
-68
lines changed

app/[locale]/(public)/auth/layout.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import { locale } from "@/types/global";
2+
import { setRequestLocale } from "next-intl/server";
13
import { ReactNode } from "react";
24

3-
const Layout = async ({ children }: { children: ReactNode }) => {
5+
type LayoutType = { children: ReactNode; params: Promise<{ locale: locale }> };
6+
7+
const Layout = async ({ children, params }: LayoutType) => {
8+
const { locale } = await params;
9+
setRequestLocale(locale);
10+
411
return <>{children}</>;
512
};
613

app/[locale]/(public)/auth/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { getTranslations } from "next-intl/server";
1+
import { getTranslations, setRequestLocale } from "next-intl/server";
22
import { LoginClient } from "./client/LoginClient";
33
import { Metadata } from "next";
4+
import { locale } from "@/types/global";
5+
6+
type PageType = { params: Promise<{ locale: locale }> };
47

58
export async function generateMetadata(): Promise<Metadata> {
69
const t = await getTranslations("auth");
@@ -9,7 +12,10 @@ export async function generateMetadata(): Promise<Metadata> {
912
};
1013
}
1114

12-
export default async function Page() {
15+
export default async function Page({ params }: PageType) {
16+
const { locale } = await params;
17+
setRequestLocale(locale);
18+
1319
return (
1420
<section className='h-full flex justify-center items-center'>
1521
<LoginClient />

app/[locale]/layout.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import "@/app/globals.css";
22
import { notFound } from "next/navigation";
33
import { routing } from "@/i18n/routing";
4-
import { Header } from "@/components/custom/Header";
5-
import { Footer } from "@/components/custom/Footer";
64
import type { locale } from "@/types/global";
75
import { type ReactNode } from "react";
86
import { _LOCALES } from "@/constants/lang";
7+
import { setRequestLocale } from "next-intl/server";
8+
import { BaseLayout } from "@/components/custom/BaseLayout";
9+
import { PageLayout } from "@/components/custom/PageLayout";
910

1011
type LocaleLayoutType = { children: ReactNode; params: Promise<{ locale: locale }> };
1112

@@ -15,16 +16,15 @@ export async function generateStaticParams() {
1516

1617
export default async function LocaleLayout({ children, params }: LocaleLayoutType) {
1718
const { locale } = await params;
19+
setRequestLocale(locale);
1820

1921
if (!routing.locales.includes(locale)) {
2022
notFound();
2123
}
2224

2325
return (
24-
<>
25-
<Header />
26-
<main className='flex-1 container'>{children}</main>
27-
<Footer />
28-
</>
26+
<BaseLayout locale={locale}>
27+
<PageLayout>{children}</PageLayout>
28+
</BaseLayout>
2929
);
3030
}

app/[locale]/not-found.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Link from "next/link";
2+
import { Button } from "@/components/ui/button";
3+
import { AlertTriangleIcon, ArrowLeft } from "lucide-react";
4+
import { useTranslations } from "next-intl";
5+
import { BaseLayout } from "@/components/custom/BaseLayout";
6+
7+
export default function NotFound() {
8+
const t = useTranslations("defaultPage.notFound");
9+
10+
return (
11+
<BaseLayout locale='en'>
12+
<div className='flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
13+
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
14+
<p className='text-2xl md:text-3xl font-semibold text-gray-600 dark:text-gray-300 mb-6'>{t("title")}</p>
15+
<p className='text-lg md:text-xl text-gray-500 dark:text-gray-400 mb-8 max-w-md'>{t("description")}</p>
16+
<Link href='/' passHref>
17+
<Button variant='outline' size='lg' className='flex items-center gap-2'>
18+
<ArrowLeft className='w-4 h-4' />
19+
{t("redirect")}
20+
</Button>
21+
</Link>
22+
</div>
23+
</BaseLayout>
24+
);
25+
}

app/actions.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/error.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"use client";
2+
3+
import { BaseLayout } from "@/components/custom/BaseLayout";
4+
import { Button } from "@/components/ui/button";
5+
import { AlertTriangleIcon, HomeIcon, RefreshCwIcon } from "lucide-react";
6+
import { useTranslations } from "next-intl";
7+
import Link from "next/link";
8+
import { useEffect } from "react";
9+
10+
type ErrorType = { error: Error & { digest?: string }; reset: () => void };
11+
12+
export default function Error({ error, reset }: ErrorType) {
13+
const t = useTranslations("defaultPage.error");
14+
15+
useEffect(() => {
16+
console.error("[error.tsx:15] ", error.message);
17+
}, [error]);
18+
19+
return (
20+
<BaseLayout locale='en'>
21+
<div className='min-h-full flex items-center justify-center'>
22+
<div className='bg-white p-8 rounded-lg shadow-md max-w-md w-full text-center'>
23+
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
24+
<h1 className='text-2xl font-bold text-gray-800 mb-4'>{t("title")}</h1>
25+
<p className='text-gray-600 mb-6'>{t("description")}</p>
26+
<div className='bg-gray-100 p-4 rounded-md mb-6'>
27+
<p className='text-sm text-gray-600'>{t("reminder")}</p>
28+
</div>
29+
<div className='flex flex-col space-y-3'>
30+
<Button onClick={() => reset()} className='w-full'>
31+
<RefreshCwIcon className='mr-2 h-4 w-4' />
32+
{t("tryAgain")}
33+
</Button>
34+
<Link href='/' passHref>
35+
<Button variant='outline' className='w-full'>
36+
<HomeIcon className='mr-2 h-4 w-4' />
37+
{t("redirect")}
38+
</Button>
39+
</Link>
40+
</div>
41+
</div>
42+
</div>
43+
</BaseLayout>
44+
);
45+
}

app/layout.tsx

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,12 @@
1-
import { NextIntlClientProvider } from "next-intl";
2-
import { getLocale, getMessages, setRequestLocale } from "next-intl/server";
3-
import { Roboto } from "next/font/google";
4-
import { cn } from "@/lib/utils";
1+
import { ReactNode } from "react";
52
import "@/app/globals.css";
6-
import type { Metadata } from "next";
7-
import { ThemeProvider } from "@/components/theme-provider";
8-
import { type ReactNode } from "react";
9-
import { Toaster } from "@/components/ui/toaster";
10-
import { routing } from "@/i18n/routing";
11-
import { TooltipProvider } from "@/components/ui/tooltip";
123

13-
const roboto = Roboto({ subsets: ["latin"], weight: ["300", "400", "500", "700"], style: ["italic", "normal"] });
14-
15-
export const metadata: Metadata = {
16-
title: "Starter Kit by @leho-dev",
17-
description: "Generated by create next app"
4+
type Props = {
5+
children: ReactNode;
186
};
197

20-
export default async function LocaleLayout({ children }: { children: ReactNode }) {
21-
const locale = await getLocale();
22-
setRequestLocale(locale);
23-
24-
const messages = await getMessages();
25-
26-
return (
27-
<html lang={locale || routing.defaultLocale} suppressHydrationWarning>
28-
<body className={cn(roboto.className, "w-screen h-screen flex flex-col")}>
29-
<ThemeProvider attribute='class' defaultTheme='system' enableSystem disableTransitionOnChange>
30-
<TooltipProvider>
31-
<NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
32-
</TooltipProvider>
33-
<Toaster />
34-
</ThemeProvider>
35-
</body>
36-
</html>
37-
);
8+
// Since we have a `not-found.tsx` page on the root, a layout file
9+
// is required, even if it's just passing children through.
10+
export default function RootLayout({ children }: Props) {
11+
return children;
3812
}

app/not-found.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@ import Link from "next/link";
22
import { Button } from "@/components/ui/button";
33
import { AlertTriangleIcon, ArrowLeft } from "lucide-react";
44
import { useTranslations } from "next-intl";
5+
import { BaseLayout } from "@/components/custom/BaseLayout";
56

67
export default function NotFound() {
78
const t = useTranslations("defaultPage.notFound");
89

910
return (
10-
<div className='flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
11-
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
12-
<p className='text-2xl md:text-3xl font-semibold text-gray-600 dark:text-gray-300 mb-6'>{t("title")}</p>
13-
<p className='text-lg md:text-xl text-gray-500 dark:text-gray-400 mb-8 max-w-md'>{t("description")}</p>
14-
<Link href='/' passHref>
15-
<Button variant='outline' size='lg' className='flex items-center gap-2'>
16-
<ArrowLeft className='w-4 h-4' />
17-
{t("redirect")}
18-
</Button>
19-
</Link>
20-
</div>
11+
<BaseLayout locale='en'>
12+
<div className='flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
13+
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
14+
<p className='text-2xl md:text-3xl font-semibold text-gray-600 dark:text-gray-300 mb-6'>{t("title")}</p>
15+
<p className='text-lg md:text-xl text-gray-500 dark:text-gray-400 mb-8 max-w-md'>{t("description")}</p>
16+
<Link prefetch={true} href='/' passHref>
17+
<Button variant='outline' size='lg' className='flex items-center gap-2'>
18+
<ArrowLeft className='w-4 h-4' />
19+
{t("redirect")}
20+
</Button>
21+
</Link>
22+
</div>
23+
</BaseLayout>
2124
);
2225
}

components/custom/BaseLayout.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import "@/app/globals.css";
2+
import type { locale } from "@/types/global";
3+
import { type ReactNode } from "react";
4+
import { getMessages } from "next-intl/server";
5+
import { cn } from "@/lib/utils";
6+
import { Roboto } from "next/font/google";
7+
import { ThemeProvider } from "../theme-provider";
8+
import { TooltipProvider } from "../ui/tooltip";
9+
import { NextIntlClientProvider } from "next-intl";
10+
import { Toaster } from "../ui/toaster";
11+
12+
const roboto = Roboto({ subsets: ["latin"], weight: ["300", "400", "500", "700"], style: ["italic", "normal"] });
13+
14+
type BaseLayoutType = { children: ReactNode; locale: locale };
15+
16+
export async function BaseLayout({ children, locale }: BaseLayoutType) {
17+
const messages = await getMessages();
18+
19+
return (
20+
<html lang={locale} suppressHydrationWarning>
21+
<body className={cn(roboto.className, "w-screen h-screen flex flex-col")}>
22+
<ThemeProvider attribute='class' defaultTheme='system' enableSystem disableTransitionOnChange>
23+
<TooltipProvider>
24+
<NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
25+
</TooltipProvider>
26+
<Toaster />
27+
</ThemeProvider>
28+
</body>
29+
</html>
30+
);
31+
}

components/custom/LocaleSelect.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@
33
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
44
import { useTranslations, useLocale } from "next-intl";
55
import { usePathname, useRouter } from "@/i18n/routing";
6+
import { useTransition } from "react";
67

78
const LocaleSelect = () => {
89
const t = useTranslations("common.locale");
910

11+
const [isPending, startTransition] = useTransition();
1012
const locale = useLocale();
1113
const router = useRouter();
1214
const pathname = usePathname();
1315

1416
const handleChangeLocale = async (newLocale: string) => {
15-
// TODO: too much rerender
16-
router.push(pathname, { locale: newLocale });
17-
router.refresh();
17+
startTransition(() => {
18+
router.replace({ pathname }, { locale: newLocale });
19+
});
1820
};
1921

22+
if (isPending) {
23+
return null;
24+
}
25+
2026
return (
2127
<Select onValueChange={handleChangeLocale} defaultValue={locale}>
2228
<SelectTrigger className='w-[180px]'>

0 commit comments

Comments
 (0)