UNPKG

@oxyhq/services

Version:

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

1,191 lines (1,172 loc) • 38.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _OxyContext = require("../context/OxyContext"); var _styles = require("../styles"); var _vectorIcons = require("@expo/vector-icons"); var _sonner = require("../../lib/sonner"); var _version = require("../../constants/version"); var _components = require("../components"); var _useI18n = require("../hooks/useI18n"); 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); } // Types for better type safety // Constants const FEEDBACK_TYPES = [{ id: 'bug', label: 'Bug Report', icon: 'bug', color: '#FF3B30', description: 'Report a problem or issue' }, { id: 'feature', label: 'Feature Request', icon: 'bulb', color: '#007AFF', description: 'Suggest a new feature' }, { id: 'general', label: 'General Feedback', icon: 'chatbubble', color: '#34C759', description: 'Share your thoughts' }, { id: 'support', label: 'Support Request', icon: 'help-circle', color: '#FF9500', description: 'Get help with something' }]; const PRIORITY_LEVELS = [{ id: 'low', label: 'Low', icon: 'arrow-down', color: '#34C759' }, { id: 'medium', label: 'Medium', icon: 'remove', color: '#FF9500' }, { id: 'high', label: 'High', icon: 'arrow-up', color: '#FF3B30' }, { id: 'critical', label: 'Critical', icon: 'warning', color: '#FF0000' }]; const CATEGORIES = { bug: ['UI/UX', 'Performance', 'Authentication', 'File Management', 'Billing', 'Other'], feature: ['User Interface', 'File Management', 'Security', 'Performance', 'Integration', 'Other'], general: ['User Experience', 'Design', 'Performance', 'Documentation', 'Other'], support: ['Account Issues', 'Billing', 'Technical Problems', 'Feature Questions', 'Other'] }; // Styles factory function const createStyles = (colors, theme) => _reactNative.StyleSheet.create({ container: { flex: 1 }, fullBleed: { width: '100%', alignSelf: 'stretch' }, scrollContent: { flexGrow: 1, paddingHorizontal: 24, paddingTop: 40, paddingBottom: 20 }, stepContainer: { flex: 1, justifyContent: 'flex-start', alignItems: 'flex-start' }, 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: 48, marginBottom: 12, textAlign: 'left', letterSpacing: -1 }, modernSubtitle: { fontSize: 18, lineHeight: 24, textAlign: 'left', opacity: 0.8, marginBottom: 24 }, stepTitle: { fontFamily: _reactNative.Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold', fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : undefined, fontSize: 42, lineHeight: 48, marginBottom: 12, textAlign: 'left', letterSpacing: -1 }, inputContainer: { width: '100%', marginBottom: 24 }, premiumInputWrapper: { flexDirection: 'row', alignItems: 'center', height: 56, borderRadius: 16, paddingHorizontal: 20, borderWidth: 2, backgroundColor: colors.inputBackground }, textAreaWrapper: { flexDirection: 'column', alignItems: 'flex-start', minHeight: 120, borderRadius: 16, paddingHorizontal: 20, paddingVertical: 16, borderWidth: 2, backgroundColor: colors.inputBackground }, inputIcon: { marginRight: 12 }, inputContent: { flex: 1 }, modernLabel: { fontSize: 12, fontWeight: '500', marginBottom: 2 }, modernInput: { flex: 1, fontSize: 16, height: '100%' }, textArea: { flex: 1, fontSize: 16, textAlignVertical: 'top', minHeight: 80 }, typeGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 12, marginBottom: 24 }, typeCard: { width: (_reactNative.Dimensions.get('window').width - 72) / 2, padding: 20, borderRadius: 16, borderWidth: 2, alignItems: 'center', justifyContent: 'center', minHeight: 120 }, typeIcon: { marginBottom: 12 }, typeLabel: { fontSize: 16, fontWeight: '600', textAlign: 'center', marginBottom: 4 }, typeDescription: { fontSize: 12, textAlign: 'center', opacity: 0.8 }, priorityContainer: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 24 }, priorityButton: { flex: 1, padding: 16, borderRadius: 12, borderWidth: 2, alignItems: 'center', marginHorizontal: 4 }, priorityLabel: { fontSize: 12, fontWeight: '600', marginTop: 4 }, categoryContainer: { marginBottom: 24 }, categoryButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: 12, paddingHorizontal: 16, borderRadius: 12, borderWidth: 1, marginBottom: 8 }, categoryText: { fontSize: 16, marginLeft: 12 }, checkboxContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 24 }, checkbox: { width: 24, height: 24, borderRadius: 6, borderWidth: 2, marginRight: 12, alignItems: 'center', justifyContent: 'center' }, checkboxText: { fontSize: 16, flex: 1 }, 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 }, navigationButtons: { flexDirection: 'row', justifyContent: 'center', marginTop: 16, marginBottom: 8, width: '100%', gap: 8 }, navButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: 6, paddingHorizontal: 12, gap: 6, minWidth: 70, borderWidth: 1, ..._reactNative.Platform.select({ web: { boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }, default: { shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2 } }) }, backButton: { backgroundColor: 'transparent', borderTopLeftRadius: 35, borderBottomLeftRadius: 35, borderTopRightRadius: 12, borderBottomRightRadius: 12 }, nextButton: { backgroundColor: 'transparent', borderTopRightRadius: 35, borderBottomRightRadius: 35, borderTopLeftRadius: 12, borderBottomLeftRadius: 12 }, navButtonText: { fontSize: 13, fontWeight: '500' }, progressContainer: { flexDirection: 'row', justifyContent: 'center', marginBottom: 20, marginTop: 8 }, progressDot: { height: 10, width: 10, borderRadius: 5, marginHorizontal: 6, borderWidth: 2, borderColor: '#fff', ..._reactNative.Platform.select({ web: { boxShadow: '0 1px 2px rgba(0,0,0,0.08)' }, default: { shadowColor: colors.primary, shadowOpacity: 0.08, shadowOffset: { width: 0, height: 1 }, shadowRadius: 2, elevation: 1 } }) }, summaryContainer: { padding: 0, marginBottom: 24, width: '100%' }, summaryRow: { flexDirection: 'row', marginBottom: 10 }, summaryLabel: { fontSize: 15, width: 90 }, summaryValue: { fontSize: 15, fontWeight: '600', flex: 1 }, successContainer: { alignItems: 'center', justifyContent: 'center', padding: 40 }, successIcon: { marginBottom: 24 }, successTitle: { fontSize: 24, fontWeight: 'bold', marginBottom: 12, textAlign: 'center' }, successMessage: { fontSize: 16, textAlign: 'center', opacity: 0.8, marginBottom: 24 } }); // Custom hooks for better separation of concerns const useFeedbackForm = () => { const [feedbackData, setFeedbackData] = (0, _react.useState)({ type: 'general', title: '', description: '', priority: 'medium', category: '', contactEmail: '', systemInfo: true }); const [feedbackState, setFeedbackState] = (0, _react.useState)({ status: 'idle', message: '' }); const updateField = (0, _react.useCallback)((field, value) => { setFeedbackData(prev => ({ ...prev, [field]: value })); }, []); const resetForm = (0, _react.useCallback)(() => { setFeedbackData({ type: 'general', title: '', description: '', priority: 'medium', category: '', contactEmail: '', systemInfo: true }); setFeedbackState({ status: 'idle', message: '' }); }, []); return { feedbackData, feedbackState, setFeedbackState, updateField, resetForm }; }; // Reusable components const FormInput = /*#__PURE__*/_react.default.memo(({ icon, label, value, onChangeText, placeholder, multiline = false, numberOfLines = 1, testID, colors, styles, borderColor }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.inputContainer, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [multiline ? styles.textAreaWrapper : styles.premiumInputWrapper, { borderColor: borderColor || colors.border, backgroundColor: colors.inputBackground, shadowColor: colors.primary, shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 3 }], children: [!multiline && /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: icon, size: 22, color: colors.secondaryText, style: styles.inputIcon }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.inputContent, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernLabel, { color: colors.secondaryText }], children: label }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, { style: [multiline ? styles.textArea : styles.modernInput, { color: colors.text }], value: value, onChangeText: onChangeText, placeholder: placeholder, placeholderTextColor: colors.secondaryText + '60', multiline: multiline, numberOfLines: multiline ? numberOfLines : undefined, testID: testID })] })] }) })); const ProgressIndicator = /*#__PURE__*/_react.default.memo(({ currentStep, totalSteps, colors, styles }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.progressContainer, children: Array.from({ length: totalSteps }, (_, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.progressDot, currentStep === index ? { backgroundColor: colors.primary, width: 24 } : { backgroundColor: colors.border }] }, index)) })); // Main component const FeedbackScreen = ({ navigate, goBack, onClose, theme }) => { const { user, oxyServices } = (0, _OxyContext.useOxy)(); const colors = (0, _styles.useThemeColors)(theme); const { t } = (0, _useI18n.useI18n)(); // Form state const { feedbackData, feedbackState, setFeedbackState, updateField, resetForm } = useFeedbackForm(); // UI state const [currentStep, setCurrentStep] = (0, _react.useState)(0); const [errorMessage, setErrorMessage] = (0, _react.useState)(''); // Animation refs const fadeAnim = (0, _react.useRef)(new _reactNative.Animated.Value(1)).current; const slideAnim = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current; // Memoized styles const styles = (0, _react.useMemo)(() => createStyles(colors, theme), [colors, theme]); // Animation functions const animateTransition = (0, _react.useCallback)(nextStep => { _reactNative.Animated.timing(fadeAnim, { toValue: 0, duration: 250, useNativeDriver: _reactNative.Platform.OS !== 'web' }).start(() => { setCurrentStep(nextStep); slideAnim.setValue(-100); _reactNative.Animated.parallel([_reactNative.Animated.timing(fadeAnim, { toValue: 1, duration: 250, useNativeDriver: _reactNative.Platform.OS !== 'web' }), _reactNative.Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: _reactNative.Platform.OS !== 'web' })]).start(); }); }, [fadeAnim, slideAnim]); const nextStep = (0, _react.useCallback)(() => { if (currentStep < 3) { animateTransition(currentStep + 1); } }, [currentStep, animateTransition]); const prevStep = (0, _react.useCallback)(() => { if (currentStep > 0) { animateTransition(currentStep - 1); } }, [currentStep, animateTransition]); // Form validation helpers const isTypeStepValid = (0, _react.useCallback)(() => { return feedbackData.type && feedbackData.category; }, [feedbackData.type, feedbackData.category]); const isDetailsStepValid = (0, _react.useCallback)(() => { return feedbackData.title.trim() && feedbackData.description.trim(); }, [feedbackData.title, feedbackData.description]); const isContactStepValid = (0, _react.useCallback)(() => { return feedbackData.contactEmail.trim() || user?.email; }, [feedbackData.contactEmail, user?.email]); // Submit feedback handler const handleSubmitFeedback = (0, _react.useCallback)(async () => { if (!isTypeStepValid() || !isDetailsStepValid() || !isContactStepValid()) { _sonner.toast.error(t('feedback.toasts.fillRequired') || 'Please fill in all required fields'); return; } try { setFeedbackState({ status: 'submitting', message: '' }); setErrorMessage(''); // Prepare feedback data const feedbackPayload = { type: feedbackData.type, title: feedbackData.title, description: feedbackData.description, priority: feedbackData.priority, category: feedbackData.category, contactEmail: feedbackData.contactEmail || user?.email, systemInfo: feedbackData.systemInfo ? { platform: _reactNative.Platform.OS, version: _reactNative.Platform.Version?.toString() || 'Unknown', appVersion: _version.packageInfo.version, userId: user?.id, username: user?.username, timestamp: new Date().toISOString() } : undefined }; // For now, we'll simulate the API call // In a real implementation, you would call oxyServices.submitFeedback(feedbackPayload) await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate API call setFeedbackState({ status: 'success', message: t('feedback.toasts.submitSuccess') || 'Feedback submitted successfully!' }); _sonner.toast.success(t('feedback.toasts.thanks') || 'Thank you for your feedback!'); // Reset form after success setTimeout(() => { resetForm(); setCurrentStep(0); }, 3000); } catch (error) { setFeedbackState({ status: 'error', message: error.message || t('feedback.toasts.submitFailed') || 'Failed to submit feedback' }); _sonner.toast.error(error.message || t('feedback.toasts.submitFailed') || 'Failed to submit feedback'); } }, [feedbackData, user, isTypeStepValid, isDetailsStepValid, isContactStepValid, resetForm]); // Step components // Memoized grouped section items const feedbackTypeItems = (0, _react.useMemo)(() => FEEDBACK_TYPES.map(type => ({ id: type.id, icon: type.icon, iconColor: type.color, title: type.label, subtitle: type.description, onPress: () => { updateField('type', type.id); updateField('category', ''); }, selected: feedbackData.type === type.id, showChevron: false, multiRow: true, dense: true })), [feedbackData.type, updateField]); const categoryItems = (0, _react.useMemo)(() => feedbackData.type ? (CATEGORIES[feedbackData.type] || []).map(cat => ({ id: cat, icon: feedbackData.category === cat ? 'checkmark-circle' : 'ellipse-outline', iconColor: feedbackData.category === cat ? colors.primary : colors.secondaryText, title: cat, onPress: () => updateField('category', cat), selected: feedbackData.category === cat, showChevron: false, dense: true })) : [], [feedbackData.type, feedbackData.category, colors.primary, colors.secondaryText, updateField]); const priorityItems = (0, _react.useMemo)(() => PRIORITY_LEVELS.map(p => ({ id: p.id, icon: p.icon, iconColor: p.color, title: p.label, onPress: () => updateField('priority', p.id), selected: feedbackData.priority === p.id, showChevron: false, dense: true })), [feedbackData.priority, updateField]); const renderTypeStep = (0, _react.useCallback)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, { style: [styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.modernHeader, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.stepTitle, { color: colors.text }], children: t('feedback.type.title') || 'What type of feedback?' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernSubtitle, { color: colors.secondaryText }], children: t('feedback.type.subtitle') || 'Choose the category that best describes your feedback' })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.fullBleed, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, { items: feedbackTypeItems, theme: theme }) }), feedbackData.type && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.categoryContainer, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernLabel, { color: colors.secondaryText, marginBottom: 8 }], children: t('feedback.category.label') || 'Category' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.fullBleed, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, { items: categoryItems, theme: theme }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.navigationButtons, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, { backgroundColor: 'transparent', borderColor: colors.border, shadowColor: colors.border, borderTopLeftRadius: 35, borderBottomLeftRadius: 35, borderTopRightRadius: 35, borderBottomRightRadius: 35 }], onPress: goBack, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-back", size: 16, color: colors.text }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: colors.text }], children: t('common.actions.back') || 'Back' })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, { backgroundColor: colors.primary, borderColor: colors.primary, shadowColor: colors.primary, borderTopLeftRadius: 35, borderBottomLeftRadius: 35, borderTopRightRadius: 35, borderBottomRightRadius: 35 }], onPress: nextStep, disabled: !isTypeStepValid(), children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: '#FFFFFF' }], children: t('common.actions.next') || 'Next' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-forward", size: 16, color: "#FFFFFF" })] })] })] }), [fadeAnim, slideAnim, colors, feedbackData, feedbackTypeItems, categoryItems, updateField, goBack, nextStep, isTypeStepValid, styles, theme]); const renderDetailsStep = (0, _react.useCallback)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, { style: [styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.modernHeader, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.stepTitle, { color: colors.text }], children: t('feedback.details.title') || 'Tell us more' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernSubtitle, { color: colors.secondaryText }], children: t('feedback.details.subtitle') || 'Provide details about your feedback' })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(FormInput, { icon: "create-outline", label: t('feedback.fields.title.label') || 'Title', value: feedbackData.title, onChangeText: text => { updateField('title', text); setErrorMessage(''); }, placeholder: t('feedback.fields.title.placeholder') || 'Brief summary of your feedback', testID: "feedback-title-input", colors: colors, styles: styles }), /*#__PURE__*/(0, _jsxRuntime.jsx)(FormInput, { icon: "document-text-outline", label: t('feedback.fields.description.label') || 'Description', value: feedbackData.description, onChangeText: text => { updateField('description', text); setErrorMessage(''); }, placeholder: t('feedback.fields.description.placeholder') || 'Please provide detailed information...', multiline: true, numberOfLines: 6, testID: "feedback-description-input", colors: colors, styles: styles }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: { marginBottom: 24 }, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernLabel, { color: colors.secondaryText, marginBottom: 8 }], children: t('feedback.priority.label') || 'Priority Level' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.fullBleed, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, { items: priorityItems, theme: theme }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.navigationButtons, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, styles.backButton, { borderColor: colors.border, shadowColor: colors.border }], onPress: prevStep, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-back", size: 16, color: colors.text }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: colors.text }], children: t('common.actions.back') || 'Back' })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, styles.nextButton, { backgroundColor: colors.primary, borderColor: colors.primary, shadowColor: colors.primary }], onPress: nextStep, disabled: !isDetailsStepValid(), children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: '#FFFFFF' }], children: t('common.actions.next') || 'Next' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-forward", size: 16, color: "#FFFFFF" })] })] })] }), [fadeAnim, slideAnim, colors, feedbackData, updateField, setErrorMessage, prevStep, nextStep, isDetailsStepValid, styles, priorityItems, theme]); const renderContactStep = (0, _react.useCallback)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, { style: [styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.modernHeader, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.stepTitle, { color: colors.text }], children: t('feedback.contact.title') || 'Contact Information' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernSubtitle, { color: colors.secondaryText }], children: t('feedback.contact.subtitle') || 'Help us get back to you' })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(FormInput, { icon: "mail-outline", label: t('feedback.fields.email.label') || 'Email Address', value: feedbackData.contactEmail, onChangeText: text => { updateField('contactEmail', text); setErrorMessage(''); }, placeholder: user?.email || t('feedback.fields.email.placeholder') || 'Enter your email address', testID: "feedback-email-input", colors: colors, styles: styles }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.checkboxContainer, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, { style: [styles.checkbox, { borderColor: feedbackData.systemInfo ? colors.primary : colors.border, backgroundColor: feedbackData.systemInfo ? colors.primary : 'transparent' }], onPress: () => updateField('systemInfo', !feedbackData.systemInfo), children: feedbackData.systemInfo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "checkmark", size: 16, color: "#FFFFFF" }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.checkboxText, { color: colors.text }], children: t('feedback.contact.includeSystemInfo') || 'Include system information to help us better understand your issue' })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.navigationButtons, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, styles.backButton, { borderColor: colors.border, shadowColor: colors.border }], onPress: prevStep, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-back", size: 16, color: colors.text }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: colors.text }], children: "Back" })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, styles.nextButton, { backgroundColor: colors.primary, borderColor: colors.primary, shadowColor: colors.primary }], onPress: nextStep, disabled: !isContactStepValid(), children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: '#FFFFFF' }], children: "Next" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-forward", size: 16, color: "#FFFFFF" })] })] })] }), [fadeAnim, slideAnim, colors, feedbackData, user, updateField, setErrorMessage, prevStep, nextStep, isContactStepValid, styles]); const renderSummaryStep = (0, _react.useCallback)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, { style: [styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.modernHeader, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.stepTitle, { color: colors.text }], children: t('feedback.summary.title') || 'Summary' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.modernSubtitle, { color: colors.secondaryText }], children: t('feedback.summary.subtitle') || 'Please review your feedback before submitting' })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryContainer, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryRow, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryLabel, { color: colors.secondaryText }], children: t('feedback.summary.type') || 'Type:' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryValue, { color: colors.text }], children: FEEDBACK_TYPES.find(t => t.id === feedbackData.type)?.label })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryRow, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryLabel, { color: colors.secondaryText }], children: t('feedback.summary.category') || 'Category:' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryValue, { color: colors.text }], children: feedbackData.category })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryRow, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryLabel, { color: colors.secondaryText }], children: t('feedback.summary.priority') || 'Priority:' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryValue, { color: colors.text }], children: PRIORITY_LEVELS.find(p => p.id === feedbackData.priority)?.label })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryRow, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryLabel, { color: colors.secondaryText }], children: t('feedback.summary.titleLabel') || 'Title:' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryValue, { color: colors.text }], children: feedbackData.title })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.summaryRow, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryLabel, { color: colors.secondaryText }], children: t('feedback.summary.contact') || 'Contact:' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.summaryValue, { color: colors.text }], children: feedbackData.contactEmail || user?.email })] })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, { style: [styles.button, { backgroundColor: colors.primary }], onPress: handleSubmitFeedback, disabled: feedbackState.status === 'submitting', testID: "submit-feedback-button", children: feedbackState.status === 'submitting' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.buttonText, children: t('feedback.actions.submit') || 'Submit Feedback' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "send", size: 20, color: "#FFFFFF" })] }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.navigationButtons, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, { style: [styles.navButton, { backgroundColor: 'transparent', borderColor: colors.border, shadowColor: colors.border, borderTopLeftRadius: 35, borderBottomLeftRadius: 35, borderTopRightRadius: 35, borderBottomRightRadius: 35 }], onPress: prevStep, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "arrow-back", size: 16, color: colors.text }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.navButtonText, { color: colors.text }], children: t('common.actions.back') || 'Back' })] }) })] }), [fadeAnim, slideAnim, colors, feedbackData, user, feedbackState.status, handleSubmitFeedback, prevStep, styles]); const renderSuccessStep = (0, _react.useCallback)(() => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, { style: [styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }], children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.successContainer, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.successIcon, { backgroundColor: colors.success + '20', padding: 24, borderRadius: 50 }], children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "checkmark-circle", size: 48, color: colors.success }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.successTitle, { color: colors.text }], children: t('feedback.success.thanks') || 'Thank You!' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.successMessage, { color: colors.secondaryText }], children: t('feedback.success.message') || "Your feedback has been submitted successfully. We'll review it and get back to you soon." }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, { style: [styles.button, { backgroundColor: colors.primary }], onPress: () => { resetForm(); setCurrentStep(0); }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.buttonText, children: t('feedback.actions.submitAnother') || 'Submit Another' }) })] }) }), [fadeAnim, slideAnim, colors, resetForm, styles]); // Render current step const renderCurrentStep = (0, _react.useCallback)(() => { if (feedbackState.status === 'success') { return renderSuccessStep(); } switch (currentStep) { case 0: return renderTypeStep(); case 1: return renderDetailsStep(); case 2: return renderContactStep(); case 3: return renderSummaryStep(); default: return renderTypeStep(); } }, [currentStep, feedbackState.status, renderTypeStep, renderDetailsStep, renderContactStep, renderSummaryStep, renderSuccessStep]); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.KeyboardAvoidingView, { style: [styles.container, { backgroundColor: theme === 'dark' ? colors.background : '#F7F9FC' }], behavior: _reactNative.Platform.OS === 'ios' ? 'padding' : 'height', children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.StatusBar, { barStyle: theme === 'dark' ? 'light-content' : 'dark-content', backgroundColor: theme === 'dark' ? colors.background : '#F7F9FC' }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, { contentContainerStyle: [styles.scrollContent, { backgroundColor: 'transparent' }], showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", children: [feedbackState.status !== 'success' && /*#__PURE__*/(0, _jsxRuntime.jsx)(ProgressIndicator, { currentStep: currentStep, totalSteps: 4, colors: colors, styles: styles }), renderCurrentStep()] })] }); }; var _default = exports.default = FeedbackScreen; //# sourceMappingURL=FeedbackScreen.js.map