diff --git a/examples/nextjs-ssr/app/authenticated-app.tsx b/examples/nextjs-ssr/app/authenticated-app.tsx new file mode 100644 index 000000000..ed6a7f0cb --- /dev/null +++ b/examples/nextjs-ssr/app/authenticated-app.tsx @@ -0,0 +1,89 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +"use client"; + +import { multiFactor, sendEmailVerification, signOut } from "firebase/auth"; +import { useRouter } from "next/navigation"; +import { useUser } from "@/lib/firebase/hooks"; +import { auth } from "@/lib/firebase/clientApp"; +import { type User } from "firebase/auth"; + +export function AuthenticatedApp({ initialUser }: { initialUser: User | null }) { + const user = useUser(initialUser); + const router = useRouter(); + + if (!user) { + return null; + } + + const mfa = multiFactor(user); + + return ( +
+
+

Welcome, {user.displayName || user.email || user.phoneNumber}

+ {user.email ? ( + <> + {user.emailVerified ? ( +
Email verified
+ ) : ( + + )} + + ) : null} + +
+

Multi-factor Authentication

+ {mfa.enrolledFactors.map((factor) => { + return ( +
+ {factor.factorId} - {factor.displayName} +
+ ); + })} + +
+ +
+
+ ); +} diff --git a/examples/nextjs-ssr/app/globals.css b/examples/nextjs-ssr/app/globals.css index 7e62d3ba8..1fda7fe64 100644 --- a/examples/nextjs-ssr/app/globals.css +++ b/examples/nextjs-ssr/app/globals.css @@ -15,7 +15,25 @@ */ @import "tailwindcss"; +@custom-variant dark (&:where(.dark, .dark *)); @import "@invertase/firebaseui-styles/tailwind"; +/* Prevent flash by hiding content until theme is loaded */ +html:not(.theme-loaded) body { + visibility: hidden; +} + +html.theme-loaded body { + visibility: visible; +} + +.fui-provider__button[data-provider="oidc.line"][data-themed="true"] { + --line-primary: #07B53B; + --color-primary: var(--line-primary); + --color-primary-hover: --alpha(var(--line-primary) / 85%); + --color-primary-surface: #FFFFFF; + --color-border: var(--line-primary); +} + /* @import "@invertase/firebaseui-styles/themes/dark.css"; */ /* @import "@invertase/firebaseui-styles/themes/brutalist.css"; */ diff --git a/examples/nextjs-ssr/app/layout.tsx b/examples/nextjs-ssr/app/layout.tsx index bea3a80e7..425dab048 100644 --- a/examples/nextjs-ssr/app/layout.tsx +++ b/examples/nextjs-ssr/app/layout.tsx @@ -14,24 +14,13 @@ * limitations under the License. */ -import { getCurrentUser } from "@/lib/firebase/serverApp"; import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; - -import { Header } from "@/lib/components/header"; +import Script from "next/script"; import { FirebaseUIProviderHoc } from "@/lib/firebase/ui"; +import { ThemeToggle } from "@/lib/components/theme-toggle"; +import { PirateToggle } from "@/lib/components/pirate-toggle"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - export const metadata: Metadata = { title: "Create Next App (SSR)", description: "Generated by create next app with SSR", @@ -42,13 +31,36 @@ export default async function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const { currentUser } = await getCurrentUser(); - return ( - - -
- {children} + + +