import React from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import type { SensorSetupState, SensorSetupStep } from '@/types'; import { AppColors, BorderRadius, FontSizes, FontWeights, Spacing, Shadows, } from '@/constants/theme'; interface BatchSetupProgressProps { sensors: SensorSetupState[]; currentIndex: number; ssid: string; isPaused: boolean; onRetry?: (deviceId: string) => void; onSkip?: (deviceId: string) => void; onCancelAll?: () => void; } const STEP_LABELS: Record = { connect: 'Connecting', unlock: 'Unlocking', wifi: 'Setting WiFi', attach: 'Registering', reboot: 'Rebooting', }; function StepIndicator({ step }: { step: SensorSetupStep }) { const getIcon = () => { switch (step.status) { case 'completed': return ; case 'in_progress': return ; case 'failed': return ; default: return ; } }; const getTextColor = () => { switch (step.status) { case 'completed': return AppColors.success; case 'in_progress': return AppColors.primary; case 'failed': return AppColors.error; default: return AppColors.textMuted; } }; return ( {getIcon()} {STEP_LABELS[step.name]} {step.error && ( {step.error} )} ); } function SensorCard({ sensor, isActive, onRetry, onSkip, }: { sensor: SensorSetupState; isActive: boolean; onRetry?: () => void; onSkip?: () => void; }) { const getStatusColor = () => { switch (sensor.status) { case 'success': return AppColors.success; case 'error': return AppColors.error; case 'skipped': return AppColors.warning; case 'pending': return AppColors.textMuted; default: return AppColors.primary; } }; const getStatusIcon = () => { switch (sensor.status) { case 'success': return ; case 'error': return ; case 'skipped': return ; case 'pending': return ; default: return ; } }; const showActions = sensor.status === 'error' && onRetry && onSkip; return ( {sensor.deviceName} {sensor.wellId && ( Well ID: {sensor.wellId} )} {getStatusIcon()} {/* Show steps for active or completed sensors */} {(isActive || sensor.status === 'success' || sensor.status === 'error') && ( {sensor.steps.map((step, index) => ( ))} )} {/* Error message */} {sensor.error && ( {sensor.error} )} {/* Action buttons for failed sensors */} {showActions && ( Retry Skip )} ); } export default function BatchSetupProgress({ sensors, currentIndex, ssid, isPaused, onRetry, onSkip, onCancelAll, }: BatchSetupProgressProps) { const completedCount = sensors.filter(s => s.status === 'success').length; const failedCount = sensors.filter(s => s.status === 'error').length; const skippedCount = sensors.filter(s => s.status === 'skipped').length; const totalProcessed = completedCount + failedCount + skippedCount; const progress = (totalProcessed / sensors.length) * 100; return ( {/* Progress Header */} Connecting sensors to "{ssid}"... {totalProcessed} of {sensors.length} complete {/* Progress bar */} {/* Sensors List */} {sensors.map((sensor, index) => ( onRetry(sensor.deviceId) : undefined} onSkip={onSkip ? () => onSkip(sensor.deviceId) : undefined} /> ))} {/* Cancel button */} {onCancelAll && ( Cancel Setup )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, progressHeader: { marginBottom: Spacing.lg, }, progressTitle: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, marginBottom: Spacing.xs, }, progressSubtitle: { fontSize: FontSizes.sm, color: AppColors.textSecondary, marginBottom: Spacing.md, }, progressBarContainer: { height: 4, backgroundColor: AppColors.border, borderRadius: 2, overflow: 'hidden', }, progressBar: { height: '100%', backgroundColor: AppColors.primary, borderRadius: 2, }, sensorsList: { flex: 1, }, sensorsListContent: { gap: Spacing.md, paddingBottom: Spacing.lg, }, sensorCard: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.lg, padding: Spacing.md, ...Shadows.xs, }, sensorCardActive: { borderWidth: 2, borderColor: AppColors.primary, }, sensorHeader: { flexDirection: 'row', alignItems: 'center', }, sensorIcon: { width: 40, height: 40, borderRadius: BorderRadius.md, backgroundColor: AppColors.primaryLighter, justifyContent: 'center', alignItems: 'center', marginRight: Spacing.sm, }, sensorInfo: { flex: 1, }, sensorName: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, sensorMeta: { fontSize: FontSizes.xs, color: AppColors.textMuted, }, statusIcon: { marginLeft: Spacing.sm, }, stepsContainer: { marginTop: Spacing.md, paddingTop: Spacing.sm, borderTopWidth: 1, borderTopColor: AppColors.border, gap: Spacing.xs, }, stepRow: { flexDirection: 'row', alignItems: 'center', gap: Spacing.sm, }, stepIcon: { width: 16, height: 16, justifyContent: 'center', alignItems: 'center', }, pendingDot: { width: 6, height: 6, borderRadius: 3, backgroundColor: AppColors.textMuted, }, stepLabel: { fontSize: FontSizes.sm, fontWeight: FontWeights.medium, }, stepError: { fontSize: FontSizes.xs, color: AppColors.error, flex: 1, }, errorContainer: { flexDirection: 'row', alignItems: 'center', marginTop: Spacing.sm, padding: Spacing.sm, backgroundColor: AppColors.errorLight, borderRadius: BorderRadius.sm, gap: Spacing.xs, }, errorText: { fontSize: FontSizes.xs, color: AppColors.error, flex: 1, }, actionButtons: { flexDirection: 'row', marginTop: Spacing.md, gap: Spacing.md, }, retryButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: Spacing.xs, paddingHorizontal: Spacing.md, backgroundColor: AppColors.primaryLighter, borderRadius: BorderRadius.md, gap: Spacing.xs, }, retryText: { fontSize: FontSizes.sm, fontWeight: FontWeights.medium, color: AppColors.primary, }, skipButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: Spacing.xs, paddingHorizontal: Spacing.md, backgroundColor: AppColors.surfaceSecondary, borderRadius: BorderRadius.md, gap: Spacing.xs, }, skipText: { fontSize: FontSizes.sm, fontWeight: FontWeights.medium, color: AppColors.textMuted, }, cancelAllButton: { alignItems: 'center', paddingVertical: Spacing.sm, marginTop: Spacing.md, }, cancelAllText: { fontSize: FontSizes.sm, fontWeight: FontWeights.medium, color: AppColors.error, }, });