@oxyhq/services 5.16.29 → 5.16.31
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.
- package/lib/commonjs/core/services/SessionService.js +2 -1
- package/lib/commonjs/core/services/SessionService.js.map +1 -1
- package/lib/commonjs/core/services/TokenService.js +17 -9
- package/lib/commonjs/core/services/TokenService.js.map +1 -1
- package/lib/commonjs/index.js +64 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/interfaces.js +9 -8
- package/lib/commonjs/models/interfaces.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +40 -4
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +25 -14
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/auth/index.js +37 -0
- package/lib/commonjs/ui/hooks/auth/index.js.map +1 -0
- package/lib/commonjs/ui/hooks/auth/useUsernameValidation.js +171 -0
- package/lib/commonjs/ui/hooks/auth/useUsernameValidation.js.map +1 -0
- package/lib/commonjs/ui/hooks/index.js +20 -0
- package/lib/commonjs/ui/hooks/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/index.js +12 -0
- package/lib/commonjs/ui/hooks/mutations/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +45 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/index.js +12 -0
- package/lib/commonjs/ui/hooks/queries/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +3 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +43 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +12 -4
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +8 -0
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +76 -97
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js +26 -11
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/commonjs/utils/sessionUtils.js +8 -1
- package/lib/commonjs/utils/sessionUtils.js.map +1 -1
- package/lib/module/core/services/SessionService.js +2 -1
- package/lib/module/core/services/SessionService.js.map +1 -1
- package/lib/module/core/services/TokenService.js +17 -9
- package/lib/module/core/services/TokenService.js.map +1 -1
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/interfaces.js +9 -8
- package/lib/module/models/interfaces.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +40 -4
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +25 -14
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/auth/index.js +7 -0
- package/lib/module/ui/hooks/auth/index.js.map +1 -0
- package/lib/module/ui/hooks/auth/useUsernameValidation.js +167 -0
- package/lib/module/ui/hooks/auth/useUsernameValidation.js.map +1 -0
- package/lib/module/ui/hooks/index.js +1 -0
- package/lib/module/ui/hooks/index.js.map +1 -1
- package/lib/module/ui/hooks/mutations/index.js +1 -1
- package/lib/module/ui/hooks/mutations/index.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +42 -0
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/queries/index.js +1 -1
- package/lib/module/ui/hooks/queries/index.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +3 -1
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +40 -0
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js +13 -5
- package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +8 -0
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +77 -98
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/utils/sessionHelpers.js +26 -11
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/module/utils/sessionUtils.js +8 -1
- package/lib/module/utils/sessionUtils.js.map +1 -1
- package/lib/typescript/core/services/SessionService.d.ts +4 -2
- package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
- package/lib/typescript/core/services/TokenService.d.ts +8 -3
- package/lib/typescript/core/services/TokenService.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +4 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +9 -8
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +4 -2
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/auth/index.d.ts +6 -0
- package/lib/typescript/ui/hooks/auth/index.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/auth/useUsernameValidation.d.ts +32 -0
- package/lib/typescript/ui/hooks/auth/useUsernameValidation.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/index.d.ts +1 -0
- package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/mutations/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +12 -0
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/queries/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts +2 -0
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +12 -0
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/utils/sessionHelpers.d.ts +6 -2
- package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/services/SessionService.ts +4 -2
- package/src/core/services/TokenService.ts +18 -10
- package/src/index.ts +6 -0
- package/src/models/interfaces.ts +11 -10
- package/src/models/session.ts +5 -3
- package/src/ui/context/OxyContext.tsx +56 -20
- package/src/ui/context/hooks/useAuthOperations.ts +23 -15
- package/src/ui/hooks/auth/index.ts +7 -0
- package/src/ui/hooks/auth/useUsernameValidation.ts +177 -0
- package/src/ui/hooks/index.ts +2 -1
- package/src/ui/hooks/mutations/index.ts +2 -0
- package/src/ui/hooks/mutations/useAccountMutations.ts +36 -0
- package/src/ui/hooks/queries/index.ts +2 -0
- package/src/ui/hooks/queries/queryKeys.ts +2 -0
- package/src/ui/hooks/queries/useAccountQueries.ts +34 -0
- package/src/ui/hooks/queries/useServicesQueries.ts +8 -3
- package/src/ui/hooks/useSessionManagement.ts +8 -1
- package/src/ui/screens/PrivacySettingsScreen.tsx +67 -101
- package/src/ui/utils/sessionHelpers.ts +32 -15
- package/src/utils/sessionUtils.ts +8 -1
- package/lib/commonjs/ui/context/hooks/useSessionManagement.js +0 -281
- package/lib/commonjs/ui/context/hooks/useSessionManagement.js.map +0 -1
- package/lib/commonjs/ui/context/hooks/useStorage.js +0 -79
- package/lib/commonjs/ui/context/hooks/useStorage.js.map +0 -1
- package/lib/module/ui/context/hooks/useSessionManagement.js +0 -276
- package/lib/module/ui/context/hooks/useSessionManagement.js.map +0 -1
- package/lib/module/ui/context/hooks/useStorage.js +0 -74
- package/lib/module/ui/context/hooks/useStorage.js.map +0 -1
- package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts +0 -41
- package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts.map +0 -1
- package/lib/typescript/ui/context/hooks/useStorage.d.ts +0 -22
- package/lib/typescript/ui/context/hooks/useStorage.d.ts.map +0 -1
- package/src/ui/context/hooks/useSessionManagement.ts +0 -401
- package/src/ui/context/hooks/useStorage.ts +0 -104
|
@@ -499,3 +499,39 @@ export const useUploadFile = () => {
|
|
|
499
499
|
});
|
|
500
500
|
};
|
|
501
501
|
|
|
502
|
+
/**
|
|
503
|
+
* Unblock a user with query invalidation
|
|
504
|
+
*/
|
|
505
|
+
export const useUnblockUser = () => {
|
|
506
|
+
const { oxyServices } = useOxy();
|
|
507
|
+
const queryClient = useQueryClient();
|
|
508
|
+
|
|
509
|
+
return useMutation({
|
|
510
|
+
mutationFn: async (userId: string) => {
|
|
511
|
+
return await oxyServices.unblockUser(userId);
|
|
512
|
+
},
|
|
513
|
+
onSuccess: () => {
|
|
514
|
+
// Invalidate blocked users query to refetch the list
|
|
515
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.privacy.blocked() });
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Unrestrict a user with query invalidation
|
|
522
|
+
*/
|
|
523
|
+
export const useUnrestrictUser = () => {
|
|
524
|
+
const { oxyServices } = useOxy();
|
|
525
|
+
const queryClient = useQueryClient();
|
|
526
|
+
|
|
527
|
+
return useMutation({
|
|
528
|
+
mutationFn: async (userId: string) => {
|
|
529
|
+
return await oxyServices.unrestrictUser(userId);
|
|
530
|
+
},
|
|
531
|
+
onSuccess: () => {
|
|
532
|
+
// Invalidate restricted users query to refetch the list
|
|
533
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.privacy.restricted() });
|
|
534
|
+
},
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
|
|
@@ -53,6 +53,8 @@ export const queryKeys = {
|
|
|
53
53
|
privacy: {
|
|
54
54
|
all: ['privacy'] as const,
|
|
55
55
|
settings: (userId?: string) => [...queryKeys.privacy.all, 'settings', userId || 'current'] as const,
|
|
56
|
+
blocked: () => [...queryKeys.privacy.all, 'blocked'] as const,
|
|
57
|
+
restricted: () => [...queryKeys.privacy.all, 'restricted'] as const,
|
|
56
58
|
},
|
|
57
59
|
|
|
58
60
|
// Security activity queries
|
|
@@ -195,3 +195,37 @@ export const usePrivacySettings = (userId?: string, options?: { enabled?: boolea
|
|
|
195
195
|
});
|
|
196
196
|
};
|
|
197
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Get blocked users
|
|
200
|
+
*/
|
|
201
|
+
export const useBlockedUsers = (options?: { enabled?: boolean }) => {
|
|
202
|
+
const { oxyServices, isAuthenticated } = useOxy();
|
|
203
|
+
|
|
204
|
+
return useQuery({
|
|
205
|
+
queryKey: queryKeys.privacy.blocked(),
|
|
206
|
+
queryFn: async () => {
|
|
207
|
+
return await oxyServices.getBlockedUsers();
|
|
208
|
+
},
|
|
209
|
+
enabled: (options?.enabled !== false) && isAuthenticated,
|
|
210
|
+
staleTime: 1 * 60 * 1000, // 1 minute
|
|
211
|
+
gcTime: 5 * 60 * 1000, // 5 minutes
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get restricted users
|
|
217
|
+
*/
|
|
218
|
+
export const useRestrictedUsers = (options?: { enabled?: boolean }) => {
|
|
219
|
+
const { oxyServices, isAuthenticated } = useOxy();
|
|
220
|
+
|
|
221
|
+
return useQuery({
|
|
222
|
+
queryKey: queryKeys.privacy.restricted(),
|
|
223
|
+
queryFn: async () => {
|
|
224
|
+
return await oxyServices.getRestrictedUsers();
|
|
225
|
+
},
|
|
226
|
+
enabled: (options?.enabled !== false) && isAuthenticated,
|
|
227
|
+
staleTime: 1 * 60 * 1000, // 1 minute
|
|
228
|
+
gcTime: 5 * 60 * 1000, // 5 minutes
|
|
229
|
+
});
|
|
230
|
+
};
|
|
231
|
+
|
|
@@ -8,7 +8,7 @@ import { fetchSessionsWithFallback, mapSessionsToClient } from '../../utils/sess
|
|
|
8
8
|
* Get all active sessions for the current user
|
|
9
9
|
*/
|
|
10
10
|
export const useSessions = (userId?: string, options?: { enabled?: boolean }) => {
|
|
11
|
-
const { oxyServices, activeSessionId } = useOxy();
|
|
11
|
+
const { oxyServices, activeSessionId, user } = useOxy();
|
|
12
12
|
|
|
13
13
|
return useQuery({
|
|
14
14
|
queryKey: queryKeys.sessions.list(userId),
|
|
@@ -17,12 +17,14 @@ export const useSessions = (userId?: string, options?: { enabled?: boolean }) =>
|
|
|
17
17
|
throw new Error('No active session');
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
const publicKey = user?.publicKey || user?.id || ''; // user.id is now publicKey
|
|
20
21
|
const sessions = await fetchSessionsWithFallback(oxyServices, activeSessionId, {
|
|
21
22
|
fallbackDeviceId: undefined,
|
|
22
23
|
fallbackUserId: userId,
|
|
24
|
+
fallbackPublicKey: publicKey,
|
|
23
25
|
});
|
|
24
26
|
|
|
25
|
-
return
|
|
27
|
+
return sessions; // Already mapped by fetchSessionsWithFallback
|
|
26
28
|
},
|
|
27
29
|
enabled: (options?.enabled !== false) && !!activeSessionId,
|
|
28
30
|
staleTime: 2 * 60 * 1000, // 2 minutes (sessions change frequently)
|
|
@@ -49,12 +51,15 @@ export const useSession = (sessionId: string | null, options?: { enabled?: boole
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
const now = new Date();
|
|
54
|
+
// user.id is now publicKey (canonical identity)
|
|
55
|
+
const publicKey = validation.user.publicKey || validation.user.id || '';
|
|
52
56
|
return {
|
|
53
57
|
sessionId,
|
|
54
58
|
deviceId: '', // Device ID not available from validation response
|
|
55
59
|
expiresAt: validation.expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
56
60
|
lastActive: validation.lastActivity || now.toISOString(),
|
|
57
|
-
|
|
61
|
+
publicKey, // Canonical user identity
|
|
62
|
+
userId: validation.user.id?.toString(), // Optional MongoDB ObjectId
|
|
58
63
|
isCurrent: false,
|
|
59
64
|
} as ClientSession;
|
|
60
65
|
},
|
|
@@ -255,8 +255,10 @@ export const useSessionManagement = ({
|
|
|
255
255
|
await activateSession(sessionId, user);
|
|
256
256
|
|
|
257
257
|
try {
|
|
258
|
+
const publicKey = user.publicKey || user.id || ''; // user.id is now publicKey
|
|
258
259
|
const deviceSessions = await fetchSessionsWithFallback(oxyServices, sessionId, {
|
|
259
|
-
fallbackUserId: user.id,
|
|
260
|
+
fallbackUserId: user.id, // Still pass for backward compatibility
|
|
261
|
+
fallbackPublicKey: publicKey,
|
|
260
262
|
logger,
|
|
261
263
|
});
|
|
262
264
|
updateSessions(deviceSessions, { merge: true });
|
|
@@ -330,8 +332,13 @@ export const useSessionManagement = ({
|
|
|
330
332
|
|
|
331
333
|
const refreshPromise = (async () => {
|
|
332
334
|
try {
|
|
335
|
+
// Get publicKey from active session or current user
|
|
336
|
+
const activeSession = sessions.find(s => s.sessionId === activeSessionId);
|
|
337
|
+
const publicKey = activeSession?.publicKey || activeUserId || ''; // Fallback to userId if publicKey not available
|
|
338
|
+
|
|
333
339
|
const deviceSessions = await fetchSessionsWithFallback(oxyServices, activeSessionId, {
|
|
334
340
|
fallbackUserId: activeUserId,
|
|
341
|
+
fallbackPublicKey: publicKey,
|
|
335
342
|
logger,
|
|
336
343
|
});
|
|
337
344
|
updateSessions(deviceSessions, { merge: true });
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import React, { useState, useCallback,
|
|
1
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
5
5
|
StyleSheet,
|
|
6
6
|
ScrollView,
|
|
7
|
-
ActivityIndicator,
|
|
8
7
|
TouchableOpacity,
|
|
9
8
|
} from 'react-native';
|
|
10
9
|
import type { BaseScreenProps } from '../types/navigation';
|
|
@@ -15,6 +14,8 @@ import { useThemeStyles } from '../hooks/useThemeStyles';
|
|
|
15
14
|
import { normalizeTheme } from '../utils/themeUtils';
|
|
16
15
|
import type { BlockedUser, RestrictedUser } from '../../models/interfaces';
|
|
17
16
|
import { useOxy } from '../context/OxyContext';
|
|
17
|
+
import { usePrivacySettings, useBlockedUsers, useRestrictedUsers } from '../hooks/queries';
|
|
18
|
+
import { useUpdatePrivacySettings, useUnblockUser, useUnrestrictUser } from '../hooks/mutations';
|
|
18
19
|
|
|
19
20
|
interface PrivacySettings {
|
|
20
21
|
isPrivateAccount: boolean;
|
|
@@ -44,8 +45,20 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
44
45
|
goBack,
|
|
45
46
|
}) => {
|
|
46
47
|
// Use useOxy() hook for OxyContext values
|
|
47
|
-
const { oxyServices
|
|
48
|
+
const { oxyServices } = useOxy();
|
|
48
49
|
const { t } = useI18n();
|
|
50
|
+
|
|
51
|
+
// TanStack Query hooks for server state
|
|
52
|
+
const { data: privacySettingsData, isLoading: isLoadingSettings, error: settingsError } = usePrivacySettings();
|
|
53
|
+
const { data: blockedUsers = [], isLoading: isLoadingBlocked } = useBlockedUsers();
|
|
54
|
+
const { data: restrictedUsers = [], isLoading: isLoadingRestricted } = useRestrictedUsers();
|
|
55
|
+
|
|
56
|
+
// Mutations
|
|
57
|
+
const updatePrivacySettingsMutation = useUpdatePrivacySettings();
|
|
58
|
+
const unblockUserMutation = useUnblockUser();
|
|
59
|
+
const unrestrictUserMutation = useUnrestrictUser();
|
|
60
|
+
|
|
61
|
+
// Client state for optimistic UI updates
|
|
49
62
|
const [settings, setSettings] = useState<PrivacySettings>({
|
|
50
63
|
isPrivateAccount: false,
|
|
51
64
|
hideOnlineStatus: false,
|
|
@@ -67,111 +80,64 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
67
80
|
autoFilter: true,
|
|
68
81
|
muteKeywords: false,
|
|
69
82
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error('Failed to load privacy settings:', error);
|
|
92
|
-
toast.error(t('privacySettings.loadError') || 'Failed to load privacy settings');
|
|
93
|
-
} finally {
|
|
94
|
-
setIsLoading(false);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
loadSettings();
|
|
99
|
-
}, [oxyServices, t]);
|
|
100
|
-
|
|
101
|
-
// Load blocked and restricted users
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
const loadUsers = async () => {
|
|
104
|
-
if (!oxyServices) return;
|
|
105
|
-
try {
|
|
106
|
-
setIsLoadingUsers(true);
|
|
107
|
-
const [blocked, restricted] = await Promise.all([
|
|
108
|
-
oxyServices.getBlockedUsers(),
|
|
109
|
-
oxyServices.getRestrictedUsers(),
|
|
110
|
-
]);
|
|
111
|
-
setBlockedUsers(blocked);
|
|
112
|
-
setRestrictedUsers(restricted);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('Failed to load blocked/restricted users:', error);
|
|
115
|
-
} finally {
|
|
116
|
-
setIsLoadingUsers(false);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
loadUsers();
|
|
121
|
-
}, [oxyServices]);
|
|
83
|
+
|
|
84
|
+
// Update local state when server data changes
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
if (privacySettingsData) {
|
|
87
|
+
setSettings(privacySettingsData as PrivacySettings);
|
|
88
|
+
}
|
|
89
|
+
}, [privacySettingsData]);
|
|
90
|
+
|
|
91
|
+
// Show error toast if settings failed to load
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
if (settingsError) {
|
|
94
|
+
toast.error(t('privacySettings.loadError') || 'Failed to load privacy settings');
|
|
95
|
+
}
|
|
96
|
+
}, [settingsError, t]);
|
|
97
|
+
|
|
98
|
+
const isLoading = isLoadingSettings;
|
|
99
|
+
const isSaving = updatePrivacySettingsMutation.isPending;
|
|
100
|
+
const isLoadingUsers = isLoadingBlocked || isLoadingRestricted;
|
|
122
101
|
|
|
123
102
|
const updateSetting = useCallback(async (key: keyof PrivacySettings, value: boolean) => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
103
|
+
// Optimistic update
|
|
104
|
+
const newSettings = { ...settings, [key]: value };
|
|
105
|
+
setSettings(newSettings);
|
|
106
|
+
|
|
107
|
+
// Use mutation hook
|
|
108
|
+
updatePrivacySettingsMutation.mutate(
|
|
109
|
+
{ settings: { [key]: value } },
|
|
110
|
+
{
|
|
111
|
+
onError: () => {
|
|
112
|
+
// Revert on error
|
|
113
|
+
setSettings(settings);
|
|
114
|
+
toast.error(t('privacySettings.updateError') || 'Failed to update privacy setting');
|
|
115
|
+
},
|
|
135
116
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
toast.error(t('privacySettings.updateError') || 'Failed to update privacy setting');
|
|
139
|
-
// Revert on error
|
|
140
|
-
setSettings(settings);
|
|
141
|
-
} finally {
|
|
142
|
-
setIsSaving(false);
|
|
143
|
-
}
|
|
144
|
-
}, [settings, oxyServices, t]);
|
|
117
|
+
);
|
|
118
|
+
}, [settings, updatePrivacySettingsMutation, t]);
|
|
145
119
|
|
|
146
120
|
const handleUnblock = useCallback(async (userId: string) => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
console.error('Failed to unblock user:', error);
|
|
157
|
-
toast.error(t('privacySettings.unblockError') || 'Failed to unblock user');
|
|
158
|
-
}
|
|
159
|
-
}, [oxyServices, t]);
|
|
121
|
+
unblockUserMutation.mutate(userId, {
|
|
122
|
+
onSuccess: () => {
|
|
123
|
+
toast.success(t('privacySettings.userUnblocked') || 'User unblocked');
|
|
124
|
+
},
|
|
125
|
+
onError: () => {
|
|
126
|
+
toast.error(t('privacySettings.unblockError') || 'Failed to unblock user');
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}, [unblockUserMutation, t]);
|
|
160
130
|
|
|
161
131
|
const handleUnrestrict = useCallback(async (userId: string) => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
console.error('Failed to unrestrict user:', error);
|
|
172
|
-
toast.error(t('privacySettings.unrestrictError') || 'Failed to unrestrict user');
|
|
173
|
-
}
|
|
174
|
-
}, [oxyServices, t]);
|
|
132
|
+
unrestrictUserMutation.mutate(userId, {
|
|
133
|
+
onSuccess: () => {
|
|
134
|
+
toast.success(t('privacySettings.userUnrestricted') || 'User unrestricted');
|
|
135
|
+
},
|
|
136
|
+
onError: () => {
|
|
137
|
+
toast.error(t('privacySettings.unrestrictError') || 'Failed to unrestrict user');
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}, [unrestrictUserMutation, t]);
|
|
175
141
|
|
|
176
142
|
// Helper to extract user info from blocked/restricted objects
|
|
177
143
|
const extractUserInfo = useCallback((
|
|
@@ -7,14 +7,16 @@ interface DeviceSession {
|
|
|
7
7
|
deviceName?: string;
|
|
8
8
|
expiresAt?: string;
|
|
9
9
|
lastActive?: string;
|
|
10
|
-
user?: { id?: string; _id?: { toString(): string } };
|
|
10
|
+
user?: { id?: string; publicKey?: string; _id?: { toString(): string } };
|
|
11
11
|
userId?: string;
|
|
12
|
+
publicKey?: string;
|
|
12
13
|
isCurrent?: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface FetchSessionsWithFallbackOptions {
|
|
16
17
|
fallbackDeviceId?: string;
|
|
17
18
|
fallbackUserId?: string;
|
|
19
|
+
fallbackPublicKey?: string; // Canonical user identity
|
|
18
20
|
logger?: (message: string, error?: unknown) => void;
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -37,27 +39,41 @@ export interface SessionValidationResult {
|
|
|
37
39
|
* @param sessions - Raw session array returned from the API
|
|
38
40
|
* @param fallbackDeviceId - Device identifier to use when missing from payload
|
|
39
41
|
* @param fallbackUserId - User identifier to use when missing from payload
|
|
42
|
+
* @param fallbackPublicKey - Public key to use when missing from payload (canonical identity)
|
|
40
43
|
*/
|
|
41
44
|
export const mapSessionsToClient = (
|
|
42
45
|
sessions: DeviceSession[],
|
|
43
46
|
fallbackDeviceId?: string,
|
|
44
47
|
fallbackUserId?: string,
|
|
48
|
+
fallbackPublicKey?: string,
|
|
45
49
|
): ClientSession[] => {
|
|
46
50
|
const now = new Date();
|
|
47
51
|
|
|
48
|
-
return sessions.map((session) =>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
session.
|
|
52
|
+
return sessions.map((session) => {
|
|
53
|
+
// publicKey is the canonical user identity (user.id now equals publicKey)
|
|
54
|
+
// Extract from user.id (which is now publicKey), user.publicKey, or session.publicKey
|
|
55
|
+
const publicKey =
|
|
56
|
+
session.user?.id || // user.id is now publicKey (canonical identifier)
|
|
57
|
+
session.user?.publicKey ||
|
|
58
|
+
session.publicKey ||
|
|
59
|
+
fallbackPublicKey ||
|
|
60
|
+
'';
|
|
61
|
+
|
|
62
|
+
// userId is MongoDB ObjectId (internal backend reference, optional)
|
|
63
|
+
const userId =
|
|
55
64
|
session.userId ||
|
|
56
|
-
(session.user?._id ? session.user._id.toString() : undefined)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
(session.user?._id ? session.user._id.toString() : undefined);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
sessionId: session.sessionId,
|
|
69
|
+
deviceId: session.deviceId || fallbackDeviceId || '',
|
|
70
|
+
expiresAt: session.expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
71
|
+
lastActive: session.lastActive || now.toISOString(),
|
|
72
|
+
publicKey, // Canonical user identity - REQUIRED
|
|
73
|
+
userId, // MongoDB ObjectId (optional, for backward compatibility)
|
|
74
|
+
isCurrent: Boolean(session.isCurrent),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
61
77
|
};
|
|
62
78
|
|
|
63
79
|
/**
|
|
@@ -73,19 +89,20 @@ export const fetchSessionsWithFallback = async (
|
|
|
73
89
|
{
|
|
74
90
|
fallbackDeviceId,
|
|
75
91
|
fallbackUserId,
|
|
92
|
+
fallbackPublicKey,
|
|
76
93
|
logger,
|
|
77
94
|
}: FetchSessionsWithFallbackOptions = {},
|
|
78
95
|
): Promise<ClientSession[]> => {
|
|
79
96
|
try {
|
|
80
97
|
const deviceSessions = await oxyServices.getDeviceSessions(sessionId);
|
|
81
|
-
return mapSessionsToClient(deviceSessions, fallbackDeviceId, fallbackUserId);
|
|
98
|
+
return mapSessionsToClient(deviceSessions, fallbackDeviceId, fallbackUserId, fallbackPublicKey);
|
|
82
99
|
} catch (error) {
|
|
83
100
|
if (__DEV__ && logger) {
|
|
84
101
|
logger('Failed to get device sessions, falling back to user sessions', error);
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
const userSessions = await oxyServices.getSessionsBySessionId(sessionId);
|
|
88
|
-
return mapSessionsToClient(userSessions, fallbackDeviceId, fallbackUserId);
|
|
105
|
+
return mapSessionsToClient(userSessions, fallbackDeviceId, fallbackUserId, fallbackPublicKey);
|
|
89
106
|
}
|
|
90
107
|
};
|
|
91
108
|
|
|
@@ -12,12 +12,19 @@ import type { ClientSession } from '../models/session';
|
|
|
12
12
|
*/
|
|
13
13
|
export function normalizeSession(session: Partial<ClientSession> & { sessionId: string }): ClientSession {
|
|
14
14
|
const now = new Date().toISOString();
|
|
15
|
+
|
|
16
|
+
// publicKey is required (canonical user identity)
|
|
17
|
+
if (!session.publicKey) {
|
|
18
|
+
throw new Error(`Session ${session.sessionId} is missing required publicKey field`);
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
return {
|
|
16
22
|
sessionId: session.sessionId,
|
|
17
23
|
deviceId: session.deviceId || '',
|
|
18
24
|
expiresAt: session.expiresAt || now,
|
|
19
25
|
lastActive: session.lastActive || now,
|
|
20
|
-
|
|
26
|
+
publicKey: session.publicKey, // Canonical user identity - required
|
|
27
|
+
userId: session.userId, // Optional MongoDB ObjectId for backward compatibility
|
|
21
28
|
};
|
|
22
29
|
}
|
|
23
30
|
|