UNPKG

@oxyhq/services

Version:

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

381 lines (364 loc) • 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _styles = require("../styles"); var _jsxRuntime = require("react/jsx-runtime"); 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); } // Individual animated progress dot const AnimatedProgressDot = ({ isActive, colors, styles }) => { const width = (0, _reactNativeReanimated.useSharedValue)(isActive ? 12 : 6); const backgroundColor = (0, _reactNativeReanimated.useSharedValue)(isActive ? colors.primary : colors.border); (0, _react.useEffect)(() => { width.value = (0, _reactNativeReanimated.withTiming)(isActive ? 12 : 6, { duration: 300 }); backgroundColor.value = (0, _reactNativeReanimated.withTiming)(isActive ? colors.primary : colors.border, { duration: 300 }); }, [isActive, colors.primary, colors.border, width, backgroundColor]); const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({ width: width.value, backgroundColor: backgroundColor.value })); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: [styles.progressDot, animatedStyle] }); }; // Progress indicator component const ProgressIndicator = ({ currentStep, totalSteps, colors, styles }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.progressContainer, children: Array.from({ length: totalSteps }, (_, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(AnimatedProgressDot, { isActive: currentStep === index, colors: colors, styles: styles }, index)) }); // Step container with animations const AnimatedStepContainer = ({ children, fadeAnim, slideAnim, scaleAnim, styles, stepKey }) => { const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({ opacity: fadeAnim.value, transform: [{ translateX: slideAnim.value }, { scale: scaleAnim.value }] })); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: [styles.stepContainer, animatedStyle], children: children }, stepKey); }; const StepBasedScreen = ({ steps, initialStep = 0, showProgressIndicator = true, enableAnimations = true, onStepChange, onComplete, stepData = [], navigate, goBack, onAuthenticated, theme, oxyServices }) => { const colors = (0, _styles.useThemeColors)(theme); const styles = (0, _react.useMemo)(() => ({ ...(0, _styles.createAuthStyles)(colors, theme), // Additional styles for step components modernHeader: { alignItems: 'flex-start', width: '100%', marginBottom: 24 }, modernTitle: { fontFamily: _reactNative.Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold', fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : undefined, fontSize: 42, lineHeight: 50.4, // 42 * 1.2 marginBottom: 12, textAlign: 'left' }, modernSubtitle: { fontSize: 18, lineHeight: 24, textAlign: 'left', opacity: 0.8 }, modernInputContainer: { width: '100%' }, button: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 18, paddingHorizontal: 32, borderRadius: 16, marginVertical: 8, gap: 8, width: '100%', ..._reactNative.Platform.select({ web: { boxShadow: '0 4px 8px rgba(0,0,0,0.3)' }, default: { shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 6 } }) }, buttonText: { color: '#FFFFFF', fontSize: 16, fontWeight: '600', letterSpacing: 0.5 }, footerText: { fontSize: 14, lineHeight: 20 }, footerTextContainer: { flexDirection: 'row', justifyContent: 'center', marginTop: 16 }, linkText: { fontSize: 14, lineHeight: 20, fontWeight: '600', textDecorationLine: 'underline' }, progressContainer: { flexDirection: 'row', width: '100%', justifyContent: 'center', marginTop: 24, // Space for bottom sheet handle (~20px) + small buffer marginBottom: 24 // Equal spacing below dots }, progressDot: { height: 6, width: 6, borderRadius: 3, marginHorizontal: 3, backgroundColor: colors.border } }), [colors, theme]); // State management const [state, setState] = (0, _react.useState)({ currentStep: initialStep, stepData: stepData, isTransitioning: false }); // Update state when stepData prop changes (0, _react.useEffect)(() => { setState(prevState => ({ ...prevState, stepData: stepData })); }, [stepData]); // Animation values const fadeAnim = (0, _reactNativeReanimated.useSharedValue)(1); const slideAnim = (0, _reactNativeReanimated.useSharedValue)(0); const scaleAnim = (0, _reactNativeReanimated.useSharedValue)(1); // Refs for animation callbacks const onStepChangeRef = (0, _react.useRef)(onStepChange); const onCompleteRef = (0, _react.useRef)(onComplete); onStepChangeRef.current = onStepChange; onCompleteRef.current = onComplete; // Update step data const updateStepData = (0, _react.useCallback)((stepIndex, data) => { setState(prev => ({ ...prev, stepData: prev.stepData.map((item, index) => index === stepIndex ? data : item) })); }, [setState]); // Animation transition function const animateTransition = (0, _react.useCallback)(nextStep => { if (!enableAnimations) { setState(prev => ({ ...prev, currentStep: nextStep })); onStepChangeRef.current?.(nextStep, steps.length); return; } setState(prev => ({ ...prev, isTransitioning: true })); const applyStepChange = (targetStep, totalSteps) => { setState(prev => ({ ...prev, currentStep: targetStep, isTransitioning: false })); onStepChangeRef.current?.(targetStep, totalSteps); // Prepare next step animation fadeAnim.value = 0; scaleAnim.value = 0.98; slideAnim.value = 0; fadeAnim.value = (0, _reactNativeReanimated.withTiming)(1, { duration: 220 }); scaleAnim.value = (0, _reactNativeReanimated.withTiming)(1, { duration: 220 }); }; // Animate current step out scaleAnim.value = (0, _reactNativeReanimated.withTiming)(0.98, { duration: 180 }); fadeAnim.value = (0, _reactNativeReanimated.withTiming)(0, { duration: 180 }, finished => { if (finished) { (0, _reactNativeReanimated.runOnJS)(applyStepChange)(nextStep, steps.length); } }); }, [enableAnimations, steps.length, fadeAnim, scaleAnim, slideAnim]); // Navigation functions const nextStep = (0, _react.useCallback)(() => { if (state.isTransitioning) return; const currentStepConfig = steps[state.currentStep]; if (currentStepConfig?.canProceed) { const stepData = state.stepData[state.currentStep]; if (!currentStepConfig.canProceed(stepData)) { return; // Step validation failed } } if (state.currentStep < steps.length - 1) { // Call onExit for current step currentStepConfig?.onExit?.(); animateTransition(state.currentStep + 1); // Call onEnter for next step const nextStepConfig = steps[state.currentStep + 1]; nextStepConfig?.onEnter?.(); } else { // Final step - call onComplete onCompleteRef.current?.(state.stepData); } }, [state.currentStep, state.stepData, state.isTransitioning, steps, animateTransition]); const prevStep = (0, _react.useCallback)(() => { if (state.isTransitioning) return; if (state.currentStep > 0) { // Call onExit for current step const currentStepConfig = steps[state.currentStep]; currentStepConfig?.onExit?.(); animateTransition(state.currentStep - 1); // Call onEnter for previous step const prevStepConfig = steps[state.currentStep - 1]; prevStepConfig?.onEnter?.(); } else { // First step - go back goBack?.(); } }, [state.currentStep, state.isTransitioning, steps, animateTransition, goBack]); const goToStep = (0, _react.useCallback)(stepIndex => { if (state.isTransitioning || stepIndex < 0 || stepIndex >= steps.length) return; if (stepIndex !== state.currentStep) { // Call onExit for current step const currentStepConfig = steps[state.currentStep]; currentStepConfig?.onExit?.(); animateTransition(stepIndex); // Call onEnter for target step const targetStepConfig = steps[stepIndex]; targetStepConfig?.onEnter?.(); } }, [state.currentStep, state.isTransitioning, steps, animateTransition]); // Get current step component const currentStepConfig = steps[state.currentStep]; const CurrentStepComponent = currentStepConfig?.component; // Enhanced props for the step component const stepProps = { ...currentStepConfig?.props, // Common props colors, styles, theme, navigate, goBack, onAuthenticated, oxyServices, // Step navigation nextStep, prevStep, goToStep, currentStep: state.currentStep, totalSteps: steps.length, // Step data - spread the step data properties directly as props ...state.stepData[state.currentStep], // Step data management updateStepData: data => updateStepData(state.currentStep, data), allStepData: state.stepData, // State isTransitioning: state.isTransitioning, // Animation refs (for components that need direct access) fadeAnim, slideAnim, scaleAnim }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.KeyboardAvoidingView, { style: [styles.container], behavior: undefined, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.StatusBar, { barStyle: theme === 'dark' ? 'light-content' : 'dark-content', backgroundColor: colors.background }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, { contentContainerStyle: styles.scrollContent, showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", bounces: false, alwaysBounceVertical: false, overScrollMode: "never", removeClippedSubviews: true, children: [showProgressIndicator && steps.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(ProgressIndicator, { currentStep: state.currentStep, totalSteps: steps.length, colors: colors, styles: styles }), /*#__PURE__*/(0, _jsxRuntime.jsx)(AnimatedStepContainer, { fadeAnim: fadeAnim, slideAnim: slideAnim, scaleAnim: scaleAnim, styles: styles, stepKey: `step-${state.currentStep}`, children: CurrentStepComponent && /*#__PURE__*/(0, _jsxRuntime.jsx)(CurrentStepComponent, { ...stepProps }) })] })] }); }; var _default = exports.default = StepBasedScreen; //# sourceMappingURL=StepBasedScreen.js.map