@oxyhq/services 22.12.1 → 22.12.3

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 (85) hide show
  1. package/lib/commonjs/ui/components/FollowButton.js +5 -8
  2. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  3. package/lib/commonjs/ui/hooks/useSurfaceHeader.js +44 -7
  4. package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -1
  5. package/lib/commonjs/ui/navigation/surfaceNavStack.js +8 -7
  6. package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
  7. package/lib/commonjs/ui/navigation/surfaces.js +8 -3
  8. package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
  9. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +48 -42
  10. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -1
  11. package/lib/commonjs/ui/screens/CreateAccountScreen.js +60 -98
  12. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  13. package/lib/commonjs/ui/screens/FileManagementScreen.js +22 -8
  14. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  15. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +10 -7
  16. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  17. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +19 -11
  18. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
  19. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +42 -9
  20. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  21. package/lib/module/ui/components/FollowButton.js +5 -8
  22. package/lib/module/ui/components/FollowButton.js.map +1 -1
  23. package/lib/module/ui/hooks/useSurfaceHeader.js +45 -8
  24. package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -1
  25. package/lib/module/ui/navigation/surfaceNavStack.js +8 -7
  26. package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
  27. package/lib/module/ui/navigation/surfaces.js +7 -1
  28. package/lib/module/ui/navigation/surfaces.js.map +1 -1
  29. package/lib/module/ui/screens/ChangeAvatarScreen.js +48 -42
  30. package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -1
  31. package/lib/module/ui/screens/CreateAccountScreen.js +62 -100
  32. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  33. package/lib/module/ui/screens/FileManagementScreen.js +22 -8
  34. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  35. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +10 -7
  36. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  37. package/lib/module/ui/screens/fileManagement/UploadBar.js +20 -12
  38. package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
  39. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +43 -10
  40. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  41. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +7 -0
  43. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +7 -4
  45. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  46. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +9 -5
  48. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/ui/screens/fileManagement/UploadBar.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +5 -1
  54. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/ui/types/fileManagement.d.ts +10 -0
  56. package/lib/typescript/commonjs/ui/types/fileManagement.d.ts.map +1 -1
  57. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  58. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +7 -0
  59. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  60. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +7 -4
  61. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  62. package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
  63. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +9 -5
  64. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  65. package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  66. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  67. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  68. package/lib/typescript/module/ui/screens/fileManagement/UploadBar.d.ts.map +1 -1
  69. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +5 -1
  70. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  71. package/lib/typescript/module/ui/types/fileManagement.d.ts +10 -0
  72. package/lib/typescript/module/ui/types/fileManagement.d.ts.map +1 -1
  73. package/package.json +4 -4
  74. package/src/ui/components/FollowButton.tsx +5 -8
  75. package/src/ui/hooks/useSurfaceHeader.ts +65 -8
  76. package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +49 -17
  77. package/src/ui/navigation/surfaceNavStack.ts +15 -11
  78. package/src/ui/navigation/surfaces.ts +9 -1
  79. package/src/ui/screens/ChangeAvatarScreen.tsx +46 -39
  80. package/src/ui/screens/CreateAccountScreen.tsx +128 -166
  81. package/src/ui/screens/FileManagementScreen.tsx +22 -8
  82. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +4 -5
  83. package/src/ui/screens/fileManagement/UploadBar.tsx +17 -10
  84. package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +51 -10
  85. package/src/ui/types/fileManagement.ts +10 -0
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import { useCallback, useRef, useState } from 'react';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
4
  import { toast } from '@oxyhq/bloom';
5
5
  import type { AssetUploadInput, FileMetadata } from '@oxyhq/core';
