@oxyhq/services
Version:
Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀
634 lines (626 loc) • 28.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _OxyContext = require("../context/OxyContext");
var _Avatar = _interopRequireDefault(require("../components/Avatar"));
var _OxyIcon = _interopRequireDefault(require("../components/icon/OxyIcon"));
var _sonner = require("../../lib/sonner");
var _confirmAction = require("../utils/confirmAction");
var _components = require("../components");
var _useI18n = require("../hooks/useI18n");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* AccountOverviewScreen - Optimized for performance
*
* Performance optimizations implemented:
* - useMemo for theme calculations (only recalculates when theme changes)
* - useMemo for additional accounts filtering (only recalculates when dependencies change)
* - useCallback for event handlers to prevent unnecessary re-renders
* - React.memo wrapper to prevent re-renders when props haven't changed
* - GroupedSection components for better organization and cleaner code
*/const AccountOverviewScreen = ({
onClose,
theme,
navigate
}) => {
const {
user,
logout,
isLoading,
sessions,
activeSessionId,
oxyServices,
isAuthenticated
} = (0, _OxyContext.useOxy)();
const {
t
} = (0, _useI18n.useI18n)();
const [showMoreAccounts, setShowMoreAccounts] = (0, _react.useState)(false);
const [additionalAccountsData, setAdditionalAccountsData] = (0, _react.useState)([]);
const [loadingAdditionalAccounts, setLoadingAdditionalAccounts] = (0, _react.useState)(false);
// Memoize theme-related calculations to prevent unnecessary recalculations
const themeStyles = (0, _react.useMemo)(() => {
const isDarkTheme = theme === 'dark';
return {
isDarkTheme,
textColor: isDarkTheme ? '#FFFFFF' : '#000000',
backgroundColor: isDarkTheme ? '#121212' : '#FFFFFF',
secondaryBackgroundColor: isDarkTheme ? '#222222' : '#F5F5F5',
borderColor: isDarkTheme ? '#444444' : '#E0E0E0',
primaryColor: '#d169e5',
dangerColor: '#D32F2F',
iconColor: isDarkTheme ? '#BBBBBB' : '#666666'
};
}, [theme]);
// Memoize additional accounts filtering to prevent recalculation on every render
const additionalAccounts = (0, _react.useMemo)(() => sessions.filter(session => session.sessionId !== activeSessionId && session.userId !== user?.id), [sessions, activeSessionId, user?.id]);
// Load user profiles for additional accounts
_react.default.useEffect(() => {
const loadAdditionalAccountsData = async () => {
if (!oxyServices || additionalAccounts.length === 0) {
setAdditionalAccountsData([]);
return;
}
setLoadingAdditionalAccounts(true);
try {
const accountsData = await Promise.all(additionalAccounts.map(async session => {
try {
const userProfile = await oxyServices.getUserBySession(session.sessionId);
return {
id: session.sessionId,
sessionId: session.sessionId,
username: userProfile.username,
email: userProfile.email,
name: userProfile.name,
avatar: userProfile.avatar,
userProfile
};
} catch (error) {
console.error(`Failed to load profile for session ${session.sessionId}:`, error);
return {
id: session.sessionId,
sessionId: session.sessionId,
username: 'Unknown User',
email: 'No email available',
avatar: null,
userProfile: null
};
}
}));
setAdditionalAccountsData(accountsData);
} catch (error) {
console.error('Failed to load additional accounts:', error);
setAdditionalAccountsData([]);
} finally {
setLoadingAdditionalAccounts(false);
}
};
loadAdditionalAccountsData();
}, [sessions, activeSessionId, user?.id, oxyServices]);
// Feature settings (with mock values)
const features = {
safeSearch: false,
language: 'English'
};
// Memoize event handlers to prevent recreation on every render
const handleLogout = (0, _react.useCallback)(async () => {
try {
await logout();
if (onClose) {
onClose();
}
} catch (error) {
console.error('Logout failed:', error);
_sonner.toast.error(t('common.errors.signOutFailed'));
}
}, [logout, onClose]);
const confirmLogout = (0, _react.useCallback)(() => {
(0, _confirmAction.confirmAction)(t('common.confirms.signOut'), handleLogout);
}, [handleLogout]);
const handleAddAccount = (0, _react.useCallback)(() => {
_sonner.toast.info(t('accountOverview.addAccountComing'));
}, [t]);
const handleSignOutAll = (0, _react.useCallback)(() => {
(0, _confirmAction.confirmAction)(t('common.confirms.signOutAll'), handleLogout);
}, [handleLogout]);
const handleDownloadData = (0, _react.useCallback)(async () => {
if (!oxyServices || !user) {
_sonner.toast.error(t('accountOverview.items.downloadData.error') || 'Service not available');
return;
}
try {
_reactNative.Alert.alert(t('accountOverview.items.downloadData.confirmTitle') || 'Download Account Data', t('accountOverview.items.downloadData.confirmMessage') || 'Choose the format for your account data export:', [{
text: t('common.cancel') || 'Cancel',
style: 'cancel'
}, {
text: 'JSON',
onPress: async () => {
try {
_sonner.toast.loading(t('accountOverview.items.downloadData.downloading') || 'Preparing download...');
const blob = await oxyServices.downloadAccountData('json');
// Create download link for web
if (_reactNative.Platform.OS === 'web') {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `account-data-${Date.now()}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
_sonner.toast.success(t('accountOverview.items.downloadData.success') || 'Data downloaded successfully');
} else {
// For React Native, you'd need to use a library like expo-file-system
_sonner.toast.success(t('accountOverview.items.downloadData.success') || 'Data downloaded successfully');
}
} catch (error) {
console.error('Failed to download data:', error);
_sonner.toast.error(error?.message || t('accountOverview.items.downloadData.error') || 'Failed to download data');
}
}
}, {
text: 'CSV',
onPress: async () => {
try {
_sonner.toast.loading(t('accountOverview.items.downloadData.downloading') || 'Preparing download...');
const blob = await oxyServices.downloadAccountData('csv');
// Create download link for web
if (_reactNative.Platform.OS === 'web') {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `account-data-${Date.now()}.csv`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
_sonner.toast.success(t('accountOverview.items.downloadData.success') || 'Data downloaded successfully');
} else {
// For React Native, you'd need to use a library like expo-file-system
_sonner.toast.success(t('accountOverview.items.downloadData.success') || 'Data downloaded successfully');
}
} catch (error) {
console.error('Failed to download data:', error);
_sonner.toast.error(error?.message || t('accountOverview.items.downloadData.error') || 'Failed to download data');
}
}
}]);
} catch (error) {
console.error('Failed to initiate download:', error);
_sonner.toast.error(error?.message || t('accountOverview.items.downloadData.error') || 'Failed to download data');
}
}, [oxyServices, user, t]);
const handleDeleteAccount = (0, _react.useCallback)(() => {
if (!user) {
_sonner.toast.error(t('accountOverview.items.deleteAccount.error') || 'User not available');
return;
}
(0, _confirmAction.confirmAction)(t('accountOverview.items.deleteAccount.confirmMessage') || `This action cannot be undone. This will permanently delete your account and all associated data.\n\nAre you sure you want to delete your account?`, async () => {
// For React Native, we'd need a separate modal for password/confirmation input
// For now, we'll use a simplified confirmation
// In production, you'd want to create a modal with password and username confirmation fields
if (!oxyServices) {
_sonner.toast.error(t('accountOverview.items.deleteAccount.error') || 'Service not available');
return;
}
_reactNative.Alert.alert(t('accountOverview.items.deleteAccount.confirmTitle') || 'Delete Account', t('accountOverview.items.deleteAccount.finalConfirm') || `This is your final warning. Your account will be permanently deleted and cannot be recovered. Type "${user.username}" to confirm.`, [{
text: t('common.cancel') || 'Cancel',
style: 'cancel'
}, {
text: t('accountOverview.items.deleteAccount.confirm') || 'Delete Forever',
style: 'destructive',
onPress: async () => {
try {
// Note: In a production app, you'd want to show a modal with password and username confirmation fields
// For now, we'll require the user to enter these via a custom modal or prompt
_sonner.toast.error(t('accountOverview.items.deleteAccount.passwordRequired') || 'Password confirmation required. This feature needs a modal with password input.');
} catch (error) {
console.error('Failed to delete account:', error);
_sonner.toast.error(error?.message || t('accountOverview.items.deleteAccount.error') || 'Failed to delete account');
}
}
}]);
});
}, [user, oxyServices, logout, onClose, t]);
if (!isAuthenticated) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: [styles.container, {
backgroundColor: themeStyles.backgroundColor
}],
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: [styles.message, {
color: themeStyles.textColor
}],
children: t('common.status.notSignedIn')
})
});
}
if (isLoading) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: [styles.container, {
backgroundColor: themeStyles.backgroundColor,
justifyContent: 'center'
}],
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
size: "large",
color: themeStyles.primaryColor
})
});
}
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: [styles.container, {
backgroundColor: '#f2f2f2'
}],
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Header, {
title: t('accountOverview.title'),
theme: theme,
onBack: onClose,
variant: "minimal",
elevation: "subtle"
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
style: styles.content,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.profile'),
theme: theme,
isFirst: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'profile-info',
icon: 'person',
iconColor: '#007AFF',
title: user ? typeof user.name === 'string' ? user.name : user.name?.full || user.name?.first || user.username : t('common.status.loading') || 'Loading...',
subtitle: user ? user.email || user.username : t('common.status.loading') || 'Loading...',
onPress: () => _sonner.toast.info(t('accountOverview.manageComing')),
customContent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.userIcon,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Avatar.default, {
uri: user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar, 'thumb') : undefined,
name: user?.name?.full,
size: 40,
theme: theme
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
style: styles.manageButton,
onPress: () => _sonner.toast.info(t('accountOverview.manageComing')),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.manageButtonText,
children: t('accountOverview.actions.manage')
})
})]
})
}],
theme: theme
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.accountSettings'),
theme: theme,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'edit-profile',
icon: 'person-circle',
iconColor: '#007AFF',
title: t('accountOverview.items.editProfile.title'),
subtitle: t('accountOverview.items.editProfile.subtitle'),
onPress: () => navigate?.('EditProfile', {
activeTab: 'profile'
})
}, {
id: 'security-privacy',
icon: 'shield-checkmark',
iconColor: '#30D158',
title: t('accountOverview.items.security.title'),
subtitle: t('accountOverview.items.security.subtitle'),
onPress: () => navigate?.('EditProfile', {
activeTab: 'password'
})
}, {
id: 'notifications',
icon: 'notifications',
iconColor: '#FF9500',
title: t('accountOverview.items.notifications.title'),
subtitle: t('accountOverview.items.notifications.subtitle'),
onPress: () => navigate?.('EditProfile', {
activeTab: 'notifications'
})
}, {
id: 'premium-subscription',
icon: 'star',
iconColor: '#FFD700',
title: t('accountOverview.items.premium.title'),
subtitle: user?.isPremium ? t('accountOverview.items.premium.manage') : t('accountOverview.items.premium.upgrade'),
onPress: () => navigate?.('PremiumSubscription')
}, ...(user?.isPremium ? [{
id: 'billing-management',
icon: 'card',
iconColor: '#34C759',
title: t('accountOverview.items.billing.title'),
subtitle: t('accountOverview.items.billing.subtitle'),
onPress: () => _sonner.toast.info(t('accountOverview.items.billing.coming'))
}] : [])],
theme: theme
})
}), showMoreAccounts && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: `${t('accountOverview.sections.additionalAccounts') || 'Additional Accounts'}${additionalAccountsData.length > 0 ? ` (${additionalAccountsData.length})` : ''}`,
theme: theme,
children: loadingAdditionalAccounts ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'loading-accounts',
icon: 'sync',
iconColor: '#007AFF',
title: t('accountOverview.loadingAdditional.title') || 'Loading accounts...',
subtitle: t('accountOverview.loadingAdditional.subtitle') || 'Please wait while we load your additional accounts',
customContent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: styles.loadingContainer,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
size: "small",
color: "#007AFF"
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.loadingText,
children: t('accountOverview.loadingAdditional.title') || 'Loading accounts...'
})]
})
}],
theme: theme
}) : additionalAccountsData.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: additionalAccountsData.map((account, index) => ({
id: `account-${account.id}`,
icon: 'person',
iconColor: '#5856D6',
title: typeof account.name === 'object' ? account.name?.full || account.name?.first || account.username : account.name || account.username,
subtitle: account.email || account.username,
onPress: () => {
_sonner.toast.info(t('accountOverview.items.accountSwitcher.switchPrompt', {
username: account.username
}) || `Switch to ${account.username}?`);
},
customContent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.userIcon,
children: account.avatar ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
source: {
uri: oxyServices.getFileDownloadUrl(account.avatar, 'thumb')
},
style: styles.accountAvatarImage
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.accountAvatarFallback,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.accountAvatarText,
children: account.username?.charAt(0).toUpperCase() || '?'
})
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, {
name: "chevron-forward",
size: 16,
color: "#ccc"
})]
})
})),
theme: theme
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'no-accounts',
icon: 'person-outline',
iconColor: '#ccc',
title: t('accountOverview.additional.noAccounts.title') || 'No other accounts',
subtitle: t('accountOverview.additional.noAccounts.subtitle') || 'Add another account to switch between them'
}],
theme: theme
})
}), showMoreAccounts && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.accountManagement') || 'Account Management',
theme: theme,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'add-account',
icon: 'add',
iconColor: '#007AFF',
title: t('accountOverview.items.addAccount.title') || 'Add Another Account',
subtitle: t('accountOverview.items.addAccount.subtitle') || 'Sign in with a different account',
onPress: handleAddAccount
}, {
id: 'sign-out-all',
icon: 'log-out',
iconColor: '#FF3B30',
title: t('accountOverview.items.signOutAll.title') || 'Sign out of all accounts',
subtitle: t('accountOverview.items.signOutAll.subtitle') || 'Remove all accounts from this device',
onPress: handleSignOutAll
}],
theme: theme
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.quickActions'),
theme: theme,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'account-switcher',
icon: 'people',
iconColor: '#5856D6',
title: showMoreAccounts ? t('accountOverview.items.accountSwitcher.titleHide') : t('accountOverview.items.accountSwitcher.titleShow'),
subtitle: showMoreAccounts ? t('accountOverview.items.accountSwitcher.subtitleHide') : additionalAccountsData.length > 0 ? t('accountOverview.items.accountSwitcher.subtitleSwitchBetween', {
count: String(additionalAccountsData.length + 1)
}) : loadingAdditionalAccounts ? t('accountOverview.items.accountSwitcher.subtitleLoading') : t('accountOverview.items.accountSwitcher.subtitleManageMultiple'),
onPress: () => setShowMoreAccounts(!showMoreAccounts)
}, {
id: 'history-view',
icon: 'time',
iconColor: '#007AFF',
title: t('accountOverview.items.history.title') || 'History',
subtitle: t('accountOverview.items.history.subtitle') || 'View and manage your search history',
onPress: () => navigate?.('HistoryView')
}, {
id: 'saves-collections',
icon: 'bookmark',
iconColor: '#FF9500',
title: t('accountOverview.items.saves.title') || 'Saves & Collections',
subtitle: t('accountOverview.items.saves.subtitle') || 'View your saved items and collections',
onPress: () => navigate?.('SavesCollections')
}, {
id: 'download-data',
icon: 'download',
iconColor: '#34C759',
title: t('accountOverview.items.downloadData.title'),
subtitle: t('accountOverview.items.downloadData.subtitle'),
onPress: handleDownloadData
}, {
id: 'delete-account',
icon: 'trash',
iconColor: '#FF3B30',
title: t('accountOverview.items.deleteAccount.title'),
subtitle: t('accountOverview.items.deleteAccount.subtitle'),
onPress: handleDeleteAccount
}],
theme: theme
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.support'),
theme: theme,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
items: [{
id: 'search-settings',
icon: 'search',
iconColor: '#007AFF',
title: t('accountOverview.items.searchSettings.title') || 'Search Settings',
subtitle: t('accountOverview.items.searchSettings.subtitle') || 'SafeSearch and personalization',
onPress: () => navigate?.('SearchSettings')
}, {
id: 'language-settings',
icon: 'language',
iconColor: '#32D74B',
title: t('accountOverview.items.language.title') || 'Language',
subtitle: t('accountOverview.items.language.subtitle') || 'Choose your preferred language',
onPress: () => navigate?.('LanguageSelector')
}, {
id: 'account-preferences',
icon: 'settings',
iconColor: '#8E8E93',
title: t('accountOverview.items.preferences.title'),
subtitle: t('accountOverview.items.preferences.subtitle'),
onPress: () => _sonner.toast.info(t('accountOverview.items.preferences.coming'))
}, {
id: 'help-support',
icon: 'help-circle',
iconColor: '#007AFF',
title: t('accountOverview.items.help.title'),
subtitle: t('accountOverview.items.help.subtitle'),
onPress: () => navigate?.('HelpSupport')
}, {
id: 'privacy-policy',
icon: 'shield-checkmark',
iconColor: '#30D158',
title: t('accountOverview.items.privacyPolicy.title') || 'Privacy Policy',
subtitle: t('accountOverview.items.privacyPolicy.subtitle') || 'How we handle your data',
onPress: () => navigate?.('LegalDocuments', {
initialStep: 1
})
}, {
id: 'terms-of-service',
icon: 'document-text',
iconColor: '#007AFF',
title: t('accountOverview.items.termsOfService.title') || 'Terms of Service',
subtitle: t('accountOverview.items.termsOfService.subtitle') || 'Terms and conditions of use',
onPress: () => navigate?.('LegalDocuments', {
initialStep: 2
})
}, {
id: 'connected-apps',
icon: 'link',
iconColor: '#32D74B',
title: t('accountOverview.items.connectedApps.title'),
subtitle: t('accountOverview.items.connectedApps.subtitle'),
onPress: () => _sonner.toast.info(t('accountOverview.items.connectedApps.coming'))
}, {
id: 'about',
icon: 'information-circle',
iconColor: '#8E8E93',
title: t('accountOverview.items.about.title'),
subtitle: t('accountOverview.items.about.subtitle'),
onPress: () => navigate?.('AppInfo')
}],
theme: theme
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Section, {
title: t('accountOverview.sections.actions'),
theme: theme,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedItem, {
icon: "log-out",
iconColor: "#FF3B30",
title: t('accountOverview.items.signOut.title'),
subtitle: t('accountOverview.items.signOut.subtitle'),
theme: theme,
onPress: confirmLogout,
isFirst: true,
isLast: true,
showChevron: false
})
})]
})]
});
};
const styles = _reactNative.StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f2f2f2'
},
content: {
flex: 1,
padding: 16
},
userIcon: {
marginRight: 12
},
manageButton: {
backgroundColor: '#007AFF',
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 16
},
manageButtonText: {
color: '#fff',
fontSize: 14,
fontWeight: '500'
},
accountAvatarImage: {
width: 40,
height: 40,
borderRadius: 20
},
accountAvatarFallback: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#d169e5',
alignItems: 'center',
justifyContent: 'center'
},
accountAvatarText: {
color: 'white',
fontSize: 18,
fontWeight: 'bold'
},
message: {
fontSize: 16,
textAlign: 'center',
marginTop: 24,
color: '#333'
},
loadingContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 20,
gap: 12
},
loadingText: {
fontSize: 16,
color: '#666'
}
});
var _default = exports.default = /*#__PURE__*/_react.default.memo(AccountOverviewScreen);
//# sourceMappingURL=AccountOverviewScreen.js.map