@checkstack/auth-frontend 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback } from "react";
1
+ import React, { useState, useEffect } from "react";
2
2
  import {
3
3
  Card,
4
4
  CardHeader,
@@ -39,8 +39,7 @@ import {
39
39
  UserPlus,
40
40
  UserMinus,
41
41
  } from "lucide-react";
42
- import { useApi } from "@checkstack/frontend-api";
43
- import { rpcApiRef } from "@checkstack/frontend-api";
42
+ import { usePluginClient } from "@checkstack/frontend-api";
44
43
  import { AuthApi } from "@checkstack/auth-common";
45
44
  import type { AuthUser } from "../api";
46
45
 
@@ -73,45 +72,148 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
73
72
  canManageTeams,
74
73
  onDataChange,
75
74
  }) => {
76
- const rpcApi = useApi(rpcApiRef);
77
- const authClient = rpcApi.forPlugin(AuthApi);
75
+ const authClient = usePluginClient(AuthApi);
78
76
  const toast = useToast();
79
77
 
80
- const [teams, setTeams] = useState<Team[]>([]);
81
- const [loading, setLoading] = useState(true);
82
78
  const [teamToDelete, setTeamToDelete] = useState<string>();
83
79
  const [editDialogOpen, setEditDialogOpen] = useState(false);
84
80
  const [editingTeam, setEditingTeam] = useState<Team | undefined>();
85
81
  const [membersDialogOpen, setMembersDialogOpen] = useState(false);
86
- const [selectedTeamDetail, setSelectedTeamDetail] = useState<TeamDetail>();
87
- const [membersLoading, setMembersLoading] = useState(false);
82
+ const [selectedTeamId, setSelectedTeamId] = useState<string>();
88
83
 
89
84
  // Team form state
90
85
  const [formName, setFormName] = useState("");
91
86
  const [formDescription, setFormDescription] = useState("");
92
- const [formSaving, setFormSaving] = useState(false);
93
87
 
94
88
  // Member management state
95
89
  const [selectedUserId, setSelectedUserId] = useState("");
96
- const [addingMember, setAddingMember] = useState(false);
97
-
98
- const loadTeams = useCallback(async () => {
99
- setLoading(true);
100
- try {
101
- const teamsData = await authClient.getTeams();
102
- setTeams(teamsData);
103
- } catch (error) {
90
+
91
+ // Query: Teams list
92
+ const {
93
+ data: teams = [],
94
+ isLoading: loading,
95
+ refetch: refetchTeams,
96
+ } = authClient.getTeams.useQuery({}, { enabled: canReadTeams });
97
+
98
+ // Query: Team detail (for members dialog)
99
+ const {
100
+ data: selectedTeamDetail,
101
+ isLoading: membersLoading,
102
+ refetch: refetchTeamDetail,
103
+ } = authClient.getTeam.useQuery(
104
+ { teamId: selectedTeamId ?? "" },
105
+ { enabled: !!selectedTeamId && membersDialogOpen }
106
+ );
107
+
108
+ // Mutations
109
+ const createTeamMutation = authClient.createTeam.useMutation({
110
+ onSuccess: () => {
111
+ toast.success("Team created successfully");
112
+ setEditDialogOpen(false);
113
+ void refetchTeams();
114
+ void onDataChange();
115
+ },
116
+ onError: (error) => {
117
+ toast.error(
118
+ error instanceof Error ? error.message : "Failed to create team"
119
+ );
120
+ },
121
+ });
122
+
123
+ const updateTeamMutation = authClient.updateTeam.useMutation({
124
+ onSuccess: () => {
125
+ toast.success("Team updated successfully");
126
+ setEditDialogOpen(false);
127
+ void refetchTeams();
128
+ void onDataChange();
129
+ },
130
+ onError: (error) => {
131
+ toast.error(
132
+ error instanceof Error ? error.message : "Failed to update team"
133
+ );
134
+ },
135
+ });
136
+
137
+ const deleteTeamMutation = authClient.deleteTeam.useMutation({
138
+ onSuccess: () => {
139
+ toast.success("Team deleted successfully");
140
+ setTeamToDelete(undefined);
141
+ void refetchTeams();
142
+ void onDataChange();
143
+ },
144
+ onError: (error) => {
145
+ toast.error(
146
+ error instanceof Error ? error.message : "Failed to delete team"
147
+ );
148
+ },
149
+ });
150
+
151
+ const addMemberMutation = authClient.addUserToTeam.useMutation({
152
+ onSuccess: () => {
153
+ toast.success("Member added successfully");
154
+ setSelectedUserId("");
155
+ void refetchTeamDetail();
156
+ void refetchTeams();
157
+ },
158
+ onError: (error) => {
159
+ toast.error(
160
+ error instanceof Error ? error.message : "Failed to add member"
161
+ );
162
+ },
163
+ });
164
+
165
+ const removeMemberMutation = authClient.removeUserFromTeam.useMutation({
166
+ onSuccess: () => {
167
+ toast.success("Member removed");
168
+ void refetchTeamDetail();
169
+ void refetchTeams();
170
+ },
171
+ onError: (error) => {
172
+ toast.error(
173
+ error instanceof Error ? error.message : "Failed to remove member"
174
+ );
175
+ },
176
+ });
177
+
178
+ const addManagerMutation = authClient.addTeamManager.useMutation({
179
+ onSuccess: () => {
180
+ toast.success("Member promoted to manager");
181
+ void refetchTeamDetail();
182
+ },
183
+ onError: (error) => {
184
+ toast.error(
185
+ error instanceof Error ? error.message : "Failed to promote to manager"
186
+ );
187
+ },
188
+ });
189
+
190
+ const removeManagerMutation = authClient.removeTeamManager.useMutation({
191
+ onSuccess: () => {
192
+ toast.success("Manager role removed");
193
+ void refetchTeamDetail();
194
+ },
195
+ onError: (error) => {
104
196
  toast.error(
105
- error instanceof Error ? error.message : "Failed to load teams"
197
+ error instanceof Error ? error.message : "Failed to remove manager role"
106
198
  );
107
- } finally {
108
- setLoading(false);
199
+ },
200
+ });
201
+
202
+ // Reset form when dialog closes
203
+ useEffect(() => {
204
+ if (!editDialogOpen) {
205
+ setEditingTeam(undefined);
206
+ setFormName("");
207
+ setFormDescription("");
109
208
  }
110
- }, [authClient, toast]);
209
+ }, [editDialogOpen]);
111
210
 
211
+ // Reset selected team when members dialog closes
112
212
  useEffect(() => {
113
- loadTeams();
114
- }, [loadTeams]);
213
+ if (!membersDialogOpen) {
214
+ setSelectedTeamId(undefined);
215
+ }
216
+ }, [membersDialogOpen]);
115
217
 
