Skip to content

Commit e93b203

Browse files
authored
Merge pull request #23 from database-playground/pan93412/dbp-68-login-頁面需要按兩次-google-登入
DBP-68: login page needs to login to Google twice
2 parents 84c50c4 + 1b80809 commit e93b203

File tree

17 files changed

+229
-292
lines changed

17 files changed

+229
-292
lines changed

app/(admin)/layout.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { AppSidebar } from "@/components/app-sidebar";
22
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
3+
import AuthorizedApolloWrapper from "@/providers/use-apollo.rsc";
4+
import ProtectedRoute from "@/providers/use-protected-route";
35
import { unstable_ViewTransition as ViewTransition } from "react";
46

57
export default function AdminLayout({
@@ -8,20 +10,24 @@ export default function AdminLayout({
810
children: React.ReactNode;
911
}>) {
1012
return (
11-
<SidebarProvider
12-
style={{
13-
"--sidebar-width": "calc(var(--spacing) * 72)",
14-
"--header-height": "calc(var(--spacing) * 12)",
15-
} as React.CSSProperties}
16-
>
17-
<AppSidebar variant="inset" />
18-
<SidebarInset>
19-
<ViewTransition>
20-
<div suppressHydrationWarning>
21-
{children}
22-
</div>
23-
</ViewTransition>
24-
</SidebarInset>
25-
</SidebarProvider>
13+
<ProtectedRoute>
14+
<AuthorizedApolloWrapper>
15+
<SidebarProvider
16+
style={{
17+
"--sidebar-width": "calc(var(--spacing) * 72)",
18+
"--header-height": "calc(var(--spacing) * 12)",
19+
} as React.CSSProperties}
20+
>
21+
<AppSidebar variant="inset" />
22+
<SidebarInset>
23+
<ViewTransition>
24+
<div suppressHydrationWarning>
25+
{children}
26+
</div>
27+
</ViewTransition>
28+
</SidebarInset>
29+
</SidebarProvider>
30+
</AuthorizedApolloWrapper>
31+
</ProtectedRoute>
2632
);
2733
}

app/forbidden.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import ForbiddenLayout from "@/components/forbidden-layout/page";
2+
import type { Metadata } from "next";
3+
4+
export const metadata: Metadata = {
5+
title: "權限不足",
6+
};
7+
8+
export default function ForbiddenPage() {
9+
return <ForbiddenLayout />;
10+
}

app/layout.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import type { Metadata } from "next";
22
import { Geist, Geist_Mono } from "next/font/google";
33
import "./globals.css";
44
import { Toaster } from "@/components/ui/sonner";
5-
import { getAuthToken } from "@/lib/auth";
6-
import { ApolloWrapper } from "@/providers/use-apollo";
75
import { ProgressProvider } from "@/providers/use-progress-provider";
86
import { PreloadResources } from "./preload-resources";
97

@@ -18,7 +16,10 @@ const geistMono = Geist_Mono({
1816
});
1917

2018
export const metadata: Metadata = {
21-
title: { template: "%s | 管理介面 | 資料庫練功坊", default: "管理介面 | 資料庫練功坊" },
19+
title: {
20+
template: "%s | 管理介面 | 資料庫練功坊",
21+
default: "管理介面 | 資料庫練功坊",
22+
},
2223
description: "管理資料庫練功坊的題目、使用者、做題記錄等。",
2324
};
2425

@@ -29,8 +30,6 @@ export default async function RootLayout({
2930
}: Readonly<{
3031
children: React.ReactNode;
3132
}>) {
32-
const token = await getAuthToken();
33-
3433
return (
3534
<html lang="zh-hant-tw">
3635
<head>
@@ -48,9 +47,7 @@ export default async function RootLayout({
4847
font-sans antialiased
4948
`}
5049
>
51-
<ApolloWrapper token={token}>
52-
<ProgressProvider delay={500}>{children}</ProgressProvider>
53-
</ApolloWrapper>
50+
<ProgressProvider delay={500}>{children}</ProgressProvider>
5451
<Toaster />
5552
</body>
5653
</html>

app/login/page.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,13 @@
11
import { LoginForm } from "@/components/login-form";
22
import { Logo } from "@/components/logo";
3-
import { redirectIfAuthenticated } from "@/lib/auth.rsc";
43
import type { Metadata } from "next";
54
import Link from "next/link";
65

7-
interface LoginPageProps {
8-
searchParams: Promise<{
9-
error?: string;
10-
error_description?: string;
11-
message?: string;
12-
redirect?: string;
13-
}>;
14-
}
15-
166
export const metadata: Metadata = {
177
title: "登入",
188
};
199

20-
export default async function LoginPage({ searchParams }: LoginPageProps) {
21-
// Redirect if already authenticated
22-
await redirectIfAuthenticated();
23-
24-
const params = await searchParams;
25-
10+
export default function LoginPage() {
2611
return (
2712
<div
2813
className={`
@@ -46,11 +31,7 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
4631
</div>
4732
Database Playground
4833
</Link>
49-
<LoginForm
50-
error={params.error}
51-
errorDescription={params.error_description}
52-
message={params.message}
53-
/>
34+
<LoginForm />
5435
</div>
5536
</div>
5637
);

app/unauthorized.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { redirect } from "next/navigation";
2+
3+
export default async function UnauthorizedPage() {
4+
redirect("/login");
5+
}

components/app-sidebar.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ const buildNavbar = (
8484
title: "題庫管理",
8585
url: "/questions",
8686
icon: LibrarySquare,
87-
isActive: pathname.startsWith("/questions") || pathname.startsWith("/database"),
87+
isActive: pathname.startsWith("/questions")
88+
|| pathname.startsWith("/database"),
8889
items: [
8990
{
9091
title: "題庫",
@@ -167,7 +168,13 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
167168
</SidebarMenu>
168169
</SidebarHeader>
169170
<SidebarContent>
170-
{data.navMain.map((group) => <NavMain key={group.group} items={group.items} groupLabel={group.group} />)}
171+
{data.navMain.map((group) => (
172+
<NavMain
173+
key={group.group}
174+
items={group.items}
175+
groupLabel={group.group}
176+
/>
177+
))}
171178
<NavSecondary items={data.navSecondary} className="mt-auto" />
172179
</SidebarContent>
173180
<SidebarFooter>

app/forbidden/page.tsx renamed to components/forbidden-layout/page.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import { Logo } from "@/components/logo";
22
import { Button } from "@/components/ui/button";
33
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
4-
import { redirectIfAuthenticated } from "@/lib/auth.rsc";
4+
import AuthorizedApolloWrapper from "@/providers/use-apollo.rsc";
55
import { AlertTriangle } from "lucide-react";
66
import Link from "next/link";
7+
import { Suspense } from "react";
78
import { UserInfo } from "./user-info";
89

9-
import type { Metadata } from "next";
10-
export const metadata: Metadata = {
11-
title: "權限不足",
12-
};
13-
14-
export default async function ForbiddenPage() {
15-
await redirectIfAuthenticated();
16-
10+
export default async function ForbiddenLayout() {
1711
return (
1812
<div
1913
className={`
@@ -52,7 +46,11 @@ export default async function ForbiddenPage() {
5246
<CardFooter
5347
className={`justify-center text-center text-xs text-muted-foreground`}
5448
>
55-
<UserInfo />
49+
<Suspense>
50+
<AuthorizedApolloWrapper>
51+
<UserInfo />
52+
</AuthorizedApolloWrapper>
53+
</Suspense>
5654
</CardFooter>
5755
</Card>
5856
</div>
File renamed without changes.

components/login-form.tsx

Lines changed: 0 additions & 107 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"use client";
2+
3+
import { AlertCircle } from "lucide-react";
4+
import { useSearchParams } from "next/navigation";
5+
import { Alert, AlertDescription } from "../ui/alert";
6+
7+
export function ErrorAlert() {
8+
const searchParams = useSearchParams();
9+
const error = searchParams.get("error");
10+
const errorDescription = searchParams.get("error_description");
11+
12+
if (!error || !errorDescription) {
13+
return null;
14+
}
15+
16+
return (
17+
<Alert variant="destructive">
18+
<AlertCircle className="h-4 w-4" />
19+
<AlertDescription>
20+
{getErrorMessage(error, errorDescription)}
21+
</AlertDescription>
22+
</Alert>
23+
);
24+
}
25+
26+
function getErrorMessage(error: string, description?: string | null): string {
27+
if (description) return description;
28+
29+
switch (error) {
30+
case "invalid_request":
31+
return "登入請求無效,請重試。";
32+
case "unauthorized":
33+
return "您沒有權限存取此應用程式。";
34+
case "access_denied":
35+
return "登入已取消或拒絕。";
36+
case "server_error":
37+
return "伺服器發生錯誤,請稍後再試。";
38+
case "temporarily_unavailable":
39+
return "服務暫時無法使用,請稍後再試。";
40+
case "auth_error":
41+
return "認證過程中發生錯誤,請重新登入。";
42+
case "logout_failed":
43+
return "登出時發生錯誤,但您的本地工作階段已清除。";
44+
case "forbidden":
45+
return "您沒有權限存取此應用程式。";
46+
default:
47+
return "登入時發生未知錯誤,請重試。";
48+
}
49+
}

0 commit comments

Comments
 (0)