import React, { useEffect, useMemo, useState } from "react" import { BrowserDemoAuth, AuthProvider } from "jazz-browser" import { Account, CoValueClass, ID } from "jazz-tools" import { AgentSecret } from "cojson" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" // Types export type AuthState = "loading" | "ready" | "signedIn" export type ReactAuthHook = (setJazzAuthState: (state: AuthState) => void) => { auth: AuthProvider AuthUI: React.ReactNode logOut?: () => void } type DemoAuthProps = { accountSchema?: CoValueClass & typeof Account appName: string appHostname?: string Component?: DemoAuth.Component seedAccounts?: { [name: string]: { accountID: ID; accountSecret: AgentSecret } } } type AuthComponentProps = { appName: string loading: boolean existingUsers: string[] logInAs: (existingUser: string) => void signUp: (username: string) => void } // Main DemoAuth function export function DemoAuth({ accountSchema = Account as CoValueClass & typeof Account, appName, appHostname, Component = DemoAuth.BasicUI, seedAccounts }: DemoAuthProps): ReactAuthHook { return function useLocalAuth(setJazzAuthState) { const [authState, setAuthState] = useState("loading") const [existingUsers, setExistingUsers] = useState([]) const [logInAs, setLogInAs] = useState<(existingUser: string) => void>(() => () => {}) const [signUp, setSignUp] = useState<(username: string) => void>(() => () => {}) const [logOut, setLogOut] = useState<(() => void) | undefined>(undefined) const [logOutCounter, setLogOutCounter] = useState(0) useEffect(() => { setJazzAuthState(authState) }, [authState, setJazzAuthState]) const auth = useMemo(() => { return new BrowserDemoAuth( accountSchema, { onReady(next) { setAuthState("ready") setExistingUsers(next.existingUsers) setLogInAs(() => next.logInAs) setSignUp(() => next.signUp) }, onSignedIn(next) { setAuthState("signedIn") setLogOut(() => () => { next.logOut() setAuthState("loading") setLogOutCounter(c => c + 1) }) } }, appName, seedAccounts ) }, []) const AuthUI = ( ) return { auth, AuthUI, logOut } } } const DemoAuthBasicUI: React.FC = ({ appName, existingUsers, logInAs, signUp }) => { const [username, setUsername] = useState("") const darkMode = useDarkMode() return (

{appName}

) } // Helper components const SignUpForm: React.FC<{ username: string setUsername: (value: string) => void signUp: (username: string) => void darkMode: boolean }> = ({ username, setUsername, signUp, darkMode }) => (
{ e.preventDefault() signUp(username) }} className="flex flex-col gap-y-4" > setUsername(e.target.value)} autoComplete="webauthn" />
) const ExistingUsersList: React.FC<{ existingUsers: string[] logInAs: (user: string) => void darkMode: boolean }> = ({ existingUsers, logInAs, darkMode }) => (
{existingUsers.map(user => ( ))}
) // Hooks const useDarkMode = () => { const [darkMode, setDarkMode] = useState(false) useEffect(() => { const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") setDarkMode(mediaQuery.matches) const handler = (e: MediaQueryListEvent) => setDarkMode(e.matches) mediaQuery.addEventListener("change", handler) return () => mediaQuery.removeEventListener("change", handler) }, []) return darkMode } // DemoAuth namespace export namespace DemoAuth { export type Component = React.FC export const BasicUI = DemoAuthBasicUI }