116
218
  const handleCreateTeam = () => {
117
219
  setEditingTeam(undefined);
@@ -127,160 +229,78 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
127
229
  setEditDialogOpen(true);
128
230
  };
129
231
 
130
- const handleSaveTeam = async () => {
232
+ const handleSaveTeam = () => {
131
233
  if (!formName.trim()) {
132
234
  toast.error("Team name is required");
133
235
  return;
134
236
  }
135
237
 
136
- setFormSaving(true);
137
- try {
138
- if (editingTeam) {
139
- await authClient.updateTeam({
140
- id: editingTeam.id,
141
- name: formName,
142
- description: formDescription || undefined,
143
- });
144
- toast.success("Team updated successfully");
145
- } else {
146
- await authClient.createTeam({
147
- name: formName,
148
- description: formDescription || undefined,
149
- });
150
- toast.success("Team created successfully");
151
- }
152
- setEditDialogOpen(false);
153
- await loadTeams();
154
- await onDataChange();
155
- } catch (error) {
156
- toast.error(
157
- error instanceof Error ? error.message : "Failed to save team"
158
- );
159
- } finally {
160
- setFormSaving(false);
238
+ if (editingTeam) {
239
+ updateTeamMutation.mutate({
240
+ id: editingTeam.id,
241
+ name: formName,
242
+ description: formDescription || undefined,
243
+ });
244
+ } else {
245
+ createTeamMutation.mutate({
246
+ name: formName,
247
+ description: formDescription || undefined,
248
+ });
161
249
  }
162
250
  };
163
251
 
164
- const handleDeleteTeam = async () => {
252
+ const handleDeleteTeam = () => {
165
253
  if (!teamToDelete) return;
166
- try {
167
- await authClient.deleteTeam(teamToDelete);
168
- toast.success("Team deleted successfully");
169
- setTeamToDelete(undefined);
170
- await loadTeams();
171
- await onDataChange();
172
- } catch (error) {
173
- toast.error(
174
- error instanceof Error ? error.message : "Failed to delete team"
175
- );
176
- }
254
+ deleteTeamMutation.mutate(teamToDelete);
177
255
  };
178
256
 
179
- const openMembersDialog = async (teamId: string) => {
180
- setMembersLoading(true);
257
+ const openMembersDialog = (teamId: string) => {
258
+ setSelectedTeamId(teamId);
181
259
  setMembersDialogOpen(true);
182
- try {
183
- const detail = await authClient.getTeam({ teamId });
184
- setSelectedTeamDetail(detail ?? undefined);
185
- } catch (error) {
186
- toast.error(
187
- error instanceof Error ? error.message : "Failed to load team details"
188
- );
189
- setMembersDialogOpen(false);
190
- } finally {
191
- setMembersLoading(false);
192
- }
193
260
  };
194
261
 
195
- const handleAddMember = async () => {
196
- if (!selectedTeamDetail || !selectedUserId) return;
262
+ const handleAddMember = () => {
263
+ if (!selectedTeamId || !selectedUserId) return;
264
+ addMemberMutation.mutate({
265
+ teamId: selectedTeamId,
266
+ userId: selectedUserId,
267
+ });
268
+ };
197
269
 
198
- setAddingMember(true);
199
- try {
200
- await authClient.addUserToTeam({
201
- teamId: selectedTeamDetail.id,
202
- userId: selectedUserId,
203
- });
204
- toast.success("Member added successfully");
205
- // Reload team details
206
- const detail = await authClient.getTeam({
207
- teamId: selectedTeamDetail.id,
208
- });
209
- setSelectedTeamDetail(detail ?? undefined);
210
- setSelectedUserId("");
211
- await loadTeams();
212
- } catch (error) {
213
- toast.error(
214
- error instanceof Error ? error.message : "Failed to add member"
215
- );
216
- } finally {
217
- setAddingMember(false);
218
- }
270
+ const handleRemoveMember = (userId: string) => {
271
+ if (!selectedTeamId) return;
272
+ removeMemberMutation.mutate({
273
+ teamId: selectedTeamId,
274
+ userId,
275
+ });
219
276
  };
220
277
 
221
- const handleRemoveMember = async (userId: string) => {
222
- if (!selectedTeamDetail) return;
278
+ const handleToggleManager = (userId: string, isCurrentlyManager: boolean) => {
279
+ if (!selectedTeamId) return;
223
280
 
224
- try {
225
- await authClient.removeUserFromTeam({
226
- teamId: selectedTeamDetail.id,
281
+ if (isCurrentlyManager) {
282
+ removeManagerMutation.mutate({
283
+ teamId: selectedTeamId,
227
284
  userId,
228
285
  });
229
- toast.success("Member removed");
230
- // Reload team details
231
- const detail = await authClient.getTeam({
232
- teamId: selectedTeamDetail.id,
233
- });
234
- setSelectedTeamDetail(detail ?? undefined);
235
- await loadTeams();
236
- } catch (error) {
237
- toast.error(
238
- error instanceof Error ? error.message : "Failed to remove member"
239
- );
240
- }
241
- };
242
-
243
- const handleToggleManager = async (
244
- userId: string,
245
- isCurrentlyManager: boolean
246
- ) => {
247
- if (!selectedTeamDetail) return;
248
-
249
- try {
250
- if (isCurrentlyManager) {
251
- await authClient.removeTeamManager({
252
- teamId: selectedTeamDetail.id,
253
- userId,
254
- });
255
- toast.success("Manager role removed");
256
- } else {
257
- await authClient.addTeamManager({
258
- teamId: selectedTeamDetail.id,
259
- userId,
260
- });
261
- toast.success("Member promoted to manager");
262
- }
263
- // Reload team details
264
- const detail = await authClient.getTeam({
265
- teamId: selectedTeamDetail.id,
286
+ } else {
287
+ addManagerMutation.mutate({
288
+ teamId: selectedTeamId,
289
+ userId,
266
290
  });
267
- setSelectedTeamDetail(detail ?? undefined);
268
- } catch (error) {
269
- toast.error(
270
- error instanceof Error
271
- ? error.message
272
- : "Failed to update manager status"
273
- );
274
291
  }
275
292
  };
276
293
 
277
294
  // Get users not already in the team
278
- const availableUsers = selectedTeamDetail
279
- ? users.filter(
280
- (u) => !selectedTeamDetail.members.some((m) => m.id === u.id)
281
- )
295
+ const teamDetailData = selectedTeamDetail as TeamDetail | undefined;
296
+ const availableUsers = teamDetailData
297
+ ? users.filter((u) => !teamDetailData.members.some((m) => m.id === u.id))
282
298
  : [];
283
299
 
300
+ const formSaving =
301
+ createTeamMutation.isPending || updateTeamMutation.isPending;
302
+ const addingMember = addMemberMutation.isPending;
303
+
284
304
  return (
285
305
  <>
286
306
  <Card>
@@ -299,7 +319,7 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
299
319
  <div className="flex justify-center py-8">
300
320
  <LoadingSpinner />
301
321
  </div>
302
- ) : teams.length === 0 ? (
322
+ ) : (teams as Team[]).length === 0 ? (
303
323
  <p className="text-muted-foreground">No teams found.</p>
304
324
  ) : (
305
325
  <Table>
@@ -311,7 +331,7 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
311
331
  </TableRow>
312
332
  </TableHeader>
313
333
  <TableBody>
314
- {teams.map((team) => (
334
+ {(teams as Team[]).map((team) => (
315
335
  <TableRow key={team.id}>
316
336
  <TableCell>
317
337
  <div className="flex flex-col">
@@ -429,9 +449,7 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
429
449
  <Dialog open={membersDialogOpen} onOpenChange={setMembersDialogOpen}>
430
450
  <DialogContent className="max-w-lg">
431
451
  <DialogHeader>
432
- <DialogTitle>
433
- {selectedTeamDetail?.name ?? "Team"} Members
434
- </DialogTitle>
452
+ <DialogTitle>{teamDetailData?.name ?? "Team"} Members</DialogTitle>
435
453
  <DialogDescription>
436
454
  Manage team membership and assign managers.
437
455
  </DialogDescription>
@@ -441,10 +459,10 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
441
459
  <div className="flex justify-center py-8">
442
460
  <LoadingSpinner />
443
461
  </div>
444
- ) : selectedTeamDetail ? (
462
+ ) : teamDetailData ? (
445
463
  <div className="space-y-4">
446
464
  {/* Add Member Form */}
447
- {(selectedTeamDetail.managers.some((m) =>
465
+ {(teamDetailData.managers.some((m) =>
448
466
  users.some((u) => u.id === m.id)
449
467
  ) ||
450
468
  canManageTeams) && (
@@ -483,13 +501,13 @@ export const TeamsTab: React.FC<TeamsTabProps> = ({
483
501
 
484
502
  {/* Member List */}
485
503
  <div className="border rounded-lg divide-y max-h-64 overflow-y-auto">
486
- {selectedTeamDetail.members.length === 0 ? (
504
+ {teamDetailData.members.length === 0 ? (
487
505
  <p className="text-muted-foreground text-center py-4">
488
506
  No members yet
489
507
  </p>
490
508
  ) : (
491
- selectedTeamDetail.members.map((member) => {
492
- const isManager = selectedTeamDetail.managers.some(
509
+ teamDetailData.members.map((member) => {
510
+ const isManager = teamDetailData.managers.some(
493
511
  (m) => m.id === member.id
494
512
  );
495
513
  return (
@@ -18,8 +18,7 @@ import {
18
18
  useToast,
19
19
  } from "@checkstack/ui";
20
20
  import { Plus, Trash2 } from "lucide-react";
21
- import { useApi } from "@checkstack/frontend-api";
22
- import { rpcApiRef } from "@checkstack/frontend-api";
21
+ import { usePluginClient } from "@checkstack/frontend-api";
23
22
  import { AuthApi } from "@checkstack/auth-common";
24
23
  import type { AuthUser, Role, AuthStrategy } from "../api";
25
24
  import { CreateUserDialog } from "./CreateUserDialog";
@@ -47,8 +46,7 @@ export const UsersTab: React.FC<UsersTabProps> = ({
47
46
  canManageRoles,
48
47
  onDataChange,
49
48
  }) => {
50
- const rpcApi = useApi(rpcApiRef);
51
- const authClient = rpcApi.forPlugin(AuthApi);
49
+ const authClient = usePluginClient(AuthApi);
52
50
  const toast = useToast();
53
51
 
54
52
  const [userToDelete, setUserToDelete] = useState<string>();
@@ -58,21 +56,50 @@ export const UsersTab: React.FC<UsersTabProps> = ({
58
56
  (s) => s.id === "credential" && s.enabled
59
57
  );
60
58
 
61
- const handleDeleteUser = async () => {
62
- if (!userToDelete) return;
63
- try {
64
- await authClient.deleteUser(userToDelete);
59
+ // Mutations
60
+ const deleteUserMutation = authClient.deleteUser.useMutation({
61
+ onSuccess: () => {
65
62
  toast.success("User deleted successfully");
66
63
  setUserToDelete(undefined);
67
- await onDataChange();
68
- } catch (error: unknown) {
64
+ void onDataChange();
65
+ },
66
+ onError: (error) => {
69
67
  toast.error(
70
68
  error instanceof Error ? error.message : "Failed to delete user"
71
69
  );
72
- }
70
+ },
71
+ });
72
+
73
+ const updateRolesMutation = authClient.updateUserRoles.useMutation({
74
+ onSuccess: () => {
75
+ void onDataChange();
76
+ },
77
+ onError: (error) => {
78
+ toast.error(
79
+ error instanceof Error ? error.message : "Failed to update roles"
80
+ );
81
+ },
82
+ });
83
+
84
+ const createUserMutation = authClient.createCredentialUser.useMutation({
85
+ onSuccess: () => {
86
+ toast.success("User created successfully");
87
+ void onDataChange();
88
+ },
89
+ onError: (error) => {
90
+ toast.error(
91
+ error instanceof Error ? error.message : "Failed to create user"
92
+ );
93
+ throw error;
94
+ },
95
+ });
96
+
97
+ const handleDeleteUser = () => {
98
+ if (!userToDelete) return;
99
+ deleteUserMutation.mutate(userToDelete);
73
100
  };
74
101
 
75
- const handleToggleRole = async (
102
+ const handleToggleRole = (
76
103
  userId: string,
77
104
  roleId: string,
78
105
  currentRoles: string[]
@@ -86,14 +113,7 @@ export const UsersTab: React.FC<UsersTabProps> = ({
86
113
  ? currentRoles.filter((r) => r !== roleId)
87
114
  : [...currentRoles, roleId];
88
115
 
89
- try {
90
- await authClient.updateUserRoles({ userId, roles: newRoles });
91
- await onDataChange();
92
- } catch (error: unknown) {
93
- const message =
94
- error instanceof Error ? error.message : "Failed to update roles";
95
- toast.error(message);
96
- }
116
+ updateRolesMutation.mutate({ userId, roles: newRoles });
97
117
  };
98
118
 
99
119
  const handleCreateUser = async (data: {
@@ -101,16 +121,7 @@ export const UsersTab: React.FC<UsersTabProps> = ({
101
121
  email: string;
102
122
  password: string;
103
123
  }) => {
104
- try {
105
- await authClient.createCredentialUser(data);
106
- toast.success("User created successfully");
107
- await onDataChange();
108
- } catch (error: unknown) {
109
- toast.error(
110
- error instanceof Error ? error.message : "Failed to create user"
111
- );
112
- throw error;
113
- }
124
+ createUserMutation.mutate(data);
114
125
  };
115
126
 
116
127
  return (
@@ -1,43 +1,32 @@
1
- import { useEffect, useState } from "react";
2
- import { useAuthClient } from "../lib/auth-client";
3
- import { rpcApiRef, useApi } from "@checkstack/frontend-api";
1
+ import { usePluginClient } from "@checkstack/frontend-api";
4
2
  import { AuthApi } from "@checkstack/auth-common";
3
+ import { useAuthClient } from "../lib/auth-client";
5
4
 
6
5
  export const useAccessRules = () => {
7
- const authClient = useAuthClient();
8
- const { data: session, isPending: sessionPending } = authClient.useSession();
9
- const [accessRules, setAccessRules] = useState<string[]>([]);
10
- const [loading, setLoading] = useState(true);
11
- const rpcApi = useApi(rpcApiRef);
6
+ const authBetterClient = useAuthClient();
7
+ const authClient = usePluginClient(AuthApi);
8
+ const { data: session, isPending: sessionPending } =
9
+ authBetterClient.useSession();
12
10
 
13
- useEffect(() => {
14
- // Don't set loading=false while session is still pending
15
- // This prevents "Access Denied" flash during initial page load
16
- if (sessionPending) {
17
- return;
11
+ // Query: Fetch access rules (only when user is authenticated)
12
+ const { data, isLoading } = authClient.accessRules.useQuery(
13
+ {},
14
+ {
15
+ enabled: !sessionPending && !!session?.user,
18
16
  }
17
+ );
19
18
 
20
- if (!session?.user) {
21
- setAccessRules([]);
22
- setLoading(false);
23
- return;
24
- }
19
+ // If no session or pending, return empty access rules
20
+ if (sessionPending) {
21
+ return { accessRules: [], loading: true };
22
+ }
25
23
 
26
- const fetchAccessRules = async () => {
27
- try {
28
- const authRpc = rpcApi.forPlugin(AuthApi);
29
- const data = await authRpc.accessRules();
30
- if (Array.isArray(data.accessRules)) {
31
- setAccessRules(data.accessRules);
32
- }
33
- } catch (error) {
34
- console.error("Failed to fetch access rules", error);
35
- } finally {
36
- setLoading(false);
37
- }
38
- };
39
- fetchAccessRules();
40
- }, [session?.user?.id, sessionPending, rpcApi]);
24
+ if (!session?.user) {
25
+ return { accessRules: [], loading: false };
26
+ }
41
27
 
42
- return { accessRules, loading };
28
+ return {
29
+ accessRules: data?.accessRules ?? [],
30
+ loading: isLoading,
31
+ };
43
32
  };
@@ -1,5 +1,4 @@
1
- import { useState, useEffect } from "react";
2
- import { useApi, rpcApiRef } from "@checkstack/frontend-api";
1
+ import { usePluginClient } from "@checkstack/frontend-api";
3
2
  import { AuthApi } from "@checkstack/auth-common";
4
3
  import type { EnabledAuthStrategy } from "../api";
5
4
 
@@ -10,45 +9,15 @@ export interface UseEnabledStrategiesResult {
10
9
  }
11
10
 
12
11
  export const useEnabledStrategies = (): UseEnabledStrategiesResult => {
13
- const rpcApi = useApi(rpcApiRef);
14
- const authClient = rpcApi.forPlugin(AuthApi);
12
+ const authClient = usePluginClient(AuthApi);
15
13
 
16
- const [strategies, setStrategies] = useState<EnabledAuthStrategy[]>([]);
17
- const [loading, setLoading] = useState(true);
18
- const [error, setError] = useState<Error>();
14
+ const { data, isLoading, error } = authClient.getEnabledStrategies.useQuery(
15
+ {}
16
+ );
19
17
 
20
- useEffect(() => {
21
- let mounted = true;
22
-
23
- const fetchStrategies = async () => {
24
- try {
25
- setLoading(true);
26
- const result = await authClient.getEnabledStrategies();
27
- if (mounted) {
28
- setStrategies(result);
29
- setError(undefined);
30
- }
31
- } catch (error_) {
32
- if (mounted) {
33
- setError(
34
- error_ instanceof Error
35
- ? error_
36
- : new Error("Failed to fetch strategies")
37
- );
38
- }
39
- } finally {
40
- if (mounted) {
41
- setLoading(false);
42
- }
43
- }
44
- };
45
-
46
- fetchStrategies();
47
-
48
- return () => {
49
- mounted = false;
50
- };
51
- }, [authClient]);
52
-
53
- return { strategies, loading, error };
18
+ return {
19
+ strategies: (data ?? []) as EnabledAuthStrategy[],
20
+ loading: isLoading,
21
+ error: error ?? undefined,
22
+ };
54
23
  };