@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
JavaScript
;
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