From 3d1861d6d2455ee2f22c69a7dbe4a5e206285bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=82osz?= <12242002+mszekiel@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:02:28 +0200 Subject: [PATCH] feat: add useSession hook --- package-lock.json | 32 +++++++- packages/elements-react/package.json | 3 +- .../elements-react/src/hooks/useSession.ts | 74 +++++++++++++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 packages/elements-react/src/hooks/useSession.ts diff --git a/package-lock.json b/package-lock.json index b473555d..cdd16d02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34194,6 +34194,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zustand": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0.tgz", + "integrity": "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "packages/elements-react": { "name": "@ory/elements-react", "version": "1.0.0-next.10", @@ -34205,7 +34234,8 @@ "lodash.merge": "4.6.2", "react-hook-form": "7.53.0", "react-intl": "6.7.0", - "tailwind-merge": "2.5.2" + "tailwind-merge": "2.5.2", + "zustand": "5.0.0" }, "devDependencies": { "@hookform/devtools": "^4.3.1", diff --git a/packages/elements-react/package.json b/packages/elements-react/package.json index 7dac6e98..85b1f51d 100644 --- a/packages/elements-react/package.json +++ b/packages/elements-react/package.json @@ -34,7 +34,8 @@ "lodash.merge": "4.6.2", "react-hook-form": "7.53.0", "react-intl": "6.7.0", - "tailwind-merge": "2.5.2" + "tailwind-merge": "2.5.2", + "zustand": "5.0.0" }, "peerDependencies": { "react": "18.3.1", diff --git a/packages/elements-react/src/hooks/useSession.ts b/packages/elements-react/src/hooks/useSession.ts new file mode 100644 index 00000000..3cf4c571 --- /dev/null +++ b/packages/elements-react/src/hooks/useSession.ts @@ -0,0 +1,74 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { Session } from "@ory/client-fetch" +import { useCallback, useEffect } from "react" +import { create, useStore } from "zustand" +import { subscribeWithSelector } from "zustand/middleware" +import { useOryFlow } from "../context/flow-context" +import { frontendClient } from "../util/client" + +type SessionStore = { + setIsLoading: (loading: boolean) => void + setSession: (session: Session) => void + isLoading?: boolean + session?: Session + error: unknown + setError: (error: unknown) => void +} + +const sessionStore = create()( + subscribeWithSelector((set) => ({ + isLoading: false, + setIsLoading: (isLoading: boolean) => set({ isLoading }), + session: undefined, + setSession: (session: Session) => set({ session }), + error: undefined, + setError: (error: unknown) => set({ error }), + })), +) + +/** + * A hook to get the current session from the Ory Network. + * + * Usage: + * ```ts + * const { session, error, isLoading } = useSession() + * ``` + * + * @returns The current session, error and loading state. + */ +export const useSession = () => { + const { config } = useOryFlow() + const store = useStore(sessionStore) + + const fetchSession = useCallback(async () => { + const { session, isLoading, setSession, setIsLoading, setError } = + sessionStore.getState() + + if (!!session || isLoading) { + return + } + + setIsLoading(true) + + try { + const sessionData = await frontendClient(config.sdk.url).toSession() + setSession(sessionData) + } catch (e) { + setError(e instanceof Error ? e.message : "Unknown error occurred") + } finally { + setIsLoading(false) + } + }, [config.sdk.url]) + + useEffect(() => { + void fetchSession() + }, [fetchSession]) + + return { + session: store.session, + error: store.error, + isLoading: store.isLoading, + } +}