@oxyhq/services 13.0.2 → 13.1.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/index.js +18 -11
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/AccountMenuButton.js +8 -10
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +1 -1
- package/lib/commonjs/ui/components/AccountSwitcher.js +65 -35
- package/lib/commonjs/ui/components/AccountSwitcher.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +233 -0
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -0
- package/lib/commonjs/ui/components/ProfileMenu.js +374 -0
- package/lib/commonjs/ui/components/ProfileMenu.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +213 -101
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +28 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +2 -2
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/usePaymentQueries.js +12 -12
- package/lib/commonjs/ui/hooks/queries/usePaymentQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +8 -7
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/commonjs/ui/index.js +14 -0
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +11 -6
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +3 -3
- package/lib/commonjs/ui/screens/CreateAccountScreen.js +6 -4
- package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +8 -7
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +13 -13
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +7 -7
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +5 -5
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +17 -18
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +3 -3
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +9 -9
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +4 -4
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +6 -6
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +6 -6
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +4 -4
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +4 -4
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/utils/activeAuthuser.js +76 -8
- package/lib/commonjs/ui/utils/activeAuthuser.js.map +1 -1
- package/lib/module/index.js +5 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/AccountMenuButton.js +8 -10
- package/lib/module/ui/components/AccountMenuButton.js.map +1 -1
- package/lib/module/ui/components/AccountSwitcher.js +65 -35
- package/lib/module/ui/components/AccountSwitcher.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +228 -0
- package/lib/module/ui/components/ProfileButton.js.map +1 -0
- package/lib/module/ui/components/ProfileMenu.js +370 -0
- package/lib/module/ui/components/ProfileMenu.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +214 -102
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +29 -2
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +2 -2
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/usePaymentQueries.js +12 -12
- package/lib/module/ui/hooks/queries/usePaymentQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js +9 -7
- package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/module/ui/index.js +2 -0
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +11 -6
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +3 -3
- package/lib/module/ui/screens/CreateAccountScreen.js +6 -4
- package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +8 -7
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +13 -13
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +7 -7
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +5 -5
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +17 -18
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +3 -3
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +9 -9
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +1 -1
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +4 -4
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +6 -6
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +6 -6
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +4 -4
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js +4 -4
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/module/ui/utils/activeAuthuser.js +74 -9
- package/lib/module/ui/utils/activeAuthuser.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +5 -7
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ActivityIndicator.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/ActivityIndicator.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/CrossFadeIcon.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/CrossFadeIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/HelperText.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/HelperText.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +46 -0
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +39 -0
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/TextField/Addons/Outline.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/TextField/Addons/Outline.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/Addons/Underline.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/TextField/Addons/Underline.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/Adornment/TextFieldAffix.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/Adornment/TextFieldIcon.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/Label/InputLabel.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/Label/LabelBackground.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/TextField/Label/LabelBackground.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/TextFieldFlat.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/TextField/TextFieldFlat.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/TextField/TextFieldOutlined.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/TextField/TextFieldOutlined.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +11 -26
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/ThemeContext.d.ts +1 -1
- package/lib/typescript/commonjs/ui/context/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +2 -0
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +3 -3
- package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +24 -0
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +64 -61
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +26 -26
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +5 -7
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +1 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ActivityIndicator.d.ts +2 -2
- package/lib/typescript/module/ui/components/ActivityIndicator.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/BottomSheetRouter.d.ts +1 -1
- package/lib/typescript/module/ui/components/BottomSheetRouter.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/CrossFadeIcon.d.ts +4 -3
- package/lib/typescript/module/ui/components/CrossFadeIcon.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FontLoader.d.ts +1 -1
- package/lib/typescript/module/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/HelperText.d.ts +1 -1
- package/lib/typescript/module/ui/components/HelperText.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/Icon.d.ts +1 -1
- package/lib/typescript/module/ui/components/Icon.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/IconButton/IconButton.d.ts +3 -3
- package/lib/typescript/module/ui/components/IconButton/IconButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/IconButton/utils.d.ts +1 -1
- package/lib/typescript/module/ui/components/IconButton/utils.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/OxyProvider.d.ts +1 -1
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +46 -0
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts +39 -0
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/StepBasedScreen.d.ts +2 -2
- package/lib/typescript/module/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/Surface.d.ts +2 -2
- package/lib/typescript/module/ui/components/Surface.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Addons/Outline.d.ts +3 -2
- package/lib/typescript/module/ui/components/TextField/Addons/Outline.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Addons/Underline.d.ts +3 -2
- package/lib/typescript/module/ui/components/TextField/Addons/Underline.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldAdornment.d.ts +3 -3
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldAdornment.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldAffix.d.ts +3 -3
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldAffix.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldIcon.d.ts +4 -4
- package/lib/typescript/module/ui/components/TextField/Adornment/TextFieldIcon.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/types.d.ts +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/utils.d.ts +1 -1
- package/lib/typescript/module/ui/components/TextField/Adornment/utils.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Label/InputLabel.d.ts +2 -2
- package/lib/typescript/module/ui/components/TextField/Label/InputLabel.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/Label/LabelBackground.d.ts +3 -2
- package/lib/typescript/module/ui/components/TextField/Label/LabelBackground.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/TextFieldFlat.d.ts +3 -2
- package/lib/typescript/module/ui/components/TextField/TextFieldFlat.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/TextFieldOutlined.d.ts +3 -2
- package/lib/typescript/module/ui/components/TextField/TextFieldOutlined.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/helpers.d.ts +3 -3
- package/lib/typescript/module/ui/components/TextField/helpers.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField/types.d.ts +1 -1
- package/lib/typescript/module/ui/components/TextField/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TextField.d.ts +4 -4
- package/lib/typescript/module/ui/components/TextField.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TouchableRipple/TouchableRipple.d.ts +3 -3
- package/lib/typescript/module/ui/components/TouchableRipple/TouchableRipple.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TouchableRipple/TouchableRipple.native.d.ts +3 -3
- package/lib/typescript/module/ui/components/TouchableRipple/TouchableRipple.native.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/TouchableRipple/utils.d.ts +1 -1
- package/lib/typescript/module/ui/components/TouchableRipple/utils.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/Typography/AnimatedText.d.ts +3 -3
- package/lib/typescript/module/ui/components/Typography/AnimatedText.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts +1 -1
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/feedback/ProgressIndicator.d.ts +1 -1
- package/lib/typescript/module/ui/components/feedback/ProgressIndicator.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/feedback/constants.d.ts +1 -1
- package/lib/typescript/module/ui/components/feedback/constants.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/feedback/useFeedbackForm.d.ts +1 -1
- package/lib/typescript/module/ui/components/feedback/useFeedbackForm.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentDetailsStep.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentDetailsStep.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentMethodStep.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentMethodStep.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentReviewStep.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentReviewStep.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentSuccessStep.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentSuccessStep.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentSummaryStep.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/PaymentSummaryStep.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/constants.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/constants.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/payment/paymentStyles.d.ts +1 -1
- package/lib/typescript/module/ui/components/payment/paymentStyles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/theming.d.ts +1 -1
- package/lib/typescript/module/ui/components/theming.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +14 -29
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/ThemeContext.d.ts +1 -1
- package/lib/typescript/module/ui/context/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +2 -2
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/usePaymentQueries.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/queries/usePaymentQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queryClient.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/queryClient.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useLanguageManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useStorage.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useStorage.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +30 -28
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +4 -4
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FAQScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FollowersListScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/FollowersListScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FollowingListScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/FollowingListScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts +2 -2
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ProfileScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserListScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/server.d.ts +2 -2
- package/lib/typescript/module/ui/server.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/fileManagement.d.ts +1 -1
- package/lib/typescript/module/ui/types/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +24 -0
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +21 -20
- package/src/index.ts +8 -5
- package/src/ui/components/AccountMenuButton.tsx +9 -11
- package/src/ui/components/AccountSwitcher.tsx +71 -37
- package/src/ui/components/ProfileButton.tsx +270 -0
- package/src/ui/components/ProfileMenu.tsx +416 -0
- package/src/ui/context/OxyContext.tsx +217 -130
- package/src/ui/context/hooks/useAuthOperations.ts +35 -2
- package/src/ui/hooks/queries/useAccountQueries.ts +2 -2
- package/src/ui/hooks/queries/usePaymentQueries.ts +12 -12
- package/src/ui/hooks/queries/useServicesQueries.ts +9 -6
- package/src/ui/index.ts +2 -0
- package/src/ui/screens/AccountSettingsScreen.tsx +9 -5
- package/src/ui/screens/AccountSwitcherScreen.tsx +3 -3
- package/src/ui/screens/CreateAccountScreen.tsx +6 -4
- package/src/ui/screens/EditProfileFieldScreen.tsx +8 -7
- package/src/ui/screens/FileManagementScreen.tsx +13 -13
- package/src/ui/screens/HistoryViewScreen.tsx +7 -7
- package/src/ui/screens/LanguageSelectorScreen.tsx +5 -5
- package/src/ui/screens/ManageAccountScreen.tsx +17 -18
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +3 -3
- package/src/ui/screens/PrivacySettingsScreen.tsx +9 -9
- package/src/ui/screens/ProfileScreen.tsx +1 -1
- package/src/ui/screens/SavesCollectionsScreen.tsx +5 -5
- package/src/ui/screens/SearchSettingsScreen.tsx +6 -6
- package/src/ui/screens/WelcomeNewUserScreen.tsx +6 -6
- package/src/ui/screens/trust/TrustCenterScreen.tsx +5 -5
- package/src/ui/screens/trust/TrustRewardsScreen.tsx +4 -4
- package/src/ui/utils/__tests__/activeAuthuser.test.ts +75 -0
- package/src/ui/utils/activeAuthuser.ts +74 -8
- package/lib/commonjs/ui/components/ActiveAccountBanner.js +0 -144
- package/lib/commonjs/ui/components/ActiveAccountBanner.js.map +0 -1
- package/lib/module/ui/components/ActiveAccountBanner.js +0 -141
- package/lib/module/ui/components/ActiveAccountBanner.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/ActiveAccountBanner.d.ts +0 -4
- package/lib/typescript/commonjs/ui/components/ActiveAccountBanner.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/ActiveAccountBanner.d.ts +0 -4
- package/lib/typescript/module/ui/components/ActiveAccountBanner.d.ts.map +0 -1
- package/src/ui/components/ActiveAccountBanner.tsx +0 -130
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { useCallback, useRef, useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Pressable,
|
|
6
|
+
Platform,
|
|
7
|
+
type StyleProp,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
11
|
+
import { Avatar } from '@oxyhq/bloom/avatar';
|
|
12
|
+
import { Text } from '@oxyhq/bloom/typography';
|
|
13
|
+
import { useTheme } from '@oxyhq/bloom/theme';
|
|
14
|
+
import { getAccountDisplayName, getAccountFallbackHandle } from '@oxyhq/core';
|
|
15
|
+
import { useAuth } from '../hooks/useAuth';
|
|
16
|
+
import { useI18n } from '../hooks/useI18n';
|
|
17
|
+
import ProfileMenu, { type ProfileMenuAnchor } from './ProfileMenu';
|
|
18
|
+
|
|
19
|
+
const isWeb = Platform.OS === 'web';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fixed popover width used by {@link ProfileMenu} on web. `ProfileButton`
|
|
23
|
+
* mirrors this constant when computing the trigger-relative anchor so the
|
|
24
|
+
* left-edge clamp keeps the panel fully on-screen. Keep the two in sync.
|
|
25
|
+
*/
|
|
26
|
+
const MENU_WIDTH = 300;
|
|
27
|
+
|
|
28
|
+
/** Gutter, in px, kept between the popover and the viewport edges on web. */
|
|
29
|
+
const VIEWPORT_GUTTER = 8;
|
|
30
|
+
|
|
31
|
+
export interface ProfileButtonProps {
|
|
32
|
+
/**
|
|
33
|
+
* Expanded row (avatar + name + handle + chevron) when `true` (default), or a
|
|
34
|
+
* bare avatar-only trigger when `false` (collapsed sidebar).
|
|
35
|
+
*/
|
|
36
|
+
expanded?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Avatar diameter in px. Defaults to 40 when expanded, 32 when collapsed.
|
|
39
|
+
*/
|
|
40
|
+
avatarSize?: number;
|
|
41
|
+
/** Navigate to the "Manage account" surface (settings). */
|
|
42
|
+
onNavigateManage: () => void;
|
|
43
|
+
/** Start the add-account / sign-in flow for an additional account. */
|
|
44
|
+
onAddAccount: () => void;
|
|
45
|
+
/** Optional: navigate to the signed-in user's own profile. */
|
|
46
|
+
onNavigateProfile?: () => void;
|
|
47
|
+
/** Called before the active identity changes so apps can clear scoped state. */
|
|
48
|
+
onBeforeSessionChange?: () => void | Promise<void>;
|
|
49
|
+
/** Extra className applied to the outer trigger. */
|
|
50
|
+
className?: string;
|
|
51
|
+
/** Extra style applied to the outer trigger. */
|
|
52
|
+
style?: StyleProp<ViewStyle>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Self-contained sidebar account trigger, modeled on Bluesky's ProfileCard and
|
|
57
|
+
* the Oxy inbox's `MailboxDrawer` footer. Owns its own open state + anchor
|
|
58
|
+
* measurement, and renders {@link ProfileMenu} (the device-account switcher).
|
|
59
|
+
*
|
|
60
|
+
* Three auth states from {@link useAuth}:
|
|
61
|
+
* - **Undetermined** (`!isAuthResolved || isPrivateApiPending`): a neutral
|
|
62
|
+
* avatar-sized skeleton circle, no press.
|
|
63
|
+
* - **Signed in**: a pressable row — Bloom `Avatar` + display name + `@handle`
|
|
64
|
+
* + an `unfold-more-horizontal` chevron. Press opens the menu upward (web)
|
|
65
|
+
* against the measured trigger, or as a bottom sheet (native).
|
|
66
|
+
* - **Signed out**: a "Sign in" row that calls `useAuth().signIn()`.
|
|
67
|
+
*
|
|
68
|
+
* All display strings resolve through `@oxyhq/core`'s
|
|
69
|
+
* `getAccountDisplayName` / `getAccountFallbackHandle` — no hand-rolled name
|
|
70
|
+
* fallbacks. Avatars pass the bare file id as `source` + `variant="thumb"`, so
|
|
71
|
+
* the app's registered `ImageResolver` builds the thumbnail URL.
|
|
72
|
+
*/
|
|
73
|
+
const ProfileButton: React.FC<ProfileButtonProps> = ({
|
|
74
|
+
expanded = true,
|
|
75
|
+
avatarSize,
|
|
76
|
+
onNavigateManage,
|
|
77
|
+
onAddAccount,
|
|
78
|
+
onNavigateProfile,
|
|
79
|
+
onBeforeSessionChange,
|
|
80
|
+
className,
|
|
81
|
+
style,
|
|
82
|
+
}) => {
|
|
83
|
+
const {
|
|
84
|
+
user,
|
|
85
|
+
isAuthenticated,
|
|
86
|
+
isAuthResolved,
|
|
87
|
+
isPrivateApiPending,
|
|
88
|
+
signIn,
|
|
89
|
+
} = useAuth();
|
|
90
|
+
const { colors } = useTheme();
|
|
91
|
+
const { t, locale } = useI18n();
|
|
92
|
+
|
|
93
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
94
|
+
const [anchor, setAnchor] = useState<ProfileMenuAnchor | null>(null);
|
|
95
|
+
|
|
96
|
+
// Trigger ref for the web anchor measurement. RN-Web exposes `measure()` on
|
|
97
|
+
// host views, so we anchor the popover to the button rect and open upward.
|
|
98
|
+
const triggerRef = useRef<View | null>(null);
|
|
99
|
+
|
|
100
|
+
const resolvedAvatarSize = avatarSize ?? (expanded ? 40 : 32);
|
|
101
|
+
|
|
102
|
+
const openMenu = useCallback(() => {
|
|
103
|
+
if (!isWeb) {
|
|
104
|
+
setAnchor(null);
|
|
105
|
+
setMenuOpen(true);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const node = triggerRef.current;
|
|
109
|
+
if (!node || typeof node.measure !== 'function' || typeof window === 'undefined') {
|
|
110
|
+
setAnchor(null);
|
|
111
|
+
setMenuOpen(true);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
node.measure((_x, _y, _w, _h, pageX, pageY) => {
|
|
115
|
+
if (typeof pageX !== 'number' || typeof pageY !== 'number') {
|
|
116
|
+
setAnchor(null);
|
|
117
|
+
} else {
|
|
118
|
+
// Clamp the panel's left edge inside the viewport gutter.
|
|
119
|
+
const maxLeft = Math.max(
|
|
120
|
+
VIEWPORT_GUTTER,
|
|
121
|
+
window.innerWidth - MENU_WIDTH - VIEWPORT_GUTTER,
|
|
122
|
+
);
|
|
123
|
+
const left = Math.min(Math.max(VIEWPORT_GUTTER, pageX), maxLeft);
|
|
124
|
+
// Anchor the panel's BOTTOM edge just above the trigger top so
|
|
125
|
+
// the menu opens upward from this footer button.
|
|
126
|
+
const bottom = Math.max(
|
|
127
|
+
VIEWPORT_GUTTER,
|
|
128
|
+
window.innerHeight - pageY + VIEWPORT_GUTTER,
|
|
129
|
+
);
|
|
130
|
+
setAnchor({ left, bottom });
|
|
131
|
+
}
|
|
132
|
+
setMenuOpen(true);
|
|
133
|
+
});
|
|
134
|
+
}, []);
|
|
135
|
+
|
|
136
|
+
const handleClose = useCallback(() => {
|
|
137
|
+
setMenuOpen(false);
|
|
138
|
+
}, []);
|
|
139
|
+
|
|
140
|
+
// ── Undetermined: skeleton circle, no interaction. ──────────────────────
|
|
141
|
+
if (!isAuthResolved || isPrivateApiPending) {
|
|
142
|
+
return (
|
|
143
|
+
<View
|
|
144
|
+
className={className}
|
|
145
|
+
style={style}
|
|
146
|
+
accessibilityElementsHidden
|
|
147
|
+
importantForAccessibility="no-hide-descendants"
|
|
148
|
+
>
|
|
149
|
+
<View
|
|
150
|
+
className="rounded-full bg-secondary"
|
|
151
|
+
style={{ width: resolvedAvatarSize, height: resolvedAvatarSize }}
|
|
152
|
+
/>
|
|
153
|
+
</View>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Signed out: "Sign in" row. ──────────────────────────────────────────
|
|
158
|
+
if (!isAuthenticated || !user) {
|
|
159
|
+
const signInLabel = t('common.actions.signIn') || 'Sign in';
|
|
160
|
+
return (
|
|
161
|
+
<Pressable
|
|
162
|
+
className={`flex-row items-center gap-3 rounded-full px-2 py-2 ${className ?? ''}`}
|
|
163
|
+
style={style}
|
|
164
|
+
onPress={() => { void signIn(); }}
|
|
165
|
+
accessibilityRole="button"
|
|
166
|
+
accessibilityLabel={signInLabel}
|
|
167
|
+
>
|
|
168
|
+
<View
|
|
169
|
+
className="items-center justify-center rounded-full bg-secondary"
|
|
170
|
+
style={{ width: resolvedAvatarSize, height: resolvedAvatarSize }}
|
|
171
|
+
>
|
|
172
|
+
<MaterialCommunityIcons
|
|
173
|
+
name="login"
|
|
174
|
+
size={Math.round(resolvedAvatarSize * 0.5)}
|
|
175
|
+
color={colors.icon}
|
|
176
|
+
/>
|
|
177
|
+
</View>
|
|
178
|
+
{expanded ? (
|
|
179
|
+
<Text
|
|
180
|
+
className="flex-1 font-semibold text-foreground"
|
|
181
|
+
numberOfLines={1}
|
|
182
|
+
>
|
|
183
|
+
{signInLabel}
|
|
184
|
+
</Text>
|
|
185
|
+
) : null}
|
|
186
|
+
</Pressable>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ── Signed in: avatar + identity + chevron. ─────────────────────────────
|
|
191
|
+
const displayName = getAccountDisplayName(user, locale);
|
|
192
|
+
const handle = getAccountFallbackHandle(user);
|
|
193
|
+
const handleLine = handle ? `@${handle}` : null;
|
|
194
|
+
|
|
195
|
+
const avatarNode = (
|
|
196
|
+
<Avatar
|
|
197
|
+
source={user.avatar ?? undefined}
|
|
198
|
+
variant="thumb"
|
|
199
|
+
name={displayName}
|
|
200
|
+
size={resolvedAvatarSize}
|
|
201
|
+
/>
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (!expanded) {
|
|
205
|
+
return (
|
|
206
|
+
<View className={className} style={style}>
|
|
207
|
+
<Pressable
|
|
208
|
+
ref={triggerRef}
|
|
209
|
+
className="rounded-full"
|
|
210
|
+
onPress={openMenu}
|
|
211
|
+
accessibilityRole="button"
|
|
212
|
+
accessibilityLabel={t('accountSwitcher.switchWhileSignedInAs', { name: displayName })
|
|
213
|
+
|| `Switch account, signed in as ${displayName}`}
|
|
214
|
+
>
|
|
215
|
+
{avatarNode}
|
|
216
|
+
</Pressable>
|
|
217
|
+
<ProfileMenu
|
|
218
|
+
open={menuOpen}
|
|
219
|
+
onClose={handleClose}
|
|
220
|
+
anchor={anchor}
|
|
221
|
+
onNavigateManage={onNavigateManage}
|
|
222
|
+
onAddAccount={onAddAccount}
|
|
223
|
+
onNavigateProfile={onNavigateProfile}
|
|
224
|
+
onBeforeSessionChange={onBeforeSessionChange}
|
|
225
|
+
/>
|
|
226
|
+
</View>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<View className={className} style={style}>
|
|
232
|
+
<Pressable
|
|
233
|
+
ref={triggerRef}
|
|
234
|
+
className="flex-row items-center gap-3 rounded-full px-2 py-2"
|
|
235
|
+
onPress={openMenu}
|
|
236
|
+
accessibilityRole="button"
|
|
237
|
+
accessibilityLabel={t('accountSwitcher.switchWhileSignedInAs', { name: displayName })
|
|
238
|
+
|| `Switch account, signed in as ${displayName}`}
|
|
239
|
+
>
|
|
240
|
+
{avatarNode}
|
|
241
|
+
<View className="min-w-0 flex-1">
|
|
242
|
+
<Text className="font-bold text-foreground" numberOfLines={1}>
|
|
243
|
+
{displayName}
|
|
244
|
+
</Text>
|
|
245
|
+
{handleLine ? (
|
|
246
|
+
<Text className="text-xs text-muted-foreground" numberOfLines={1}>
|
|
247
|
+
{handleLine}
|
|
248
|
+
</Text>
|
|
249
|
+
) : null}
|
|
250
|
+
</View>
|
|
251
|
+
<MaterialCommunityIcons
|
|
252
|
+
name="unfold-more-horizontal"
|
|
253
|
+
size={18}
|
|
254
|
+
color={colors.textSecondary}
|
|
255
|
+
/>
|
|
256
|
+
</Pressable>
|
|
257
|
+
<ProfileMenu
|
|
258
|
+
open={menuOpen}
|
|
259
|
+
onClose={handleClose}
|
|
260
|
+
anchor={anchor}
|
|
261
|
+
onNavigateManage={onNavigateManage}
|
|
262
|
+
onAddAccount={onAddAccount}
|
|
263
|
+
onNavigateProfile={onNavigateProfile}
|
|
264
|
+
onBeforeSessionChange={onBeforeSessionChange}
|
|
265
|
+
/>
|
|
266
|
+
</View>
|
|
267
|
+
);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export default ProfileButton;
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Pressable,
|
|
6
|
+
Modal,
|
|
7
|
+
ScrollView,
|
|
8
|
+
ActivityIndicator,
|
|
9
|
+
Platform,
|
|
10
|
+
type ViewStyle,
|
|
11
|
+
} from 'react-native';
|
|
12
|
+
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
13
|
+
import { Avatar } from '@oxyhq/bloom/avatar';
|
|
14
|
+
import { Text } from '@oxyhq/bloom/typography';
|
|
15
|
+
import { useTheme } from '@oxyhq/bloom/theme';
|
|
16
|
+
import { toast, useDialogControl, Dialog } from '@oxyhq/bloom';
|
|
17
|
+
import { Divider } from '@oxyhq/bloom/divider';
|
|
18
|
+
import { isDev, logger as loggerUtil } from '@oxyhq/core';
|
|
19
|
+
import { useOxy } from '../context/OxyContext';
|
|
20
|
+
import { useI18n } from '../hooks/useI18n';
|
|
21
|
+
import { useDeviceAccounts } from '../hooks/useDeviceAccounts';
|
|
22
|
+
|
|
23
|
+
const isWeb = Platform.OS === 'web';
|
|
24
|
+
|
|
25
|
+
/** Fixed popover width on web. `ProfileButton` mirrors this when anchoring. */
|
|
26
|
+
const MENU_WIDTH = 300;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Web-only anchor. `ProfileButton` measures its trigger and anchors the panel's
|
|
30
|
+
* BOTTOM-LEFT corner so the menu opens UPWARD from the sidebar footer. Native
|
|
31
|
+
* ignores the anchor and docks the panel to the bottom as a sheet.
|
|
32
|
+
*/
|
|
33
|
+
export interface ProfileMenuAnchor {
|
|
34
|
+
/** Distance from the viewport left, for the panel's LEFT edge. */
|
|
35
|
+
left: number;
|
|
36
|
+
/** Distance from the viewport bottom, for the panel's BOTTOM edge (opens upward). */
|
|
37
|
+
bottom: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ProfileMenuProps {
|
|
41
|
+
open: boolean;
|
|
42
|
+
onClose: () => void;
|
|
43
|
+
/** Web-only trigger anchor. Native ignores this (bottom-sheet style). */
|
|
44
|
+
anchor?: ProfileMenuAnchor | null;
|
|
45
|
+
/** Navigate to the "Manage account" surface (settings). */
|
|
46
|
+
onNavigateManage: () => void;
|
|
47
|
+
/** Start the add-account / sign-in flow for an additional account. */
|
|
48
|
+
onAddAccount: () => void;
|
|
49
|
+
/** Optional: navigate to the signed-in user's own profile. */
|
|
50
|
+
onNavigateProfile?: () => void;
|
|
51
|
+
/** Called before the active identity changes so apps can clear scoped state. */
|
|
52
|
+
onBeforeSessionChange?: () => void | Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Clean device-account switcher, modeled on the inbox `AccountMenu` but written
|
|
57
|
+
* fresh with NativeWind classNames + Bloom primitives. Lists every account
|
|
58
|
+
* signed in on this device (from {@link useDeviceAccounts}); tapping a row
|
|
59
|
+
* switches, and each inactive row carries a sign-out icon. Below the list:
|
|
60
|
+
* Add account, Manage account, optional View profile, and Sign out of all.
|
|
61
|
+
*
|
|
62
|
+
* Renders as an upward-opening popover anchored to the trigger on web, and a
|
|
63
|
+
* bottom-sheet style modal on native.
|
|
64
|
+
*/
|
|
65
|
+
const ProfileMenu: React.FC<ProfileMenuProps> = ({
|
|
66
|
+
open,
|
|
67
|
+
onClose,
|
|
68
|
+
anchor,
|
|
69
|
+
onNavigateManage,
|
|
70
|
+
onAddAccount,
|
|
71
|
+
onNavigateProfile,
|
|
72
|
+
onBeforeSessionChange,
|
|
73
|
+
}) => {
|
|
74
|
+
const {
|
|
75
|
+
activeSessionId,
|
|
76
|
+
switchSession,
|
|
77
|
+
logoutAll,
|
|
78
|
+
removeSession,
|
|
79
|
+
} = useOxy();
|
|
80
|
+
const { t } = useI18n();
|
|
81
|
+
const { colors } = useTheme();
|
|
82
|
+
|
|
83
|
+
const { accounts } = useDeviceAccounts();
|
|
84
|
+
|
|
85
|
+
const [busySessionId, setBusySessionId] = useState<string | null>(null);
|
|
86
|
+
const [removingSessionId, setRemovingSessionId] = useState<string | null>(null);
|
|
87
|
+
const [signingOutAll, setSigningOutAll] = useState(false);
|
|
88
|
+
|
|
89
|
+
const signOutAllDialog = useDialogControl();
|
|
90
|
+
|
|
91
|
+
const isSwitching = busySessionId !== null;
|
|
92
|
+
const actionDisabled = isSwitching || removingSessionId !== null || signingOutAll;
|
|
93
|
+
|
|
94
|
+
// Switch to a non-active account through the SDK's canonical switch path.
|
|
95
|
+
const handleSwitch = useCallback(async (sessionId: string) => {
|
|
96
|
+
if (sessionId === activeSessionId || busySessionId) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setBusySessionId(sessionId);
|
|
100
|
+
try {
|
|
101
|
+
await onBeforeSessionChange?.();
|
|
102
|
+
await switchSession(sessionId);
|
|
103
|
+
toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched account');
|
|
104
|
+
onClose();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (!isDev()) {
|
|
107
|
+
loggerUtil.warn('Switch account failed', { component: 'ProfileMenu' }, error as unknown);
|
|
108
|
+
}
|
|
109
|
+
toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
|
|
110
|
+
} finally {
|
|
111
|
+
setBusySessionId(null);
|
|
112
|
+
}
|
|
113
|
+
}, [activeSessionId, busySessionId, switchSession, t, onClose, onBeforeSessionChange]);
|
|
114
|
+
|
|
115
|
+
// Sign out a specific inactive account without switching/clearing the active
|
|
116
|
+
// one. The menu stays open so the user can keep managing accounts.
|
|
117
|
+
const handleRemove = useCallback(async (sessionId: string) => {
|
|
118
|
+
if (sessionId === activeSessionId || removingSessionId) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
setRemovingSessionId(sessionId);
|
|
122
|
+
try {
|
|
123
|
+
await removeSession(sessionId);
|
|
124
|
+
toast.success(t('common.actions.signedOut') || 'Signed out');
|
|
125
|
+
} catch (error) {
|
|
126
|
+
loggerUtil.warn('Remove account failed', { component: 'ProfileMenu' }, error as unknown);
|
|
127
|
+
toast.error(t('common.errors.signOutFailed') || 'Failed to sign out');
|
|
128
|
+
} finally {
|
|
129
|
+
setRemovingSessionId(null);
|
|
130
|
+
}
|
|
131
|
+
}, [activeSessionId, removingSessionId, removeSession, t]);
|
|
132
|
+
|
|
133
|
+
const performSignOutAll = useCallback(async () => {
|
|
134
|
+
if (signingOutAll) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setSigningOutAll(true);
|
|
138
|
+
try {
|
|
139
|
+
await onBeforeSessionChange?.();
|
|
140
|
+
await logoutAll();
|
|
141
|
+
toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'Signed out of all accounts');
|
|
142
|
+
onClose();
|
|
143
|
+
} catch (error) {
|
|
144
|
+
loggerUtil.warn('Sign out all failed', { component: 'ProfileMenu' }, error as unknown);
|
|
145
|
+
toast.error(t('common.errors.signOutAllFailed') || 'Failed to sign out of all accounts');
|
|
146
|
+
} finally {
|
|
147
|
+
setSigningOutAll(false);
|
|
148
|
+
}
|
|
149
|
+
}, [signingOutAll, logoutAll, t, onClose, onBeforeSessionChange]);
|
|
150
|
+
|
|
151
|
+
// Escape-to-close (web only).
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!open || !isWeb || typeof document === 'undefined') {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const onKey = (event: KeyboardEvent) => {
|
|
157
|
+
if (event.key === 'Escape') {
|
|
158
|
+
event.stopPropagation();
|
|
159
|
+
onClose();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
document.addEventListener('keydown', onKey, true);
|
|
163
|
+
return () => document.removeEventListener('keydown', onKey, true);
|
|
164
|
+
}, [open, onClose]);
|
|
165
|
+
|
|
166
|
+
if (!open) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Web: anchor the panel's bottom-left corner to the measured trigger, falling
|
|
171
|
+
// back to a bottom-left placement when no anchor was captured. Native ignores
|
|
172
|
+
// this (the panel docks to the bottom via the overlay's flex-end).
|
|
173
|
+
const panelAnchorStyle: ViewStyle | undefined = isWeb
|
|
174
|
+
? {
|
|
175
|
+
position: 'absolute',
|
|
176
|
+
width: MENU_WIDTH,
|
|
177
|
+
left: anchor?.left ?? 8,
|
|
178
|
+
bottom: anchor?.bottom ?? 8,
|
|
179
|
+
}
|
|
180
|
+
: undefined;
|
|
181
|
+
|
|
182
|
+
const content = (
|
|
183
|
+
<Pressable
|
|
184
|
+
// Swallow taps inside the panel so they never reach the overlay's
|
|
185
|
+
// outside-tap-to-close handler.
|
|
186
|
+
onPress={() => undefined}
|
|
187
|
+
className={
|
|
188
|
+
isWeb
|
|
189
|
+
? 'overflow-hidden rounded-2xl border border-border bg-background'
|
|
190
|
+
: 'overflow-hidden rounded-t-3xl bg-background pb-3'
|
|
191
|
+
}
|
|
192
|
+
style={[
|
|
193
|
+
panelAnchorStyle,
|
|
194
|
+
!isWeb ? { maxHeight: '85%' } : { maxHeight: '85%' },
|
|
195
|
+
styles.shadow,
|
|
196
|
+
]}
|
|
197
|
+
accessibilityRole="menu"
|
|
198
|
+
accessibilityLabel={t('accountMenu.label') || 'Account menu'}
|
|
199
|
+
>
|
|
200
|
+
<ScrollView
|
|
201
|
+
className="grow-0"
|
|
202
|
+
contentContainerClassName="py-1"
|
|
203
|
+
showsVerticalScrollIndicator={false}
|
|
204
|
+
>
|
|
205
|
+
{/* 1) Device accounts — active first (checkmark), others switchable. */}
|
|
206
|
+
{accounts.map((account) => {
|
|
207
|
+
const isActive = account.isCurrent;
|
|
208
|
+
const isBusy = busySessionId === account.sessionId;
|
|
209
|
+
const isRemoving = removingSessionId === account.sessionId;
|
|
210
|
+
return (
|
|
211
|
+
<Pressable
|
|
212
|
+
key={`account-${account.sessionId}`}
|
|
213
|
+
accessibilityRole="menuitem"
|
|
214
|
+
accessibilityLabel={account.displayName}
|
|
215
|
+
accessibilityState={{ selected: isActive }}
|
|
216
|
+
onPress={() => handleSwitch(account.sessionId)}
|
|
217
|
+
disabled={isActive || isBusy || isSwitching}
|
|
218
|
+
className={`flex-row items-center gap-3 px-4 py-2.5 ${
|
|
219
|
+
isActive ? 'bg-secondary' : ''
|
|
220
|
+
} ${isSwitching && !isActive ? 'opacity-40' : ''}`}
|
|
221
|
+
>
|
|
222
|
+
<Avatar
|
|
223
|
+
source={account.user.avatar ?? undefined}
|
|
224
|
+
uri={account.avatarUrl}
|
|
225
|
+
variant="thumb"
|
|
226
|
+
name={account.displayName}
|
|
227
|
+
size={isActive ? 40 : 32}
|
|
228
|
+
/>
|
|
229
|
+
<View className="min-w-0 flex-1">
|
|
230
|
+
<Text
|
|
231
|
+
className={`text-foreground ${isActive ? 'font-semibold' : 'font-medium'}`}
|
|
232
|
+
numberOfLines={1}
|
|
233
|
+
>
|
|
234
|
+
{account.displayName}
|
|
235
|
+
</Text>
|
|
236
|
+
{account.email ? (
|
|
237
|
+
<Text
|
|
238
|
+
className="text-xs text-muted-foreground"
|
|
239
|
+
numberOfLines={1}
|
|
240
|
+
>
|
|
241
|
+
{account.email}
|
|
242
|
+
</Text>
|
|
243
|
+
) : null}
|
|
244
|
+
</View>
|
|
245
|
+
{isBusy ? (
|
|
246
|
+
<ActivityIndicator color={colors.primary} size="small" />
|
|
247
|
+
) : isActive ? (
|
|
248
|
+
<MaterialCommunityIcons name="check" size={20} color={colors.primary} />
|
|
249
|
+
) : isRemoving ? (
|
|
250
|
+
<ActivityIndicator color={colors.textSecondary} size="small" />
|
|
251
|
+
) : (
|
|
252
|
+
<Pressable
|
|
253
|
+
accessibilityRole="button"
|
|
254
|
+
accessibilityLabel={
|
|
255
|
+
t('accountMenu.signOutAccount', { name: account.displayName })
|
|
256
|
+
|| `Sign out ${account.displayName}`
|
|
257
|
+
}
|
|
258
|
+
onPress={() => handleRemove(account.sessionId)}
|
|
259
|
+
disabled={actionDisabled}
|
|
260
|
+
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
261
|
+
className="h-7 w-7 items-center justify-center rounded-full opacity-60"
|
|
262
|
+
>
|
|
263
|
+
<MaterialCommunityIcons
|
|
264
|
+
name="logout"
|
|
265
|
+
size={18}
|
|
266
|
+
color={colors.textSecondary}
|
|
267
|
+
/>
|
|
268
|
+
</Pressable>
|
|
269
|
+
)}
|
|
270
|
+
</Pressable>
|
|
271
|
+
);
|
|
272
|
+
})}
|
|
273
|
+
|
|
274
|
+
{/* 2) Switching indicator. */}
|
|
275
|
+
{isSwitching ? (
|
|
276
|
+
<View className="flex-row items-center justify-center gap-2 py-2">
|
|
277
|
+
<ActivityIndicator color={colors.textSecondary} size="small" />
|
|
278
|
+
<Text className="text-xs font-medium text-muted-foreground">
|
|
279
|
+
{t('accountMenu.switching') || 'Switching account…'}
|
|
280
|
+
</Text>
|
|
281
|
+
</View>
|
|
282
|
+
) : null}
|
|
283
|
+
|
|
284
|
+
<Divider color={colors.border} spacing={4} />
|
|
285
|
+
|
|
286
|
+
{/* 3) Add another account. */}
|
|
287
|
+
<ActionRow
|
|
288
|
+
icon="account-plus-outline"
|
|
289
|
+
iconColor={colors.icon}
|
|
290
|
+
label={t('accountMenu.addAnother') || 'Add another account'}
|
|
291
|
+
disabled={actionDisabled}
|
|
292
|
+
onPress={() => {
|
|
293
|
+
onClose();
|
|
294
|
+
onAddAccount();
|
|
295
|
+
}}
|
|
296
|
+
/>
|
|
297
|
+
|
|
298
|
+
{/* 4) Manage account. */}
|
|
299
|
+
<ActionRow
|
|
300
|
+
icon="cog-outline"
|
|
301
|
+
iconColor={colors.icon}
|
|
302
|
+
label={t('accountMenu.manage') || 'Manage your Oxy Account'}
|
|
303
|
+
disabled={actionDisabled}
|
|
304
|
+
onPress={() => {
|
|
305
|
+
onClose();
|
|
306
|
+
onNavigateManage();
|
|
307
|
+
}}
|
|
308
|
+
/>
|
|
309
|
+
|
|
310
|
+
{/* 5) View profile (optional). */}
|
|
311
|
+
{onNavigateProfile ? (
|
|
312
|
+
<ActionRow
|
|
313
|
+
icon="account-outline"
|
|
314
|
+
iconColor={colors.icon}
|
|
315
|
+
label={t('accountMenu.viewProfile') || 'View profile'}
|
|
316
|
+
disabled={actionDisabled}
|
|
317
|
+
onPress={() => {
|
|
318
|
+
onClose();
|
|
319
|
+
onNavigateProfile();
|
|
320
|
+
}}
|
|
321
|
+
/>
|
|
322
|
+
) : null}
|
|
323
|
+
|
|
324
|
+
{/* 6) Sign out of all accounts. */}
|
|
325
|
+
<Divider color={colors.border} spacing={4} />
|
|
326
|
+
<Pressable
|
|
327
|
+
accessibilityRole="menuitem"
|
|
328
|
+
accessibilityLabel={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
329
|
+
onPress={() => signOutAllDialog.open()}
|
|
330
|
+
disabled={actionDisabled}
|
|
331
|
+
className={`flex-row items-center gap-3 px-4 py-3 ${actionDisabled ? 'opacity-40' : ''}`}
|
|
332
|
+
>
|
|
333
|
+
{signingOutAll ? (
|
|
334
|
+
<ActivityIndicator color={colors.error} size="small" />
|
|
335
|
+
) : (
|
|
336
|
+
<MaterialCommunityIcons name="logout" size={18} color={colors.error} />
|
|
337
|
+
)}
|
|
338
|
+
<Text className="font-medium" style={{ color: colors.error }}>
|
|
339
|
+
{t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
340
|
+
</Text>
|
|
341
|
+
</Pressable>
|
|
342
|
+
</ScrollView>
|
|
343
|
+
</Pressable>
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<Modal
|
|
348
|
+
visible={open}
|
|
349
|
+
transparent
|
|
350
|
+
animationType={isWeb ? 'fade' : 'slide'}
|
|
351
|
+
onRequestClose={onClose}
|
|
352
|
+
>
|
|
353
|
+
<Pressable
|
|
354
|
+
accessibilityRole="button"
|
|
355
|
+
accessibilityLabel={t('common.actions.close') || 'Close'}
|
|
356
|
+
onPress={onClose}
|
|
357
|
+
className={isWeb ? 'flex-1 relative' : 'flex-1 justify-end'}
|
|
358
|
+
style={!isWeb ? styles.nativeScrim : undefined}
|
|
359
|
+
>
|
|
360
|
+
{content}
|
|
361
|
+
</Pressable>
|
|
362
|
+
|
|
363
|
+
<Dialog
|
|
364
|
+
control={signOutAllDialog}
|
|
365
|
+
title={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
366
|
+
description={t('common.confirms.signOutAll') || 'Are you sure you want to sign out of all accounts?'}
|
|
367
|
+
actions={[
|
|
368
|
+
{
|
|
369
|
+
label: t('accountMenu.signOutAll') || 'Sign out of all accounts',
|
|
370
|
+
color: 'destructive',
|
|
371
|
+
onPress: performSignOutAll,
|
|
372
|
+
},
|
|
373
|
+
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
374
|
+
]}
|
|
375
|
+
/>
|
|
376
|
+
</Modal>
|
|
377
|
+
);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/** Bottom-section action row (Add account / Manage / View profile). */
|
|
381
|
+
const ActionRow: React.FC<{
|
|
382
|
+
icon: string;
|
|
383
|
+
iconColor: string;
|
|
384
|
+
label: string;
|
|
385
|
+
disabled: boolean;
|
|
386
|
+
onPress: () => void;
|
|
387
|
+
}> = ({ icon, iconColor, label, disabled, onPress }) => (
|
|
388
|
+
<Pressable
|
|
389
|
+
accessibilityRole="menuitem"
|
|
390
|
+
accessibilityLabel={label}
|
|
391
|
+
onPress={onPress}
|
|
392
|
+
disabled={disabled}
|
|
393
|
+
className={`flex-row items-center gap-3 px-4 py-3 ${disabled ? 'opacity-40' : ''}`}
|
|
394
|
+
>
|
|
395
|
+
<MaterialCommunityIcons name={icon} size={20} color={iconColor} />
|
|
396
|
+
<Text className="font-medium text-foreground">{label}</Text>
|
|
397
|
+
</Pressable>
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
// The panel's drop shadow and the native scrim are the only values with no
|
|
401
|
+
// NativeWind class equivalent in this package (dynamic elevation + rgba scrim),
|
|
402
|
+
// so they stay as small inline objects rather than raw class-replaceable styles.
|
|
403
|
+
const styles = {
|
|
404
|
+
shadow: {
|
|
405
|
+
shadowColor: '#000',
|
|
406
|
+
shadowOpacity: 0.18,
|
|
407
|
+
shadowRadius: 24,
|
|
408
|
+
shadowOffset: { width: 0, height: 8 },
|
|
409
|
+
elevation: 12,
|
|
410
|
+
} satisfies ViewStyle,
|
|
411
|
+
nativeScrim: {
|
|
412
|
+
backgroundColor: 'rgba(0,0,0,0.32)',
|
|
413
|
+
} satisfies ViewStyle,
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
export default ProfileMenu;
|