diff --git a/web/components/custom/auth-ui.tsx b/web/components/custom/auth-ui.tsx new file mode 100644 index 00000000..e2dd2686 --- /dev/null +++ b/web/components/custom/auth-ui.tsx @@ -0,0 +1,45 @@ +"use client" + +import { useState } from "react" +import { DemoAuth } from "jazz-react" +import { Input } from "../ui/input" +import { Button } from "../ui/button" + +export const AuthUI: DemoAuth.Component = ({ existingUsers, logInAs, signUp, appName, loading }) => { + const [username, setUsername] = useState("") + + if (loading) return
Loading...
+ + return ( +
+
+

{appName}

+
{ + e.preventDefault() + signUp(username) + }} + > + setUsername(e.target.value)} + autoComplete="webauthn" + /> + +
+ +
+ {existingUsers.map(user => ( + + ))} +
+
+
+ ) +} + +export default AuthUI diff --git a/web/components/custom/demo-auth.tsx b/web/components/custom/demo-auth.tsx deleted file mode 100644 index 1de84dd3..00000000 --- a/web/components/custom/demo-auth.tsx +++ /dev/null @@ -1,166 +0,0 @@ -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 -}