UNPKG

@oxyhq/services

Version:

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

213 lines (201 loc) • 7.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.OxyRouter = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _ErrorBoundary = _interopRequireDefault(require("../components/ErrorBoundary")); var _routes = require("./routes"); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } // Import types and route registry // Helper function to validate route names at runtime const isValidRouteName = screen => { return _routes.routeNames.includes(screen); }; // Helper function for safe navigation with validation const validateAndNavigate = (screen, props, setCurrentScreen, setScreenHistory, setScreenPropsMap) => { if (!isValidRouteName(screen)) { const errorMsg = `Invalid route name: "${screen}". Valid routes are: ${_routes.routeNames.join(', ')}`; console.error('OxyRouter:', errorMsg); if (process.env.NODE_ENV !== 'production') { console.error('Navigation error:', errorMsg); } return false; } if (!_routes.routes[screen]) { const errorMsg = `Route "${screen}" is registered but component is missing`; console.error('OxyRouter:', errorMsg); if (process.env.NODE_ENV !== 'production') { console.error('Navigation error:', errorMsg); } return false; } return true; }; const OxyRouter = ({ oxyServices, initialScreen, onClose, onAuthenticated, theme, adjustSnapPoints, navigationRef, containerWidth }) => { const [currentScreen, setCurrentScreen] = (0, _react.useState)(initialScreen); const [screenHistory, setScreenHistory] = (0, _react.useState)([initialScreen]); // Store props per screen for correct restoration on back const [screenPropsMap, setScreenPropsMap] = (0, _react.useState)({ [initialScreen]: {} }); // Update snap points when the screen changes (0, _react.useEffect)(() => { if (_routes.routes[currentScreen] && typeof adjustSnapPoints === 'function') { adjustSnapPoints(_routes.routes[currentScreen].snapPoints); } }, [currentScreen, adjustSnapPoints]); // Memoized navigation methods with validation const navigate = (0, _react.useCallback)((screen, props = {}) => { if (__DEV__) console.log('OxyRouter: navigate called', screen, props); // Validate route before navigating if (!validateAndNavigate(screen, props, setCurrentScreen, setScreenHistory, setScreenPropsMap)) { return; // Early return if validation fails } // All validations passed, proceed with navigation setCurrentScreen(screen); setScreenHistory(prev => [...prev, screen]); setScreenPropsMap(prev => ({ ...prev, [screen]: props })); }, []); const goBack = (0, _react.useCallback)(() => { setScreenHistory(prev => { if (prev.length > 1) { const newHistory = [...prev]; newHistory.pop(); const previousScreen = newHistory[newHistory.length - 1]; setCurrentScreen(previousScreen); return newHistory; } else { if (onClose) onClose(); return prev; } }); }, [onClose]); // Expose the navigate function to the parent component (0, _react.useEffect)(() => { if (navigationRef) { navigationRef.current = navigate; if (__DEV__) console.log('OxyRouter: navigationRef set'); } return () => { if (navigationRef) { navigationRef.current = null; if (__DEV__) console.log('OxyRouter: navigationRef cleared'); } }; }, [navigate, navigationRef]); // Expose the navigate method to the parent component (OxyProvider) (0, _react.useEffect)(() => { const handleNavigationEvent = event => { if (event && event.detail) { if (typeof event.detail === 'string') { // Validate string route name before navigating if (isValidRouteName(event.detail)) { navigate(event.detail); } else { console.error('OxyRouter: Invalid route name in event:', event.detail); } } else if (typeof event.detail === 'object' && event.detail.screen) { const { screen, props } = event.detail; // Validate route name before navigating if (isValidRouteName(screen)) { navigate(screen, props || {}); } else { console.error('OxyRouter: Invalid route name in event:', screen); } } } }; let intervalId = null; if (typeof document !== 'undefined' && document.addEventListener) { document.addEventListener('oxy:navigate', handleNavigationEvent); } else { intervalId = setInterval(() => { const globalNav = globalThis.oxyNavigateEvent; if (globalNav && globalNav.screen) { // Validate route name before navigating if (isValidRouteName(globalNav.screen)) { navigate(globalNav.screen, globalNav.props || {}); globalThis.oxyNavigateEvent = null; } else { console.error('OxyRouter: Invalid route name in global event:', globalNav.screen); globalThis.oxyNavigateEvent = null; // Clear invalid event } } }, 100); } return () => { if (typeof document !== 'undefined' && document.removeEventListener) { document.removeEventListener('oxy:navigate', handleNavigationEvent); } if (intervalId) { clearInterval(intervalId); } }; }, [navigate]); // Render the current screen component with error boundary const renderScreen = () => { const CurrentScreen = _routes.routes[currentScreen]?.component; if (!CurrentScreen) { if (process.env.NODE_ENV !== 'production') { console.error(`Screen "${currentScreen}" not found`); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.errorContainer }); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorBoundary.default, { onError: (error, errorInfo) => { console.error(`Error in screen "${currentScreen}":`, error, errorInfo); }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(CurrentScreen, { oxyServices: oxyServices, navigate: navigate, goBack: goBack, onClose: onClose, onAuthenticated: onAuthenticated, theme: theme, containerWidth: containerWidth, ...(screenPropsMap[currentScreen] || {}) }) }); }; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.container, children: renderScreen() }); }; // Memoize the router component to prevent unnecessary re-renders exports.OxyRouter = OxyRouter; const MemoizedOxyRouter = /*#__PURE__*/(0, _react.memo)(OxyRouter); const styles = _reactNative.StyleSheet.create({ container: { flex: 1 }, errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', minHeight: 100 } }); // Export both the memoized version (default) and the original for testing var _default = exports.default = MemoizedOxyRouter; //# sourceMappingURL=OxyRouter.js.map