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() {
|
export default function EquipmentScreen() {
|
||||||
const { id } = useLocalSearchParams<{ id: string }>();
|
const { id } = useLocalSearchParams<{ id: string }>();
|
||||||
const { currentBeneficiary } = useBeneficiary();
|
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)
|
// Separate state for API sensors (attached) and BLE sensors (nearby)
|
||||||
const [apiSensors, setApiSensors] = useState<WPSensor[]>([]);
|
const [apiSensors, setApiSensors] = useState<WPSensor[]>([]);
|
||||||
const [bleSensors, setBleSensors] = useState<WPSensor[]>([]);
|
const [bleSensors, setBleSensors] = useState<WPSensor[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [isScanning, setIsScanning] = useState(false);
|
|
||||||
const [isDetaching, setIsDetaching] = useState<string | null>(null);
|
const [isDetaching, setIsDetaching] = useState<string | null>(null);
|
||||||
|
|
||||||
const beneficiaryName = currentBeneficiary?.name || 'this person';
|
const beneficiaryName = currentBeneficiary?.name || 'this person';
|
||||||
@ -72,7 +71,7 @@ export default function EquipmentScreen() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setApiSensors(response.data);
|
setApiSensors(response.data || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Equipment] Failed to load sensors:', error);
|
console.error('[Equipment] Failed to load sensors:', error);
|
||||||
// Show empty state instead of Alert
|
// Show empty state instead of Alert
|
||||||
@ -90,23 +89,31 @@ export default function EquipmentScreen() {
|
|||||||
|
|
||||||
// BLE Scan for nearby sensors
|
// BLE Scan for nearby sensors
|
||||||
const handleScanNearby = async () => {
|
const handleScanNearby = async () => {
|
||||||
if (isScanning) {
|
if (isBLEScanning) {
|
||||||
// Stop scan
|
// Stop scan
|
||||||
stopScan();
|
stopScan();
|
||||||
setIsScanning(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsScanning(true);
|
|
||||||
setBleSensors([]); // Clear previous results
|
setBleSensors([]); // Clear previous results
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const devices = await scanForDevices(10000); // 10 second scan
|
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.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Effect to convert BLE foundDevices to WPSensor format
|
||||||
|
useEffect(() => {
|
||||||
|
if (foundDevices.length === 0) return;
|
||||||
|
|
||||||
// Convert BLE devices to WPSensor format
|
// Convert BLE devices to WPSensor format
|
||||||
const nearbyWPSensors: WPSensor[] = devices
|
const nearbyWPSensors: WPSensor[] = foundDevices
|
||||||
.filter(d => d.name?.startsWith('WP_')) // Only WP sensors
|
.filter((d: { name?: string }) => d.name?.startsWith('WP_')) // Only WP sensors
|
||||||
.map(d => {
|
.map((d: { id: string; name?: string }) => {
|
||||||
// Parse WP_<wellId>_<mac> format
|
// Parse WP_<wellId>_<mac> format
|
||||||
const parts = d.name!.split('_');
|
const parts = d.name!.split('_');
|
||||||
const wellId = parseInt(parts[1], 10) || 0;
|
const wellId = parseInt(parts[1], 10) || 0;
|
||||||
@ -130,13 +137,7 @@ export default function EquipmentScreen() {
|
|||||||
const uniqueBleSensors = nearbyWPSensors.filter(s => !apiDeviceIds.has(s.mac));
|
const uniqueBleSensors = nearbyWPSensors.filter(s => !apiDeviceIds.has(s.mac));
|
||||||
|
|
||||||
setBleSensors(uniqueBleSensors);
|
setBleSensors(uniqueBleSensors);
|
||||||
} catch (error) {
|
}, [foundDevices, apiSensors, id]);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle sensor click - show action sheet for offline, navigate to settings for online
|
// Handle sensor click - show action sheet for offline, navigate to settings for online
|
||||||
const handleSensorPress = (sensor: WPSensor) => {
|
const handleSensorPress = (sensor: WPSensor) => {
|
||||||
@ -451,15 +452,33 @@ export default function EquipmentScreen() {
|
|||||||
<Text style={styles.deviceMetaSeparator}>•</Text>
|
<Text style={styles.deviceMetaSeparator}>•</Text>
|
||||||
<Text style={styles.deviceRoom}>{formatLastSeen(sensor.lastSeen)}</Text>
|
<Text style={styles.deviceRoom}>{formatLastSeen(sensor.lastSeen)}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleDeviceSettings(sensor);
|
||||||
|
}}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
<Text style={[
|
<Text style={[
|
||||||
styles.deviceLocation,
|
styles.deviceLocation,
|
||||||
!sensor.location && styles.deviceLocationPlaceholder
|
!sensor.location && styles.deviceLocationPlaceholder
|
||||||
]}>
|
]}>
|
||||||
{sensor.location || 'No location set'}
|
{sensor.location || 'No location set'}
|
||||||
</Text>
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<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
|
<TouchableOpacity
|
||||||
style={styles.detachButton}
|
style={styles.detachButton}
|
||||||
onPress={(e) => {
|
onPress={(e) => {
|
||||||
@ -474,6 +493,7 @@ export default function EquipmentScreen() {
|
|||||||
<Ionicons name="unlink-outline" size={20} color={AppColors.error} />
|
<Ionicons name="unlink-outline" size={20} color={AppColors.error} />
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -491,11 +511,11 @@ export default function EquipmentScreen() {
|
|||||||
|
|
||||||
{/* Scan Nearby Button */}
|
{/* Scan Nearby Button */}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.scanButton, isScanning && styles.scanButtonActive]}
|
style={[styles.scanButton, isBLEScanning && styles.scanButtonActive]}
|
||||||
onPress={handleScanNearby}
|
onPress={handleScanNearby}
|
||||||
disabled={!isBLEAvailable}
|
disabled={!isBLEAvailable}
|
||||||
>
|
>
|
||||||
{isScanning ? (
|
{isBLEScanning ? (
|
||||||
<>
|
<>
|
||||||
<ActivityIndicator size="small" color={AppColors.white} />
|
<ActivityIndicator size="small" color={AppColors.white} />
|
||||||
<Text style={styles.scanButtonText}>Scanning... ({bleSensors.length} found)</Text>
|
<Text style={styles.scanButtonText}>Scanning... ({bleSensors.length} found)</Text>
|
||||||
@ -720,6 +740,19 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: FontSizes.xs,
|
fontSize: FontSizes.xs,
|
||||||
color: AppColors.textMuted,
|
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: {
|
detachButton: {
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
@ -852,7 +885,7 @@ const styles = StyleSheet.create({
|
|||||||
...Shadows.md,
|
...Shadows.md,
|
||||||
},
|
},
|
||||||
scanButtonActive: {
|
scanButtonActive: {
|
||||||
backgroundColor: AppColors.secondary,
|
backgroundColor: AppColors.primaryDark,
|
||||||
},
|
},
|
||||||
scanButtonText: {
|
scanButtonText: {
|
||||||
fontSize: FontSizes.base,
|
fontSize: FontSizes.base,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user