From 055b3a43301ddc167b87a9ea86cc6d5d4d3becdf Mon Sep 17 00:00:00 2001 From: Nemo Date: Tue, 24 Mar 2026 22:36:08 +0800 Subject: [PATCH] fix: onboarding button disabled state; feat: update GPS from client profile --- app/(app)/clients/[id].tsx | 44 ++++++++++++++++++++++++++++++++++++++ app/(app)/clients/new.tsx | 5 +++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/(app)/clients/[id].tsx b/app/(app)/clients/[id].tsx index 0b8a5a9..fe70b83 100644 --- a/app/(app)/clients/[id].tsx +++ b/app/(app)/clients/[id].tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { View, Text, ScrollView, TouchableOpacity, ActivityIndicator, Linking, Alert, TextInput, Modal, KeyboardAvoidingView, Platform } from 'react-native'; +import * as Location from 'expo-location'; import { SlideToConfirm } from '../../../components/SlideToConfirm'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, router } from 'expo-router'; @@ -130,6 +131,7 @@ export default function ClientDetailScreen() { const initialTab = (params.tab === 'invoices' ? 'Invoices' : 'Profile') as Tab; const [activeTab, setActiveTab] = useState(initialTab); const [payingInvoice, setPayingInvoice] = useState(null); + const [locationLoading, setLocationLoading] = useState(false); const { data: client, isLoading } = useQuery({ queryKey: ['client', id], @@ -172,6 +174,26 @@ export default function ClientDetailScreen() { ]); }; + const updateLocation = async () => { + setLocationLoading(true); + try { + const { status } = await Location.requestForegroundPermissionsAsync(); + if (status !== 'granted') { + Alert.alert('Permission denied', 'Location permission is required to update coordinates.'); + return; + } + const loc = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High }); + const { latitude: lat, longitude: lng } = loc.coords; + await api.patch(`/api/v1/clients/${id}`, { lat, lng }); + qc.setQueryData(['client', id], (old: any) => ({ ...old, lat, lng })); + Alert.alert('Location updated', '📍 GPS coordinates saved successfully.'); + } catch (e: any) { + Alert.alert('Error', 'Could not get location. Make sure GPS is enabled.'); + } finally { + setLocationLoading(false); + } + }; + if (isLoading) { return ( @@ -256,6 +278,28 @@ export default function ClientDetailScreen() { Location is recorded when a technician confirms an installation )} + + {/* Update Location */} + + {locationLoading + ? + : 📍 Update Location + } + + {client?.lat && client?.lng + ? + 📍 {Number(client.lat).toFixed(5)}, {Number(client.lng).toFixed(5)} + + : No location set + } )} diff --git a/app/(app)/clients/new.tsx b/app/(app)/clients/new.tsx index 39943b6..a9b67f1 100644 --- a/app/(app)/clients/new.tsx +++ b/app/(app)/clients/new.tsx @@ -128,6 +128,7 @@ export default function NewClientScreen() { // ── Submit ───────────────────────────────────────────────────────────────── const submit = async () => { + if (submitting) return; // guard against double-tap setSubmitting(true); try { // 1. Create client @@ -395,8 +396,8 @@ export default function NewClientScreen() { ) : ( {submitting ?