@@ -58,8 +58,12 @@ export interface UseFileUploadStateParams {
58
58
  multiSelect: boolean;
59
59
  afterSelect: 'close' | 'back' | 'none';
60
60
  onSelect?: (file: FileMetadata) => void;
61
+ /** Forward-navigation picker: see {@link FileManagementScreenProps.onPicked}. */
62
+ onPicked?: (file: FileMetadata) => void;
61
63
  goBack?: () => void;
62
64
  onClose?: () => void;
65
+ /** When true, the document picker and pre-upload validation accept images only. */
66
+ imagesOnly?: boolean;
63
67
  selectedIds: Set<string>;
64
68
  setSelectedIds: React.Dispatch<React.SetStateAction<Set<string>>>;
65
69
  t: (key: string, vars?: Record<string, string | number>) => string;
@@ -94,8 +98,10 @@ export const useFileUploadState = ({
94
98
  multiSelect,
95
99
  afterSelect,
96
100
  onSelect,
101
+ onPicked,
97
102
  goBack,
98
103
  onClose,
104
+ imagesOnly = false,
99
105
  selectedIds,
100
106
  setSelectedIds,
101
107
  t,
@@ -108,6 +114,23 @@ export const useFileUploadState = ({
108
114
 
109
115
  const queryClient = useQueryClient();
110
116
  const uploadStartRef = useRef<number | null>(null);
117
+ const postSelectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
118
+ const isActiveRef = useRef(true);
119
+
120
+ const clearPostSelectTimer = useCallback(() => {
121
+ if (postSelectTimerRef.current) {
122
+ clearTimeout(postSelectTimerRef.current);
123
+ postSelectTimerRef.current = null;
124
+ }
125
+ }, []);
126
+
127
+ useEffect(() => {
128
+ isActiveRef.current = true;
129
+ return () => {
130
+ isActiveRef.current = false;
131
+ clearPostSelectTimer();
132
+ };
133
+ }, [clearPostSelectTimer]);
111
134
 
112
135
  const endUpload = useCallback(() => {
113
136
  const started = uploadStartRef.current;
@@ -274,6 +297,11 @@ export const useFileUploadState = ({
274
297
 
275
298
  const fileType = candidateType(file);
276
299
 
300
+ if (imagesOnly && !fileType.startsWith('image/')) {
301
+ toast.error(t('fileManagement.toasts.imagesOnlyRequired'));
302
+ continue;
303
+ }
304
+
277
305
  // Generate preview for images - unified approach
278
306
  let preview: string | undefined;
279
307
  if (fileType.startsWith('image/')) {
@@ -308,7 +336,7 @@ export const useFileUploadState = ({
308
336
  // Show preview modal for user to review files before upload
309
337
  setPendingFiles(processedFiles);
310
338
  setShowUploadPreview(true);
311
- }, [t]);
339
+ }, [imagesOnly, t]);
312
340
 
313
341
  const handleConfirmUpload = async () => {
314
342
  if (pendingFiles.length === 0) return;
@@ -332,15 +360,26 @@ export const useFileUploadState = ({
332
360
  // If in selectMode, automatically select the uploaded file(s)
333
361
  if (selectMode && uploadedFiles.length > 0) {
334
362
  // Defer one tick so the query cache has settled before selecting.
335
- setTimeout(() => {
363
+ clearPostSelectTimer();
364
+ postSelectTimerRef.current = setTimeout(() => {
365
+ postSelectTimerRef.current = null;
366
+ if (!isActiveRef.current) return;
367
+
336
368
  const fileToSelect = uploadedFiles[0];
337
369
  if (!multiSelect && fileToSelect) {
338
- // Single select mode - directly call onSelect callback
339
- onSelect?.(fileToSelect);
340
- if (afterSelect === 'back') {
341
- goBack?.();
342
- } else if (afterSelect === 'close') {
343
- onClose?.();
370
+ if (onPicked) {
371
+ // Forward-navigation picker (avatar flow): hand the
372
+ // freshly-uploaded file onward (to the cropper). No
373
+ // dismiss/close — the picker frame stays below.
374
+ onPicked(fileToSelect);
375
+ } else {
376
+ // Single select mode - directly call onSelect callback
377
+ onSelect?.(fileToSelect);
378
+ if (afterSelect === 'back') {
379
+ goBack?.();
380
+ } else if (afterSelect === 'close') {
381
+ onClose?.();
382
+ }
344
383
  }
345
384
  } else if (multiSelect) {
346
385
  // Multi-select mode - add all uploaded files to selection
@@ -361,6 +400,8 @@ export const useFileUploadState = ({
361
400
  };
362
401
 
363
402
  const handleCancelUpload = () => {
403
+ clearPostSelectTimer();
404
+
364
405
  // Cleanup preview URLs
365
406
  for (const pf of pendingFiles) {
366
407
  revokePreviewUrl(pf.preview);
@@ -402,7 +443,7 @@ export const useFileUploadState = ({
402
443
  // Use expo-document-picker (works on all platforms including web)
403
444
  // On web, it uses the native file input and provides File objects directly
404
445
  const result = await picker.getDocumentAsync({
405
- type: '*/*',
446
+ type: imagesOnly ? 'image/*' : '*/*',
406
447
  multiple: true,
407
448
  copyToCacheDirectory: true,
408
449
  });
@@ -14,6 +14,16 @@ export interface FileManagementScreenProps extends BaseScreenProps {
14
14
  multiSelect?: boolean;
15
15
  // Callback when a file is selected (single select mode)
16
16
  onSelect?: (file: FileMetadata) => void;
17
+ /**
18
+ * Forward-navigation picker: called with the picked file in single-select
19
+ * mode when the picker is one FRAME of a larger in-surface flow. Unlike
20
+ * {@link onSelect}, the caller is expected to NAVIGATE the surface onward
21
+ * (e.g. the avatar flow pushes the cropper on top of this picker) — so on
22
+ * select the picker neither dismisses nor closes the session, and its
23
+ * Cancel/back pops THIS frame (returning to the frame that opened the picker)
24
+ * rather than closing. Takes precedence over `onSelect`/`dismiss` when set.
25
+ */
26
+ onPicked?: (file: FileMetadata) => void;
17
27
  // Callback when confirm pressed in multi-select mode
18
28
  onConfirmSelection?: OnConfirmFileSelection;
19
29
  // Initial selected file IDs for multi-select