@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.
@@ -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 initialField changed, reset the flag
229
- if (previousInitialFieldRef.current !== initialField) {
230
- hasSetInitialFieldRef.current = false;
231
- previousInitialFieldRef.current = initialField;
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
- // Set the editing field if initialField is provided and we haven't set it yet
235
- if (initialField && !hasSetInitialFieldRef.current) {
236
- setEditingField(initialField);
237
- hasSetInitialFieldRef.current = true;
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
- }, [initialField]);
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: avatarSectionRef,
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'