@oxyhq/services 19.2.0 → 20.0.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/ui/components/FollowButton.js +1 -2
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/SettingsIcon.js +1 -2
- package/lib/commonjs/ui/components/SettingsIcon.js.map +1 -1
- package/lib/commonjs/ui/components/logo/LogoIcon.js +0 -2
- package/lib/commonjs/ui/components/logo/LogoIcon.js.map +1 -1
- package/lib/commonjs/ui/components/logo/LogoText.js +0 -2
- package/lib/commonjs/ui/components/logo/LogoText.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +9 -8
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +1 -3
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/useLanguageManagement.js +109 -28
- package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +1 -3
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +151 -88
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +5 -6
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +1 -1
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/SettingsIcon.js +1 -1
- package/lib/module/ui/components/SettingsIcon.js.map +1 -1
- package/lib/module/ui/components/logo/LogoIcon.js +0 -1
- package/lib/module/ui/components/logo/LogoIcon.js.map +1 -1
- package/lib/module/ui/components/logo/LogoText.js +0 -1
- package/lib/module/ui/components/logo/LogoText.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +9 -8
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +1 -3
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/useLanguageManagement.js +107 -29
- package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +1 -3
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +153 -91
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +5 -6
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +1 -2
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +3 -0
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +2 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useLanguageManagement.d.ts +52 -8
- package/lib/typescript/commonjs/ui/hooks/useLanguageManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts +1 -2
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileListSection.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowButton.d.ts +2 -2
- package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyPayButton.d.ts +1 -1
- package/lib/typescript/module/ui/components/OxyPayButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/SettingsIcon.d.ts +1 -1
- package/lib/typescript/module/ui/components/SettingsIcon.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts +1 -1
- package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/logo/LogoText.d.ts +1 -1
- package/lib/typescript/module/ui/components/logo/LogoText.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +1 -2
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +3 -0
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +2 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useFollow.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts +52 -8
- package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +1 -2
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/FileListSection.d.ts +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/package.json +18 -17
- package/src/ui/components/FollowButton.tsx +6 -5
- package/src/ui/components/OxyPayButton.tsx +1 -1
- package/src/ui/components/SettingsIcon.tsx +2 -1
- package/src/ui/components/logo/LogoIcon.tsx +2 -1
- package/src/ui/components/logo/LogoText.tsx +2 -1
- package/src/ui/context/OxyContext.tsx +13 -11
- package/src/ui/context/hooks/useAuthOperations.ts +1 -5
- package/src/ui/context/oxyContextTypes.ts +3 -0
- package/src/ui/hooks/useFollow.ts +1 -1
- package/src/ui/hooks/useLanguageManagement.ts +144 -42
- package/src/ui/hooks/useSessionManagement.ts +1 -4
- package/src/ui/screens/FeedbackScreen.tsx +1 -1
- package/src/ui/screens/LanguageSelectorScreen.tsx +195 -104
- package/src/ui/screens/PreferencesScreen.tsx +4 -6
- package/src/ui/screens/fileManagement/FileListSection.tsx +1 -1
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFileUploadState.d.ts","sourceRoot":"","sources":["../../../../../../../src/ui/screens/fileManagement/hooks/useFileUploadState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"useFileUploadState.d.ts","sourceRoot":"","sources":["../../../../../../../src/ui/screens/fileManagement/hooks/useFileUploadState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAA8C,CAAC;AAElF,OAAO,EACH,KAAK,iBAAiB,EAQzB,MAAM,cAAW,CAAC;AAEnB,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;IACrD,iBAAiB,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACrD,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtF,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC;CACtE;AAED,mDAAmD;AACnD,MAAM,WAAW,wBAAwB;IACrC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,sKAchC,wBAAwB,KAAG,wBA4a7B,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -126,24 +126,16 @@
|
|
|
126
126
|
}
|
|
127
127
|
},
|
|
128
128
|
"dependencies": {
|
|
129
|
-
"@oxyhq/contracts": "0.
|
|
129
|
+
"@oxyhq/contracts": "0.14.0",
|
|
130
|
+
"@oxyhq/core": "^10.0.0",
|
|
130
131
|
"color": "^4.2.3"
|
|
131
132
|
},
|
|
132
133
|
"devDependencies": {
|
|
133
|
-
"@oxyhq/core": "9.2.4",
|
|
134
|
-
"nativewind": "5.0.0-preview.3",
|
|
135
|
-
"react-native-css": "^3.0.0",
|
|
136
|
-
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
137
|
-
"@types/react": "*",
|
|
138
|
-
"copyfiles": "^2.4.1",
|
|
139
|
-
"react-native-keyboard-controller": "1.21.13",
|
|
140
|
-
"react-native-qrcode-svg": "^6.3.0",
|
|
141
|
-
"socket.io-client": "^4.8.1",
|
|
142
|
-
"typescript": "^5.9.2",
|
|
143
|
-
"zustand": "^5.0.14",
|
|
144
134
|
"@biomejs/biome": "^1.9.4",
|
|
145
135
|
"@commitlint/cli": "^17.6.5",
|
|
146
136
|
"@commitlint/config-conventional": "^17.6.5",
|
|
137
|
+
"@oxyhq/core": "10.0.0",
|
|
138
|
+
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
147
139
|
"@react-native-community/netinfo": "^11.4.1",
|
|
148
140
|
"@react-native/babel-preset": "^0.86.0",
|
|
149
141
|
"@release-it/conventional-changelog": "^10.0.2",
|
|
@@ -155,6 +147,8 @@
|
|
|
155
147
|
"@types/color": "^4.2.1",
|
|
156
148
|
"@types/jest": "^29.5.14",
|
|
157
149
|
"@types/node": "^20.19.9",
|
|
150
|
+
"@types/react": "*",
|
|
151
|
+
"copyfiles": "^2.4.1",
|
|
158
152
|
"expo-file-system": "~57.0.0",
|
|
159
153
|
"expo-font": "~57.0.0",
|
|
160
154
|
"expo-haptics": "~57.0.0",
|
|
@@ -163,18 +157,25 @@
|
|
|
163
157
|
"husky": "^4.3.8",
|
|
164
158
|
"jest": "~29.7.0",
|
|
165
159
|
"lint-staged": "^15.2.4",
|
|
160
|
+
"nativewind": "5.0.0-preview.3",
|
|
166
161
|
"react-native-builder-bob": "^0.43.0",
|
|
162
|
+
"react-native-css": "^3.0.0",
|
|
167
163
|
"react-native-gesture-handler": "~2.32.0",
|
|
164
|
+
"react-native-keyboard-controller": "1.21.13",
|
|
165
|
+
"react-native-qrcode-svg": "^6.3.0",
|
|
168
166
|
"react-native-reanimated": "4.5.0",
|
|
169
167
|
"react-native-safe-area-context": "~5.8.0",
|
|
170
168
|
"react-native-svg": "15.15.5",
|
|
171
169
|
"release-it": "^19.0.6",
|
|
172
|
-
"
|
|
170
|
+
"socket.io-client": "^4.8.1",
|
|
171
|
+
"ts-jest": "^29.4.0",
|
|
172
|
+
"typescript": "^5.9.2",
|
|
173
|
+
"zustand": "^5.0.14"
|
|
173
174
|
},
|
|
174
175
|
"peerDependencies": {
|
|
175
176
|
"@expo/vector-icons": "^15.0.3",
|
|
176
177
|
"@oxyhq/bloom": ">=0.16.0",
|
|
177
|
-
"@oxyhq/core": "^
|
|
178
|
+
"@oxyhq/core": "^10.0.0",
|
|
178
179
|
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
179
180
|
"@react-native-community/netinfo": "^11.4.1",
|
|
180
181
|
"@tanstack/query-async-storage-persister": "^5.101",
|
|
@@ -192,6 +193,7 @@
|
|
|
192
193
|
"expo-image": ">=2.0.0",
|
|
193
194
|
"expo-image-manipulator": ">=56.0.0",
|
|
194
195
|
"expo-linear-gradient": ">=56.0.0",
|
|
196
|
+
"nativewind": ">=5.0.0",
|
|
195
197
|
"react": ">=18.0.0",
|
|
196
198
|
"react-native": ">=0.85.0",
|
|
197
199
|
"react-native-gesture-handler": "~2.32.0",
|
|
@@ -201,8 +203,7 @@
|
|
|
201
203
|
"react-native-safe-area-context": "~5.8.0",
|
|
202
204
|
"react-native-svg": ">=15.15.0",
|
|
203
205
|
"socket.io-client": "^4.8.0",
|
|
204
|
-
"zustand": "^5.0.0"
|
|
205
|
-
"nativewind": ">=5.0.0"
|
|
206
|
+
"zustand": "^5.0.0"
|
|
206
207
|
},
|
|
207
208
|
"peerDependenciesMeta": {
|
|
208
209
|
"nativewind": {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { useEffect, useCallback, useMemo, useState, memo } from 'react';
|
|
3
|
+
import type {
|
|
4
|
+
ViewStyle,
|
|
5
|
+
TextStyle,
|
|
6
|
+
StyleProp,
|
|
6
7
|
} from 'react-native';
|
|
7
8
|
import { useOxy } from '../context/OxyContext';
|
|
8
9
|
import { toast } from '@oxyhq/bloom';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { ViewStyle, TextStyle, StyleProp } from 'react-native';
|
|
3
3
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
4
4
|
import { Button } from '@oxyhq/bloom/button';
|
|
5
5
|
import type { PaymentItem, PaymentGatewayResult } from '../screens/PaymentGatewayScreen';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
2
3
|
import Svg, { ClipPath, Defs, G, Path } from 'react-native-svg';
|
|
3
4
|
import type { ViewStyle } from 'react-native';
|
|
4
5
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
2
3
|
import Svg, { G, Path } from 'react-native-svg';
|
|
3
4
|
import type { ViewStyle } from 'react-native';
|
|
4
5
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
@@ -56,11 +56,11 @@ import {
|
|
|
56
56
|
activeUserOf,
|
|
57
57
|
accountIdsOf,
|
|
58
58
|
} from '../session';
|
|
59
|
-
import {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
import type {
|
|
60
|
+
OxyContextState,
|
|
61
|
+
PasswordSignInResult,
|
|
62
|
+
OxyContextProviderProps,
|
|
63
|
+
CommitInput,
|
|
64
64
|
} from './oxyContextTypes';
|
|
65
65
|
import { DEFAULT_SESSION_VALIDITY_MS, loadUseFollowHook } from './oxyContextHelpers';
|
|
66
66
|
import { commitDeviceSetAndResolve } from './commitSessionFlow';
|
|
@@ -210,14 +210,15 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
210
210
|
|
|
211
211
|
const {
|
|
212
212
|
currentLanguage,
|
|
213
|
+
languages: currentLanguages,
|
|
213
214
|
metadata: currentLanguageMetadata,
|
|
214
215
|
languageName: currentLanguageName,
|
|
215
216
|
nativeLanguageName: currentNativeLanguageName,
|
|
216
217
|
setLanguage,
|
|
217
|
-
applyLanguagePreference,
|
|
218
218
|
} = useLanguageManagement({
|
|
219
219
|
storage,
|
|
220
220
|
languageKey: storageKeys.language,
|
|
221
|
+
user,
|
|
221
222
|
onError,
|
|
222
223
|
logger,
|
|
223
224
|
});
|
|
@@ -238,7 +239,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
238
239
|
storageKeyPrefix,
|
|
239
240
|
loginSuccess,
|
|
240
241
|
logoutStore,
|
|
241
|
-
applyLanguagePreference,
|
|
242
242
|
onAuthStateChange,
|
|
243
243
|
onError,
|
|
244
244
|
setAuthError: (message) => setAuthState({ error: message }),
|
|
@@ -376,7 +376,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
376
376
|
switchSession,
|
|
377
377
|
sessionClient,
|
|
378
378
|
syncFromClient,
|
|
379
|
-
applyLanguagePreference,
|
|
380
379
|
onAuthStateChange,
|
|
381
380
|
onError,
|
|
382
381
|
loginSuccess,
|
|
@@ -873,6 +872,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
873
872
|
isStorageReady: storage !== null,
|
|
874
873
|
error,
|
|
875
874
|
currentLanguage,
|
|
875
|
+
currentLanguages,
|
|
876
876
|
currentLanguageMetadata,
|
|
877
877
|
currentLanguageName,
|
|
878
878
|
currentNativeLanguageName,
|
|
@@ -924,6 +924,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
924
924
|
storage,
|
|
925
925
|
error,
|
|
926
926
|
currentLanguage,
|
|
927
|
+
currentLanguages,
|
|
927
928
|
currentLanguageMetadata,
|
|
928
929
|
currentLanguageName,
|
|
929
930
|
currentNativeLanguageName,
|
|
@@ -992,10 +993,11 @@ const LOADING_STATE: OxyContextState = {
|
|
|
992
993
|
isAuthResolved: false,
|
|
993
994
|
isStorageReady: false,
|
|
994
995
|
error: null,
|
|
995
|
-
currentLanguage: 'en',
|
|
996
|
+
currentLanguage: 'en-US',
|
|
997
|
+
currentLanguages: [],
|
|
996
998
|
currentLanguageMetadata: null,
|
|
997
|
-
currentLanguageName: 'English',
|
|
998
|
-
currentNativeLanguageName: 'English',
|
|
999
|
+
currentLanguageName: 'English (United States)',
|
|
1000
|
+
currentNativeLanguageName: 'English (United States)',
|
|
999
1001
|
hasIdentity: () => Promise.resolve(false),
|
|
1000
1002
|
getPublicKey: () => Promise.resolve(null),
|
|
1001
1003
|
signIn: () => rejectMissingProvider<User>(),
|
|
@@ -36,7 +36,6 @@ export interface UseAuthOperationsOptions {
|
|
|
36
36
|
sessionClient: SessionClient;
|
|
37
37
|
/** Reprojects `sessionClient.getState()` onto sessions/activeSessionId/user (Task 1's callback). Awaited after a partial `signOut` so the exposed state reflects the server truth before the call resolves. */
|
|
38
38
|
syncFromClient: () => Promise<void>;
|
|
39
|
-
applyLanguagePreference: (user: User) => Promise<void>;
|
|
40
39
|
onAuthStateChange?: (user: User | null) => void;
|
|
41
40
|
onError?: (error: ApiError) => void;
|
|
42
41
|
loginSuccess: (user: User) => void;
|
|
@@ -91,7 +90,6 @@ export const useAuthOperations = ({
|
|
|
91
90
|
switchSession,
|
|
92
91
|
sessionClient,
|
|
93
92
|
syncFromClient,
|
|
94
|
-
applyLanguagePreference,
|
|
95
93
|
onAuthStateChange,
|
|
96
94
|
onError,
|
|
97
95
|
loginSuccess,
|
|
@@ -219,14 +217,12 @@ export const useAuthOperations = ({
|
|
|
219
217
|
await saveActiveSessionId(sessionResponse.sessionId);
|
|
220
218
|
updateSessions(allDeviceSessions, { merge: true });
|
|
221
219
|
|
|
222
|
-
await applyLanguagePreference(fullUser);
|
|
223
220
|
loginSuccess(fullUser);
|
|
224
221
|
onAuthStateChange?.(fullUser);
|
|
225
|
-
|
|
222
|
+
|
|
226
223
|
return fullUser;
|
|
227
224
|
},
|
|
228
225
|
[
|
|
229
|
-
applyLanguagePreference,
|
|
230
226
|
logger,
|
|
231
227
|
loginSuccess,
|
|
232
228
|
onAuthStateChange,
|
|
@@ -28,7 +28,10 @@ export interface OxyContextState {
|
|
|
28
28
|
isAuthResolved: boolean;
|
|
29
29
|
isStorageReady: boolean;
|
|
30
30
|
error: string | null;
|
|
31
|
+
/** Active UI locale (`language-REGION`): the account's primary locale when signed in, else the guest/device locale. */
|
|
31
32
|
currentLanguage: string;
|
|
33
|
+
/** Ordered account locales (primary first) when signed in, or the single guest override when signed out. */
|
|
34
|
+
currentLanguages: string[];
|
|
32
35
|
currentLanguageMetadata: ReturnType<typeof useLanguageManagement>['metadata'];
|
|
33
36
|
currentLanguageName: string;
|
|
34
37
|
currentNativeLanguageName: string;
|
|
@@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react';
|
|
|
2
2
|
import { useQuery } from '@tanstack/react-query';
|
|
3
3
|
import { useFollowStore } from '../stores/followStore';
|
|
4
4
|
import { useOxy } from '../context/OxyContext';
|
|
5
|
-
import {
|
|
5
|
+
import type { OxyServices, BulkFollowResult, BulkUnfollowResult } from '@oxyhq/core';
|
|
6
6
|
import { useShallow } from 'zustand/react/shallow';
|
|
7
7
|
import { queryKeys } from './queries/queryKeys';
|
|
8
8
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import type { ApiError, User } from '@oxyhq/core';
|
|
2
|
+
import type { ApiError, User, SupportedLanguage } from '@oxyhq/core';
|
|
3
3
|
import {
|
|
4
|
+
FALLBACK_LOCALE,
|
|
5
|
+
SUPPORTED_LANGUAGES,
|
|
6
|
+
getBaseLanguage,
|
|
4
7
|
getLanguageMetadata,
|
|
5
8
|
getLanguageName,
|
|
6
9
|
getNativeLanguageName,
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
getPrimaryLanguage,
|
|
11
|
+
getUserLanguages,
|
|
12
|
+
normalizeLocale,
|
|
9
13
|
} from '@oxyhq/core';
|
|
10
14
|
import type { StorageInterface } from '../utils/storageHelpers';
|
|
11
15
|
import { extractErrorMessage } from '../utils/errorHandlers';
|
|
@@ -13,34 +17,143 @@ import { extractErrorMessage } from '../utils/errorHandlers';
|
|
|
13
17
|
export interface UseLanguageManagementOptions {
|
|
14
18
|
storage: StorageInterface | null;
|
|
15
19
|
languageKey: string;
|
|
20
|
+
/**
|
|
21
|
+
* The active account, when signed in. When present, the account's primary
|
|
22
|
+
* locale (`languages[0]`) is authoritative for the app's UI locale; when
|
|
23
|
+
* `null` the device locale (or a locally-chosen guest override) is used.
|
|
24
|
+
*/
|
|
25
|
+
user: User | null;
|
|
16
26
|
onError?: (error: ApiError) => void;
|
|
17
27
|
logger?: (message: string, error?: unknown) => void;
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
export interface UseLanguageManagementResult {
|
|
31
|
+
/**
|
|
32
|
+
* The active UI locale (a canonical `language-REGION` tag). Derived, never
|
|
33
|
+
* stored: the account's primary locale when signed in, otherwise the
|
|
34
|
+
* locally-chosen guest override, otherwise the device locale.
|
|
35
|
+
*/
|
|
21
36
|
currentLanguage: string;
|
|
22
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The ordered account locales (primary first) when signed in, or the single
|
|
39
|
+
* guest override when signed out. Empty only before the guest override loads
|
|
40
|
+
* and no device locale resolves.
|
|
41
|
+
*/
|
|
42
|
+
languages: string[];
|
|
43
|
+
metadata: SupportedLanguage | null;
|
|
23
44
|
languageName: string;
|
|
24
45
|
nativeLanguageName: string;
|
|
25
|
-
|
|
26
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Persist a single locally-owned locale (guest / device override) and mark it
|
|
48
|
+
* primary. For signed-in accounts, locale changes are written to the account
|
|
49
|
+
* (`updateProfile({ languages })`) instead — the derived `currentLanguage`
|
|
50
|
+
* then follows the refreshed `user`.
|
|
51
|
+
*/
|
|
52
|
+
setLanguage: (locale: string) => Promise<void>;
|
|
27
53
|
hydrateLanguage: () => Promise<void>;
|
|
28
54
|
}
|
|
29
55
|
|
|
30
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Append `locale` to an ordered locale list if not already present. Canonical
|
|
58
|
+
* order is preserved; the new locale lands last (non-primary).
|
|
59
|
+
*/
|
|
60
|
+
export function addLocale(languages: readonly string[], locale: string): string[] {
|
|
61
|
+
const canonical = normalizeLocale(locale);
|
|
62
|
+
if (!canonical) return [...languages];
|
|
63
|
+
if (languages.includes(canonical)) return [...languages];
|
|
64
|
+
return [...languages, canonical];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Remove `locale` from an ordered locale list. The list's new first element
|
|
69
|
+
* becomes the primary locale.
|
|
70
|
+
*/
|
|
71
|
+
export function removeLocale(languages: readonly string[], locale: string): string[] {
|
|
72
|
+
const canonical = normalizeLocale(locale);
|
|
73
|
+
if (!canonical) return [...languages];
|
|
74
|
+
return languages.filter((entry) => entry !== canonical);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Move `locale` to the front of an ordered locale list, making it primary.
|
|
79
|
+
* Adds it if it was not already present.
|
|
80
|
+
*/
|
|
81
|
+
export function setPrimaryLocale(languages: readonly string[], locale: string): string[] {
|
|
82
|
+
const canonical = normalizeLocale(locale);
|
|
83
|
+
if (!canonical) return [...languages];
|
|
84
|
+
return [canonical, ...languages.filter((entry) => entry !== canonical)];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the device/browser locale, mapped to a supported catalog locale.
|
|
89
|
+
*
|
|
90
|
+
* Reads the platform's ordered locale preferences (`navigator.languages` /
|
|
91
|
+
* `navigator.language` on web, `Intl.DateTimeFormat().resolvedOptions().locale`
|
|
92
|
+
* on Hermes) and returns the first that resolves to a supported locale —
|
|
93
|
+
* either exactly or by base-language match (`fr-BE` → `fr-FR`). Falls back to
|
|
94
|
+
* {@link FALLBACK_LOCALE} when nothing resolves. Pure and side-effect free.
|
|
95
|
+
*/
|
|
96
|
+
function resolveDeviceLocale(): string {
|
|
97
|
+
const candidates: string[] = [];
|
|
98
|
+
|
|
99
|
+
if (typeof navigator !== 'undefined') {
|
|
100
|
+
const nav = navigator as Navigator & { languages?: readonly string[] };
|
|
101
|
+
if (Array.isArray(nav.languages)) {
|
|
102
|
+
candidates.push(...nav.languages);
|
|
103
|
+
}
|
|
104
|
+
if (typeof nav.language === 'string') {
|
|
105
|
+
candidates.push(nav.language);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const intlLocale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
111
|
+
if (intlLocale) {
|
|
112
|
+
candidates.push(intlLocale);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
// Intl is unavailable or incomplete on this runtime — fall through to the
|
|
116
|
+
// navigator-provided candidates (or the fallback locale below).
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const candidate of candidates) {
|
|
120
|
+
const exact = normalizeLocale(candidate);
|
|
121
|
+
if (exact) return exact;
|
|
122
|
+
const base = getBaseLanguage(candidate);
|
|
123
|
+
const byBase = SUPPORTED_LANGUAGES.find((entry) => entry.language === base);
|
|
124
|
+
if (byBase) return byBase.code;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return FALLBACK_LOCALE;
|
|
128
|
+
}
|
|
31
129
|
|
|
32
130
|
/**
|
|
33
|
-
*
|
|
131
|
+
* Resolve and manage the app's active UI locale.
|
|
132
|
+
*
|
|
133
|
+
* The active locale is DERIVED, not stored:
|
|
134
|
+
* - Signed in → the account's primary locale (`getPrimaryLanguage(user)`),
|
|
135
|
+
* falling back to {@link FALLBACK_LOCALE}. This is what makes every Oxy app
|
|
136
|
+
* follow the account's language automatically.
|
|
137
|
+
* - Signed out → a locally-chosen guest override if one exists, otherwise the
|
|
138
|
+
* device locale.
|
|
34
139
|
*
|
|
35
|
-
*
|
|
140
|
+
* The only external system this hook synchronizes with is local storage (the
|
|
141
|
+
* guest override), which is loaded once on mount.
|
|
36
142
|
*/
|
|
37
143
|
export const useLanguageManagement = ({
|
|
38
144
|
storage,
|
|
39
145
|
languageKey,
|
|
146
|
+
user,
|
|
40
147
|
onError,
|
|
41
148
|
logger,
|
|
42
149
|
}: UseLanguageManagementOptions): UseLanguageManagementResult => {
|
|
43
|
-
|
|
150
|
+
// The device locale is fixed for the lifetime of the runtime.
|
|
151
|
+
const deviceLanguage = useMemo(resolveDeviceLocale, []);
|
|
152
|
+
|
|
153
|
+
// The locally-owned guest override (a single locale). `null` until loaded
|
|
154
|
+
// from storage or explicitly set; the derived locale falls back to the device
|
|
155
|
+
// locale while it is `null`.
|
|
156
|
+
const [guestLanguage, setGuestLanguage] = useState<string | null>(null);
|
|
44
157
|
|
|
45
158
|
const loadLanguageFromStorage = useCallback(async (): Promise<void> => {
|
|
46
159
|
if (!storage) {
|
|
@@ -49,9 +162,9 @@ export const useLanguageManagement = ({
|
|
|
49
162
|
|
|
50
163
|
try {
|
|
51
164
|
const savedLanguageRaw = await storage.getItem(languageKey);
|
|
52
|
-
const normalized =
|
|
165
|
+
const normalized = savedLanguageRaw ? normalizeLocale(savedLanguageRaw) : undefined;
|
|
53
166
|
if (normalized) {
|
|
54
|
-
|
|
167
|
+
setGuestLanguage(normalized);
|
|
55
168
|
}
|
|
56
169
|
} catch (error) {
|
|
57
170
|
const message = extractErrorMessage(error, 'Failed to load language preference');
|
|
@@ -77,16 +190,19 @@ export const useLanguageManagement = ({
|
|
|
77
190
|
}, [loadLanguageFromStorage, logger]);
|
|
78
191
|
|
|
79
192
|
const setLanguage = useCallback(
|
|
80
|
-
async (
|
|
193
|
+
async (locale: string): Promise<void> => {
|
|
81
194
|
if (!storage) {
|
|
82
195
|
throw new Error('Storage not initialized');
|
|
83
196
|
}
|
|
84
197
|
|
|
85
|
-
const normalized =
|
|
198
|
+
const normalized = normalizeLocale(locale);
|
|
199
|
+
if (!normalized) {
|
|
200
|
+
throw new Error(`Unsupported locale: ${locale}`);
|
|
201
|
+
}
|
|
86
202
|
|
|
87
203
|
try {
|
|
88
204
|
await storage.setItem(languageKey, normalized);
|
|
89
|
-
|
|
205
|
+
setGuestLanguage(normalized);
|
|
90
206
|
} catch (error) {
|
|
91
207
|
const message = extractErrorMessage(error, 'Failed to save language preference');
|
|
92
208
|
onError?.({
|
|
@@ -105,31 +221,19 @@ export const useLanguageManagement = ({
|
|
|
105
221
|
[languageKey, logger, onError, storage],
|
|
106
222
|
);
|
|
107
223
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const userLanguage = (user as Record<string, unknown>)?.language as string | undefined;
|
|
115
|
-
if (!userLanguage) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
224
|
+
const languages = useMemo<string[]>(() => {
|
|
225
|
+
if (user) {
|
|
226
|
+
return getUserLanguages(user);
|
|
227
|
+
}
|
|
228
|
+
return guestLanguage ? [guestLanguage] : [];
|
|
229
|
+
}, [user, guestLanguage]);
|
|
118
230
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
logger('Failed to apply server language preference', error);
|
|
126
|
-
} else if (__DEV__) {
|
|
127
|
-
console.warn('Failed to apply server language preference', error);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
[languageKey, logger, storage],
|
|
132
|
-
);
|
|
231
|
+
const currentLanguage = useMemo<string>(() => {
|
|
232
|
+
if (user) {
|
|
233
|
+
return getPrimaryLanguage(user) ?? FALLBACK_LOCALE;
|
|
234
|
+
}
|
|
235
|
+
return guestLanguage ?? deviceLanguage;
|
|
236
|
+
}, [user, guestLanguage, deviceLanguage]);
|
|
133
237
|
|
|
134
238
|
const metadata = useMemo(() => getLanguageMetadata(currentLanguage), [currentLanguage]);
|
|
135
239
|
const languageName = useMemo(() => getLanguageName(currentLanguage), [currentLanguage]);
|
|
@@ -140,13 +244,11 @@ export const useLanguageManagement = ({
|
|
|
140
244
|
|
|
141
245
|
return {
|
|
142
246
|
currentLanguage,
|
|
247
|
+
languages,
|
|
143
248
|
metadata,
|
|
144
249
|
languageName,
|
|
145
250
|
nativeLanguageName,
|
|
146
251
|
setLanguage,
|
|
147
|
-
applyLanguagePreference,
|
|
148
252
|
hydrateLanguage: loadLanguageFromStorage,
|
|
149
253
|
};
|
|
150
254
|
};
|
|
151
|
-
|
|
152
|
-
|
|
@@ -17,7 +17,6 @@ export interface UseSessionManagementOptions {
|
|
|
17
17
|
storageKeyPrefix?: string;
|
|
18
18
|
loginSuccess: (user: User) => void;
|
|
19
19
|
logoutStore: () => void;
|
|
20
|
-
applyLanguagePreference: (user: User) => Promise<void>;
|
|
21
20
|
onAuthStateChange?: (user: User | null) => void;
|
|
22
21
|
onError?: (error: ApiError) => void;
|
|
23
22
|
setAuthError?: (message: string | null) => void;
|
|
@@ -54,7 +53,6 @@ export const useSessionManagement = ({
|
|
|
54
53
|
storageKeyPrefix,
|
|
55
54
|
loginSuccess,
|
|
56
55
|
logoutStore,
|
|
57
|
-
applyLanguagePreference,
|
|
58
56
|
onAuthStateChange,
|
|
59
57
|
onError,
|
|
60
58
|
setAuthError,
|
|
@@ -207,10 +205,9 @@ export const useSessionManagement = ({
|
|
|
207
205
|
setActiveSessionId(sessionId);
|
|
208
206
|
loginSuccess(user);
|
|
209
207
|
await saveActiveSessionId(sessionId);
|
|
210
|
-
await applyLanguagePreference(user);
|
|
211
208
|
onAuthStateChange?.(user);
|
|
212
209
|
},
|
|
213
|
-
[
|
|
210
|
+
[loginSuccess, onAuthStateChange, saveActiveSessionId, setTokenReady],
|
|
214
211
|
);
|
|
215
212
|
|
|
216
213
|
const removalTimerIdsRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());
|
|
@@ -12,7 +12,7 @@ import type { BaseScreenProps } from '../types/navigation';
|
|
|
12
12
|
import { normalizeTheme } from '@oxyhq/core';
|
|
13
13
|
import { packageInfo } from '@oxyhq/core';
|
|
14
14
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
15
|
-
import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
|
|
15
|
+
import { Ionicons, type MaterialCommunityIcons } from '@expo/vector-icons';
|
|
16
16
|
import { toast } from '@oxyhq/bloom';
|
|
17
17
|
import { H2, Text } from '@oxyhq/bloom/typography';
|
|
18
18
|
import { Button } from '@oxyhq/bloom/button';
|