UNPKG

@oxyhq/services

Version:

OxyHQ Expo/React Native SDK — UI components, screens, and native features

310 lines (306 loc) 9.79 kB
"use strict"; import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, ScrollView, TextInput, Platform } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { toast } from '../../lib/sonner'; import { Header, LoadingState, EmptyState } from "../components/index.js"; import { useI18n } from "../hooks/useI18n.js"; import { useThemeStyles } from "../hooks/useThemeStyles.js"; import { useOxy } from "../context/OxyContext.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const FAQScreen = ({ onClose, theme, goBack }) => { const { oxyServices } = useOxy(); const { t } = useI18n(); const themeStyles = useThemeStyles(theme || 'light'); const [faqs, setFaqs] = useState([]); const [isLoading, setIsLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [expandedIds, setExpandedIds] = useState(new Set()); const [selectedCategory, setSelectedCategory] = useState(null); // Load FAQs from API useEffect(() => { const loadFAQs = async () => { try { setIsLoading(true); const data = await oxyServices.getFAQs(); setFaqs(data); } catch (error) { toast.error(t('faq.loadError') || 'Failed to load FAQs'); } finally { setIsLoading(false); } }; loadFAQs(); }, [oxyServices, t]); // Get unique categories const categories = useMemo(() => { const cats = [...new Set(faqs.map(f => f.category))]; return cats.sort(); }, [faqs]); // Filter FAQs based on search and category const filteredFaqs = useMemo(() => { let result = faqs; if (selectedCategory) { result = result.filter(f => f.category === selectedCategory); } if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); result = result.filter(f => f.question.toLowerCase().includes(query) || f.answer.toLowerCase().includes(query)); } return result; }, [faqs, searchQuery, selectedCategory]); const toggleExpanded = useCallback(id => { setExpandedIds(prev => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); }, []); const styles = useMemo(() => createStyles(themeStyles), [themeStyles]); return /*#__PURE__*/_jsxs(View, { style: [styles.container, { backgroundColor: themeStyles.backgroundColor }], children: [/*#__PURE__*/_jsx(Header, { title: t('faq.title') || 'FAQ', onBack: goBack || onClose, variant: "minimal", elevation: "subtle" }), /*#__PURE__*/_jsx(View, { style: styles.searchContainer, children: /*#__PURE__*/_jsxs(View, { style: [styles.searchInputWrapper, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor: themeStyles.borderColor }], children: [/*#__PURE__*/_jsx(Ionicons, { name: "search", size: 20, color: themeStyles.mutedTextColor, style: styles.searchIcon }), /*#__PURE__*/_jsx(TextInput, { style: [styles.searchInput, { color: themeStyles.textColor }], placeholder: t('faq.searchPlaceholder') || 'Search FAQs...', placeholderTextColor: themeStyles.mutedTextColor, value: searchQuery, onChangeText: setSearchQuery, accessibilityLabel: "Search FAQs" }), searchQuery.length > 0 && /*#__PURE__*/_jsx(TouchableOpacity, { onPress: () => setSearchQuery(''), accessibilityRole: "button", accessibilityLabel: "Clear search", children: /*#__PURE__*/_jsx(Ionicons, { name: "close-circle", size: 20, color: themeStyles.mutedTextColor }) })] }) }), categories.length > 0 && /*#__PURE__*/_jsxs(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.categoriesContainer, contentContainerStyle: styles.categoriesContent, children: [/*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.categoryChip, !selectedCategory && styles.categoryChipActive, { backgroundColor: !selectedCategory ? themeStyles.primaryColor : themeStyles.secondaryBackgroundColor }], onPress: () => setSelectedCategory(null), accessibilityRole: "button", accessibilityLabel: "Show all categories", accessibilityState: { selected: !selectedCategory }, children: /*#__PURE__*/_jsx(Text, { style: [styles.categoryChipText, { color: !selectedCategory ? '#FFFFFF' : themeStyles.textColor }], children: t('faq.allCategories') || 'All' }) }), categories.map(cat => /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.categoryChip, selectedCategory === cat && styles.categoryChipActive, { backgroundColor: selectedCategory === cat ? themeStyles.primaryColor : themeStyles.secondaryBackgroundColor }], onPress: () => setSelectedCategory(cat), accessibilityRole: "button", accessibilityLabel: `Filter by ${cat}`, accessibilityState: { selected: selectedCategory === cat }, children: /*#__PURE__*/_jsx(Text, { style: [styles.categoryChipText, { color: selectedCategory === cat ? '#FFFFFF' : themeStyles.textColor }], children: cat }) }, cat))] }), /*#__PURE__*/_jsx(ScrollView, { style: styles.content, showsVerticalScrollIndicator: false, children: isLoading ? /*#__PURE__*/_jsx(LoadingState, { message: t('faq.loading') || 'Loading FAQs...', color: themeStyles.textColor }) : filteredFaqs.length === 0 ? /*#__PURE__*/_jsx(EmptyState, { message: searchQuery ? t('faq.noResults') || 'No FAQs match your search' : t('faq.empty') || 'No FAQs available', textColor: themeStyles.textColor }) : filteredFaqs.map((faq, index) => { const isExpanded = expandedIds.has(faq.id); return /*#__PURE__*/_jsxs(View, { style: [styles.faqItem, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor: themeStyles.borderColor }, index === 0 && styles.faqItemFirst], children: [/*#__PURE__*/_jsxs(TouchableOpacity, { style: styles.faqQuestion, onPress: () => toggleExpanded(faq.id), accessibilityRole: "button", accessibilityLabel: faq.question, accessibilityHint: isExpanded ? 'Collapse answer' : 'Expand answer', accessibilityState: { expanded: isExpanded }, children: [/*#__PURE__*/_jsx(Text, { style: [styles.faqQuestionText, { color: themeStyles.textColor }], children: faq.question }), /*#__PURE__*/_jsx(Ionicons, { name: isExpanded ? 'chevron-up' : 'chevron-down', size: 20, color: themeStyles.mutedTextColor })] }), isExpanded && /*#__PURE__*/_jsxs(View, { style: [styles.faqAnswer, { borderTopColor: themeStyles.borderColor }], children: [/*#__PURE__*/_jsx(Text, { style: [styles.faqAnswerText, { color: themeStyles.mutedTextColor }], children: faq.answer }), /*#__PURE__*/_jsxs(View, { style: styles.faqCategory, children: [/*#__PURE__*/_jsx(Ionicons, { name: "pricetag-outline", size: 14, color: themeStyles.primaryColor }), /*#__PURE__*/_jsx(Text, { style: [styles.faqCategoryText, { color: themeStyles.primaryColor }], children: faq.category })] })] })] }, faq.id); }) })] }); }; const createStyles = themeStyles => StyleSheet.create({ container: { flex: 1 }, searchContainer: { paddingHorizontal: 16, paddingVertical: 12 }, searchInputWrapper: { flexDirection: 'row', alignItems: 'center', borderRadius: 12, borderWidth: 1, paddingHorizontal: 12, height: 44 }, searchIcon: { marginRight: 8 }, searchInput: { flex: 1, fontSize: 16, ...Platform.select({ web: { outlineStyle: 'none' } }) }, categoriesContainer: { maxHeight: 50 }, categoriesContent: { paddingHorizontal: 16, gap: 8 }, categoryChip: { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, marginRight: 8 }, categoryChipActive: {}, categoryChipText: { fontSize: 14, fontWeight: '500' }, content: { flex: 1, padding: 16 }, faqItem: { borderRadius: 12, borderWidth: 1, marginBottom: 12, overflow: 'hidden' }, faqItemFirst: { marginTop: 0 }, faqQuestion: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', padding: 16 }, faqQuestionText: { flex: 1, fontSize: 16, fontWeight: '600', marginRight: 12 }, faqAnswer: { padding: 16, paddingTop: 12, borderTopWidth: 1 }, faqAnswerText: { fontSize: 14, lineHeight: 22 }, faqCategory: { flexDirection: 'row', alignItems: 'center', marginTop: 12 }, faqCategoryText: { fontSize: 12, marginLeft: 6, fontWeight: '500' } }); export default FAQScreen; //# sourceMappingURL=FAQScreen.js.map