326 lines
12 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import {
View,
Text,
ScrollView,
TouchableOpacity,
FlatList,
Modal,
TextInput,
ActivityIndicator,
Alert,
} from 'react-native';
import { useNavigation, useIsFocused } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { getStyles } from './helpSupportScreen.styles';
import { Header } from '@components';
import { useAppTheme } from '@theme';
import { AppStackParamList } from '../../../navigation/appStack';
import { useCustomerSupport } from '../../../hooks/useCustomerSupport';
import { TicketCategory, TicketPriority } from '@interfaces';
import { formatDate } from '../../../utils/helper';
type HelpSupportNavProp = StackNavigationProp<AppStackParamList, 'HelpSupportScreen'>;
const FAQS = [
{ q: 'How do I track my order?', a: 'Go to Orders tab and tap on your active order to see tracking.' },
{ q: 'What is the delivery time?', a: 'Standard delivery takes 25-30 min, Express takes 10-15 min.' },
{ q: 'How do I cancel an order?', a: 'Contact support to cancel an order before it is dispatched.' },
{ q: 'What payment methods are accepted?', a: 'UPI, Credit/Debit Card, Wallet, and Cash on Delivery.' },
];
const TICKET_CATEGORIES: { value: TicketCategory; label: string }[] = [
{ value: 'ORDER', label: 'Order' },
{ value: 'PAYMENT', label: 'Payment' },
{ value: 'PAYOUT', label: 'Payout' },
{ value: 'TECHNICAL_ISSUE', label: 'Technical Issue' },
{ value: 'ACCOUNT', label: 'Account' },
{ value: 'OTHER', label: 'Other' },
];
export const HelpSupportScreen: React.FC = () => {
const { colors } = useAppTheme();
const styles = getStyles(colors);
const navigation = useNavigation<HelpSupportNavProp>();
const isFocused = useIsFocused();
// Tab State
const [activeTab, setActiveTab] = useState<'faq' | 'tickets'>('faq');
// Custom Support Hook
const { tickets, loading, fetchTickets, createTicket } = useCustomerSupport();
// Create Ticket Modal State
const [createModalVisible, setCreateModalVisible] = useState(false);
const [categorySelectVisible, setCategorySelectVisible] = useState(false);
const [category, setCategory] = useState<TicketCategory>('ORDER');
const [priority] = useState<TicketPriority>('MEDIUM');
const [subject, setSubject] = useState('');
const [description, setDescription] = useState('');
useEffect(() => {
if (isFocused && activeTab === 'tickets') {
fetchTickets();
}
}, [isFocused, activeTab, fetchTickets]);
const handleCreateTicketSubmit = async () => {
if (!subject.trim()) {
Alert.alert('Error', 'Please enter a subject.');
return;
}
if (!description.trim()) {
Alert.alert('Error', 'Please enter ticket details.');
return;
}
try {
const newTicket = await createTicket({
category,
priority,
subject: subject.trim(),
description: description.trim(),
});
setCreateModalVisible(false);
setSubject('');
setDescription('');
Alert.alert('Success', 'Support Ticket created successfully!');
// Navigate to chat
navigation.navigate('SupportChatScreen', { ticketId: newTicket.id });
} catch (error) {
Alert.alert('Error', 'Failed to create support ticket. Please try again.');
}
};
const getStatusColor = (status: string) => {
switch (status) {
case 'OPEN':
return { bg: '#E3F2FD', text: '#1E88E5' }; // Blue
case 'IN_PROGRESS':
return { bg: '#FFF3E0', text: '#FB8C00' }; // Amber
case 'RESOLVED':
return { bg: '#E8F5E9', text: '#43A047' }; // Green
case 'CLOSED':
return { bg: '#ECEFF1', text: '#546E7A' }; // Grey
default:
return { bg: '#F5F5F5', text: '#9E9E9E' };
}
};
const renderFaqTab = () => (
<ScrollView contentContainerStyle={styles.content} showsVerticalScrollIndicator={false}>
<Text style={styles.sectionTitle}>Frequently Asked Questions</Text>
{FAQS.map((faq, index) => (
<View key={index} style={styles.faqItem}>
<Text style={styles.faqQuestion}>{faq.q}</Text>
<Text style={styles.faqAnswer}>{faq.a}</Text>
</View>
))}
<Text style={styles.sectionTitle}>Contact Support</Text>
<TouchableOpacity style={styles.supportCard} activeOpacity={0.7}>
<Text style={styles.supportIcon}>📞</Text>
<View>
<Text style={styles.supportLabel}>Call us</Text>
<Text style={styles.supportValue}>+91 1800 123 4567</Text>
</View>
</TouchableOpacity>
<TouchableOpacity style={styles.supportCard} activeOpacity={0.7}>
<Text style={styles.supportIcon}></Text>
<View>
<Text style={styles.supportLabel}>Email us</Text>
<Text style={styles.supportValue}>support@sgdelivery.com</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
const renderTicketsTab = () => (
<View style={[styles.container, { padding: 16 }]}>
{loading && tickets.length === 0 ? (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color={colors.primary} />
<Text style={{ marginTop: 8, color: colors.textSecondary }}>Fetching tickets...</Text>
</View>
) : (
<FlatList
data={tickets}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
ListEmptyComponent={
<View style={{ paddingVertical: 40, alignItems: 'center' }}>
<Text style={{ fontSize: 16, color: colors.textSecondary, marginBottom: 12 }}>
No support tickets found
</Text>
<Text style={{ fontSize: 12, color: colors.textSecondary, textAlign: 'center' }}>
Need help with your account or order? Create a ticket below!
</Text>
</View>
}
renderItem={({ item }) => {
const statusStyle = getStatusColor(item.status);
return (
<TouchableOpacity
style={styles.ticketCard}
activeOpacity={0.7}
onPress={() => navigation.navigate('SupportChatScreen', { ticketId: item.id })}
>
<View style={styles.ticketHeader}>
<Text style={styles.ticketNumber}>Ticket #{item.ticketNumber}</Text>
<Text style={styles.ticketDate}>{formatDate(item.createdAt)}</Text>
</View>
<Text style={styles.ticketSubjectText} numberOfLines={1}>
{item.subject}
</Text>
<View style={styles.ticketFooter}>
<View style={styles.categoryBadge}>
<Text style={styles.categoryText}>{item.category.replace('_', ' ')}</Text>
</View>
<View style={[styles.statusBadge, { backgroundColor: statusStyle.bg }]}>
<Text style={[styles.statusText, { color: statusStyle.text }]}>
{item.status.replace('_', ' ')}
</Text>
</View>
</View>
</TouchableOpacity>
);
}}
/>
)}
<TouchableOpacity
style={styles.createTicketBtn}
onPress={() => setCreateModalVisible(true)}
activeOpacity={0.8}
>
<Text style={styles.createTicketBtnText}>+ Create Support Ticket</Text>
</TouchableOpacity>
</View>
);
return (
<View style={styles.container}>
<Header title="Help & Support" onBack={() => navigation.goBack()} />
<View style={{ paddingHorizontal: 16, paddingTop: 16 }}>
<View style={styles.tabContainer}>
<TouchableOpacity
style={[styles.tabButton, activeTab === 'faq' && styles.activeTabButton]}
onPress={() => setActiveTab('faq')}
>
<Text style={[styles.tabText, activeTab === 'faq' && styles.activeTabText]}>FAQs</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tabButton, activeTab === 'tickets' && styles.activeTabButton]}
onPress={() => setActiveTab('tickets')}
>
<Text style={[styles.tabText, activeTab === 'tickets' && styles.activeTabText]}>
My Support Tickets
</Text>
</TouchableOpacity>
</View>
</View>
{activeTab === 'faq' ? renderFaqTab() : renderTicketsTab()}
{/* Create Ticket Modal */}
<Modal
visible={createModalVisible}
transparent
animationType="slide"
onRequestClose={() => setCreateModalVisible(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Create Support Ticket</Text>
<ScrollView showsVerticalScrollIndicator={false}>
<Text style={styles.label}>Category</Text>
<TouchableOpacity
style={styles.categorySelect}
onPress={() => setCategorySelectVisible(true)}
>
<Text style={styles.categorySelectText}>
{TICKET_CATEGORIES.find((c) => c.value === category)?.label || 'Select category'}
</Text>
<Text style={{ color: colors.textSecondary }}></Text>
</TouchableOpacity>
<Text style={styles.label}>Subject</Text>
<TextInput
style={styles.input}
value={subject}
onChangeText={setSubject}
placeholder="What is the issue about?"
placeholderTextColor={colors.textSecondary}
/>
<Text style={styles.label}>Description</Text>
<TextInput
style={[styles.input, styles.textArea]}
value={description}
onChangeText={setDescription}
placeholder="Please describe your issue in detail..."
placeholderTextColor={colors.textSecondary}
multiline
numberOfLines={4}
/>
<View style={styles.modalActions}>
<TouchableOpacity
style={[styles.modalBtn, styles.cancelBtn]}
onPress={() => setCreateModalVisible(false)}
>
<Text style={styles.cancelBtnText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.modalBtn, styles.submitBtn]}
onPress={handleCreateTicketSubmit}
>
<Text style={styles.submitBtnText}>Submit</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
</View>
</Modal>
{/* Category Dropdown Modal */}
<Modal
visible={categorySelectVisible}
transparent
animationType="fade"
onRequestClose={() => setCategorySelectVisible(false)}
>
<View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', padding: 24 }}>
<View style={{ backgroundColor: colors.cardBg, borderRadius: 12, padding: 16 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', color: colors.text, marginBottom: 12, textAlign: 'center' }}>
Select Category
</Text>
{TICKET_CATEGORIES.map((item) => (
<TouchableOpacity
key={item.value}
style={{ paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: colors.border }}
onPress={() => {
setCategory(item.value);
setCategorySelectVisible(false);
}}
>
<Text style={{ fontSize: 16, color: colors.text }}>{item.label}</Text>
</TouchableOpacity>
))}
<TouchableOpacity
style={{ marginTop: 16, paddingVertical: 12, alignItems: 'center' }}
onPress={() => setCategorySelectVisible(false)}
>
<Text style={{ color: colors.primary, fontWeight: 'bold' }}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
export default HelpSupportScreen;