diff --git a/app/(tabs)/beneficiaries/[id]/device-settings/[deviceId].tsx b/app/(tabs)/beneficiaries/[id]/device-settings/[deviceId].tsx index 35a7b58..d0859d9 100644 --- a/app/(tabs)/beneficiaries/[id]/device-settings/[deviceId].tsx +++ b/app/(tabs)/beneficiaries/[id]/device-settings/[deviceId].tsx @@ -8,13 +8,15 @@ import { Alert, ActivityIndicator, TextInput, + Modal, + FlatList, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useLocalSearchParams } from 'expo-router'; import * as Device from 'expo-device'; import { useBLE } from '@/contexts/BLEContext'; -import { api } from '@/services/api'; +import { api, ROOM_LOCATIONS, type RoomLocationId } from '@/services/api'; import type { WiFiStatus } from '@/services/ble'; import { AppColors, @@ -58,8 +60,9 @@ export default function DeviceSettingsScreen() { const [isSaving, setIsSaving] = useState(false); // Editable fields - const [location, setLocation] = useState(''); + const [location, setLocation] = useState(''); const [description, setDescription] = useState(''); + const [showLocationPicker, setShowLocationPicker] = useState(false); const isConnected = connectedDevices.has(deviceId!); @@ -82,13 +85,12 @@ export default function DeviceSettingsScreen() { if (sensor) { setSensorInfo(sensor); - setLocation(sensor.location || ''); + setLocation((sensor.location as RoomLocationId) || ''); setDescription(sensor.description || ''); } else { throw new Error('Sensor not found'); } } catch (error: any) { - console.error('[DeviceSettings] Failed to load sensor info:', error); Alert.alert('Error', 'Failed to load sensor information'); router.back(); } finally { @@ -111,7 +113,6 @@ export default function DeviceSettingsScreen() { // Load WiFi status after connecting loadWiFiStatus(); } catch (error: any) { - console.error('[DeviceSettings] Connection failed:', error); Alert.alert('Connection Failed', 'Failed to connect to sensor via Bluetooth.'); } finally { setIsConnecting(false); @@ -127,7 +128,6 @@ export default function DeviceSettingsScreen() { const wifiStatus = await getCurrentWiFi(deviceId!); setCurrentWiFi(wifiStatus); } catch (error: any) { - console.error('[DeviceSettings] Failed to get WiFi status:', error); Alert.alert('Error', 'Failed to get WiFi status'); } finally { setIsLoadingWiFi(false); @@ -173,9 +173,8 @@ export default function DeviceSettingsScreen() { Alert.alert('Success', 'Sensor is rebooting. It will be back online in a minute.'); router.back(); } catch (error: any) { - console.error('[DeviceSettings] Reboot failed:', error); Alert.alert('Error', 'Failed to reboot sensor'); - } finally { + } finally{ setIsRebooting(false); } }, @@ -218,7 +217,6 @@ export default function DeviceSettingsScreen() { Alert.alert('Success', 'Device information updated.'); } catch (error: any) { - console.error('[DeviceSettings] Save failed:', error); Alert.alert('Error', error.message || 'Failed to save device information'); } finally { setIsSaving(false); @@ -353,13 +351,20 @@ export default function DeviceSettingsScreen() { Location - + setShowLocationPicker(true)} + > + + {location + ? `${ROOM_LOCATIONS.find(l => l.id === location)?.icon} ${ROOM_LOCATIONS.find(l => l.id === location)?.label}` + : 'Select location...'} + + + @@ -514,6 +519,56 @@ export default function DeviceSettingsScreen() { + + {/* Location Picker Modal */} + setShowLocationPicker(false)} + > + + + + Select Location + setShowLocationPicker(false)} + > + + + + item.id} + renderItem={({ item }) => ( + { + setLocation(item.id); + setShowLocationPicker(false); + }} + > + {item.icon} + + {item.label} + + {location === item.id && ( + + )} + + )} + ItemSeparatorComponent={() => } + /> + + + ); } @@ -688,6 +743,26 @@ const styles = StyleSheet.create({ minHeight: 60, textAlignVertical: 'top', }, + // Picker Button + pickerButton: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + backgroundColor: AppColors.background, + borderRadius: BorderRadius.md, + paddingHorizontal: Spacing.md, + paddingVertical: Spacing.sm, + borderWidth: 1, + borderColor: AppColors.border, + minHeight: 44, + }, + pickerButtonText: { + fontSize: FontSizes.base, + color: AppColors.textPrimary, + }, + pickerButtonPlaceholder: { + color: AppColors.textMuted, + }, saveButton: { flexDirection: 'row', alignItems: 'center', @@ -872,4 +947,63 @@ const styles = StyleSheet.create({ color: AppColors.info, lineHeight: 20, }, + // Modal styles + modalOverlay: { + flex: 1, + backgroundColor: 'rgba(0, 0, 0, 0.5)', + justifyContent: 'flex-end', + }, + modalContent: { + backgroundColor: AppColors.surface, + borderTopLeftRadius: BorderRadius.xl, + borderTopRightRadius: BorderRadius.xl, + maxHeight: '70%', + paddingBottom: Spacing.xl, + }, + modalHeader: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: Spacing.lg, + paddingVertical: Spacing.md, + borderBottomWidth: 1, + borderBottomColor: AppColors.border, + }, + modalTitle: { + fontSize: FontSizes.lg, + fontWeight: FontWeights.semibold, + color: AppColors.textPrimary, + }, + modalCloseButton: { + padding: Spacing.xs, + }, + locationOption: { + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: Spacing.lg, + paddingVertical: Spacing.md, + gap: Spacing.md, + }, + locationOptionSelected: { + backgroundColor: AppColors.primaryLighter, + }, + locationOptionIcon: { + fontSize: 24, + width: 32, + textAlign: 'center', + }, + locationOptionText: { + flex: 1, + fontSize: FontSizes.base, + color: AppColors.textPrimary, + }, + locationOptionTextSelected: { + fontWeight: FontWeights.semibold, + color: AppColors.primary, + }, + locationSeparator: { + height: 1, + backgroundColor: AppColors.border, + marginLeft: Spacing.lg + 32 + Spacing.md, + }, });