From 5b3d816a77d0e6e91504410e0e4b38ad005cfdb7 Mon Sep 17 00:00:00 2001 From: Mohammad Akash Date: Sun, 25 Oct 2026 11:31:09 +0600 Subject: [PATCH 1/4] feat: add login provider options --- app/connect/page.tsx | 345 ++++++++++++++++++++++++++++++++++++------- src/oidc.ts | 6 +- test/oidc.test.ts | 25 +++- 3 files changed, 322 insertions(+), 54 deletions(-) diff --git a/app/connect/page.tsx b/app/connect/page.tsx index 13aeaa9..89a4331 100644 --- a/app/connect/page.tsx +++ b/app/connect/page.tsx @@ -1,38 +1,50 @@ "use client"; -import { useEffect, useState, type FormEvent } from "react"; -import { api, DEMO_ACCOUNT_EMAIL, isDemoSession, oidcConfig, saveTokens, session, startDemoSession } from "@/src/api/client"; -import type { ClientConfig } from "@/src/api/types"; +import { type FormEvent, useCallback, useEffect, useState } from "react"; +import { + api, + DEMO_ACCOUNT_EMAIL, + isDemoSession, + oidcConfig, + saveTokens, + session, + startDemoSession, +} from "@/src/api/client"; import type { DevToken } from "@/src/api/generated"; +import type { ClientConfig } from "@/src/api/types"; import * as oidc from "@/src/oidc"; export default function ConnectPage() { const [config, setConfig] = useState(null); const [email, setEmail] = useState(""); + const [phoneNumber, setPhoneNumber] = useState(""); + const [phoneFormOpen, setPhoneFormOpen] = useState(false); const [error, setError] = useState(""); const [ready, setReady] = useState(false); - const destination = () => { + const destination = useCallback(() => { const requested = new URLSearchParams(window.location.search).get("returnTo"); return requested?.startsWith("/") && !requested.startsWith("//") ? requested : "/"; - }; + }, []); useEffect(() => { - void api("/v1/config").then(async (clientConfig) => { - session.config = clientConfig; - setConfig(clientConfig); - const oidcSettings = oidcConfig(); - if (oidcSettings) { - const tokens = await oidc.finish(oidcSettings); - if (tokens) saveTokens(tokens); - } - if (session.token || isDemoSession()) window.location.assign(destination()); - setReady(true); - }).catch(() => { - setError(`Couldn't reach the API. You can still preview the app with ${DEMO_ACCOUNT_EMAIL}.`); - setReady(true); - }); - }, []); + void api("/v1/config") + .then(async (clientConfig) => { + session.config = clientConfig; + setConfig(clientConfig); + const oidcSettings = oidcConfig(); + if (oidcSettings) { + const tokens = await oidc.finish(oidcSettings); + if (tokens) saveTokens(tokens); + } + if (session.token || isDemoSession()) window.location.assign(destination()); + setReady(true); + }) + .catch(() => { + setError(`Couldn't reach the API. You can still preview the app with ${DEMO_ACCOUNT_EMAIL}.`); + setReady(true); + }); + }, [destination]); const signInDev = async (event: FormEvent) => { event.preventDefault(); @@ -52,7 +64,7 @@ export default function ConnectPage() { body: JSON.stringify({ email: email.trim() }), }); if (!response.ok) throw new Error("Couldn't sign in. Check the email address."); - const token = await response.json() as DevToken; + const token = (await response.json()) as DevToken; saveTokens({ access_token: token.access_token, expires_in: 12 * 3600 }); window.location.assign(destination()); } catch (cause) { @@ -60,51 +72,280 @@ export default function ConnectPage() { } }; - const login = (prompt?: string) => { + const login = (prompt?: string, loginHint?: string) => { const settings = oidcConfig(); - if (settings) void oidc.login(settings, { prompt }).catch(() => setError("Couldn't reach the sign-in page. Try again.")); + if (settings) + void oidc + .login(settings, { prompt, loginHint }) + .catch(() => setError("Couldn't reach the sign-in page. Try again.")); + }; + + const loginWithProvider = (provider: "Google" | "Microsoft") => { + if (!oidcConfig()) { + setError(`${provider} sign-in will be available when an identity provider is configured.`); + return; + } + setError(""); + login(); + }; + + const signInWithPhone = (event: FormEvent) => { + event.preventDefault(); + if (!oidcConfig()) { + setError("Phone sign-in will be available when an identity provider is configured."); + return; + } + setError(""); + login(undefined, phoneNumber.trim()); }; return ( -
-