@oxyhq/services 10.2.10 → 10.3.0
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/index.js.map +1 -1
- package/lib/commonjs/ui/components/ActingAsBanner.js +2 -1
- package/lib/commonjs/ui/components/ActingAsBanner.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +107 -1
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +19 -10
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +38 -122
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +9 -7
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js +20 -25
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.js +7 -0
- package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.types.js +4 -0
- package/lib/commonjs/ui/hooks/useProfileEditing.js +19 -10
- package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +1 -2
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +1 -2
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +11 -13
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +2 -3
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HelpSupportScreen.js +2 -2
- package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +2 -2
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +2 -3
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +2 -2
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +1 -2
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/NotificationsScreen.js +2 -2
- package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +2 -2
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +2 -2
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +4 -3
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +3 -4
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +2 -2
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js +2 -2
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +2 -2
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/stores/followStore.js +68 -0
- package/lib/commonjs/ui/stores/followStore.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/ActingAsBanner.js +2 -1
- package/lib/module/ui/components/ActingAsBanner.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +109 -3
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +19 -10
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +38 -122
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +9 -7
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceAccounts.js +20 -25
- package/lib/module/ui/hooks/useDeviceAccounts.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.js +7 -0
- package/lib/module/ui/hooks/useFollow.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.types.js +2 -0
- package/lib/module/ui/hooks/useProfileEditing.js +19 -10
- package/lib/module/ui/hooks/useProfileEditing.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +10 -11
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/NotificationsScreen.js +1 -1
- package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +5 -4
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +2 -3
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustFAQScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/stores/followStore.js +68 -0
- package/lib/module/ui/stores/followStore.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +1 -1
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +24 -4
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/StepBasedScreen.d.ts +5 -3
- package/lib/typescript/commonjs/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +52 -6
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts +3 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.types.d.ts +2 -0
- package/lib/typescript/commonjs/ui/hooks/useFollow.types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useProfileEditing.d.ts +22 -18
- package/lib/typescript/commonjs/ui/hooks/useProfileEditing.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/authStore.d.ts +2 -10
- package/lib/typescript/commonjs/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/followStore.d.ts +2 -1
- package/lib/typescript/commonjs/ui/stores/followStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +0 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts +2 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ActingAsBanner.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowButton.d.ts +24 -4
- package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/StepBasedScreen.d.ts +5 -3
- package/lib/typescript/module/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +52 -6
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useFollow.d.ts +3 -1
- package/lib/typescript/module/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useFollow.types.d.ts +2 -0
- package/lib/typescript/module/ui/hooks/useFollow.types.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useProfileEditing.d.ts +22 -18
- package/lib/typescript/module/ui/hooks/useProfileEditing.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/authStore.d.ts +2 -10
- package/lib/typescript/module/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/followStore.d.ts +2 -1
- package/lib/typescript/module/ui/stores/followStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +0 -1
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts +2 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +1 -0
- package/src/ui/components/ActingAsBanner.tsx +2 -4
- package/src/ui/components/FollowButton.tsx +154 -10
- package/src/ui/components/StepBasedScreen.tsx +37 -22
- package/src/ui/context/hooks/useAuthOperations.ts +51 -144
- package/src/ui/hooks/mutations/useAccountMutations.ts +9 -8
- package/src/ui/hooks/useDeviceAccounts.ts +20 -24
- package/src/ui/hooks/useFollow.ts +8 -1
- package/src/ui/hooks/useFollow.types.ts +3 -0
- package/src/ui/hooks/useProfileEditing.ts +43 -30
- package/src/ui/screens/AppInfoScreen.tsx +1 -1
- package/src/ui/screens/ConnectedAppsScreen.tsx +1 -1
- package/src/ui/screens/EditProfileFieldScreen.tsx +24 -14
- package/src/ui/screens/FeedbackScreen.tsx +1 -1
- package/src/ui/screens/HelpSupportScreen.tsx +1 -1
- package/src/ui/screens/HistoryViewScreen.tsx +1 -1
- package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
- package/src/ui/screens/LegalDocumentsScreen.tsx +1 -1
- package/src/ui/screens/ManageAccountScreen.tsx +1 -1
- package/src/ui/screens/NotificationsScreen.tsx +1 -1
- package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
- package/src/ui/screens/PreferencesScreen.tsx +1 -1
- package/src/ui/screens/ProfileScreen.tsx +4 -4
- package/src/ui/screens/SavesCollectionsScreen.tsx +3 -6
- package/src/ui/screens/trust/TrustCenterScreen.tsx +1 -1
- package/src/ui/screens/trust/TrustFAQScreen.tsx +1 -1
- package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
- package/src/ui/stores/authStore.ts +4 -13
- package/src/ui/stores/followStore.ts +47 -1
- package/src/ui/types/navigation.ts +0 -4
- package/src/ui/utils/avatarUtils.ts +3 -2
- package/lib/commonjs/ui/styles/spacing.js +0 -68
- package/lib/commonjs/ui/styles/spacing.js.map +0 -1
- package/lib/commonjs/ui/utils/themeUtils.js +0 -37
- package/lib/commonjs/ui/utils/themeUtils.js.map +0 -1
- package/lib/module/ui/styles/spacing.js +0 -16
- package/lib/module/ui/styles/spacing.js.map +0 -1
- package/lib/module/ui/utils/themeUtils.js +0 -13
- package/lib/module/ui/utils/themeUtils.js.map +0 -1
- package/lib/typescript/commonjs/ui/styles/spacing.d.ts +0 -13
- package/lib/typescript/commonjs/ui/styles/spacing.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/utils/themeUtils.d.ts +0 -11
- package/lib/typescript/commonjs/ui/utils/themeUtils.d.ts.map +0 -1
- package/lib/typescript/module/ui/styles/spacing.d.ts +0 -13
- package/lib/typescript/module/ui/styles/spacing.d.ts.map +0 -1
- package/lib/typescript/module/ui/utils/themeUtils.d.ts +0 -11
- package/lib/typescript/module/ui/utils/themeUtils.d.ts.map +0 -1
- package/src/ui/styles/spacing.ts +0 -22
- package/src/ui/utils/themeUtils.ts +0 -18
|
@@ -1,38 +1,51 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
import { useI18n } from './useI18n';
|
|
3
2
|
import { useUpdateProfile } from './mutations/useAccountMutations';
|
|
4
3
|
import { useAuthStore } from '../stores/authStore';
|
|
4
|
+
import type { UserProfileUpdate } from '@oxyhq/contracts';
|
|
5
|
+
|
|
6
|
+
interface ProfileLocation {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
coordinates?: { lat: number; lon: number };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ProfileLinkMetadata {
|
|
14
|
+
url: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
image?: string;
|
|
18
|
+
id: string;
|
|
19
|
+
}
|
|
5
20
|
|
|
6
21
|
export interface ProfileUpdateData {
|
|
7
|
-
|
|
22
|
+
firstName?: string;
|
|
8
23
|
lastName?: string;
|
|
9
24
|
username?: string;
|
|
10
25
|
email?: string;
|
|
11
26
|
bio?: string;
|
|
12
27
|
location?: string;
|
|
13
|
-
locations?:
|
|
14
|
-
id: string;
|
|
15
|
-
name: string;
|
|
16
|
-
label?: string;
|
|
17
|
-
coordinates?: { lat: number; lon: number };
|
|
18
|
-
}>;
|
|
28
|
+
locations?: ProfileLocation[];
|
|
19
29
|
links?: string[];
|
|
20
|
-
linksMetadata?:
|
|
21
|
-
url: string;
|
|
22
|
-
title?: string;
|
|
23
|
-
description?: string;
|
|
24
|
-
image?: string;
|
|
25
|
-
id: string;
|
|
26
|
-
}>;
|
|
30
|
+
linksMetadata?: ProfileLinkMetadata[];
|
|
27
31
|
avatar?: string;
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
type ProfileFieldValue = string | ProfileLocation[] | ProfileLinkMetadata[];
|
|
35
|
+
|
|
36
|
+
function isProfileLocationArray(value: ProfileFieldValue): value is ProfileLocation[] {
|
|
37
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'object' && item !== null && 'name' in item);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isProfileLinkMetadataArray(value: ProfileFieldValue): value is ProfileLinkMetadata[] {
|
|
41
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'object' && item !== null && 'url' in item);
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
/**
|
|
31
45
|
* Hook for managing profile editing operations
|
|
32
46
|
* Provides functions to update profile fields and handle saving
|
|
33
47
|
*/
|
|
34
48
|
export const useProfileEditing = () => {
|
|
35
|
-
const { t } = useI18n();
|
|
36
49
|
const updateProfileMutation = useUpdateProfile();
|
|
37
50
|
|
|
38
51
|
/**
|
|
@@ -40,7 +53,7 @@ export const useProfileEditing = () => {
|
|
|
40
53
|
*/
|
|
41
54
|
const saveProfile = useCallback(async (updates: ProfileUpdateData) => {
|
|
42
55
|
// Prepare update object
|
|
43
|
-
const updateData:
|
|
56
|
+
const updateData: UserProfileUpdate = {};
|
|
44
57
|
|
|
45
58
|
if (updates.username !== undefined) {
|
|
46
59
|
updateData.username = updates.username;
|
|
@@ -70,11 +83,11 @@ export const useProfileEditing = () => {
|
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
// Handle name field
|
|
73
|
-
if (updates.
|
|
86
|
+
if (updates.firstName !== undefined || updates.lastName !== undefined) {
|
|
74
87
|
const currentUser = useAuthStore.getState().user;
|
|
75
88
|
const currentName = currentUser?.name;
|
|
76
89
|
updateData.name = {
|
|
77
|
-
first: updates.
|
|
90
|
+
first: updates.firstName ?? (typeof currentName === 'object' ? currentName?.first : '') ?? '',
|
|
78
91
|
last: updates.lastName ?? (typeof currentName === 'object' ? currentName?.last : '') ?? '',
|
|
79
92
|
};
|
|
80
93
|
}
|
|
@@ -86,33 +99,39 @@ export const useProfileEditing = () => {
|
|
|
86
99
|
// Error toast is handled by the mutation
|
|
87
100
|
return false;
|
|
88
101
|
}
|
|
89
|
-
}, [updateProfileMutation
|
|
102
|
+
}, [updateProfileMutation]);
|
|
90
103
|
|
|
91
104
|
/**
|
|
92
105
|
* Update a single profile field
|
|
93
106
|
*/
|
|
94
|
-
const updateField = useCallback(async (field: string, value:
|
|
107
|
+
const updateField = useCallback(async (field: string, value: ProfileFieldValue) => {
|
|
95
108
|
const updates: ProfileUpdateData = {};
|
|
96
109
|
|
|
97
110
|
switch (field) {
|
|
98
|
-
case '
|
|
99
|
-
|
|
111
|
+
case 'firstName':
|
|
112
|
+
if (typeof value !== 'string') return false;
|
|
113
|
+
updates.firstName = value;
|
|
100
114
|
break;
|
|
101
115
|
case 'username':
|
|
116
|
+
if (typeof value !== 'string') return false;
|
|
102
117
|
updates.username = value;
|
|
103
118
|
break;
|
|
104
119
|
case 'email':
|
|
120
|
+
if (typeof value !== 'string') return false;
|
|
105
121
|
updates.email = value;
|
|
106
122
|
break;
|
|
107
123
|
case 'bio':
|
|
124
|
+
if (typeof value !== 'string') return false;
|
|
108
125
|
updates.bio = value;
|
|
109
126
|
break;
|
|
110
127
|
case 'location':
|
|
128
|
+
if (!isProfileLocationArray(value)) return false;
|
|
111
129
|
updates.locations = value;
|
|
112
130
|
break;
|
|
113
131
|
case 'links':
|
|
132
|
+
if (!isProfileLinkMetadataArray(value)) return false;
|
|
114
133
|
updates.linksMetadata = value;
|
|
115
|
-
updates.links = value.map((link
|
|
134
|
+
updates.links = value.map((link) => link.url);
|
|
116
135
|
break;
|
|
117
136
|
default:
|
|
118
137
|
return false;
|
|
@@ -129,9 +148,3 @@ export const useProfileEditing = () => {
|
|
|
129
148
|
};
|
|
130
149
|
|
|
131
150
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
@@ -20,7 +20,7 @@ import { SettingsIcon } from '../components/SettingsIcon';
|
|
|
20
20
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
21
21
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
22
22
|
import { Colors } from '../constants/theme';
|
|
23
|
-
import { normalizeColorScheme } from '
|
|
23
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
24
24
|
import { useOxy } from '../context/OxyContext';
|
|
25
25
|
import { useI18n } from '../hooks/useI18n';
|
|
26
26
|
import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
|
|
@@ -15,7 +15,7 @@ import { useAuthorizedApps } from '../hooks/queries/useAccountQueries';
|
|
|
15
15
|
import { useRevokeAuthorizedApp } from '../hooks/mutations/useAccountMutations';
|
|
16
16
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
17
17
|
import { Colors } from '../constants/theme';
|
|
18
|
-
import { normalizeColorScheme, normalizeTheme } from '
|
|
18
|
+
import { normalizeColorScheme, normalizeTheme } from '@oxyhq/core';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Format an ISO-8601 timestamp as a human-readable relative time. Mirrors the
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { Ionicons } from '@expo/vector-icons';
|
|
15
15
|
import type { BaseScreenProps } from '../types/navigation';
|
|
16
16
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
17
|
-
import { normalizeTheme } from '
|
|
17
|
+
import { normalizeTheme } from '@oxyhq/core';
|
|
18
18
|
import Header from '../components/Header';
|
|
19
19
|
import { useI18n } from '../hooks/useI18n';
|
|
20
20
|
import { useOxy } from '../context/OxyContext';
|
|
@@ -59,6 +59,17 @@ interface EditProfileFieldScreenProps extends BaseScreenProps {
|
|
|
59
59
|
fieldType?: ProfileFieldType;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
type EditableListItem = {
|
|
63
|
+
id: string;
|
|
64
|
+
name?: string;
|
|
65
|
+
label?: string;
|
|
66
|
+
url?: string;
|
|
67
|
+
title?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
image?: string;
|
|
70
|
+
coordinates?: { lat: number; lon: number };
|
|
71
|
+
};
|
|
72
|
+
|
|
62
73
|
/**
|
|
63
74
|
* EditProfileFieldScreen - A dedicated screen for editing profile fields
|
|
64
75
|
*
|
|
@@ -84,7 +95,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
84
95
|
const [fieldErrors, setFieldErrors] = useState<Record<string, string | undefined>>({});
|
|
85
96
|
|
|
86
97
|
// State for list fields (locations, links)
|
|
87
|
-
const [listItems, setListItems] = useState<
|
|
98
|
+
const [listItems, setListItems] = useState<EditableListItem[]>([]);
|
|
88
99
|
const [newItemValue, setNewItemValue] = useState('');
|
|
89
100
|
|
|
90
101
|
// Get field configuration based on fieldType
|
|
@@ -96,7 +107,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
96
107
|
subtitle: t('editProfile.items.displayName.subtitle') || 'This is how your name will appear to others',
|
|
97
108
|
fields: [
|
|
98
109
|
{
|
|
99
|
-
key: '
|
|
110
|
+
key: 'firstName',
|
|
100
111
|
label: t('editProfile.items.displayName.firstName') || 'First Name',
|
|
101
112
|
placeholder: t('editProfile.items.displayName.firstNamePlaceholder') || 'Enter first name',
|
|
102
113
|
},
|
|
@@ -255,30 +266,29 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
255
266
|
|
|
256
267
|
if (fieldConfig.isList) {
|
|
257
268
|
if (fieldType === 'locations') {
|
|
258
|
-
const locations = Array.isArray(userData.locations) ? userData.locations
|
|
269
|
+
const locations = Array.isArray(userData.locations) ? userData.locations : [];
|
|
259
270
|
setListItems(locations.map((loc, i) => ({
|
|
260
271
|
id: String(loc.id || `location-${i}`),
|
|
261
272
|
name: String(loc.name || ''),
|
|
262
273
|
...loc,
|
|
263
274
|
})));
|
|
264
275
|
} else if (fieldType === 'links') {
|
|
265
|
-
const linksMetadata = Array.isArray(userData.linksMetadata) ? userData.linksMetadata
|
|
276
|
+
const linksMetadata = Array.isArray(userData.linksMetadata) ? userData.linksMetadata : [];
|
|
266
277
|
const links = Array.isArray(userData.links) ? userData.links : [];
|
|
267
278
|
// Use linksMetadata if available, otherwise convert links array
|
|
268
279
|
if (linksMetadata.length > 0) {
|
|
269
280
|
setListItems(linksMetadata.map((link, i) => ({
|
|
281
|
+
...link,
|
|
270
282
|
id: String(link.id || `link-${i}`),
|
|
271
|
-
url: String(link.url ||
|
|
283
|
+
url: String(link.url || ''),
|
|
272
284
|
title: String(link.title || ''),
|
|
273
|
-
...link,
|
|
274
285
|
})));
|
|
275
286
|
} else {
|
|
276
287
|
setListItems(links.map((item, i) => {
|
|
277
|
-
const url = typeof item === 'string' ? item : (item.link || '');
|
|
278
288
|
return {
|
|
279
289
|
id: `link-${i}`,
|
|
280
|
-
url,
|
|
281
|
-
title:
|
|
290
|
+
url: item,
|
|
291
|
+
title: item.replace(/^https?:\/\//, '').replace(/\/$/, ''),
|
|
282
292
|
};
|
|
283
293
|
}));
|
|
284
294
|
}
|
|
@@ -286,8 +296,8 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
286
296
|
} else {
|
|
287
297
|
const initialValues: Record<string, string> = {};
|
|
288
298
|
fieldConfig.fields.forEach(field => {
|
|
289
|
-
if (field.key === '
|
|
290
|
-
initialValues[field.key] = String(userData.
|
|
299
|
+
if (field.key === 'firstName') {
|
|
300
|
+
initialValues[field.key] = String(userData.name?.first || '');
|
|
291
301
|
} else if (field.key === 'lastName') {
|
|
292
302
|
initialValues[field.key] = String(userData.lastName || userData.name?.last || '');
|
|
293
303
|
} else if (field.key === 'birthday') {
|
|
@@ -390,7 +400,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
390
400
|
let success = false;
|
|
391
401
|
if (fieldType === 'displayName') {
|
|
392
402
|
success = await saveProfile({
|
|
393
|
-
|
|
403
|
+
firstName: fieldValues.firstName,
|
|
394
404
|
lastName: fieldValues.lastName,
|
|
395
405
|
});
|
|
396
406
|
} else {
|
|
@@ -496,7 +506,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
496
506
|
<Text style={[styles.listTitle, { color: bloomTheme.colors.text }]}>
|
|
497
507
|
{listTitle} ({listItems.length})
|
|
498
508
|
</Text>
|
|
499
|
-
{listItems.map((item
|
|
509
|
+
{listItems.map((item) => (
|
|
500
510
|
<View
|
|
501
511
|
key={item.id}
|
|
502
512
|
style={[
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from 'react-native';
|
|
14
14
|
import type { BaseScreenProps } from '../types/navigation';
|
|
15
15
|
import { useThemeColors } from '../styles/theme';
|
|
16
|
-
import { normalizeTheme } from '
|
|
16
|
+
import { normalizeTheme } from '@oxyhq/core';
|
|
17
17
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
18
18
|
import { Ionicons } from '@expo/vector-icons';
|
|
19
19
|
import { toast } from '@oxyhq/bloom';
|
|
@@ -13,7 +13,7 @@ import { useI18n } from '../hooks/useI18n';
|
|
|
13
13
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
14
14
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
15
15
|
import { Colors } from '../constants/theme';
|
|
16
|
-
import { normalizeColorScheme } from '
|
|
16
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
17
17
|
import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
|
|
18
18
|
|
|
19
19
|
const HelpSupportScreen: React.FC<BaseScreenProps> = ({
|
|
@@ -11,7 +11,7 @@ import { useI18n } from '../hooks/useI18n';
|
|
|
11
11
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
12
12
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
13
13
|
import { Colors } from '../constants/theme';
|
|
14
|
-
import { normalizeColorScheme } from '
|
|
14
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
15
15
|
import { useOxy } from '../context/OxyContext';
|
|
16
16
|
import { Dialog, useDialogControl } from '@oxyhq/bloom';
|
|
17
17
|
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
import type { BaseScreenProps } from '../types/navigation';
|
|
11
11
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
12
|
-
import { normalizeTheme } from '
|
|
12
|
+
import { normalizeTheme } from '@oxyhq/core';
|
|
13
13
|
import { Ionicons } from '@expo/vector-icons';
|
|
14
14
|
import { toast } from '@oxyhq/bloom';
|
|
15
15
|
import Header from '../components/Header';
|
|
@@ -15,7 +15,7 @@ import { useI18n } from '../hooks/useI18n';
|
|
|
15
15
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
16
16
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
17
17
|
import { Colors } from '../constants/theme';
|
|
18
|
-
import { normalizeColorScheme } from '
|
|
18
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
19
19
|
|
|
20
20
|
const LegalDocumentsScreen: React.FC<BaseScreenProps> = ({
|
|
21
21
|
onClose,
|
|
@@ -32,7 +32,7 @@ import { useUserSubscription } from '../hooks/queries/usePaymentQueries';
|
|
|
32
32
|
import { useDeviceSessions } from '../hooks/queries/useServicesQueries';
|
|
33
33
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
34
34
|
import { Colors } from '../constants/theme';
|
|
35
|
-
import { normalizeColorScheme, normalizeTheme } from '
|
|
35
|
+
import { normalizeColorScheme, normalizeTheme } from '@oxyhq/core';
|
|
36
36
|
import { screenContentStyle } from '../constants/spacing';
|
|
37
37
|
|
|
38
38
|
interface DeviceSessionRow {
|
|
@@ -14,7 +14,7 @@ import { useUpdateNotificationPreferences } from '../hooks/mutations/useAccountM
|
|
|
14
14
|
import { useSettingToggles } from '../hooks/useSettingToggle';
|
|
15
15
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
16
16
|
import { Colors } from '../constants/theme';
|
|
17
|
-
import { normalizeColorScheme, normalizeTheme } from '
|
|
17
|
+
import { normalizeColorScheme, normalizeTheme } from '@oxyhq/core';
|
|
18
18
|
|
|
19
19
|
interface NotificationToggleValues {
|
|
20
20
|
pushEnabled: boolean;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from 'react-native';
|
|
11
11
|
import type { BaseScreenProps } from '../types/navigation';
|
|
12
12
|
import { useThemeColors } from '../styles/theme';
|
|
13
|
-
import { normalizeTheme } from '
|
|
13
|
+
import { normalizeTheme } from '@oxyhq/core';
|
|
14
14
|
import { Button } from '@oxyhq/bloom/button';
|
|
15
15
|
import { Ionicons } from '@expo/vector-icons';
|
|
16
16
|
import { useI18n } from '../hooks/useI18n';
|
|
@@ -13,7 +13,7 @@ import { useCurrentUser } from '../hooks/queries/useAccountQueries';
|
|
|
13
13
|
import { useUpdateUserPreferences } from '../hooks/mutations/useAccountMutations';
|
|
14
14
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
15
15
|
import { Colors } from '../constants/theme';
|
|
16
|
-
import { normalizeColorScheme, normalizeTheme } from '
|
|
16
|
+
import { normalizeColorScheme, normalizeTheme } from '@oxyhq/core';
|
|
17
17
|
|
|
18
18
|
type ThemePreference = 'light' | 'dark' | 'system';
|
|
19
19
|
|
|
@@ -9,7 +9,7 @@ import { useFollow } from '../hooks/useFollow';
|
|
|
9
9
|
import { Ionicons } from '@expo/vector-icons';
|
|
10
10
|
import { useI18n } from '../hooks/useI18n';
|
|
11
11
|
import { useOxy } from '../context/OxyContext';
|
|
12
|
-
import { logger } from '@oxyhq/core';
|
|
12
|
+
import { getAccountDisplayName, logger } from '@oxyhq/core';
|
|
13
13
|
import type { User } from '@oxyhq/core';
|
|
14
14
|
import { extractErrorMessage } from '../utils/errorHandlers';
|
|
15
15
|
|
|
@@ -54,7 +54,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
54
54
|
|
|
55
55
|
const bloomTheme = useTheme();
|
|
56
56
|
const styles = createStyles();
|
|
57
|
-
const { t } = useI18n();
|
|
57
|
+
const { t, locale } = useI18n();
|
|
58
58
|
|
|
59
59
|
// Check if current user is viewing their own profile
|
|
60
60
|
// Normalize IDs by trimming whitespace to handle format mismatches
|
|
@@ -214,7 +214,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
214
214
|
<View style={styles.avatarWrapper} className="border-background bg-background">
|
|
215
215
|
<Avatar
|
|
216
216
|
uri={profile?.avatar ? oxyServices.getFileDownloadUrl(profile.avatar, 'thumb') : undefined}
|
|
217
|
-
name={profile
|
|
217
|
+
name={profile ? getAccountDisplayName(profile, locale) : username}
|
|
218
218
|
size={96}
|
|
219
219
|
|
|
220
220
|
/>
|
|
@@ -246,7 +246,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
246
246
|
{/* Profile Info */}
|
|
247
247
|
<View style={styles.header}>
|
|
248
248
|
<Text style={styles.displayName} className="text-foreground">
|
|
249
|
-
{
|
|
249
|
+
{profile ? getAccountDisplayName(profile, locale) : username || ''}
|
|
250
250
|
</Text>
|
|
251
251
|
{profile?.username && (
|
|
252
252
|
<Text style={styles.subText} className="text-muted-foreground">@{profile.username}</Text>
|
|
@@ -17,7 +17,7 @@ import { useI18n } from '../hooks/useI18n';
|
|
|
17
17
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
18
18
|
import { useColorScheme } from '../hooks/useColorScheme';
|
|
19
19
|
import { Colors } from '../constants/theme';
|
|
20
|
-
import { normalizeColorScheme } from '
|
|
20
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
21
21
|
import { useOxy } from '../context/OxyContext';
|
|
22
22
|
|
|
23
23
|
interface SavedItem {
|
|
@@ -25,7 +25,6 @@ interface SavedItem {
|
|
|
25
25
|
title: string;
|
|
26
26
|
type: 'post' | 'collection';
|
|
27
27
|
savedAt: Date;
|
|
28
|
-
url?: string;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
interface Collection {
|
|
@@ -67,14 +66,13 @@ const SavesCollectionsScreen: React.FC<BaseScreenProps> = ({
|
|
|
67
66
|
oxyServices.getSavedItems(user.id),
|
|
68
67
|
oxyServices.getCollections(user.id),
|
|
69
68
|
]);
|
|
70
|
-
setSavedItems(saved.map((item
|
|
69
|
+
setSavedItems(saved.map((item) => ({
|
|
71
70
|
id: item.id,
|
|
72
71
|
title: item.title,
|
|
73
72
|
type: item.itemType === 'post' ? 'post' : 'collection',
|
|
74
73
|
savedAt: new Date(item.createdAt),
|
|
75
|
-
url: item.url,
|
|
76
74
|
})));
|
|
77
|
-
setCollections(cols.map((col
|
|
75
|
+
setCollections(cols.map((col) => ({
|
|
78
76
|
id: col.id,
|
|
79
77
|
name: col.name,
|
|
80
78
|
description: col.description,
|
|
@@ -220,4 +218,3 @@ const styles = StyleSheet.create({
|
|
|
220
218
|
});
|
|
221
219
|
|
|
222
220
|
export default React.memo(SavesCollectionsScreen);
|
|
223
|
-
|
|
@@ -16,7 +16,7 @@ import { useI18n } from '../../hooks/useI18n';
|
|
|
16
16
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
17
17
|
import { useColorScheme } from '../../hooks/useColorScheme';
|
|
18
18
|
import { Colors } from '../../constants/theme';
|
|
19
|
-
import { normalizeColorScheme } from '
|
|
19
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
20
20
|
import { darkenColor } from '../../utils/colorUtils';
|
|
21
21
|
import { useOxy } from '../../context/OxyContext';
|
|
22
22
|
import { getTrustTierLabel } from './trustTier';
|
|
@@ -6,7 +6,7 @@ import Header from '../../components/Header';
|
|
|
6
6
|
import { SettingsListItem } from '@oxyhq/bloom/settings-list';
|
|
7
7
|
import { useI18n } from '../../hooks/useI18n';
|
|
8
8
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
9
|
-
import { normalizeColorScheme } from '
|
|
9
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
10
10
|
import { useColorScheme } from '../../hooks/useColorScheme';
|
|
11
11
|
import { Colors } from '../../constants/theme';
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ import Header from '../../components/Header';
|
|
|
6
6
|
import { Ionicons } from '@expo/vector-icons';
|
|
7
7
|
import { useI18n } from '../../hooks/useI18n';
|
|
8
8
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
9
|
-
import { normalizeColorScheme } from '
|
|
9
|
+
import { normalizeColorScheme } from '@oxyhq/core';
|
|
10
10
|
import { useColorScheme } from '../../hooks/useColorScheme';
|
|
11
11
|
import { Colors } from '../../constants/theme';
|
|
12
12
|
import { useOxy } from '../../context/OxyContext';
|
|
@@ -4,15 +4,6 @@ import type { User } from '@oxyhq/core';
|
|
|
4
4
|
|
|
5
5
|
const debug = createDebugLogger('AuthStore');
|
|
6
6
|
|
|
7
|
-
type LegacyUserIdentity = Partial<Omit<User, 'id' | 'publicKey' | 'username'>> & {
|
|
8
|
-
id?: string;
|
|
9
|
-
_id: string;
|
|
10
|
-
publicKey: string;
|
|
11
|
-
username: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
type AuthStoreUserInput = User | LegacyUserIdentity;
|
|
15
|
-
|
|
16
7
|
export interface AuthState {
|
|
17
8
|
user: User | null;
|
|
18
9
|
isAuthenticated: boolean;
|
|
@@ -20,11 +11,11 @@ export interface AuthState {
|
|
|
20
11
|
error: string | null;
|
|
21
12
|
lastUserFetch: number | null; // Timestamp of last user fetch for caching
|
|
22
13
|
|
|
23
|
-
loginSuccess: (user:
|
|
14
|
+
loginSuccess: (user: User) => void;
|
|
24
15
|
loginFailure: (error: string) => void;
|
|
25
16
|
logout: () => void;
|
|
26
17
|
fetchUser: (oxyServices: { getCurrentUser: () => Promise<User> }, forceRefresh?: boolean) => Promise<void>;
|
|
27
|
-
setUser: (user:
|
|
18
|
+
setUser: (user: User) => void; // Direct user setter for caching
|
|
28
19
|
}
|
|
29
20
|
|
|
30
21
|
export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>) => void, get: () => AuthState) => ({
|
|
@@ -34,7 +25,7 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
|
|
|
34
25
|
error: null,
|
|
35
26
|
lastUserFetch: null,
|
|
36
27
|
|
|
37
|
-
loginSuccess: (user:
|
|
28
|
+
loginSuccess: (user: User) => set({
|
|
38
29
|
isLoading: false,
|
|
39
30
|
isAuthenticated: true,
|
|
40
31
|
user: normalizeUserIdentity(user),
|
|
@@ -46,7 +37,7 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
|
|
|
46
37
|
isAuthenticated: false,
|
|
47
38
|
lastUserFetch: null,
|
|
48
39
|
}),
|
|
49
|
-
setUser: (user:
|
|
40
|
+
setUser: (user: User) => set({ user: normalizeUserIdentity(user), lastUserFetch: Date.now() }),
|
|
50
41
|
fetchUser: async (oxyServices, forceRefresh = false) => {
|
|
51
42
|
const state = get();
|
|
52
43
|
const now = Date.now();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
-
import type { OxyServices } from '@oxyhq/core';
|
|
2
|
+
import type { OxyServices, BulkFollowResult } from '@oxyhq/core';
|
|
3
3
|
|
|
4
4
|
interface FollowState {
|
|
5
5
|
followingUsers: Record<string, boolean>;
|
|
@@ -16,6 +16,8 @@ interface FollowState {
|
|
|
16
16
|
resetFollowState: () => void;
|
|
17
17
|
fetchFollowStatus: (userId: string, oxyServices: OxyServices) => Promise<void>;
|
|
18
18
|
toggleFollowUser: (userId: string, oxyServices: OxyServices, isCurrentlyFollowing: boolean) => Promise<void>;
|
|
19
|
+
// Bulk follow — follows MANY users in one network call; never unfollows.
|
|
20
|
+
followManyUsers: (userIds: string[], oxyServices: OxyServices) => Promise<BulkFollowResult>;
|
|
19
21
|
// New methods for follower counts
|
|
20
22
|
setFollowerCount: (userId: string, count: number) => void;
|
|
21
23
|
setFollowingCount: (userId: string, count: number) => void;
|
|
@@ -126,6 +128,50 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
|
|
|
126
128
|
}));
|
|
127
129
|
}
|
|
128
130
|
},
|
|
131
|
+
followManyUsers: async (userIds: string[], oxyServices: OxyServices): Promise<BulkFollowResult> => {
|
|
132
|
+
set((state: FollowState) => {
|
|
133
|
+
const loadingUsers = { ...state.loadingUsers };
|
|
134
|
+
const errors = { ...state.errors };
|
|
135
|
+
for (const uid of userIds) {
|
|
136
|
+
loadingUsers[uid] = true;
|
|
137
|
+
errors[uid] = null;
|
|
138
|
+
}
|
|
139
|
+
return { loadingUsers, errors };
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
const result = await oxyServices.followUsers(userIds);
|
|
143
|
+
set((state: FollowState) => {
|
|
144
|
+
const followingUsers = { ...state.followingUsers };
|
|
145
|
+
const loadingUsers = { ...state.loadingUsers };
|
|
146
|
+
const errors = { ...state.errors };
|
|
147
|
+
for (const uid of userIds) {
|
|
148
|
+
loadingUsers[uid] = false;
|
|
149
|
+
}
|
|
150
|
+
for (const entry of result.results) {
|
|
151
|
+
if (entry.success || entry.alreadyFollowing) {
|
|
152
|
+
followingUsers[entry.userId] = true;
|
|
153
|
+
errors[entry.userId] = null;
|
|
154
|
+
} else {
|
|
155
|
+
errors[entry.userId] = 'Failed to update follow status';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { followingUsers, loadingUsers, errors };
|
|
159
|
+
});
|
|
160
|
+
return result;
|
|
161
|
+
} catch (error: unknown) {
|
|
162
|
+
const message = (error instanceof Error ? error.message : null) || 'Failed to update follow status';
|
|
163
|
+
set((state: FollowState) => {
|
|
164
|
+
const loadingUsers = { ...state.loadingUsers };
|
|
165
|
+
const errors = { ...state.errors };
|
|
166
|
+
for (const uid of userIds) {
|
|
167
|
+
loadingUsers[uid] = false;
|
|
168
|
+
errors[uid] = message;
|
|
169
|
+
}
|
|
170
|
+
return { loadingUsers, errors };
|
|
171
|
+
});
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
129
175
|
setFollowerCount: (userId: string, count: number) => set((state: FollowState) => ({
|
|
130
176
|
followerCounts: { ...state.followerCounts, [userId]: count },
|
|
131
177
|
})),
|
|
@@ -4,9 +4,6 @@ import type { RouteName } from '../navigation/routes';
|
|
|
4
4
|
import type { User } from '@oxyhq/core';
|
|
5
5
|
import type { ClientSession } from '@oxyhq/core';
|
|
6
6
|
|
|
7
|
-
// Re-export RouteName from routes for convenience
|
|
8
|
-
export type { RouteName };
|
|
9
|
-
|
|
10
7
|
export interface StepController {
|
|
11
8
|
canGoBack: () => boolean;
|
|
12
9
|
goBack: () => void;
|
|
@@ -67,4 +64,3 @@ export interface OxyProviderProps {
|
|
|
67
64
|
authRedirectUri?: string;
|
|
68
65
|
queryClient?: QueryClient;
|
|
69
66
|
}
|
|
70
|
-
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { authenticatedApiCall } from '@oxyhq/core';
|
|
2
2
|
import type { OxyServices, User } from '@oxyhq/core';
|
|
3
|
+
import type { UserProfileUpdate } from '@oxyhq/contracts';
|
|
3
4
|
import { useAccountStore } from '../stores/accountStore';
|
|
4
5
|
import { useAuthStore } from '../stores/authStore';
|
|
5
6
|
import type { QueryClient } from '@tanstack/react-query';
|
|
@@ -37,7 +38,7 @@ export function refreshAvatarInStore(
|
|
|
37
38
|
* @returns Promise that resolves with updated user data
|
|
38
39
|
*/
|
|
39
40
|
export async function updateProfileWithAvatar(
|
|
40
|
-
updates:
|
|
41
|
+
updates: UserProfileUpdate,
|
|
41
42
|
oxyServices: OxyServices,
|
|
42
43
|
activeSessionId: string | null,
|
|
43
44
|
queryClient: QueryClient,
|
|
@@ -60,7 +61,7 @@ export async function updateProfileWithAvatar(
|
|
|
60
61
|
useAuthStore.getState().setUser(data);
|
|
61
62
|
|
|
62
63
|
// If avatar was updated, refresh accountStore with cache-busted URL
|
|
63
|
-
if (updates.avatar && activeSessionId) {
|
|
64
|
+
if (typeof updates.avatar === 'string' && activeSessionId) {
|
|
64
65
|
refreshAvatarInStore(activeSessionId, updates.avatar, oxyServices);
|
|
65
66
|
}
|
|
66
67
|
|