Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return a function from auth hooks to refresh the session/user #711

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 29 additions & 22 deletions packages/react/spec/auth/useSession.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ describe("useSession", () => {
}
}"
`);
expect(result.current.id).toEqual("123");
expect(result.current.user!.id).toEqual("321");
expect(result.current.user!.firstName).toEqual("Jane");
expect(result.current.user!.lastName).toEqual("Doe");
const [session] = result.current;
expect(session.id).toEqual("123");
expect(session.user!.id).toEqual("321");
expect(session.user!.firstName).toEqual("Jane");
expect(session.user!.lastName).toEqual("Doe");
});

test("it returns the current session when the user is logged in and api client is passed", async () => {
Expand Down Expand Up @@ -110,10 +111,11 @@ describe("useSession", () => {
}
}"
`);
expect(result.current.id).toEqual("123");
expect(result.current.user!.id).toEqual("321");
expect(result.current.user!.firstName).toEqual("Jane");
expect(result.current.user!.lastName).toEqual("Doe");
const [session] = result.current;
expect(session.id).toEqual("123");
expect(session.user!.id).toEqual("321");
expect(session.user!.firstName).toEqual("Jane");
expect(session.user!.lastName).toEqual("Doe");
});

test("it returns the current session when the user is logged in and api client with options is passed", async () => {
Expand All @@ -140,9 +142,10 @@ describe("useSession", () => {
}
}"
`);
expect(result.current.id).toEqual("123");
expect(result.current.user?.id).toEqual("321");
expect(result.current.user?.firstName).toEqual("Jane");
const [session] = result.current;
expect(session.id).toEqual("123");
expect(session.user?.id).toEqual("321");
expect(session.user?.firstName).toEqual("Jane");

const { result: noUserResult, rerender: _noUserRerender } = renderHook(
() => useSession(fullAuthApi, { filter: { user: { firstName: { equals: "Bob" } } } }),
Expand All @@ -158,9 +161,10 @@ describe("useSession", () => {
expectMockSignedOutUser();
rerender();

expect(result.current).toBeDefined();
expect(result.current.id).toEqual("123");
expect(result.current.user).toBe(null);
const [session] = result.current;
expect(session).toBeDefined();
expect(session.id).toEqual("123");
expect(session.user).toBe(null);
});

test("it returns the current session when the user is logged out and no options are passed", async () => {
Expand All @@ -169,9 +173,10 @@ describe("useSession", () => {
expectMockSignedOutUser();
rerender();

expect(result.current).toBeDefined();
expect(result.current.id).toEqual("123");
expect(result.current.user).toBe(null);
const [session] = result.current;
expect(session).toBeDefined();
expect(session.id).toEqual("123");
expect(session.user).toBe(null);
});

test("it returns the current session when the user is logged out and an api client with options is passed", async () => {
Expand All @@ -180,9 +185,10 @@ describe("useSession", () => {
expectMockSignedOutUser();
rerender();

expect(result.current).toBeDefined();
expect(result.current.id).toEqual("123");
expect(result.current.user).toBe(null);
const [session] = result.current;
expect(session).toBeDefined();
expect(session.id).toEqual("123");
expect(session.user).toBe(null);
});

test("it throws when the server responds with an error", async () => {
Expand Down Expand Up @@ -214,7 +220,8 @@ describe("useSession", () => {
expectMockSignedOutUser();
rerender();

expect(result.current.id).toEqual("123");
expect(result.current.user).toBeNull();
const [session] = result.current;
expect(session.id).toEqual("123");
expect(session.user).toBeNull();
});
});
21 changes: 12 additions & 9 deletions packages/react/spec/auth/useUser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ describe("useUser", () => {
}
}"
`);
expect(result.current.id).toEqual("321");
expect(result.current.firstName).toEqual("Jane");
expect(result.current.lastName).toEqual("Doe");
const [user] = result.current;
expect(user.id).toEqual("321");
expect(user.firstName).toEqual("Jane");
expect(user.lastName).toEqual("Doe");
});

