UNPKG

@oxyhq/services

Version:

Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀

664 lines (649 loc) 25.2 kB
"use strict"; 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 _fonts = require("../styles/fonts"); var _version = require("../../constants/version"); var _sonner = require("../../lib/sonner"); var _OxyIcon = _interopRequireDefault(require("../components/icon/OxyIcon")); var _vectorIcons = require("@expo/vector-icons"); var _OxyServices = _interopRequireDefault(require("../../assets/icons/OxyServices")); 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); } const AppInfoScreen = ({ onClose, theme, navigate }) => { const { user, sessions, oxyServices } = (0, _OxyContext.useOxy)(); const [systemInfo, setSystemInfo] = (0, _react.useState)(null); const [isRunningSystemCheck, setIsRunningSystemCheck] = (0, _react.useState)(false); const [connectionStatus, setConnectionStatus] = (0, _react.useState)('unknown'); const isDarkTheme = theme === 'dark'; const backgroundColor = isDarkTheme ? '#121212' : '#f2f2f2'; const primaryColor = '#007AFF'; (0, _react.useEffect)(() => { const updateDimensions = () => { const dimensions = _reactNative.Dimensions.get('window'); setSystemInfo(prev => ({ ...prev, platform: _reactNative.Platform.OS, version: _reactNative.Platform.Version?.toString() || 'Unknown', screenDimensions: { width: dimensions.width, height: dimensions.height }, timestamp: new Date().toISOString() })); }; // Set initial dimensions updateDimensions(); // Listen for dimension changes const subscription = _reactNative.Dimensions.addEventListener('change', updateDimensions); // Check API connection on mount const checkConnection = async () => { setConnectionStatus('checking'); const apiBaseUrl = oxyServices?.getBaseURL() || 'https://api.oxy.so'; try { const response = await fetch(`${apiBaseUrl}/`, { method: 'GET', timeout: 3000 }); if (response.ok) { setConnectionStatus('connected'); } else { setConnectionStatus('disconnected'); } } catch (error) { setConnectionStatus('disconnected'); } }; checkConnection(); // Cleanup listener on unmount return () => { subscription?.remove(); }; }, []); const copyToClipboard = async (text, label) => { try { await _reactNative.Clipboard.setString(text); _sonner.toast.success(`${label} copied to clipboard`); } catch (error) { _sonner.toast.error('Failed to copy to clipboard'); } }; const runSystemCheck = async () => { if (!oxyServices) { _sonner.toast.error('OxyServices not initialized'); return; } setIsRunningSystemCheck(true); const checks = []; // Get the API base URL from the services instance const apiBaseUrl = oxyServices?.getBaseURL() || 'https://api.oxy.so'; // Default for now, could be made configurable try { // Check 1: API Server Health checks.push('🔍 Checking API server connection...'); _sonner.toast.info('Running system checks...', { duration: 2000 }); try { const response = await fetch(`${apiBaseUrl}/`, { method: 'GET', timeout: 5000 }); if (response.ok) { const data = await response.json(); checks.push('✅ API server is responding'); checks.push(`📊 Server stats: ${data.users || 0} users`); checks.push(`🌐 API URL: ${apiBaseUrl}`); setConnectionStatus('connected'); } else { checks.push('❌ API server returned error status'); checks.push(` Status: ${response.status} ${response.statusText}`); setConnectionStatus('disconnected'); } } catch (error) { checks.push('❌ API server connection failed'); checks.push(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`); checks.push(` URL: ${apiBaseUrl}`); setConnectionStatus('disconnected'); } // Check 2: Authentication Status checks.push('🔍 Checking authentication...'); if (oxyServices.isAuthenticated()) { checks.push('✅ User is authenticated'); // Check 3: Token Validation try { const isValid = await oxyServices.validate(); if (isValid) { checks.push('✅ Authentication token is valid'); } else { checks.push('❌ Authentication token is invalid'); } } catch (error) { checks.push('❌ Token validation failed'); checks.push(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`); } } else { checks.push('⚠️ User is not authenticated'); } // Check 4: Session Validation (if user has active sessions) if (user && sessions && sessions.length > 0) { checks.push('🔍 Checking active sessions...'); try { // Just check if we can fetch sessions const userSessions = await oxyServices.getUserSessions(); checks.push(`✅ Session validation successful (${userSessions.length} sessions)`); } catch (error) { checks.push('❌ Session validation failed'); checks.push(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`); } } // Check 5: Platform Information checks.push('🔍 Checking platform information...'); checks.push(`✅ Platform: ${_reactNative.Platform.OS} ${_reactNative.Platform.Version || 'Unknown'}`); checks.push(`✅ Screen: ${systemInfo?.screenDimensions.width || 0}x${systemInfo?.screenDimensions.height || 0}`); checks.push(`✅ Environment: ${__DEV__ ? 'Development' : 'Production'}`); // Check 6: Package Information checks.push('🔍 Checking package information...'); checks.push(`✅ Package: ${_version.packageInfo.name}@${_version.packageInfo.version}`); // Check 7: Memory and Performance (basic) checks.push('🔍 Checking performance metrics...'); const memoryUsage = performance.memory; if (memoryUsage) { const usedMB = Math.round(memoryUsage.usedJSHeapSize / 1024 / 1024); const totalMB = Math.round(memoryUsage.totalJSHeapSize / 1024 / 1024); checks.push(`✅ Memory usage: ${usedMB}MB / ${totalMB}MB`); } else { checks.push('✅ Performance metrics not available on this platform'); } // Final summary const errorCount = checks.filter(check => check.includes('❌')).length; const warningCount = checks.filter(check => check.includes('⚠️')).length; checks.push(''); checks.push('📋 SYSTEM CHECK SUMMARY:'); if (errorCount === 0 && warningCount === 0) { checks.push('✅ All systems operational'); _sonner.toast.success('System check completed - All systems operational!'); } else if (errorCount === 0) { checks.push(`⚠️ ${warningCount} warning(s) found`); _sonner.toast.warning(`System check completed with ${warningCount} warning(s)`); } else { checks.push(`❌ ${errorCount} error(s) and ${warningCount} warning(s) found`); _sonner.toast.error(`System check failed with ${errorCount} error(s)`); } // Show results in an alert and copy to clipboard const report = checks.join('\n'); _reactNative.Alert.alert('System Check Results', `Check completed. Results copied to clipboard.\n\nSummary: ${errorCount} errors, ${warningCount} warnings`, [{ text: 'View Full Report', onPress: () => copyToClipboard(report, 'System check report') }, { text: 'OK', style: 'default' }]); } catch (error) { _sonner.toast.error('System check failed to run'); console.error('System check error:', error); } finally { setIsRunningSystemCheck(false); } }; const generateFullReport = () => { const report = { packageInfo: { name: _version.packageInfo.name, version: _version.packageInfo.version, description: _version.packageInfo.description }, systemInfo, userInfo: { isAuthenticated: !!user, userId: user?.id || 'Not authenticated', username: user?.username || 'N/A', totalUsers: sessions?.length || 0 }, apiConfiguration: { apiUrl: oxyServices?.getBaseURL() || 'Not configured' }, buildInfo: { timestamp: new Date().toISOString(), environment: __DEV__ ? 'Development' : 'Production' } }; return JSON.stringify(report, null, 2); }; const handleCopyFullReport = () => { const report = generateFullReport(); copyToClipboard(report, 'Full application report'); }; const InfoRow = ({ label, value, copyable = false, icon = 'information-circle', iconComponent, color = '#8E8E93', isFirst = false, isLast = false, onPress, showChevron = false }) => { const handlePress = () => { if (onPress) { onPress(); } else if (copyable) { copyToClipboard(value, label); } }; const isInteractive = copyable || !!onPress; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.settingItem, isFirst && styles.firstSettingItem, isLast && styles.lastSettingItem], onPress: isInteractive ? handlePress : undefined, disabled: !isInteractive, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingInfo, children: [iconComponent ? (/*#__PURE__*/_react.default.cloneElement(iconComponent, { style: styles.settingIcon })) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: icon, size: 20, color: color, style: styles.settingIcon }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingDetails, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.settingLabel, children: label }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.settingValue, (copyable || onPress) && { color: primaryColor }], children: value })] })] }), copyable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: "copy", size: 16, color: "#ccc" }), showChevron && /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: "chevron-forward", size: 16, color: "#ccc" })] }); }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.container, { backgroundColor }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.header, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, { style: styles.cancelButton, onPress: onClose, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "close", size: 24, color: "#666" }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.headerTitle, children: "App Information" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.placeholder })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, { style: styles.content, showsVerticalScrollIndicator: false, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "Package Information" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Name", value: _version.packageInfo.name, copyable: true, iconComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyServices.default, { width: 20, height: 20 }), color: "#007AFF", isFirst: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Version", value: _version.packageInfo.version, copyable: true, icon: "pricetag", color: "#5856D6" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Description", value: _version.packageInfo.description || 'No description', icon: "document-text", color: "#34C759" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Main Entry", value: _version.packageInfo.main || 'N/A', icon: "code", color: "#FF9500" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Module Entry", value: _version.packageInfo.module || 'N/A', icon: "library", color: "#FF3B30" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Types Entry", value: _version.packageInfo.types || 'N/A', icon: "construct", color: "#32D74B", isLast: true })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "System Information" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Platform", value: _reactNative.Platform.OS, icon: "phone-portrait", color: "#007AFF", isFirst: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Platform Version", value: systemInfo?.version || 'Loading...', icon: "hardware-chip", color: "#5856D6" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Screen Width", value: `${systemInfo?.screenDimensions.width || 0}px`, icon: "resize", color: "#FF9500" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Screen Height", value: `${systemInfo?.screenDimensions.height || 0}px`, icon: "resize", color: "#FF3B30" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Environment", value: __DEV__ ? 'Development' : 'Production', icon: "settings", color: "#34C759", isLast: true })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "User Information" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Authentication Status", value: user ? 'Authenticated' : 'Not Authenticated', icon: "shield-checkmark", color: user ? '#34C759' : '#FF3B30', isFirst: true }), user && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "User ID", value: user.id, copyable: true, icon: "person", color: "#007AFF" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Username", value: user.username || 'N/A', icon: "at", color: "#5856D6", onPress: () => { if (user?.username && navigate) { navigate('Profile', { userId: user.id }); } else { _sonner.toast.info('No username available or navigation not supported'); } }, showChevron: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Email", value: user.email || 'N/A', icon: "mail", color: "#FF9500" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Premium Status", value: user.isPremium ? 'Premium' : 'Standard', icon: "star", color: user.isPremium ? '#FFD700' : '#8E8E93' })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Total Active Sessions", value: sessions?.length?.toString() || '0', icon: "people", color: "#32D74B", isLast: true })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "API Configuration" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "API Base URL", value: oxyServices?.getBaseURL() || 'Not configured', copyable: true, icon: "server", color: "#007AFF", isFirst: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Connection Status", value: connectionStatus === 'checking' ? 'Checking...' : connectionStatus === 'connected' ? 'Connected' : connectionStatus === 'disconnected' ? 'Disconnected' : 'Unknown', icon: connectionStatus === 'checking' ? 'sync' : connectionStatus === 'connected' ? 'wifi' : 'wifi-off', color: connectionStatus === 'checking' ? '#FF9500' : connectionStatus === 'connected' ? '#34C759' : '#FF3B30', onPress: async () => { setConnectionStatus('checking'); const apiBaseUrl = oxyServices?.getBaseURL() || 'https://api.oxy.so'; try { const response = await fetch(`${apiBaseUrl}/`, { method: 'GET', timeout: 3000 }); if (response.ok) { setConnectionStatus('connected'); _sonner.toast.success('API connection successful'); } else { setConnectionStatus('disconnected'); _sonner.toast.error(`API server error: ${response.status}`); } } catch (error) { setConnectionStatus('disconnected'); _sonner.toast.error('Failed to connect to API server'); } }, showChevron: true, isLast: true })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "Build Information" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "Build Timestamp", value: systemInfo?.timestamp || 'Loading...', copyable: true, icon: "time", color: "#007AFF", isFirst: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "React Native", value: "Expo/React Native", icon: "logo-react", color: "#61DAFB" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, { label: "JavaScript Engine", value: "Hermes", icon: "flash", color: "#FF3B30", isLast: true })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.section, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.sectionTitle, children: "Quick Actions" }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.settingItem, styles.firstSettingItem], onPress: handleCopyFullReport, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingInfo, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: "copy", size: 20, color: "#007AFF", style: styles.settingIcon }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingDetails, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.settingLabel, children: "Copy Full Report" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.settingDescription, children: "Copy complete application information to clipboard" })] })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: "chevron-forward", size: 16, color: "#ccc" })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.settingItem, styles.lastSettingItem, isRunningSystemCheck && styles.disabledSettingItem], onPress: runSystemCheck, disabled: isRunningSystemCheck, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingInfo, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: isRunningSystemCheck ? "sync" : "checkmark-circle", size: 20, color: isRunningSystemCheck ? "#FF9500" : "#34C759", style: [styles.settingIcon, isRunningSystemCheck && styles.spinningIcon] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.settingDetails, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.settingLabel, children: isRunningSystemCheck ? 'Running System Check...' : 'Run System Check' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.settingDescription, children: isRunningSystemCheck ? 'Checking API, authentication, and platform status...' : 'Verify application health and status' })] })] }), !isRunningSystemCheck && /*#__PURE__*/(0, _jsxRuntime.jsx)(_OxyIcon.default, { name: "chevron-forward", size: 16, color: "#ccc" })] })] })] })] }); }; const styles = _reactNative.StyleSheet.create({ container: { flex: 1 }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 16, paddingVertical: 12, backgroundColor: '#fff' }, cancelButton: { padding: 5 }, headerTitle: { fontSize: 24, fontWeight: 'bold', color: '#000', fontFamily: _fonts.fontFamilies.phuduBold }, placeholder: { width: 34 // Same width as cancel button to center title }, content: { flex: 1, padding: 16 }, section: { marginBottom: 24 }, sectionTitle: { fontSize: 16, fontWeight: '600', color: '#333', marginBottom: 12, fontFamily: _fonts.fontFamilies.phuduSemiBold }, settingItem: { backgroundColor: '#fff', padding: 16, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 2 }, firstSettingItem: { borderTopLeftRadius: 24, borderTopRightRadius: 24 }, lastSettingItem: { borderBottomLeftRadius: 24, borderBottomRightRadius: 24, marginBottom: 8 }, settingInfo: { flexDirection: 'row', alignItems: 'center', flex: 1 }, settingIcon: { marginRight: 12 }, settingDetails: { flex: 1 }, settingLabel: { fontSize: 16, fontWeight: '500', color: '#333', marginBottom: 2 }, settingValue: { fontSize: 14, color: '#666' }, settingDescription: { fontSize: 14, color: '#999' }, disabledSettingItem: { opacity: 0.6 }, spinningIcon: { // Note: Animation would need to be implemented with Animated API // For now, just showing the sync icon to indicate loading } }); var _default = exports.default = AppInfoScreen; //# sourceMappingURL=AppInfoScreen.js.map