mobileapp / src /screens /profile /HelpScreen.tsx
Antaram Dev Bot
feat: complete ANTARAM.ORG ride-sharing app frontend
5c876be
import React, { useState } from 'react';
import { View, StyleSheet, ScrollView, Linking } from 'react-native';
import {
Appbar,
Text,
Searchbar,
List,
Card,
Divider,
Button,
Surface,
} from 'react-native-paper';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import type { ProfileStackParamList } from '../../navigation/types';
import { customTheme } from '../../theme';
type NavigationProp = NativeStackNavigationProp<ProfileStackParamList, 'Help'>;
// ─── FAQ Data ────────────────────────────────────────────────────────────────────
const FAQ_ITEMS = [
{
id: '1',
title: 'How does ride matching work?',
content:
'Antaram uses your origin and destination to find rides going in the same direction. Our algorithm considers route overlap, timing, and preferences to suggest the best matches. You can review each match and accept or decline.',
},
{
id: '2',
title: 'Is my data safe?',
content:
'Yes! Your personal data is encrypted and stored securely. We only share necessary information with your ride partner (name, profile photo) during an active ride. Your phone number is never shared without your explicit consent.',
},
{
id: '3',
title: 'How do I report an issue?',
content:
'You can report any issue through this Help screen by tapping "Report a Bug" below, or by emailing us at support@antaram.org. For emergencies during a ride, use the SOS button in the ride screen.',
},
{
id: '4',
title: 'What happens if I cancel?',
content:
'If you cancel before a match is accepted, no penalty applies. If you cancel after accepting a match, it may affect your reliability rating. Repeated cancellations could temporarily limit your ability to book rides.',
},
{
id: '5',
title: 'How are fares calculated?',
content:
'Fares are estimated based on distance, time, and vehicle type. The actual fare is agreed upon between the rider and passenger before the ride starts. Antaram does not take any commission on shared rides.',
},
];
// ─── Main Screen ─────────────────────────────────────────────────────────────────
export default function HelpScreen() {
const navigation = useNavigation<NavigationProp>();
const [search, setSearch] = useState('');
const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());
// ── Filter FAQ by search ───────────────────────────────────────────────────
const filteredFAQ = search.trim()
? FAQ_ITEMS.filter(
(item) =>
item.title.toLowerCase().includes(search.toLowerCase()) ||
item.content.toLowerCase().includes(search.toLowerCase()),
)
: FAQ_ITEMS;
// ── Toggle accordion ───────────────────────────────────────────────────────
const handleAccordionPress = (id: string) => {
setExpandedIds((prev) => {
const next = new Set(prev);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return next;
});
};
return (
<SafeAreaView style={styles.container} edges={['top']}>
<Appbar.Header>
<Appbar.BackAction onPress={navigation.goBack} />
<Appbar.Content title="Help & Support" />
</Appbar.Header>
<ScrollView
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
>
{/* Search */}
<Searchbar
placeholder="Search FAQ..."
value={search}
onChangeText={setSearch}
style={styles.searchbar}
/>
{/* FAQ */}
<Text variant="labelLarge" style={styles.sectionTitle}>
FREQUENTLY ASKED QUESTIONS
</Text>
{filteredFAQ.length === 0 ? (
<View style={styles.emptyFAQ}>
<Text variant="bodyMedium" style={{ opacity: 0.6 }}>
No matching questions found.
</Text>
</View>
) : (
filteredFAQ.map((item) => (
<List.Accordion
key={item.id}
title={item.title}
id={item.id}
expanded={expandedIds.has(item.id)}
onPress={() => handleAccordionPress(item.id)}
style={styles.accordion}
>
<List.Item
description={item.content}
descriptionNumberOfLines={20}
style={styles.accordionContent}
/>
</List.Accordion>
))
)}
<Divider style={styles.divider} />
{/* Contact Us */}
<Text variant="labelLarge" style={styles.sectionTitle}>
CONTACT US
</Text>
<Card style={styles.contactCard} mode="outlined">
<Card.Content>
<Text variant="titleSmall" style={styles.contactTitle}>
Need more help?
</Text>
<Text variant="bodyMedium" style={styles.contactText}>
Email us at{' '}
<Text
style={styles.contactLink}
onPress={() => Linking.openURL('mailto:support@antaram.org')}
>
support@antaram.org
</Text>
</Text>
<Text variant="bodyMedium" style={styles.contactText}>
Visit our{' '}
<Text
style={styles.contactLink}
onPress={() => Linking.openURL('https://antaram.org/support')}
>
support form
</Text>
{' '}for detailed help.
</Text>
</Card.Content>
</Card>
{/* Report Bug */}
<Button
mode="outlined"
icon="bug-outline"
onPress={() => Linking.openURL('mailto:support@antaram.org?subject=Bug Report')}
style={styles.reportButton}
>
Report a Bug
</Button>
</ScrollView>
</SafeAreaView>
);
}
// ─── Styles ──────────────────────────────────────────────────────────────────────
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: customTheme.colors.brand.background,
},
scrollContent: {
paddingHorizontal: 16,
paddingBottom: 32,
},
searchbar: {
marginBottom: 16,
borderRadius: 28,
},
sectionTitle: {
fontWeight: '700',
textTransform: 'uppercase',
color: customTheme.colors.brand.primaryDark,
marginBottom: 8,
},
accordion: {
backgroundColor: 'transparent',
},
accordionContent: {
paddingLeft: 16,
},
emptyFAQ: {
paddingVertical: 32,
alignItems: 'center',
},
divider: {
marginVertical: 16,
},
contactCard: {
marginBottom: 16,
},
contactTitle: {
fontWeight: '600',
marginBottom: 8,
},
contactText: {
lineHeight: 22,
marginBottom: 4,
},
contactLink: {
color: customTheme.colors.brand.primary,
fontWeight: '600',
},
reportButton: {
borderRadius: 24,
borderColor: customTheme.colors.brand.primary,
},
});