@oxyhq/services 5.13.29 → 5.13.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/ui/context/OxyContext.js +62 -4
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +66 -17
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +150 -13
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +62 -4
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +66 -17
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +150 -13
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionSocket.d.ts +3 -1
- package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +1 -0
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ui/context/OxyContext.tsx +71 -3
- package/src/ui/hooks/useSessionSocket.ts +66 -17
- package/src/ui/screens/AccountSettingsScreen.tsx +158 -18
|
@@ -30,7 +30,8 @@ const AccountSettingsScreen = ({
|
|
|
30
30
|
theme,
|
|
31
31
|
goBack,
|
|
32
32
|
navigate,
|
|
33
|
-
initialField
|
|
33
|
+
initialField,
|
|
34
|
+
initialSection
|
|
34
35
|
}) => {
|
|
35
36
|
const {
|
|
36
37
|
user: userFromContext,
|
|
@@ -54,6 +55,20 @@ const AccountSettingsScreen = ({
|
|
|
54
55
|
const avatarSectionRef = (0, _react.useRef)(null);
|
|
55
56
|
const [avatarSectionY, setAvatarSectionY] = (0, _react.useState)(null);
|
|
56
57
|
|
|
58
|
+
// Section refs for navigation
|
|
59
|
+
const profilePictureSectionRef = (0, _react.useRef)(null);
|
|
60
|
+
const basicInfoSectionRef = (0, _react.useRef)(null);
|
|
61
|
+
const aboutSectionRef = (0, _react.useRef)(null);
|
|
62
|
+
const quickActionsSectionRef = (0, _react.useRef)(null);
|
|
63
|
+
const securitySectionRef = (0, _react.useRef)(null);
|
|
64
|
+
|
|
65
|
+
// Section Y positions for scrolling
|
|
66
|
+
const [profilePictureSectionY, setProfilePictureSectionY] = (0, _react.useState)(null);
|
|
67
|
+
const [basicInfoSectionY, setBasicInfoSectionY] = (0, _react.useState)(null);
|
|
68
|
+
const [aboutSectionY, setAboutSectionY] = (0, _react.useState)(null);
|
|
69
|
+
const [quickActionsSectionY, setQuickActionsSectionY] = (0, _react.useState)(null);
|
|
70
|
+
const [securitySectionY, setSecuritySectionY] = (0, _react.useState)(null);
|
|
71
|
+
|
|
57
72
|
// Two-Factor (TOTP) state
|
|
58
73
|
const [totpSetupUrl, setTotpSetupUrl] = (0, _react.useState)(null);
|
|
59
74
|
const [totpCode, setTotpCode] = (0, _react.useState)('');
|
|
@@ -224,19 +239,67 @@ const AccountSettingsScreen = ({
|
|
|
224
239
|
// Use a ref to track if we've already set the initial field to avoid loops
|
|
225
240
|
const hasSetInitialFieldRef = (0, _react.useRef)(false);
|
|
226
241
|
const previousInitialFieldRef = (0, _react.useRef)(undefined);
|
|
242
|
+
const initialFieldTimeoutRef = (0, _react.useRef)(null);
|
|
243
|
+
|
|
244
|
+
// Delay constant for scroll completion
|
|
245
|
+
const SCROLL_DELAY_MS = 600;
|
|
246
|
+
|
|
247
|
+
// Helper to get current value for a field
|
|
248
|
+
const getFieldCurrentValue = (0, _react.useCallback)(field => {
|
|
249
|
+
switch (field) {
|
|
250
|
+
case 'displayName':
|
|
251
|
+
return displayName;
|
|
252
|
+
case 'username':
|
|
253
|
+
return username;
|
|
254
|
+
case 'email':
|
|
255
|
+
return email;
|
|
256
|
+
case 'bio':
|
|
257
|
+
return bio;
|
|
258
|
+
case 'location':
|
|
259
|
+
case 'links':
|
|
260
|
+
case 'twoFactor':
|
|
261
|
+
return '';
|
|
262
|
+
default:
|
|
263
|
+
return '';
|
|
264
|
+
}
|
|
265
|
+
}, [displayName, username, email, bio]);
|
|
266
|
+
|
|
267
|
+
// Handle initialSection prop to scroll to specific section
|
|
268
|
+
const hasScrolledToSectionRef = (0, _react.useRef)(false);
|
|
269
|
+
const previousInitialSectionRef = (0, _react.useRef)(undefined);
|
|
270
|
+
const SCROLL_OFFSET = 100; // Offset to show section near top of viewport
|
|
271
|
+
|
|
272
|
+
// Map section names to their Y positions
|
|
273
|
+
const sectionYPositions = (0, _react.useMemo)(() => ({
|
|
274
|
+
profilePicture: profilePictureSectionY,
|
|
275
|
+
basicInfo: basicInfoSectionY,
|
|
276
|
+
about: aboutSectionY,
|
|
277
|
+
quickActions: quickActionsSectionY,
|
|
278
|
+
security: securitySectionY
|
|
279
|
+
}), [profilePictureSectionY, basicInfoSectionY, aboutSectionY, quickActionsSectionY, securitySectionY]);
|
|
227
280
|
(0, _react.useEffect)(() => {
|
|
228
|
-
// If
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
|
|
281
|
+
// If initialSection changed, reset the flag
|
|
282
|
+
if (previousInitialSectionRef.current !== initialSection) {
|
|
283
|
+
hasScrolledToSectionRef.current = false;
|
|
284
|
+
previousInitialSectionRef.current = initialSection;
|
|
232
285
|
}
|
|
233
286
|
|
|
234
|
-
//
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
287
|
+
// Scroll to the specified section if initialSection is provided and we haven't scrolled yet
|
|
288
|
+
if (initialSection && !hasScrolledToSectionRef.current) {
|
|
289
|
+
const sectionY = sectionYPositions[initialSection];
|
|
290
|
+
if (sectionY !== null && sectionY !== undefined && scrollViewRef.current) {
|
|
291
|
+
requestAnimationFrame(() => {
|
|
292
|
+
requestAnimationFrame(() => {
|
|
293
|
+
scrollViewRef.current?.scrollTo({
|
|
294
|
+
y: Math.max(0, sectionY - SCROLL_OFFSET),
|
|
295
|
+
animated: true
|
|
296
|
+
});
|
|
297
|
+
hasScrolledToSectionRef.current = true;
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
}
|
|
238
301
|
}
|
|
239
|
-
}, [
|
|
302
|
+
}, [initialSection, sectionYPositions]);
|
|
240
303
|
const handleSave = async () => {
|
|
241
304
|
if (!user) return;
|
|
242
305
|
try {
|
|
@@ -381,7 +444,7 @@ const AccountSettingsScreen = ({
|
|
|
381
444
|
}
|
|
382
445
|
});
|
|
383
446
|
}, [showBottomSheet, oxyServices, avatarFileId, updateUser, user]);
|
|
384
|
-
const startEditing = (type, currentValue) => {
|
|
447
|
+
const startEditing = (0, _react.useCallback)((type, currentValue) => {
|
|
385
448
|
switch (type) {
|
|
386
449
|
case 'displayName':
|
|
387
450
|
setTempDisplayName(displayName);
|
|
@@ -410,7 +473,49 @@ const AccountSettingsScreen = ({
|
|
|
410
473
|
break;
|
|
411
474
|
}
|
|
412
475
|
setEditingField(type);
|
|
413
|
-
};
|
|
476
|
+
}, [displayName, lastName]);
|
|
477
|
+
|
|
478
|
+
// Handle initialField prop - must be after startEditing and openAvatarPicker are declared
|
|
479
|
+
(0, _react.useEffect)(() => {
|
|
480
|
+
// Clear any pending timeout
|
|
481
|
+
if (initialFieldTimeoutRef.current) {
|
|
482
|
+
clearTimeout(initialFieldTimeoutRef.current);
|
|
483
|
+
initialFieldTimeoutRef.current = null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// If initialField changed, reset the flag
|
|
487
|
+
if (previousInitialFieldRef.current !== initialField) {
|
|
488
|
+
hasSetInitialFieldRef.current = false;
|
|
489
|
+
previousInitialFieldRef.current = initialField;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Set the editing field if initialField is provided and we haven't set it yet
|
|
493
|
+
if (initialField && !hasSetInitialFieldRef.current) {
|
|
494
|
+
// Special handling for avatar - open avatar picker directly
|
|
495
|
+
if (initialField === 'avatar') {
|
|
496
|
+
// Wait for section to be scrolled, then open picker
|
|
497
|
+
initialFieldTimeoutRef.current = setTimeout(() => {
|
|
498
|
+
openAvatarPicker();
|
|
499
|
+
hasSetInitialFieldRef.current = true;
|
|
500
|
+
}, SCROLL_DELAY_MS);
|
|
501
|
+
} else {
|
|
502
|
+
// For other fields, get current value and start editing after scroll
|
|
503
|
+
const currentValue = getFieldCurrentValue(initialField);
|
|
504
|
+
|
|
505
|
+
// Wait for section to be scrolled, then start editing
|
|
506
|
+
initialFieldTimeoutRef.current = setTimeout(() => {
|
|
507
|
+
startEditing(initialField, currentValue);
|
|
508
|
+
hasSetInitialFieldRef.current = true;
|
|
509
|
+
}, SCROLL_DELAY_MS);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return () => {
|
|
513
|
+
if (initialFieldTimeoutRef.current) {
|
|
514
|
+
clearTimeout(initialFieldTimeoutRef.current);
|
|
515
|
+
initialFieldTimeoutRef.current = null;
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}, [initialField, getFieldCurrentValue, startEditing, openAvatarPicker]);
|
|
414
519
|
const saveField = type => {
|
|
415
520
|
animateSaveButton(0.95); // Scale down slightly for animation
|
|
416
521
|
|
|
@@ -1409,13 +1514,17 @@ const AccountSettingsScreen = ({
|
|
|
1409
1514
|
})]
|
|
1410
1515
|
})
|
|
1411
1516
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1412
|
-
ref:
|
|
1517
|
+
ref: ref => {
|
|
1518
|
+
avatarSectionRef.current = ref;
|
|
1519
|
+
profilePictureSectionRef.current = ref;
|
|
1520
|
+
},
|
|
1413
1521
|
style: styles.section,
|
|
1414
1522
|
onLayout: event => {
|
|
1415
1523
|
const {
|
|
1416
1524
|
y
|
|
1417
1525
|
} = event.nativeEvent.layout;
|
|
1418
1526
|
setAvatarSectionY(y);
|
|
1527
|
+
setProfilePictureSectionY(y);
|
|
1419
1528
|
},
|
|
1420
1529
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
1421
1530
|
style: [styles.sectionTitle, {
|
|
@@ -1482,7 +1591,14 @@ const AccountSettingsScreen = ({
|
|
|
1482
1591
|
})
|
|
1483
1592
|
})]
|
|
1484
1593
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1594
|
+
ref: basicInfoSectionRef,
|
|
1485
1595
|
style: styles.section,
|
|
1596
|
+
onLayout: event => {
|
|
1597
|
+
const {
|
|
1598
|
+
y
|
|
1599
|
+
} = event.nativeEvent.layout;
|
|
1600
|
+
setBasicInfoSectionY(y);
|
|
1601
|
+
},
|
|
1486
1602
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
1487
1603
|
style: [styles.sectionTitle, {
|
|
1488
1604
|
color: themeStyles.isDarkTheme ? '#8E8E93' : '#8E8E93'
|
|
@@ -1517,7 +1633,14 @@ const AccountSettingsScreen = ({
|
|
|
1517
1633
|
})
|
|
1518
1634
|
})]
|
|
1519
1635
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1636
|
+
ref: aboutSectionRef,
|
|
1520
1637
|
style: styles.section,
|
|
1638
|
+
onLayout: event => {
|
|
1639
|
+
const {
|
|
1640
|
+
y
|
|
1641
|
+
} = event.nativeEvent.layout;
|
|
1642
|
+
setAboutSectionY(y);
|
|
1643
|
+
},
|
|
1521
1644
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
1522
1645
|
style: [styles.sectionTitle, {
|
|
1523
1646
|
color: themeStyles.isDarkTheme ? '#8E8E93' : '#8E8E93'
|
|
@@ -1612,7 +1735,14 @@ const AccountSettingsScreen = ({
|
|
|
1612
1735
|
})
|
|
1613
1736
|
})]
|
|
1614
1737
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1738
|
+
ref: quickActionsSectionRef,
|
|
1615
1739
|
style: styles.section,
|
|
1740
|
+
onLayout: event => {
|
|
1741
|
+
const {
|
|
1742
|
+
y
|
|
1743
|
+
} = event.nativeEvent.layout;
|
|
1744
|
+
setQuickActionsSectionY(y);
|
|
1745
|
+
},
|
|
1616
1746
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
1617
1747
|
style: [styles.sectionTitle, {
|
|
1618
1748
|
color: themeStyles.isDarkTheme ? '#8E8E93' : '#8E8E93'
|
|
@@ -1649,7 +1779,14 @@ const AccountSettingsScreen = ({
|
|
|
1649
1779
|
})
|
|
1650
1780
|
})]
|
|
1651
1781
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1782
|
+
ref: securitySectionRef,
|
|
1652
1783
|
style: styles.section,
|
|
1784
|
+
onLayout: event => {
|
|
1785
|
+
const {
|
|
1786
|
+
y
|
|
1787
|
+
} = event.nativeEvent.layout;
|
|
1788
|
+
setSecuritySectionY(y);
|
|
1789
|
+
},
|
|
1653
1790
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
1654
1791
|
style: [styles.sectionTitle, {
|
|
1655
1792
|
color: themeStyles.isDarkTheme ? '#8E8E93' : '#8E8E93'
|