import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; import { router } from 'expo-router'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { api } from '../../../services/api'; const PRIORITIES = ['LOW', 'MEDIUM', 'HIGH']; const PRIORITY_COLOR: Record = { HIGH: '#DC2626', MEDIUM: '#D97706', LOW: '#16A34A' }; const CATEGORIES: { value: string; label: string }[] = [ { value: 'NO_SIGNAL', label: 'No Signal' }, { value: 'SLOW_CONNECTION', label: 'Slow Connection' }, { value: 'BILLING', label: 'Billing' }, { value: 'INSTALLATION', label: 'Installation' }, { value: 'RELOCATION', label: 'Relocation' }, { value: 'OTHER', label: 'Other' }, ]; export default function NewTicketScreen() { const qc = useQueryClient(); const [subject, setSubject] = useState(''); const [description, setDescription] = useState(''); const [priority, setPriority] = useState('MEDIUM'); const [category, setCategory] = useState('NO_SIGNAL'); const [search, setSearch] = useState(''); const [debouncedSearch, setDebouncedSearch] = useState(''); const [client, setClient] = useState(null); const [loading, setLoading] = useState(false); const { data: searchResults, isFetching: searching } = useQuery({ queryKey: ['client-search', debouncedSearch], queryFn: () => api.get(`/api/v1/clients?search=${debouncedSearch}&limit=8`).then(r => r.data?.data ?? r.data ?? []), enabled: debouncedSearch.trim().length >= 2, }); const handleSearchChange = (v: string) => { setSearch(v); setTimeout(() => setDebouncedSearch(v), 400); }; const submit = async () => { if (!subject.trim()) return Alert.alert('Required', 'Enter a subject.'); if (!client) return Alert.alert('Required', 'Select a client.'); setLoading(true); try { await api.post('/api/v1/tickets', { subject: subject.trim(), description: description.trim() || undefined, priority, category, clientId: client.id, }); qc.invalidateQueries({ queryKey: ['tickets'] }); qc.invalidateQueries({ queryKey: ['dashboard'] }); Alert.alert('✅ Ticket Created', subject, [{ text: 'OK', onPress: () => router.back() }]); } catch (e: any) { Alert.alert('Error', e?.response?.data?.message ?? 'Could not create ticket.'); } finally { setLoading(false); } }; return ( router.back()} className="mr-3 p-1"> New Ticket {/* Client */} Client * {client ? ( {client.firstName} {client.lastName} {client.accountNumber} { setClient(null); setSearch(''); setDebouncedSearch(''); }} className="p-2"> Change ) : ( {searching && } {debouncedSearch.trim().length >= 2 && ( {(searchResults ?? []).length === 0 && !searching && ( No clients found )} {(searchResults ?? []).map((c: any) => ( { setClient(c); setSearch(''); setDebouncedSearch(''); }} > {c.firstName} {c.lastName} {c.accountNumber} ))} )} )} {/* Subject */} Subject * {/* Category */} Category {CATEGORIES.map(c => ( setCategory(c.value)} className={`rounded-xl px-3 py-2 mr-2 mb-2 border ${category === c.value ? 'bg-primary border-primary' : 'bg-white border-gray-200'}`} > {c.label} ))} {/* Priority */} Priority {PRIORITIES.map(p => ( setPriority(p)} className={`flex-1 rounded-xl py-2.5 items-center mx-1 border ${priority === p ? 'border-transparent' : 'bg-white border-gray-200'}`} style={priority === p ? { backgroundColor: PRIORITY_COLOR[p] } : {}} > {p} ))} {/* Description */} Description (optional) {loading ? : Create Ticket} ); }