test("it returns the current user when the user is logged in with an api client passed", async () => {
Expand Down Expand Up @@ -109,9 +110,10 @@ describe("useUser", () => {
}
}"
`);
expect(result.current.id).toEqual("321");
expect(result.current.firstName).toEqual("Jane");
expect(result.current.lastName).toEqual("Doe");
const [user] = result.current;
expect(user.id).toEqual("321");
expect(user.firstName).toEqual("Jane");
expect(user.lastName).toEqual("Doe");
});

test("it returns the current user when the user is logged in with an api client and options passed", async () => {
Expand Down Expand Up @@ -141,8 +143,9 @@ describe("useUser", () => {
}
}"
`);
expect(result.current.firstName).toEqual("Jane");
expect(result.current).toMatchInlineSnapshot(`
const [user] = result.current;
expect(user.firstName).toEqual("Jane");
expect(user).toMatchInlineSnapshot(`
{
"firstName": "Jane",
"id": "321",
Expand All @@ -157,7 +160,7 @@ describe("useUser", () => {
expectMockSignedOutUser();

rerender();
expect(result.current).toBe(null);
expect(result.current[0]).toBe(null);
});

test("it throws when the server responds with an error", async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/auth/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ export const useAuth = <
isSignedIn: boolean;
configuration: GadgetAuthConfiguration;
} => {
const session = useSession(client);
const user = useUser(client);
const [session] = useSession(client);
const [user] = useUser(client);
const context = useContext(GadgetConfigurationContext);

if (!context) {
Expand Down
35 changes: 20 additions & 15 deletions packages/react/src/auth/useSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
LimitToKnownKeys,
Select,
} from "@gadgetinc/api-client-core";
import { useCallback } from "react";
import { useApi } from "../GadgetProvider.js";
import { useGet } from "../useGet.js";
import type { OptionsType, ReadOperationOptions } from "../utils.js";
Expand Down Expand Up @@ -35,20 +36,23 @@ export function useSession<
>(
client?: ClientType,
options?: LimitToKnownKeys<Options, Client["currentSession"]["get"]["optionsType"] & ReadOperationOptions>
): undefined extends ClientType
? GadgetSession
: GadgetRecord<
Select<
Exclude<Exclude<ClientType, undefined>["currentSession"]["get"]["schemaType"], null | undefined>,
DefaultSelection<
Exclude<ClientType, undefined>["currentSession"]["get"]["selectionType"],
Options,
Exclude<ClientType, undefined>["currentSession"]["get"]["defaultSelection"] & {
user: Exclude<ClientType, undefined>["user"]["findMany"]["defaultSelection"];
}
): [
undefined extends ClientType
? GadgetSession
: GadgetRecord<
Select<
Exclude<Exclude<ClientType, undefined>["currentSession"]["get"]["schemaType"], null | undefined>,
DefaultSelection<
Exclude<ClientType, undefined>["currentSession"]["get"]["selectionType"],
Options,
Exclude<ClientType, undefined>["currentSession"]["get"]["defaultSelection"] & {
user: Exclude<ClientType, undefined>["user"]["findMany"]["defaultSelection"];
}
>
>
>
> {
>,
() => void
] {
const fallbackApi = useApi();
const api = client ?? (fallbackApi as ClientType);

Expand All @@ -67,12 +71,13 @@ export function useSession<
...(restOptions ?? {}),
};

const [{ data: session, error }] = useGet(api.currentSession, opts);
const [{ data: session, error }, refresh] = useGet(api.currentSession, opts);
const refreshFunction = useCallback(() => refresh(opts), [refresh, opts]);

if (error) throw error;
if (!session) throw new Error("currentSession not found but should be present");
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
return typeof client == "undefined" ? session : (session as any);
return [typeof client == "undefined" ? session : (session as any), refreshFunction];
} else {
throw new Error("api client does not have a Session model");
}
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/auth/useSignOut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useSignOut = (opts?: { redirectOnSuccess?: boolean; redirectToPath?
const redirectOnSuccess = opts?.redirectOnSuccess ?? true;
const redirectToPath = opts?.redirectToPath;
const api = useApi();
const user = useUser();
const [user, refreshUser] = useUser();
const context = useContext(GadgetConfigurationContext);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { signOutActionApiIdentifier, signInPath } = context!.auth;
Expand All @@ -38,6 +38,7 @@ export const useSignOut = (opts?: { redirectOnSuccess?: boolean; redirectToPath?
if (!user) throw new Error("attempting to sign out when the user is not signed in");
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await signOutAction({ id: user.id });
refreshUser();
}, [user, signOutAction]);
} else {
throw new Error(`missing configured signOutActionApiIdentifier '${signOutActionApiIdentifier}' on the \`api.user\` model manager.`);
Expand Down
29 changes: 16 additions & 13 deletions packages/react/src/auth/useUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ export function useUser<
>(
client?: ClientType,
options?: LimitToKnownKeys<Options, Client["user"]["findMany"]["optionsType"] & ReadOperationOptions>
): undefined extends ClientType
? GadgetRecord<Record<string, any>>
: GadgetRecord<
Select<
Exclude<Exclude<ClientType, undefined>["user"]["findMany"]["schemaType"], null | undefined>,
DefaultSelection<
Exclude<ClientType, undefined>["user"]["findMany"]["selectionType"],
Options,
Exclude<ClientType, undefined>["user"]["findMany"]["defaultSelection"]
): [
undefined extends ClientType
? GadgetRecord<Record<string, any>>
: GadgetRecord<
Select<
Exclude<Exclude<ClientType, undefined>["user"]["findMany"]["schemaType"], null | undefined>,
DefaultSelection<
Exclude<ClientType, undefined>["user"]["findMany"]["selectionType"],
Options,
Exclude<ClientType, undefined>["user"]["findMany"]["defaultSelection"]
>
>
>
> {
>,
() => void
] {
const fallbackApi = useApi() as any;
const api = client ?? fallbackApi;

Expand All @@ -48,6 +51,6 @@ export function useUser<
user: select,
};
}
const session = useSession(api, opts);
return session && session.getField("user");
const [session, refreshSession] = useSession(api, opts);
return [session && session.getField("user"), refreshSession];
}
Loading