- Restructured profile screens location - Updated beneficiary detail page - Updated API service - Updated all scheme files (MainScheme, ENV API, Discussion, AppStore, SysAnal) - Added PageHeader component 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1069 lines
32 KiB
TypeScript
1069 lines
32 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
TextInput,
|
|
Linking,
|
|
Alert,
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
Modal,
|
|
} from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { router } from 'expo-router';
|
|
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
|
import { PageHeader } from '@/components/PageHeader';
|
|
|
|
// Mock data for tickets
|
|
const mockTickets = [
|
|
{
|
|
id: 'WN-2024-12341',
|
|
subject: 'Notifications not working',
|
|
category: 'Technical Issue',
|
|
status: 'resolved',
|
|
createdAt: '2024-12-08',
|
|
updatedAt: '2024-12-10',
|
|
messages: [
|
|
{
|
|
from: 'user',
|
|
text: 'I am not receiving push notifications when my mother triggers an alert. I have notifications enabled in the app settings.',
|
|
date: '2024-12-08 14:32',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Thank you for reaching out! Let me help you with this. Could you please confirm that notifications are also enabled in your device settings (Settings > WellNuo > Notifications)?',
|
|
date: '2024-12-08 15:45',
|
|
agent: 'Sarah M.',
|
|
},
|
|
{
|
|
from: 'user',
|
|
text: 'Oh, I checked and they were disabled there. I enabled them now.',
|
|
date: '2024-12-09 09:12',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Great! That should fix it. Please let us know if you have any other issues. Have a wonderful day!',
|
|
date: '2024-12-09 09:30',
|
|
agent: 'Sarah M.',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'WN-2024-12338',
|
|
subject: 'How to add a second beneficiary?',
|
|
category: 'Account Help',
|
|
status: 'resolved',
|
|
createdAt: '2024-12-05',
|
|
updatedAt: '2024-12-06',
|
|
messages: [
|
|
{
|
|
from: 'user',
|
|
text: 'I want to add my father as a second beneficiary. How can I do that?',
|
|
date: '2024-12-05 11:20',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Hello! To add a second beneficiary:\n\n1. Go to Dashboard\n2. Tap the + button or "Add Beneficiary"\n3. Enter their details and sensor ID\n\nNote: Free plan supports 1 beneficiary. For multiple beneficiaries, consider upgrading to WellNuo Pro. Would you like more information about our plans?',
|
|
date: '2024-12-05 12:15',
|
|
agent: 'Mike R.',
|
|
},
|
|
{
|
|
from: 'user',
|
|
text: 'Thank you! I upgraded to Pro and it works now.',
|
|
date: '2024-12-06 08:45',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'WN-2024-12345',
|
|
subject: 'Battery status shows wrong percentage',
|
|
category: 'Technical Issue',
|
|
status: 'open',
|
|
createdAt: '2024-12-11',
|
|
updatedAt: '2024-12-11',
|
|
messages: [
|
|
{
|
|
from: 'user',
|
|
text: 'The sensor shows 15% battery in the app, but I just charged it fully yesterday. Is there something wrong with the sensor?',
|
|
date: '2024-12-11 16:20',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Hi there! This could be a sync issue. Please try the following:\n\n1. Force close the WellNuo app\n2. Wait 30 seconds\n3. Reopen the app\n\nIf the issue persists, try restarting the sensor by pressing the reset button for 5 seconds. Let me know the results!',
|
|
date: '2024-12-11 17:05',
|
|
agent: 'Alex K.',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'WN-2024-12340',
|
|
subject: 'Request: Add medication reminders',
|
|
category: 'Feature Request',
|
|
status: 'in_progress',
|
|
createdAt: '2024-12-07',
|
|
updatedAt: '2024-12-10',
|
|
messages: [
|
|
{
|
|
from: 'user',
|
|
text: 'It would be great if WellNuo could also send medication reminders to my beneficiaries. Is this something you\'re considering?',
|
|
date: '2024-12-07 10:15',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Thank you for your feedback! We love hearing feature suggestions from our users.\n\nMedication reminders are actually on our roadmap! Our development team is working on this feature, and we expect to release it in Q1 2025.\n\nWe\'ve added your vote to this feature request. You\'ll be notified when it becomes available!',
|
|
date: '2024-12-07 14:30',
|
|
agent: 'Emma T.',
|
|
},
|
|
{
|
|
from: 'support',
|
|
text: 'Quick update: The medication reminders feature has moved to active development. We\'re targeting a late January release. Stay tuned!',
|
|
date: '2024-12-10 09:00',
|
|
agent: 'Emma T.',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
interface ContactMethodProps {
|
|
icon: keyof typeof Ionicons.glyphMap;
|
|
iconColor: string;
|
|
iconBgColor: string;
|
|
title: string;
|
|
subtitle: string;
|
|
onPress: () => void;
|
|
}
|
|
|
|
function ContactMethod({
|
|
icon,
|
|
iconColor,
|
|
iconBgColor,
|
|
title,
|
|
subtitle,
|
|
onPress,
|
|
}: ContactMethodProps) {
|
|
return (
|
|
<TouchableOpacity style={styles.contactMethod} onPress={onPress}>
|
|
<View style={[styles.contactIcon, { backgroundColor: iconBgColor }]}>
|
|
<Ionicons name={icon} size={24} color={iconColor} />
|
|
</View>
|
|
<View style={styles.contactContent}>
|
|
<Text style={styles.contactTitle}>{title}</Text>
|
|
<Text style={styles.contactSubtitle}>{subtitle}</Text>
|
|
</View>
|
|
<Ionicons name="chevron-forward" size={20} color={AppColors.textMuted} />
|
|
</TouchableOpacity>
|
|
);
|
|
}
|
|
|
|
const getStatusColor = (status: string) => {
|
|
switch (status) {
|
|
case 'open':
|
|
return '#3B82F6';
|
|
case 'in_progress':
|
|
return '#F59E0B';
|
|
case 'resolved':
|
|
return '#10B981';
|
|
default:
|
|
return AppColors.textMuted;
|
|
}
|
|
};
|
|
|
|
const getStatusBgColor = (status: string) => {
|
|
switch (status) {
|
|
case 'open':
|
|
return '#DBEAFE';
|
|
case 'in_progress':
|
|
return '#FEF3C7';
|
|
case 'resolved':
|
|
return '#D1FAE5';
|
|
default:
|
|
return AppColors.surface;
|
|
}
|
|
};
|
|
|
|
const getStatusLabel = (status: string) => {
|
|
switch (status) {
|
|
case 'open':
|
|
return 'Open';
|
|
case 'in_progress':
|
|
return 'In Progress';
|
|
case 'resolved':
|
|
return 'Resolved';
|
|
default:
|
|
return status;
|
|
}
|
|
};
|
|
|
|
export default function SupportScreen() {
|
|
const [subject, setSubject] = useState('');
|
|
const [message, setMessage] = useState('');
|
|
const [category, setCategory] = useState('');
|
|
const [isSending, setIsSending] = useState(false);
|
|
const [selectedTicket, setSelectedTicket] = useState<typeof mockTickets[0] | null>(null);
|
|
const [showTicketModal, setShowTicketModal] = useState(false);
|
|
const [activeTab, setActiveTab] = useState<'contact' | 'tickets'>('tickets');
|
|
|
|
const categories = [
|
|
'Technical Issue',
|
|
'Billing Question',
|
|
'Feature Request',
|
|
'Account Help',
|
|
'Emergency',
|
|
'Other',
|
|
];
|
|
|
|
const handleCall = () => {
|
|
Linking.openURL('tel:+15551234567').catch(() => {
|
|
Alert.alert('Error', 'Unable to make phone call');
|
|
});
|
|
};
|
|
|
|
const handleEmail = () => {
|
|
Linking.openURL('mailto:support@wellnuo.com?subject=Support Request').catch(() => {
|
|
Alert.alert('Error', 'Unable to open email client');
|
|
});
|
|
};
|
|
|
|
const handleChat = () => {
|
|
Alert.alert(
|
|
'Live Chat',
|
|
'Connecting to a support agent...\n\nEstimated wait time: 2 minutes',
|
|
[
|
|
{ text: 'Cancel', style: 'cancel' },
|
|
{ text: 'Start Chat', onPress: () => Alert.alert('Coming Soon', 'Live chat feature coming soon!') },
|
|
]
|
|
);
|
|
};
|
|
|
|
const handleSendTicket = async () => {
|
|
if (!category) {
|
|
Alert.alert('Error', 'Please select a category');
|
|
return;
|
|
}
|
|
if (!subject.trim()) {
|
|
Alert.alert('Error', 'Please enter a subject');
|
|
return;
|
|
}
|
|
if (!message.trim()) {
|
|
Alert.alert('Error', 'Please describe your issue');
|
|
return;
|
|
}
|
|
|
|
setIsSending(true);
|
|
|
|
// Simulate API call
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
setIsSending(false);
|
|
setSubject('');
|
|
setMessage('');
|
|
setCategory('');
|
|
Alert.alert(
|
|
'Ticket Submitted',
|
|
'Thank you for contacting us!\n\nTicket #WN-2024-12346\n\nWe\'ll respond within 24 hours.',
|
|
[{ text: 'OK' }]
|
|
);
|
|
};
|
|
|
|
const openTicket = (ticket: typeof mockTickets[0]) => {
|
|
setSelectedTicket(ticket);
|
|
setShowTicketModal(true);
|
|
};
|
|
|
|
const renderTicketModal = () => (
|
|
<Modal
|
|
visible={showTicketModal}
|
|
animationType="slide"
|
|
presentationStyle="pageSheet"
|
|
onRequestClose={() => setShowTicketModal(false)}
|
|
>
|
|
<SafeAreaView style={styles.modalContainer} edges={['top']}>
|
|
{/* Modal Header */}
|
|
<View style={styles.modalHeader}>
|
|
<TouchableOpacity onPress={() => setShowTicketModal(false)}>
|
|
<Ionicons name="close" size={28} color={AppColors.textPrimary} />
|
|
</TouchableOpacity>
|
|
<Text style={styles.modalTitle}>Ticket Details</Text>
|
|
<View style={{ width: 28 }} />
|
|
</View>
|
|
|
|
{selectedTicket && (
|
|
<ScrollView style={styles.modalContent}>
|
|
{/* Ticket Info */}
|
|
<View style={styles.ticketInfo}>
|
|
<View style={styles.ticketInfoRow}>
|
|
<Text style={styles.ticketInfoLabel}>Ticket ID</Text>
|
|
<Text style={styles.ticketInfoValue}>{selectedTicket.id}</Text>
|
|
</View>
|
|
<View style={styles.ticketInfoRow}>
|
|
<Text style={styles.ticketInfoLabel}>Category</Text>
|
|
<Text style={styles.ticketInfoValue}>{selectedTicket.category}</Text>
|
|
</View>
|
|
<View style={styles.ticketInfoRow}>
|
|
<Text style={styles.ticketInfoLabel}>Status</Text>
|
|
<View
|
|
style={[
|
|
styles.statusBadge,
|
|
{ backgroundColor: getStatusBgColor(selectedTicket.status) },
|
|
]}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.statusBadgeText,
|
|
{ color: getStatusColor(selectedTicket.status) },
|
|
]}
|
|
>
|
|
{getStatusLabel(selectedTicket.status)}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<View style={styles.ticketInfoRow}>
|
|
<Text style={styles.ticketInfoLabel}>Created</Text>
|
|
<Text style={styles.ticketInfoValue}>{selectedTicket.createdAt}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Subject */}
|
|
<View style={styles.ticketSubjectContainer}>
|
|
<Text style={styles.ticketSubjectLabel}>Subject</Text>
|
|
<Text style={styles.ticketSubjectText}>{selectedTicket.subject}</Text>
|
|
</View>
|
|
|
|
{/* Messages */}
|
|
<View style={styles.messagesContainer}>
|
|
<Text style={styles.messagesTitle}>Conversation</Text>
|
|
{selectedTicket.messages.map((msg, index) => (
|
|
<View
|
|
key={index}
|
|
style={[
|
|
styles.messageCard,
|
|
msg.from === 'support' && styles.messageCardSupport,
|
|
]}
|
|
>
|
|
<View style={styles.messageHeader}>
|
|
<View style={styles.messageFrom}>
|
|
<Ionicons
|
|
name={msg.from === 'user' ? 'person' : 'headset'}
|
|
size={16}
|
|
color={msg.from === 'user' ? AppColors.primary : '#10B981'}
|
|
/>
|
|
<Text style={styles.messageFromText}>
|
|
{msg.from === 'user' ? 'You' : `Support (${(msg as any).agent})`}
|
|
</Text>
|
|
</View>
|
|
<Text style={styles.messageDate}>{msg.date}</Text>
|
|
</View>
|
|
<Text style={styles.messageText}>{msg.text}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
|
|
{/* Reply section for open tickets */}
|
|
{selectedTicket.status !== 'resolved' && (
|
|
<View style={styles.replySection}>
|
|
<Text style={styles.replyTitle}>Reply</Text>
|
|
<TextInput
|
|
style={styles.replyInput}
|
|
placeholder="Type your reply..."
|
|
placeholderTextColor={AppColors.textMuted}
|
|
multiline
|
|
numberOfLines={4}
|
|
textAlignVertical="top"
|
|
/>
|
|
<TouchableOpacity style={styles.replyButton}>
|
|
<Text style={styles.replyButtonText}>Send Reply</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
)}
|
|
</SafeAreaView>
|
|
</Modal>
|
|
);
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
|
|
<PageHeader title="Contact Support" />
|
|
<KeyboardAvoidingView
|
|
style={styles.keyboardView}
|
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
>
|
|
{/* Tabs */}
|
|
<View style={styles.tabsContainer}>
|
|
<TouchableOpacity
|
|
style={[styles.tab, activeTab === 'tickets' && styles.tabActive]}
|
|
onPress={() => setActiveTab('tickets')}
|
|
>
|
|
<Ionicons
|
|
name="ticket-outline"
|
|
size={20}
|
|
color={activeTab === 'tickets' ? AppColors.primary : AppColors.textMuted}
|
|
/>
|
|
<Text
|
|
style={[styles.tabText, activeTab === 'tickets' && styles.tabTextActive]}
|
|
>
|
|
My Tickets
|
|
</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity
|
|
style={[styles.tab, activeTab === 'contact' && styles.tabActive]}
|
|
onPress={() => setActiveTab('contact')}
|
|
>
|
|
<Ionicons
|
|
name="add-circle-outline"
|
|
size={20}
|
|
color={activeTab === 'contact' ? AppColors.primary : AppColors.textMuted}
|
|
/>
|
|
<Text
|
|
style={[styles.tabText, activeTab === 'contact' && styles.tabTextActive]}
|
|
>
|
|
New Ticket
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
{activeTab === 'tickets' ? (
|
|
<>
|
|
{/* My Tickets */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>My Tickets ({mockTickets.length})</Text>
|
|
<View style={styles.ticketsList}>
|
|
{mockTickets.map((ticket) => (
|
|
<TouchableOpacity
|
|
key={ticket.id}
|
|
style={styles.ticketCard}
|
|
onPress={() => openTicket(ticket)}
|
|
>
|
|
<View style={styles.ticketHeader}>
|
|
<Text style={styles.ticketId}>{ticket.id}</Text>
|
|
<View
|
|
style={[
|
|
styles.statusBadge,
|
|
{ backgroundColor: getStatusBgColor(ticket.status) },
|
|
]}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.statusBadgeText,
|
|
{ color: getStatusColor(ticket.status) },
|
|
]}
|
|
>
|
|
{getStatusLabel(ticket.status)}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<Text style={styles.ticketSubject} numberOfLines={1}>
|
|
{ticket.subject}
|
|
</Text>
|
|
<View style={styles.ticketFooter}>
|
|
<View style={styles.ticketCategory}>
|
|
<Ionicons
|
|
name="pricetag-outline"
|
|
size={14}
|
|
color={AppColors.textMuted}
|
|
/>
|
|
<Text style={styles.ticketCategoryText}>{ticket.category}</Text>
|
|
</View>
|
|
<Text style={styles.ticketDate}>
|
|
Updated: {ticket.updatedAt}
|
|
</Text>
|
|
</View>
|
|
<View style={styles.ticketMessages}>
|
|
<Ionicons
|
|
name="chatbubbles-outline"
|
|
size={14}
|
|
color={AppColors.textMuted}
|
|
/>
|
|
<Text style={styles.ticketMessagesText}>
|
|
{ticket.messages.length} message{ticket.messages.length !== 1 ? 's' : ''}
|
|
</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
</View>
|
|
</>
|
|
) : (
|
|
<>
|
|
{/* Quick Contact */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Quick Contact</Text>
|
|
<View style={styles.card}>
|
|
<ContactMethod
|
|
icon="call"
|
|
iconColor="#10B981"
|
|
iconBgColor="#D1FAE5"
|
|
title="Call Us"
|
|
subtitle="+1 (555) 123-4567"
|
|
onPress={handleCall}
|
|
/>
|
|
<View style={styles.divider} />
|
|
<ContactMethod
|
|
icon="mail"
|
|
iconColor="#3B82F6"
|
|
iconBgColor="#DBEAFE"
|
|
title="Email Support"
|
|
subtitle="support@wellnuo.com"
|
|
onPress={handleEmail}
|
|
/>
|
|
<View style={styles.divider} />
|
|
<ContactMethod
|
|
icon="chatbubbles"
|
|
iconColor="#8B5CF6"
|
|
iconBgColor="#EDE9FE"
|
|
title="Live Chat"
|
|
subtitle="Available 24/7"
|
|
onPress={handleChat}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Support Hours */}
|
|
<View style={styles.section}>
|
|
<View style={styles.hoursCard}>
|
|
<Ionicons name="time" size={24} color={AppColors.primary} />
|
|
<View style={styles.hoursContent}>
|
|
<Text style={styles.hoursTitle}>Support Hours</Text>
|
|
<Text style={styles.hoursText}>Phone: Mon-Fri 8am-8pm EST</Text>
|
|
<Text style={styles.hoursText}>Email & Chat: 24/7</Text>
|
|
<Text style={styles.hoursText}>Emergency: 24/7</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Submit a Ticket */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Submit a Ticket</Text>
|
|
<View style={styles.formCard}>
|
|
{/* Category */}
|
|
<View style={styles.inputGroup}>
|
|
<Text style={styles.label}>Category *</Text>
|
|
<View style={styles.categoryContainer}>
|
|
{categories.map((cat) => (
|
|
<TouchableOpacity
|
|
key={cat}
|
|
style={[
|
|
styles.categoryChip,
|
|
category === cat && styles.categoryChipSelected,
|
|
]}
|
|
onPress={() => setCategory(cat)}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.categoryChipText,
|
|
category === cat && styles.categoryChipTextSelected,
|
|
]}
|
|
>
|
|
{cat}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
</View>
|
|
|
|
{/* Subject */}
|
|
<View style={styles.inputGroup}>
|
|
<Text style={styles.label}>Subject *</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={subject}
|
|
onChangeText={setSubject}
|
|
placeholder="Brief description of your issue"
|
|
placeholderTextColor={AppColors.textMuted}
|
|
/>
|
|
</View>
|
|
|
|
{/* Message */}
|
|
<View style={styles.inputGroup}>
|
|
<Text style={styles.label}>Message *</Text>
|
|
<TextInput
|
|
style={[styles.input, styles.textArea]}
|
|
value={message}
|
|
onChangeText={setMessage}
|
|
placeholder="Please describe your issue in detail."
|
|
placeholderTextColor={AppColors.textMuted}
|
|
multiline
|
|
numberOfLines={5}
|
|
textAlignVertical="top"
|
|
/>
|
|
</View>
|
|
|
|
{/* Submit Button */}
|
|
<TouchableOpacity
|
|
style={[styles.submitButton, isSending && styles.submitButtonDisabled]}
|
|
onPress={handleSendTicket}
|
|
disabled={isSending}
|
|
>
|
|
<Text style={styles.submitButtonText}>
|
|
{isSending ? 'Sending...' : 'Submit Ticket'}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</>
|
|
)}
|
|
|
|
{/* FAQ Link */}
|
|
<View style={styles.section}>
|
|
<TouchableOpacity
|
|
style={styles.faqLink}
|
|
onPress={() => router.push('/(tabs)/profile/help')}
|
|
>
|
|
<View style={styles.faqLinkContent}>
|
|
<Ionicons name="help-circle" size={24} color={AppColors.primary} />
|
|
<View style={styles.faqLinkText}>
|
|
<Text style={styles.faqLinkTitle}>Check our Help Center</Text>
|
|
<Text style={styles.faqLinkSubtitle}>
|
|
Find answers to common questions
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
<Ionicons name="chevron-forward" size={20} color={AppColors.textMuted} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Emergency Notice */}
|
|
<View style={styles.emergencyNotice}>
|
|
<Ionicons name="warning" size={20} color={AppColors.error} />
|
|
<Text style={styles.emergencyText}>
|
|
If you're experiencing a medical emergency, please call 911 or your local
|
|
emergency services immediately.
|
|
</Text>
|
|
</View>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
|
|
{/* Ticket Detail Modal */}
|
|
{renderTicketModal()}
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.surface,
|
|
},
|
|
keyboardView: {
|
|
flex: 1,
|
|
},
|
|
tabsContainer: {
|
|
flexDirection: 'row',
|
|
backgroundColor: AppColors.background,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: AppColors.border,
|
|
},
|
|
tab: {
|
|
flex: 1,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingVertical: Spacing.md,
|
|
gap: Spacing.xs,
|
|
},
|
|
tabActive: {
|
|
borderBottomWidth: 2,
|
|
borderBottomColor: AppColors.primary,
|
|
},
|
|
tabText: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '500',
|
|
color: AppColors.textMuted,
|
|
},
|
|
tabTextActive: {
|
|
color: AppColors.primary,
|
|
},
|
|
section: {
|
|
marginTop: Spacing.md,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
paddingHorizontal: Spacing.lg,
|
|
paddingVertical: Spacing.sm,
|
|
textTransform: 'uppercase',
|
|
},
|
|
card: {
|
|
backgroundColor: AppColors.background,
|
|
},
|
|
ticketsList: {
|
|
paddingHorizontal: Spacing.lg,
|
|
gap: Spacing.sm,
|
|
},
|
|
ticketCard: {
|
|
backgroundColor: AppColors.background,
|
|
borderRadius: BorderRadius.lg,
|
|
padding: Spacing.md,
|
|
borderWidth: 1,
|
|
borderColor: AppColors.border,
|
|
},
|
|
ticketHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: Spacing.xs,
|
|
},
|
|
ticketId: {
|
|
fontSize: FontSizes.xs,
|
|
fontWeight: '600',
|
|
color: AppColors.primary,
|
|
},
|
|
statusBadge: {
|
|
paddingHorizontal: Spacing.sm,
|
|
paddingVertical: 2,
|
|
borderRadius: BorderRadius.full,
|
|
},
|
|
statusBadgeText: {
|
|
fontSize: FontSizes.xs,
|
|
fontWeight: '600',
|
|
},
|
|
ticketSubject: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '500',
|
|
color: AppColors.textPrimary,
|
|
marginBottom: Spacing.sm,
|
|
},
|
|
ticketFooter: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
ticketCategory: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 4,
|
|
},
|
|
ticketCategoryText: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
},
|
|
ticketDate: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
},
|
|
ticketMessages: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 4,
|
|
marginTop: Spacing.xs,
|
|
paddingTop: Spacing.xs,
|
|
borderTopWidth: 1,
|
|
borderTopColor: AppColors.border,
|
|
},
|
|
ticketMessagesText: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
},
|
|
contactMethod: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingVertical: Spacing.md,
|
|
paddingHorizontal: Spacing.lg,
|
|
},
|
|
contactIcon: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: BorderRadius.md,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
contactContent: {
|
|
flex: 1,
|
|
marginLeft: Spacing.md,
|
|
},
|
|
contactTitle: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '500',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
contactSubtitle: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
marginTop: 2,
|
|
},
|
|
divider: {
|
|
height: 1,
|
|
backgroundColor: AppColors.border,
|
|
marginLeft: Spacing.lg + 48 + Spacing.md,
|
|
},
|
|
hoursCard: {
|
|
flexDirection: 'row',
|
|
backgroundColor: AppColors.background,
|
|
marginHorizontal: Spacing.lg,
|
|
padding: Spacing.md,
|
|
borderRadius: BorderRadius.lg,
|
|
alignItems: 'flex-start',
|
|
},
|
|
hoursContent: {
|
|
flex: 1,
|
|
marginLeft: Spacing.md,
|
|
},
|
|
hoursTitle: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
marginBottom: Spacing.xs,
|
|
},
|
|
hoursText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
marginTop: 2,
|
|
},
|
|
formCard: {
|
|
backgroundColor: AppColors.background,
|
|
padding: Spacing.lg,
|
|
},
|
|
inputGroup: {
|
|
marginBottom: Spacing.md,
|
|
},
|
|
label: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
marginBottom: Spacing.xs,
|
|
},
|
|
input: {
|
|
backgroundColor: AppColors.surface,
|
|
borderRadius: BorderRadius.md,
|
|
paddingHorizontal: Spacing.md,
|
|
paddingVertical: Spacing.md,
|
|
fontSize: FontSizes.base,
|
|
color: AppColors.textPrimary,
|
|
borderWidth: 1,
|
|
borderColor: AppColors.border,
|
|
},
|
|
textArea: {
|
|
minHeight: 100,
|
|
paddingTop: Spacing.md,
|
|
},
|
|
categoryContainer: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
marginTop: Spacing.xs,
|
|
},
|
|
categoryChip: {
|
|
paddingHorizontal: Spacing.md,
|
|
paddingVertical: Spacing.xs,
|
|
borderRadius: BorderRadius.full,
|
|
backgroundColor: AppColors.surface,
|
|
marginRight: Spacing.xs,
|
|
marginBottom: Spacing.xs,
|
|
borderWidth: 1,
|
|
borderColor: AppColors.border,
|
|
},
|
|
categoryChipSelected: {
|
|
backgroundColor: AppColors.primary,
|
|
borderColor: AppColors.primary,
|
|
},
|
|
categoryChipText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
},
|
|
categoryChipTextSelected: {
|
|
color: AppColors.white,
|
|
},
|
|
submitButton: {
|
|
backgroundColor: AppColors.primary,
|
|
borderRadius: BorderRadius.lg,
|
|
paddingVertical: Spacing.md,
|
|
alignItems: 'center',
|
|
marginTop: Spacing.sm,
|
|
},
|
|
submitButtonDisabled: {
|
|
opacity: 0.6,
|
|
},
|
|
submitButtonText: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '600',
|
|
color: AppColors.white,
|
|
},
|
|
faqLink: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: AppColors.background,
|
|
marginHorizontal: Spacing.lg,
|
|
padding: Spacing.md,
|
|
borderRadius: BorderRadius.lg,
|
|
},
|
|
faqLinkContent: {
|
|
flex: 1,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
faqLinkText: {
|
|
marginLeft: Spacing.md,
|
|
},
|
|
faqLinkTitle: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '500',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
faqLinkSubtitle: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
marginTop: 2,
|
|
},
|
|
emergencyNotice: {
|
|
flexDirection: 'row',
|
|
alignItems: 'flex-start',
|
|
backgroundColor: '#FEE2E2',
|
|
marginHorizontal: Spacing.lg,
|
|
marginVertical: Spacing.lg,
|
|
padding: Spacing.md,
|
|
borderRadius: BorderRadius.lg,
|
|
},
|
|
emergencyText: {
|
|
flex: 1,
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.error,
|
|
marginLeft: Spacing.sm,
|
|
lineHeight: 18,
|
|
},
|
|
// Modal styles
|
|
modalContainer: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.surface,
|
|
},
|
|
modalHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
paddingHorizontal: Spacing.lg,
|
|
paddingVertical: Spacing.md,
|
|
backgroundColor: AppColors.background,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: AppColors.border,
|
|
},
|
|
modalTitle: {
|
|
fontSize: FontSizes.lg,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
modalContent: {
|
|
flex: 1,
|
|
},
|
|
ticketInfo: {
|
|
backgroundColor: AppColors.background,
|
|
padding: Spacing.lg,
|
|
marginBottom: Spacing.md,
|
|
},
|
|
ticketInfoRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
paddingVertical: Spacing.xs,
|
|
},
|
|
ticketInfoLabel: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
},
|
|
ticketInfoValue: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '500',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
ticketSubjectContainer: {
|
|
backgroundColor: AppColors.background,
|
|
padding: Spacing.lg,
|
|
marginBottom: Spacing.md,
|
|
},
|
|
ticketSubjectLabel: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
marginBottom: Spacing.xs,
|
|
},
|
|
ticketSubjectText: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
messagesContainer: {
|
|
padding: Spacing.lg,
|
|
},
|
|
messagesTitle: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
marginBottom: Spacing.md,
|
|
textTransform: 'uppercase',
|
|
},
|
|
messageCard: {
|
|
backgroundColor: AppColors.background,
|
|
borderRadius: BorderRadius.lg,
|
|
padding: Spacing.md,
|
|
marginBottom: Spacing.sm,
|
|
borderLeftWidth: 3,
|
|
borderLeftColor: AppColors.primary,
|
|
},
|
|
messageCardSupport: {
|
|
borderLeftColor: '#10B981',
|
|
backgroundColor: '#F0FDF4',
|
|
},
|
|
messageHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: Spacing.xs,
|
|
},
|
|
messageFrom: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: Spacing.xs,
|
|
},
|
|
messageFromText: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
messageDate: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
},
|
|
messageText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textPrimary,
|
|
lineHeight: 20,
|
|
},
|
|
replySection: {
|
|
padding: Spacing.lg,
|
|
backgroundColor: AppColors.background,
|
|
marginTop: Spacing.md,
|
|
},
|
|
replyTitle: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
marginBottom: Spacing.sm,
|
|
textTransform: 'uppercase',
|
|
},
|
|
replyInput: {
|
|
backgroundColor: AppColors.surface,
|
|
borderRadius: BorderRadius.md,
|
|
paddingHorizontal: Spacing.md,
|
|
paddingVertical: Spacing.md,
|
|
fontSize: FontSizes.base,
|
|
color: AppColors.textPrimary,
|
|
borderWidth: 1,
|
|
borderColor: AppColors.border,
|
|
minHeight: 100,
|
|
marginBottom: Spacing.md,
|
|
},
|
|
replyButton: {
|
|
backgroundColor: AppColors.primary,
|
|
borderRadius: BorderRadius.lg,
|
|
paddingVertical: Spacing.md,
|
|
alignItems: 'center',
|
|
},
|
|
replyButtonText: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '600',
|
|
color: AppColors.white,
|
|
},
|
|
});
|