fix: tickets freeze (useFocusEffect), comment body render, client status from subscription, activation ticket on install, keyboard avoid payment modal

This commit is contained in:
Nemo
2026-03-24 11:57:24 +08:00
parent f8c5402b02
commit f346951052
5 changed files with 35 additions and 7 deletions

View File

@@ -125,12 +125,22 @@ export default function TicketDetailScreen() {
: `Installation confirmed. Location recorded: ${coordStr}`;
await api.post(`/api/v1/tickets/${id}/messages`, { body: note }).catch(() => {});
// 4. Create follow-up activation ticket
await api.post('/api/v1/tickets', {
clientId: ticket?.clientId,
subject: `Account Activation — ${ticket?.client?.firstName ?? ''} ${ticket?.client?.lastName ?? ''}`.trim(),
type: 'BILLING',
priority: 'NORMAL',
description: `Follow-up after installation confirmed. Please activate the client account and generate the first invoice.\n\nInstallation ref: ${id}\nLocation: ${coordStr}`,
}).catch(() => {});
setInstNotes('');
setCoords(null);
Alert.alert('Installation Complete!', 'Ticket resolved and client location updated.');
Alert.alert('Installation Complete!', 'Ticket resolved, location updated, and activation ticket created.');
refetch();
qc.invalidateQueries({ queryKey: ['tasks'] });
qc.invalidateQueries({ queryKey: ['client', ticket?.clientId] });
qc.invalidateQueries({ queryKey: ['client-tickets', ticket?.clientId] });
setActiveTab('comments');
} catch {
Alert.alert('Error', 'Could not confirm installation. Please try again.');
@@ -404,7 +414,7 @@ export default function TicketDetailScreen() {
</View>
) : (
messages.map((m: any, i: number) => {
const isSystem = m.senderType === 'SYSTEM' || m.message?.startsWith('Status changed') || m.message?.startsWith('Installation confirmed');
const isSystem = m.senderType === 'SYSTEM' || m.body?.startsWith('Status changed') || m.body?.startsWith('Installation confirmed');
const isMe = m.sender?.id === user?.id;
if (isSystem) {
@@ -412,7 +422,7 @@ export default function TicketDetailScreen() {
return (
<View key={m.id ?? i} style={{ alignItems: 'center', marginBottom: 14 }}>
<View style={{ backgroundColor: '#F1F5F9', borderRadius: 20, paddingHorizontal: 14, paddingVertical: 6 }}>
<Text style={{ fontSize: 13, color: '#64748B', fontStyle: 'italic' }}>{m.message}</Text>
<Text style={{ fontSize: 13, color: '#64748B', fontStyle: 'italic' }}>{m.body}</Text>
</View>
{m.createdAt && (
<Text style={{ fontSize: 11, color: '#CBD5E1', marginTop: 3 }}>
@@ -441,7 +451,7 @@ export default function TicketDetailScreen() {
borderWidth: isMe ? 0 : 1, borderColor: '#F1F5F9',
}}>
<Text style={{ fontSize: 16, color: isMe ? '#FFF' : '#0F172A', lineHeight: 22 }}>
{m.message}
{m.body}
</Text>
</View>
{m.createdAt && (

View File

@@ -2,6 +2,8 @@ import { useState } from 'react';
import { View, Text, FlatList, TextInput, TouchableOpacity, ActivityIndicator, RefreshControl, ScrollView } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useQuery } from '@tanstack/react-query';
import { useFocusEffect } from 'expo-router';
import { useCallback } from 'react';
import { router } from 'expo-router';
import { api } from '../../../services/api';
@@ -23,6 +25,9 @@ export default function TasksScreen() {
queryFn: () => api.get('/api/v1/tickets?limit=100').then(r => r.data?.data ?? r.data ?? []),
});
// Refetch list every time this screen comes into focus (fixes stale list after navigating back)
useFocusEffect(useCallback(() => { refetch(); }, []));
const tasks = (data ?? []).filter((t: any) => {
const matchSearch = `${t.subject} ${t.client?.firstName ?? ''} ${t.client?.lastName ?? ''}`.toLowerCase().includes(search.toLowerCase());
const matchStatus = statusFilter === 'All' || t.status === statusFilter;