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