@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.
Files changed (118) hide show
  1. package/lib/commonjs/ui/components/FollowButton.js +1 -2
  2. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  3. package/lib/commonjs/ui/components/SettingsIcon.js +1 -2
  4. package/lib/commonjs/ui/components/SettingsIcon.js.map +1 -1
  5. package/lib/commonjs/ui/components/logo/LogoIcon.js +0 -2
  6. package/lib/commonjs/ui/components/logo/LogoIcon.js.map +1 -1
  7. package/lib/commonjs/ui/components/logo/LogoText.js +0 -2
  8. package/lib/commonjs/ui/components/logo/LogoText.js.map +1 -1
  9. package/lib/commonjs/ui/context/OxyContext.js +9 -8
  10. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  11. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +1 -3
  12. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  13. package/lib/commonjs/ui/hooks/useLanguageManagement.js +109 -28
  14. package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
  15. package/lib/commonjs/ui/hooks/useSessionManagement.js +1 -3
  16. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  17. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +151 -88
  18. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  19. package/lib/commonjs/ui/screens/PreferencesScreen.js +5 -6
  20. package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
  21. package/lib/module/ui/components/FollowButton.js +1 -1
  22. package/lib/module/ui/components/FollowButton.js.map +1 -1
  23. package/lib/module/ui/components/SettingsIcon.js +1 -1
  24. package/lib/module/ui/components/SettingsIcon.js.map +1 -1
  25. package/lib/module/ui/components/logo/LogoIcon.js +0 -1
  26. package/lib/module/ui/components/logo/LogoIcon.js.map +1 -1
  27. package/lib/module/ui/components/logo/LogoText.js +0 -1
  28. package/lib/module/ui/components/logo/LogoText.js.map +1 -1
  29. package/lib/module/ui/context/OxyContext.js +9 -8
  30. package/lib/module/ui/context/OxyContext.js.map +1 -1
  31. package/lib/module/ui/context/hooks/useAuthOperations.js +1 -3
  32. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  33. package/lib/module/ui/hooks/useLanguageManagement.js +107 -29
  34. package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
  35. package/lib/module/ui/hooks/useSessionManagement.js +1 -3
  36. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  37. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  38. package/lib/module/ui/screens/LanguageSelectorScreen.js +153 -91
  39. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  40. package/lib/module/ui/screens/PreferencesScreen.js +5 -6
  41. package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
  42. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +2 -2
  43. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts +1 -1
  45. package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts.map +1 -1
  46. package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts +1 -1
  47. package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts +1 -1
  49. package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts +1 -1
  51. package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +1 -1
  53. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +1 -2
  55. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +3 -0
  57. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +2 -1
  59. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts +1 -1
  61. package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/ui/hooks/useLanguageManagement.d.ts +52 -8
  63. package/lib/typescript/commonjs/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts +1 -2
  65. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/ui/screens/fileManagement/FileListSection.d.ts +1 -1
  69. package/lib/typescript/commonjs/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +1 -1
  71. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  72. package/lib/typescript/module/ui/components/FollowButton.d.ts +2 -2
  73. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  74. package/lib/typescript/module/ui/components/OxyPayButton.d.ts +1 -1
  75. package/lib/typescript/module/ui/components/OxyPayButton.d.ts.map +1 -1
  76. package/lib/typescript/module/ui/components/SettingsIcon.d.ts +1 -1
  77. package/lib/typescript/module/ui/components/SettingsIcon.d.ts.map +1 -1
  78. package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts +1 -1
  79. package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts.map +1 -1
  80. package/lib/typescript/module/ui/components/logo/LogoText.d.ts +1 -1
  81. package/lib/typescript/module/ui/components/logo/LogoText.d.ts.map +1 -1
  82. package/lib/typescript/module/ui/context/OxyContext.d.ts +1 -1
  83. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  84. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +1 -2
  85. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  86. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +3 -0
  87. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  88. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +2 -1
  89. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  90. package/lib/typescript/module/ui/hooks/useFollow.d.ts +1 -1
  91. package/lib/typescript/module/ui/hooks/useFollow.d.ts.map +1 -1
  92. package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts +52 -8
  93. package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  94. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +1 -2
  95. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  96. package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  97. package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
  98. package/lib/typescript/module/ui/screens/fileManagement/FileListSection.d.ts +1 -1
  99. package/lib/typescript/module/ui/screens/fileManagement/FileListSection.d.ts.map +1 -1
  100. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +1 -1
  101. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  102. package/package.json +18 -17
  103. package/src/ui/components/FollowButton.tsx +6 -5
  104. package/src/ui/components/OxyPayButton.tsx +1 -1
  105. package/src/ui/components/SettingsIcon.tsx +2 -1
  106. package/src/ui/components/logo/LogoIcon.tsx +2 -1
  107. package/src/ui/components/logo/LogoText.tsx +2 -1
  108. package/src/ui/context/OxyContext.tsx +13 -11
  109. package/src/ui/context/hooks/useAuthOperations.ts +1 -5
  110. package/src/ui/context/oxyContextTypes.ts +3 -0
  111. package/src/ui/hooks/useFollow.ts +1 -1
  112. package/src/ui/hooks/useLanguageManagement.ts +144 -42
  113. package/src/ui/hooks/useSessionManagement.ts +1 -4
  114. package/src/ui/screens/FeedbackScreen.tsx +1 -1
  115. package/src/ui/screens/LanguageSelectorScreen.tsx +195 -104
  116. package/src/ui/screens/PreferencesScreen.tsx +4 -6
  117. package/src/ui/screens/fileManagement/FileListSection.tsx +1 -1
  118. 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;AAE7E,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"}
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": "19.2.0",
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.13.2",
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
- "ts-jest": "^29.4.0"
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": "^9.2.3",
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, { useEffect, useCallback, useMemo, useState, memo } from 'react';
2
- import {
3
- type ViewStyle,
4
- type TextStyle,
5
- type StyleProp,
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 { type ViewStyle, type TextStyle, type StyleProp } from 'react-native';
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 React, { memo } from 'react';
1
+ import type React from 'react';
2
+ import { memo } from 'react';
2
3
  import { View, StyleSheet } from 'react-native';
3
4
  import { MaterialCommunityIcons } from '@expo/vector-icons';
4
5
  import { darkenColor } from '../utils/colorUtils';
@@ -1,4 +1,5 @@
1
- import React, { type ReactElement } from 'react';
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 React, { type ReactElement } from 'react';
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
- type OxyContextState,
61
- type PasswordSignInResult,
62
- type OxyContextProviderProps,
63
- type CommitInput,
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 { type OxyServices, type BulkFollowResult, type BulkUnfollowResult } from '@oxyhq/core';
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
- normalizeLanguageCode,
8
- type LanguageMetadata,
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
- metadata: LanguageMetadata | null;
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
- setLanguage: (languageId: string) => Promise<void>;
26
- applyLanguagePreference: (user: User | null) => Promise<void>;
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
- const DEFAULT_LANGUAGE = 'en-US';
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
- * Manage UI language state, persistence, and metadata derivation.
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
- * @param options - Configuration for storage access and error reporting
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
- const [currentLanguage, setCurrentLanguage] = useState<string>(DEFAULT_LANGUAGE);
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 = normalizeLanguageCode(savedLanguageRaw) || savedLanguageRaw;
165
+ const normalized = savedLanguageRaw ? normalizeLocale(savedLanguageRaw) : undefined;
53
166
  if (normalized) {
54
- setCurrentLanguage(normalized);
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 (languageId: string): Promise<void> => {
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 = normalizeLanguageCode(languageId) || languageId;
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
- setCurrentLanguage(normalized);
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 applyLanguagePreference = useCallback(
109
- async (user: User | null): Promise<void> => {
110
- if (!storage || !user) {
111
- return;
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
- try {
120
- const normalized = normalizeLanguageCode(userLanguage) || userLanguage;
121
- await storage.setItem(languageKey, normalized);
122
- setCurrentLanguage(normalized);
123
- } catch (error) {
124
- if (logger) {
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
- [applyLanguagePreference, loginSuccess, onAuthStateChange, saveActiveSessionId, setTokenReady],
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';