react-native-acoustic-connect-beta
Version:
BETA: React native plugin for Acoustic Connect
282 lines (257 loc) • 13.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createTrackedDialogComponents = createTrackedDialogComponents;
exports.useTrackedDialogs = useTrackedDialogs;
exports.withAcousticAutoDialog = withAcousticAutoDialog;
var _react = _interopRequireWildcard(require("react"));
var _useDialogTracking = require("./useDialogTracking");
var _index = _interopRequireDefault(require("../index"));
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); }
/********************************************************************************************
* Copyright (C) 2025 Acoustic, L.P. All rights reserved.
*
* NOTICE: This file contains material that is confidential and proprietary to
* Acoustic, L.P. and/or other developers. No license is granted under any intellectual or
* industrial property rights of Acoustic, L.P. except as may be provided in an agreement with
* Acoustic, L.P. Any unauthorized copying or distribution of content from this file is
* prohibited.
*
* Created by Omar Hernandez on 5/9/25.
*
********************************************************************************************/
/**
* HOC Wrapper that automatically tracks dialog show/dismiss events and button clicks
* Works with any dialog component that has 'visible' and 'onDismiss' props
*
* Supported Dialog Patterns:
* - react-native-paper Dialog components
* - Custom modal components with visible/onDismiss props
* - Components with different prop names (show/hide, open/close, etc.)
* - Components with custom button implementations
* - Components with nested dialog structures
*/
function withAcousticAutoDialog(DialogComponent) {
return /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
const {
generateDialogId
} = (0, _useDialogTracking.useDialogTracking)();
const dialogIdRef = (0, _react.useRef)(null);
const isVisibleRef = (0, _react.useRef)(false);
// Track button click event
const trackButtonClick = (0, _react.useCallback)((buttonText, buttonIndex) => {
if (dialogIdRef.current) {
_index.default.logDialogButtonClickEvent(dialogIdRef.current, buttonText, buttonIndex);
console.log(`🔍 withAcousticAutoDialog: Button clicked - ${buttonText} (${dialogIdRef.current})`);
}
}, []);
// Wrap button onPress handlers to track clicks
const wrapButtonOnPress = (0, _react.useCallback)((originalOnPress, buttonText, buttonIndex) => {
return () => {
trackButtonClick(buttonText, buttonIndex);
if (originalOnPress) {
originalOnPress();
}
};
}, [trackButtonClick]);
// Recursively wrap buttons in children
const wrapButtonsInChildren = (0, _react.useCallback)((children, buttonIndex = 0) => {
if (!children) return children;
if (Array.isArray(children)) {
return children.map((child, index) => wrapButtonsInChildren(child, buttonIndex + index));
}
if (/*#__PURE__*/_react.default.isValidElement(children)) {
const childProps = children.props;
// Check if this is a button component (supports various button types)
const isButton = typeof children.type === 'function' && (children.type.displayName === 'Button' || children.type.name === 'Button' || children.type.displayName === 'DialogAction' || children.type.name === 'DialogAction' || children.type.displayName === 'TouchableOpacity' || children.type.name === 'TouchableOpacity' || children.type.displayName === 'Pressable' || children.type.name === 'Pressable') || childProps && (childProps.onPress || childProps.onPressIn || childProps.onPressOut || childProps.onTouchEnd);
if (isButton && childProps?.onPress) {
const buttonText = childProps.children || childProps.title || 'Button';
return /*#__PURE__*/_react.default.cloneElement(children, {
...childProps,
onPress: wrapButtonOnPress(childProps.onPress, buttonText, buttonIndex)
});
}
// Recursively wrap buttons in nested children
if (childProps?.children) {
return /*#__PURE__*/_react.default.cloneElement(children, {
...childProps,
children: wrapButtonsInChildren(childProps.children, buttonIndex)
});
}
}
return children;
}, [wrapButtonOnPress]);
// Track dialog show event when visible changes to true
// Supports various visibility prop names: visible, show, open, isOpen, isVisible
const isVisible = props.visible || props.show || props.open || props.isOpen || props.isVisible;
(0, _react.useEffect)(() => {
if (isVisible && !isVisibleRef.current) {
const dialogId = generateDialogId();
dialogIdRef.current = dialogId;
isVisibleRef.current = true;
// Get dialog title from various possible sources
const getDialogTitle = () => {
// Try to get title from props (supports various prop names)
if (props.title) return props.title;
if (props.dialogTitle) return props.dialogTitle;
if (props.header) return props.header;
if (props.heading) return props.heading;
if (props.name) return props.name;
// Try to get title from children (for react-native-paper Dialog)
if (props.children) {
console.log(`🔍 withAcousticAutoDialog: Starting title extraction from children`);
console.log(`🔍 withAcousticAutoDialog: Initial children:`, props.children);
const extractTitleFromChildren = (children, depth = 0) => {
if (!children) return null;
if (Array.isArray(children)) {
for (const child of children) {
const title = extractTitleFromChildren(child, depth + 1);
if (title) return title;
}
return null;
}
if (/*#__PURE__*/_react.default.isValidElement(children)) {
const childProps = children.props;
// Debug: Log component info for debugging
console.log(`🔍 withAcousticAutoDialog: Processing component at depth ${depth}:`, {
type: children.type,
displayName: children.type?.displayName,
name: children.type?.name,
hasChildren: !!childProps?.children,
childrenType: typeof childProps?.children
});
// Check if this is a Dialog component from react-native-paper
if (children.type && typeof children.type === 'function' && (children.type.displayName === 'Dialog' || children.type.name === 'Dialog')) {
console.log(`🔍 withAcousticAutoDialog: Found Dialog component at depth ${depth}`);
// Extract title from Dialog children
if (childProps?.children) {
return extractTitleFromChildren(childProps.children, depth + 1);
}
}
// Check if this is a Portal component (common wrapper for dialogs)
if (children.type && typeof children.type === 'function' && (children.type.displayName === 'Portal' || children.type.name === 'Portal')) {
console.log(`🔍 withAcousticAutoDialog: Found Portal component at depth ${depth}`);
// Extract title from Portal children
if (childProps?.children) {
return extractTitleFromChildren(childProps.children, depth + 1);
}
}
// Check if this is a DialogTitle component (supports various title component types)
if (children.type && typeof children.type === 'function' && (children.type.displayName === 'DialogTitle' || children.type.name === 'DialogTitle' || children.type.displayName === 'Title' || children.type.name === 'Title' || children.type.displayName === 'Header' || children.type.name === 'Header' || children.type.displayName === 'Heading' || children.type.name === 'Heading')) {
if (childProps?.children && typeof childProps.children === 'string') {
console.log(`🔍 withAcousticAutoDialog: Found title in title component: "${childProps.children}"`);
return childProps.children;
}
}
// Check if this component has title content
if (childProps?.title) {
return childProps.title;
}
// Recursively search in nested children
if (childProps?.children) {
return extractTitleFromChildren(childProps.children, depth + 1);
}
}
return null;
};
const title = extractTitleFromChildren(props.children);
if (title) {
console.log(`🔍 withAcousticAutoDialog: Found title from children: "${title}"`);
return title;
}
}
return 'Dialog';
};
const title = getDialogTitle();
// Log dialog show event
_index.default.logDialogShowEvent(dialogId, title, 'custom');
console.log(`🔍 withAcousticAutoDialog: Dialog shown - ${title} (${dialogId})`);
} else if (!isVisible && isVisibleRef.current) {
// Track dialog dismiss event when visible changes to false
if (dialogIdRef.current) {
_index.default.logDialogDismissEvent(dialogIdRef.current, 'user_action');
console.log(`🔍 withAcousticAutoDialog: Dialog dismissed - ${dialogIdRef.current}`);
dialogIdRef.current = null;
}
isVisibleRef.current = false;
}
}, [isVisible, generateDialogId]);
// Handle dismiss events (supports various dismiss prop names)
const handleDismiss = () => {
if (dialogIdRef.current) {
_index.default.logDialogDismissEvent(dialogIdRef.current, 'user_action');
console.log(`🔍 withAcousticAutoDialog: Dialog dismissed via dismiss handler - ${dialogIdRef.current}`);
dialogIdRef.current = null;
}
isVisibleRef.current = false;
// Call original dismiss handler if it exists (supports various prop names)
if (props.onDismiss) {
props.onDismiss();
} else if (props.onClose) {
props.onClose();
} else if (props.onHide) {
props.onHide();
} else if (props.close) {
props.close();
} else if (props.hide) {
props.hide();
}
};
// Forward ref to the wrapped component
(0, _react.useImperativeHandle)(ref, () => {
return {
...ref
// Add any additional methods if needed
};
}, [ref]);
// Wrap buttons in children to track clicks
const wrappedChildren = wrapButtonsInChildren(props.children);
// Determine which dismiss prop to use based on what the original component expects
const dismissProps = {};
if (props.onDismiss) {
dismissProps.onDismiss = handleDismiss;
} else if (props.onClose) {
dismissProps.onClose = handleDismiss;
} else if (props.onHide) {
dismissProps.onHide = handleDismiss;
} else if (props.close) {
dismissProps.close = handleDismiss;
} else if (props.hide) {
dismissProps.hide = handleDismiss;
} else {
// Default to onDismiss if no dismiss prop is found
dismissProps.onDismiss = handleDismiss;
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)(DialogComponent, {
...props,
...dismissProps,
ref: ref,
children: wrappedChildren
});
});
}
/**
* Convenience function to create tracked versions of common dialog components
*/
function createTrackedDialogComponents() {
// Note: These would need to be imported in the consuming app
// This is just a template for how to use the HOC
return {
// Example usage (uncomment when react-native-paper is available):
// TrackedDialog: withAcousticAutoDialog(require('react-native-paper').Dialog),
// TrackedPortal: withAcousticAutoDialog(require('react-native-paper').Portal),
};
}
/**
* Hook to get tracked dialog components
*/
function useTrackedDialogs() {
return {
withAcousticAutoDialog,
createTrackedDialogComponents
};
}
//# sourceMappingURL=withAcousticAutoDialog.js.map
;