import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, ActivityIndicator, RefreshControl, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useLocalSearchParams } from 'expo-router'; import { useBeneficiary } from '@/contexts/BeneficiaryContext'; import { api } from '@/services/api'; import { AppColors, BorderRadius, FontSizes, FontWeights, Spacing, Shadows, } from '@/constants/theme'; interface Device { id: string; name: string; type: 'motion' | 'door' | 'temperature' | 'hub'; status: 'online' | 'offline'; lastSeen?: string; room?: string; } const deviceTypeConfig = { motion: { icon: 'body-outline' as const, label: 'Motion Sensor', color: AppColors.primary, bgColor: AppColors.primaryLighter, }, door: { icon: 'enter-outline' as const, label: 'Door Sensor', color: AppColors.info, bgColor: AppColors.infoLight, }, temperature: { icon: 'thermometer-outline' as const, label: 'Temperature', color: AppColors.warning, bgColor: AppColors.warningLight, }, hub: { icon: 'git-network-outline' as const, label: 'Hub', color: AppColors.accent, bgColor: AppColors.accentLight, }, }; export default function EquipmentScreen() { const { id } = useLocalSearchParams<{ id: string }>(); const { currentBeneficiary } = useBeneficiary(); const [devices, setDevices] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false); const [isDetaching, setIsDetaching] = useState(null); const beneficiaryName = currentBeneficiary?.name || 'this person'; useEffect(() => { loadDevices(); }, [id]); const loadDevices = async () => { if (!id) return; try { // For now, mock data - replace with actual API call // const response = await api.getDevices(id); // Mock devices for demonstration const mockDevices: Device[] = [ { id: '1', name: 'Living Room Motion', type: 'motion', status: 'online', lastSeen: '2 min ago', room: 'Living Room', }, { id: '2', name: 'Front Door', type: 'door', status: 'online', lastSeen: '5 min ago', room: 'Entrance', }, { id: '3', name: 'Bedroom Motion', type: 'motion', status: 'offline', lastSeen: '2 hours ago', room: 'Bedroom', }, { id: '4', name: 'Temperature Monitor', type: 'temperature', status: 'online', lastSeen: '1 min ago', room: 'Kitchen', }, { id: '5', name: 'WellNuo Hub', type: 'hub', status: 'online', lastSeen: 'Just now', }, ]; setDevices(mockDevices); } catch (error) { console.error('Failed to load devices:', error); Alert.alert('Error', 'Failed to load devices'); } finally { setIsLoading(false); setIsRefreshing(false); } }; const handleRefresh = useCallback(() => { setIsRefreshing(true); loadDevices(); }, [id]); const handleDetachDevice = (device: Device) => { Alert.alert( 'Detach Device', `Are you sure you want to detach "${device.name}" from ${beneficiaryName}?\n\nThe device will become available for use with another person.`, [ { text: 'Cancel', style: 'cancel' }, { text: 'Detach', style: 'destructive', onPress: async () => { setIsDetaching(device.id); try { // API call to detach device // await api.detachDevice(id, device.id); // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1000)); // Remove from local state setDevices(prev => prev.filter(d => d.id !== device.id)); Alert.alert('Success', `${device.name} has been detached.`); } catch (error) { Alert.alert('Error', 'Failed to detach device. Please try again.'); } finally { setIsDetaching(null); } }, }, ] ); }; const handleDetachAll = () => { if (devices.length === 0) { Alert.alert('No Devices', 'There are no devices to detach.'); return; } Alert.alert( 'Detach All Devices', `Are you sure you want to detach all ${devices.length} devices from ${beneficiaryName}?\n\nThis action cannot be undone.`, [ { text: 'Cancel', style: 'cancel' }, { text: 'Detach All', style: 'destructive', onPress: async () => { setIsLoading(true); try { // API call to detach all devices // await api.detachAllDevices(id); // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1500)); setDevices([]); Alert.alert('Success', 'All devices have been detached.'); } catch (error) { Alert.alert('Error', 'Failed to detach devices. Please try again.'); } finally { setIsLoading(false); } }, }, ] ); }; const handleAddDevice = () => { router.push({ pathname: '/(auth)/activate', params: { lovedOneName: beneficiaryName, beneficiaryId: id }, }); }; if (isLoading) { return ( router.back()}> Equipment Loading devices... ); } return ( {/* Header */} router.back()}> Equipment } > {/* Summary Card */} {devices.length} Total Devices {devices.filter(d => d.status === 'online').length} Online {devices.filter(d => d.status === 'offline').length} Offline {/* Devices List */} {devices.length === 0 ? ( No Devices Connected Add sensors to start monitoring {beneficiaryName}'s wellness. Add Device ) : ( <> Connected Devices {devices.map((device) => { const config = deviceTypeConfig[device.type]; const isDetachingThis = isDetaching === device.id; return ( {device.name} {device.status === 'online' ? 'Online' : 'Offline'} {device.room && ( <> {device.room} )} handleDetachDevice(device)} disabled={isDetachingThis} > {isDetachingThis ? ( ) : ( )} ); })} {/* Detach All Button */} {devices.length > 1 && ( Detach All Devices )} )} {/* Info Section */} About Equipment Detaching a device will remove it from {beneficiaryName}'s monitoring setup. You can then attach it to another person or re-attach it later using the activation code. ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: AppColors.background, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: Spacing.md, paddingVertical: Spacing.sm, borderBottomWidth: 1, borderBottomColor: AppColors.border, }, backButton: { padding: Spacing.xs, }, headerTitle: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, placeholder: { width: 32, }, addButton: { width: 40, height: 40, borderRadius: BorderRadius.md, backgroundColor: AppColors.primaryLighter, justifyContent: 'center', alignItems: 'center', }, content: { flex: 1, }, scrollContent: { padding: Spacing.lg, paddingBottom: Spacing.xxl, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', gap: Spacing.md, }, loadingText: { fontSize: FontSizes.base, color: AppColors.textSecondary, }, // Summary Card summaryCard: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, padding: Spacing.lg, marginBottom: Spacing.lg, ...Shadows.sm, }, summaryRow: { flexDirection: 'row', alignItems: 'center', }, summaryItem: { flex: 1, alignItems: 'center', }, summaryValue: { fontSize: FontSizes['2xl'], fontWeight: FontWeights.bold, color: AppColors.textPrimary, }, summaryLabel: { fontSize: FontSizes.xs, color: AppColors.textMuted, marginTop: 2, }, summaryDivider: { width: 1, height: 32, backgroundColor: AppColors.border, }, // Section Title sectionTitle: { fontSize: FontSizes.sm, fontWeight: FontWeights.semibold, color: AppColors.textSecondary, marginBottom: Spacing.md, textTransform: 'uppercase', letterSpacing: 0.5, }, // Devices List devicesList: { gap: Spacing.md, }, deviceCard: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.lg, padding: Spacing.md, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', ...Shadows.xs, }, deviceInfo: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: Spacing.md, }, deviceIcon: { width: 48, height: 48, borderRadius: BorderRadius.lg, justifyContent: 'center', alignItems: 'center', }, deviceDetails: { flex: 1, }, deviceName: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, deviceMeta: { flexDirection: 'row', alignItems: 'center', marginTop: 2, gap: 4, }, statusDot: { width: 6, height: 6, borderRadius: 3, }, deviceStatus: { fontSize: FontSizes.xs, color: AppColors.textSecondary, }, deviceMetaSeparator: { fontSize: FontSizes.xs, color: AppColors.textMuted, }, deviceRoom: { fontSize: FontSizes.xs, color: AppColors.textMuted, }, detachButton: { width: 40, height: 40, borderRadius: BorderRadius.md, backgroundColor: AppColors.errorLight, justifyContent: 'center', alignItems: 'center', }, // Empty State emptyState: { alignItems: 'center', padding: Spacing.xl, backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, ...Shadows.sm, }, emptyIconContainer: { width: 80, height: 80, borderRadius: 40, backgroundColor: AppColors.surfaceSecondary, justifyContent: 'center', alignItems: 'center', marginBottom: Spacing.md, }, emptyTitle: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, marginBottom: Spacing.xs, }, emptyText: { fontSize: FontSizes.sm, color: AppColors.textMuted, textAlign: 'center', marginBottom: Spacing.lg, }, addDeviceButton: { flexDirection: 'row', alignItems: 'center', backgroundColor: AppColors.primary, paddingVertical: Spacing.sm, paddingHorizontal: Spacing.lg, borderRadius: BorderRadius.lg, gap: Spacing.xs, }, addDeviceButtonText: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.white, }, // Detach All Button detachAllButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: AppColors.errorLight, paddingVertical: Spacing.md, borderRadius: BorderRadius.lg, marginTop: Spacing.lg, gap: Spacing.sm, }, detachAllText: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.error, }, // Info Card infoCard: { backgroundColor: AppColors.infoLight, borderRadius: BorderRadius.lg, padding: Spacing.md, marginTop: Spacing.xl, }, infoHeader: { flexDirection: 'row', alignItems: 'center', gap: Spacing.sm, marginBottom: Spacing.xs, }, infoTitle: { fontSize: FontSizes.sm, fontWeight: FontWeights.semibold, color: AppColors.info, }, infoText: { fontSize: FontSizes.sm, color: AppColors.info, lineHeight: 20, }, });