Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions app/(app)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import AppShell from "@/components/app-shell";
import AuthorizedApolloWrapper from "@/providers/use-apollo.rsc";
import ProtectedRoute from "@/providers/use-protected-route";
import { unstable_ViewTransition as ViewTransition } from "react";

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<AppShell>
<div className="mx-auto w-full max-w-7xl flex-1 p-3">
<ViewTransition name="app-content">
<div suppressHydrationWarning>
{children}
<ProtectedRoute>
<AuthorizedApolloWrapper>
<AppShell>
<div className="mx-auto w-full max-w-7xl flex-1 p-3">
<ViewTransition name="app-content">
<div suppressHydrationWarning>{children}</div>
</ViewTransition>
</div>
</ViewTransition>
</div>
</AppShell>
</AppShell>
</AuthorizedApolloWrapper>
</ProtectedRoute>
);
}
8 changes: 1 addition & 7 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { Metadata } from "next";
import "./globals.css";
import { Toaster } from "@/components/ui/sonner";
import { getAuthToken } from "@/lib/auth";
import { ApolloWrapper } from "@/providers/use-apollo";
import { ProgressProvider } from "@/providers/use-progress-provider";
import { PreloadResources } from "./preload-resources";

Expand All @@ -18,8 +16,6 @@ export default async function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
const token = await getAuthToken();

return (
<html lang="zh-hant-tw">
<head>
Expand All @@ -31,9 +27,7 @@ export default async function RootLayout({
/>
</head>
<body className={`font-sans antialiased`}>
<ApolloWrapper token={token}>
<ProgressProvider delay={500}>{children}</ProgressProvider>
</ApolloWrapper>
<ProgressProvider delay={500}>{children}</ProgressProvider>
<Toaster />
</body>
</html>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export default async function DoYouKnow() {
</div>
);
}

export { DoYouKnowSkeleton } from "./skeleton";
10 changes: 10 additions & 0 deletions app/login/_components/do-you-know/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Skeleton } from "@/components/ui/skeleton";

export function DoYouKnowSkeleton() {
return (
<div className="flex flex-col justify-center gap-2 text-center">
<div className="text-sm text-gray-500">你知道嗎?</div>
<Skeleton className="h-12 w-56 self-center" />
</div>
);
}
30 changes: 30 additions & 0 deletions app/login/_components/github-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";

export default function GithubLink() {
return (
<Tooltip>
<TooltipTrigger>
<a
className="flex items-center gap-2"
href="https://github.com/database-playground"
target="_blank"
>
<svg
className="h-3.5 w-3.5"
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
<span className="text-sm">GitHub</span>
</a>
</TooltipTrigger>

<TooltipContent>
向 GitHub 貢獻程式碼,每次都能直接獲得 200 - 700 點不等的點數!
</TooltipContent>
</Tooltip>
);
}
49 changes: 49 additions & 0 deletions app/login/_components/login-form/error-alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use client";

import { Alert, AlertDescription } from "@/components/ui/alert";
import { AlertCircle } from "lucide-react";
import { useSearchParams } from "next/navigation";

export function ErrorAlert() {
const searchParams = useSearchParams();
const error = searchParams.get("error");
const errorDescription = searchParams.get("error_description");

if (!error || !errorDescription) {
return null;
}

return (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
{getErrorMessage(error, errorDescription)}
</AlertDescription>
</Alert>
);
}

function getErrorMessage(error: string, description?: string | null): string {
if (description) return description;

switch (error) {
case "invalid_request":
return "登入請求無效,請重試。";
case "unauthorized":
return "您沒有權限存取此應用程式。";
case "access_denied":
return "登入已取消或拒絕。";
case "server_error":
return "伺服器發生錯誤,請稍後再試。";
case "temporarily_unavailable":
return "服務暫時無法使用,請稍後再試。";
case "auth_error":
return "認證過程中發生錯誤,請重新登入。";
case "logout_failed":
return "登出時發生錯誤,但您的本地工作階段已清除。";
case "forbidden":
return "您沒有權限存取此應用程式。";
default:
return "登入時發生未知錯誤,請重試。";
}
}
50 changes: 50 additions & 0 deletions app/login/_components/login-form/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { Suspense } from "react";
import { ErrorAlert } from "./error-alert";
import { MessageAlert } from "./message-alert";

export function LoginForm({
className,
...props
}: React.ComponentPropsWithoutRef<"div">) {
return (
<div className={cn("flex flex-col gap-6", className)} {...props}>
<Suspense>
<ErrorAlert />
<MessageAlert />
</Suspense>

<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">登入資料庫練功坊</CardTitle>
<CardDescription>
使用您的學校 Gmail 登入資料庫練功坊。
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-6">
<div className="flex flex-col gap-4">
<a href="/api/auth/login">
<Button variant="outline" className="w-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
className={`mr-2 h-4 w-4`}
>
<path
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
fill="currentColor"
/>
</svg>
使用 Google 登入
</Button>
</a>
</div>
</div>
</CardContent>
</Card>
</div>
);
}
32 changes: 32 additions & 0 deletions app/login/_components/login-form/message-alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";

import { Alert, AlertDescription } from "@/components/ui/alert";
import { AlertCircle } from "lucide-react";
import { useSearchParams } from "next/navigation";

export function MessageAlert() {
const searchParams = useSearchParams();
const message = searchParams.get("message");

if (!message) {
return null;
}

return (
<Alert variant="default">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
{getSuccessMessage(message)}
</AlertDescription>
</Alert>
);
}

function getSuccessMessage(message: string): string {
switch (message) {
case "logged_out":
return "您已成功登出。";
default:
return message;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export async function getUpstreamLatency(): Promise<number> {
try {
const start = Date.now();

const response = await fetch(buildUri("/"));
const response = await fetch(buildUri("/"), {
next: {
revalidate: 120, // update latency every 2 minutes
},
});
if (!response.ok) {
return -1;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { Circle } from "lucide-react";
import { getUpstreamLatency } from "./status.action";
import { getUpstreamLatency } from "./action";

export async function UpstreamStatus() {
const latency = await getUpstreamLatency();
Expand Down
107 changes: 0 additions & 107 deletions app/login/form.tsx

This file was deleted.

Loading