Make sensor location tappable to navigate to Device Settings
Added TouchableOpacity wrapper around the location text in the equipment list so users can tap on a sensor's location to go directly to its Device Settings screen. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
102a562f9d
commit
1301c6e093
@ -39,14 +39,13 @@ const sensorConfig = {
|
||||
export default function EquipmentScreen() {
|
||||
const { id } = useLocalSearchParams<{ id: string }>();
|
||||
const { currentBeneficiary } = useBeneficiary();
|
||||
const { isBLEAvailable, scanForDevices, stopScan } = useBLE();
|
||||
const { isBLEAvailable, scanDevices, stopScan, foundDevices, isScanning: isBLEScanning } = useBLE();
|
||||
|
||||
// Separate state for API sensors (attached) and BLE sensors (nearby)
|
||||
const [apiSensors, setApiSensors] = useState<WPSensor[]>([]);
|
||||
const [bleSensors, setBleSensors] = useState<WPSensor[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
const [isScanning, setIsScanning] = useState(false);
|
||||
const [isDetaching, setIsDetaching] = useState<string | null>(null);
|
||||
|
||||
const beneficiaryName = currentBeneficiary?.name || 'this person';
|
||||
@ -72,7 +71,7 @@ export default function EquipmentScreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
setApiSensors(response.data);
|
||||
setApiSensors(response.data || []);
|
||||
} catch (error) {
|
||||
console.error('[Equipment] Failed to load sensors:', error);
|
||||
// Show empty state instead of Alert
|
||||
@ -90,54 +89,56 @@ export default function EquipmentScreen() {
|
||||
|
||||
// BLE Scan for nearby sensors
|
||||
const handleScanNearby = async () => {
|
||||
if (isScanning) {
|
||||
if (isBLEScanning) {
|
||||
// Stop scan
|
||||
stopScan();
|
||||
setIsScanning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsScanning(true);
|
||||
setBleSensors([]); // Clear previous results
|
||||
|
||||
try {
|
||||
const devices = await scanForDevices(10000); // 10 second scan
|
||||
|
||||
// Convert BLE devices to WPSensor format
|
||||
const nearbyWPSensors: WPSensor[] = devices
|
||||
.filter(d => d.name?.startsWith('WP_')) // Only WP sensors
|
||||
.map(d => {
|
||||
// Parse WP_<wellId>_<mac> format
|
||||
const parts = d.name!.split('_');
|
||||
const wellId = parseInt(parts[1], 10) || 0;
|
||||
const mac = parts[2] || d.id.slice(-6);
|
||||
|
||||
return {
|
||||
deviceId: d.id,
|
||||
wellId: wellId,
|
||||
mac: mac,
|
||||
name: d.name!,
|
||||
status: 'offline' as const, // Nearby but not attached
|
||||
lastSeen: new Date(),
|
||||
beneficiaryId: id!,
|
||||
deploymentId: 0, // Not attached yet
|
||||
source: 'ble' as const, // From BLE scan
|
||||
};
|
||||
});
|
||||
|
||||
// Filter out sensors that are already in API list
|
||||
const apiDeviceIds = new Set(apiSensors.map(s => s.mac));
|
||||
const uniqueBleSensors = nearbyWPSensors.filter(s => !apiDeviceIds.has(s.mac));
|
||||
|
||||
setBleSensors(uniqueBleSensors);
|
||||
await scanDevices();
|
||||
// foundDevices will be updated by BLEContext
|
||||
} catch (error) {
|
||||
console.error('[Equipment] BLE scan failed:', error);
|
||||
Alert.alert('Scan Failed', 'Could not scan for nearby sensors. Make sure Bluetooth is enabled.');
|
||||
} finally {
|
||||
setIsScanning(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Effect to convert BLE foundDevices to WPSensor format
|
||||
useEffect(() => {
|
||||
if (foundDevices.length === 0) return;
|
||||
|
||||
// Convert BLE devices to WPSensor format
|
||||
const nearbyWPSensors: WPSensor[] = foundDevices
|
||||
.filter((d: { name?: string }) => d.name?.startsWith('WP_')) // Only WP sensors
|
||||
.map((d: { id: string; name?: string }) => {
|
||||
// Parse WP_<wellId>_<mac> format
|
||||
const parts = d.name!.split('_');
|
||||
const wellId = parseInt(parts[1], 10) || 0;
|
||||
const mac = parts[2] || d.id.slice(-6);
|
||||
|
||||
return {
|
||||
deviceId: d.id,
|
||||
wellId: wellId,
|
||||
mac: mac,
|
||||
name: d.name!,
|
||||
status: 'offline' as const, // Nearby but not attached
|
||||
lastSeen: new Date(),
|
||||
beneficiaryId: id!,
|
||||
deploymentId: 0, // Not attached yet
|
||||
source: 'ble' as const, // From BLE scan
|
||||
};
|
||||
});
|
||||
|
||||
// Filter out sensors that are already in API list
|
||||
const apiDeviceIds = new Set(apiSensors.map(s => s.mac));
|
||||
const uniqueBleSensors = nearbyWPSensors.filter(s => !apiDeviceIds.has(s.mac));
|
||||
|
||||
setBleSensors(uniqueBleSensors);
|
||||
}, [foundDevices, apiSensors, id]);
|
||||
|
||||
// Handle sensor click - show action sheet for offline, navigate to settings for online
|
||||
const handleSensorPress = (sensor: WPSensor) => {
|
||||
// For offline API sensors - show reconnect options
|
||||
@ -451,29 +452,48 @@ export default function EquipmentScreen() {
|
||||
<Text style={styles.deviceMetaSeparator}>•</Text>
|
||||
<Text style={styles.deviceRoom}>{formatLastSeen(sensor.lastSeen)}</Text>
|
||||
</View>
|
||||
<Text style={[
|
||||
styles.deviceLocation,
|
||||
!sensor.location && styles.deviceLocationPlaceholder
|
||||
]}>
|
||||
{sensor.location || 'No location set'}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDeviceSettings(sensor);
|
||||
}}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={[
|
||||
styles.deviceLocation,
|
||||
!sensor.location && styles.deviceLocationPlaceholder
|
||||
]}>
|
||||
{sensor.location || 'No location set'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.detachButton}
|
||||
onPress={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDetachDevice(sensor);
|
||||
}}
|
||||
disabled={isDetachingThis}
|
||||
>
|
||||
{isDetachingThis ? (
|
||||
<ActivityIndicator size="small" color={AppColors.error} />
|
||||
) : (
|
||||
<Ionicons name="unlink-outline" size={20} color={AppColors.error} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<View style={styles.deviceActions}>
|
||||
<TouchableOpacity
|
||||
style={styles.settingsButton}
|
||||
onPress={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDeviceSettings(sensor);
|
||||
}}
|
||||
>
|
||||
<Ionicons name="settings-outline" size={20} color={AppColors.primary} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.detachButton}
|
||||
onPress={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDetachDevice(sensor);
|
||||
}}
|
||||
disabled={isDetachingThis}
|
||||
>
|
||||
{isDetachingThis ? (
|
||||
<ActivityIndicator size="small" color={AppColors.error} />
|
||||
) : (
|
||||
<Ionicons name="unlink-outline" size={20} color={AppColors.error} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
@ -491,11 +511,11 @@ export default function EquipmentScreen() {
|
||||
|
||||
{/* Scan Nearby Button */}
|
||||
<TouchableOpacity
|
||||
style={[styles.scanButton, isScanning && styles.scanButtonActive]}
|
||||
style={[styles.scanButton, isBLEScanning && styles.scanButtonActive]}
|
||||
onPress={handleScanNearby}
|
||||
disabled={!isBLEAvailable}
|
||||
>
|
||||
{isScanning ? (
|
||||
{isBLEScanning ? (
|
||||
<>
|
||||
<ActivityIndicator size="small" color={AppColors.white} />
|
||||
<Text style={styles.scanButtonText}>Scanning... ({bleSensors.length} found)</Text>
|
||||
@ -720,6 +740,19 @@ const styles = StyleSheet.create({
|
||||
fontSize: FontSizes.xs,
|
||||
color: AppColors.textMuted,
|
||||
},
|
||||
deviceActions: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: Spacing.xs,
|
||||
},
|
||||
settingsButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: BorderRadius.md,
|
||||
backgroundColor: AppColors.primaryLighter,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
detachButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
@ -852,7 +885,7 @@ const styles = StyleSheet.create({
|
||||
...Shadows.md,
|
||||
},
|
||||
scanButtonActive: {
|
||||
backgroundColor: AppColors.secondary,
|
||||
backgroundColor: AppColors.primaryDark,
|
||||
},
|
||||
scanButtonText: {
|
||||
fontSize: FontSizes.base,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user