fix: tab stack reset, GPS optional for install, status picker mutation fix
This commit is contained in:
@@ -29,9 +29,12 @@ export default function AppLayout() {
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="clients"
|
||||
options={{ title: 'Clients', tabBarIcon: ({ color }) => <Icon name="users" size={22} color={color} /> }}
|
||||
options={{ title: 'Clients', tabBarIcon: ({ color }) => <Icon name="users" size={22} color={color} />, unmountOnBlur: true }}
|
||||
listeners={({ navigation }: any) => ({
|
||||
tabPress: () => { navigation.navigate('clients', { screen: 'index' }); },
|
||||
tabPress: (e) => {
|
||||
e.preventDefault();
|
||||
navigation.reset({ index: 0, routes: [{ name: 'clients' }] });
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
@@ -40,9 +43,12 @@ export default function AppLayout() {
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="tasks"
|
||||
options={{ title: 'Tickets', tabBarIcon: ({ color }) => <Icon name="ticket" size={22} color={color} /> }}
|
||||
options={{ title: 'Tickets', tabBarIcon: ({ color }) => <Icon name="ticket" size={22} color={color} />, unmountOnBlur: true }}
|
||||
listeners={({ navigation }: any) => ({
|
||||
tabPress: () => { navigation.navigate('tasks', { screen: 'index' }); },
|
||||
tabPress: (e) => {
|
||||
e.preventDefault();
|
||||
navigation.reset({ index: 0, routes: [{ name: 'tasks' }] });
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
|
||||
@@ -84,14 +84,11 @@ export default function TicketDetailScreen() {
|
||||
});
|
||||
|
||||
const updateStatus = useMutation({
|
||||
mutationFn: async (status: TaskStatus) => {
|
||||
mutationFn: async ({ status, activationTicket, subId }: { status: string; activationTicket: boolean; subId?: string }) => {
|
||||
await api.patch(`/api/v1/tickets/${id}`, { status });
|
||||
// If this is an activation ticket being RESOLVED → activate subscription
|
||||
if ((status === 'RESOLVED' || status === 'CLOSED') && isActivationTicket) {
|
||||
const sub = clientDetail?.subscriptions?.[0];
|
||||
if (sub?.id && sub?.status !== 'ACTIVE') {
|
||||
await api.patch(`/api/v1/subscriptions/${sub.id}`, { status: 'ACTIVE' }).catch(() => {});
|
||||
}
|
||||
if ((status === 'RESOLVED' || status === 'CLOSED') && activationTicket && subId) {
|
||||
await api.patch(`/api/v1/subscriptions/${subId}`, { status: 'ACTIVE' }).catch(() => {});
|
||||
}
|
||||
const who = user?.firstName ?? 'Staff';
|
||||
await api.post(`/api/v1/tickets/${id}/messages`, {
|
||||
@@ -107,7 +104,10 @@ export default function TicketDetailScreen() {
|
||||
await refetchClient().catch(() => {});
|
||||
await refetchInvoices().catch(() => {});
|
||||
},
|
||||
onError: () => Alert.alert('Error', 'Could not update status.'),
|
||||
onError: (e: any) => {
|
||||
const msg = e?.response?.data?.message ?? 'Could not update status.';
|
||||
Alert.alert('Error', Array.isArray(msg) ? msg.join('\n') : msg);
|
||||
},
|
||||
});
|
||||
|
||||
const captureLocation = async () => {
|
||||
@@ -128,20 +128,13 @@ export default function TicketDetailScreen() {
|
||||
};
|
||||
|
||||
const confirmInstallation = async () => {
|
||||
if (!coords) {
|
||||
Alert.alert('Location Required', 'Please capture the installation coordinates before confirming.', [
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{ text: 'Capture Now', onPress: captureLocation },
|
||||
]);
|
||||
return;
|
||||
}
|
||||
setInstConfirming(true);
|
||||
try {
|
||||
// 1. Resolve the ticket
|
||||
await api.patch(`/api/v1/tickets/${id}`, { status: 'RESOLVED' });
|
||||
|
||||
// 2. Update client location with recorded coordinates
|
||||
if (ticket?.clientId) {
|
||||
// 2. Update client location with recorded coordinates (skip if GPS unavailable)
|
||||
if (ticket?.clientId && coords) {
|
||||
await api.patch(`/api/v1/clients/${ticket.clientId}`, {
|
||||
lat: coords.lat,
|
||||
lng: coords.lng,
|
||||
@@ -149,7 +142,7 @@ export default function TicketDetailScreen() {
|
||||
}
|
||||
|
||||
// 3. Log activity comment
|
||||
const coordStr = `${coords.lat.toFixed(6)}, ${coords.lng.toFixed(6)}`;
|
||||
const coordStr = coords ? `${coords.lat.toFixed(6)}, ${coords.lng.toFixed(6)}` : 'Not captured';
|
||||
const note = instNotes.trim()
|
||||
? `Installation confirmed. Location recorded: ${coordStr}. Notes: ${instNotes.trim()}`
|
||||
: `Installation confirmed. Location recorded: ${coordStr}`;
|
||||
@@ -468,26 +461,37 @@ export default function TicketDetailScreen() {
|
||||
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: coords ? '#059669' : '#94A3B8',
|
||||
backgroundColor: '#059669',
|
||||
borderRadius: 14, paddingVertical: 16, alignItems: 'center',
|
||||
}}
|
||||
onPress={() =>
|
||||
onPress={() => {
|
||||
if (!coords) {
|
||||
Alert.alert(
|
||||
'Location Not Captured',
|
||||
'Location not captured — are you sure you want to proceed without GPS coordinates?',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{ text: 'Confirm Without Location', onPress: confirmInstallation },
|
||||
]
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
'Confirm Installation',
|
||||
`Mark this installation as complete?\n\nLocation: ${coords ? `${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)}` : 'Not captured'}\n\nThis will update the client's location and resolve the ticket.`,
|
||||
`Mark this installation as complete?\n\nLocation: ${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)}\n\nThis will update the client's location and resolve the ticket.`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{ text: 'Confirm', onPress: confirmInstallation },
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
disabled={instConfirming || !coords}
|
||||
}}
|
||||
disabled={instConfirming}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
{instConfirming
|
||||
? <ActivityIndicator color="#FFF" />
|
||||
: <Text style={{ color: '#FFF', fontSize: 17, fontWeight: '700' }}>
|
||||
{coords ? '✓ Mark Installation Complete' : 'Capture Location First'}
|
||||
✓ Mark Installation Complete
|
||||
</Text>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
@@ -643,7 +647,11 @@ export default function TicketDetailScreen() {
|
||||
);
|
||||
return;
|
||||
}
|
||||
updateStatus.mutate(s);
|
||||
updateStatus.mutate({
|
||||
status: s,
|
||||
activationTicket: isActivationTicket,
|
||||
subId: clientDetail?.subscriptions?.[0]?.id,
|
||||
});
|
||||
}}
|
||||
disabled={isActive || updateStatus.isPending}
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user