forked from Vero-protocol/vero-guardian-dashboard
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRoleContext.tsx
More file actions
119 lines (100 loc) · 3.01 KB
/
Copy pathRoleContext.tsx
File metadata and controls
119 lines (100 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
'use client';
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
type ReactNode,
} from 'react';
import { useWallet } from '@/context/WalletContext';
import { useNetwork } from '@/context/NetworkContext';
import { useChainState } from '@/hooks/useChainState';
import { fetchUserRole, type UserRole } from '@/services/roleClient';
interface RoleContextValue {
role: UserRole;
isAdmin: boolean;
isGuardian: boolean;
canVote: boolean;
canManageTasks: boolean;
isLoading: boolean;
error: string | null;
refreshRole: () => Promise<void>;
}
const RoleContext = createContext<RoleContextValue | undefined>(undefined);
function getRoleErrorMessage(error: unknown): string {
if (error instanceof Error && error.message) {
return error.message;
}
return 'Unable to load wallet role';
}
export function RoleProvider({ children }: { children: ReactNode }) {
const { publicKey, isLoading: isWalletLoading } = useWallet();
const { networkConfig } = useNetwork();
const [role, setRole] = useState<UserRole>('unauthorized');
const [isRoleLoading, setIsRoleLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const requestIdRef = useRef(0);
const { syncVersion: roleSyncVersion } = useChainState({
cacheKeys: publicKey ? [`account:${publicKey}`, `role:${publicKey}`] : ['role'],
});
const refreshRole = useCallback(async () => {
const requestId = requestIdRef.current + 1;
requestIdRef.current = requestId;
if (!publicKey) {
setRole('unauthorized');
setError(null);
setIsRoleLoading(false);
return;
}
setIsRoleLoading(true);
setError(null);
try {
const nextRole = await fetchUserRole(publicKey, networkConfig.horizonUrl);
if (requestIdRef.current !== requestId) {
return;
}
setRole(nextRole);
} catch (roleError) {
if (requestIdRef.current !== requestId) {
return;
}
setRole('unauthorized');
setError(getRoleErrorMessage(roleError));
} finally {
if (requestIdRef.current === requestId) {
setIsRoleLoading(false);
}
}
}, [publicKey, networkConfig.horizonUrl]);
useEffect(() => {
void refreshRole();
return () => {
requestIdRef.current += 1;
};
}, [refreshRole, roleSyncVersion]);
const value = useMemo<RoleContextValue>(() => {
const isAdmin = role === 'admin';
const isGuardian = role === 'guardian';
return {
role,
isAdmin,
isGuardian,
canVote: isAdmin || isGuardian,
canManageTasks: isAdmin,
isLoading: isWalletLoading || isRoleLoading,
error,
refreshRole,
};
}, [error, isRoleLoading, isWalletLoading, refreshRole, role]);
return <RoleContext.Provider value={value}>{children}</RoleContext.Provider>;
}
export function useRole(): RoleContextValue {
const context = useContext(RoleContext);
if (!context) {
throw new Error('useRole must be used within a RoleProvider');
}
return context;
}