WellNuo/components/SetupProgressIndicator.tsx
Sergei dad084c775 Add setup progress indicator to onboarding flow
Add SetupProgressIndicator component that shows users their current
position in the 4-step onboarding journey: Name → Beneficiary →
Equipment → Connect. The indicator displays:
- Visual progress bar with percentage fill
- Step circles with icons showing completed/current/pending status
- Current step label with "Step X of 4" text

Integrate the indicator into all four auth screens:
- enter-name.tsx (Step 1)
- add-loved-one.tsx (Step 2)
- purchase.tsx (Step 3)
- activate.tsx (Step 4)

Also add @expo/vector-icons mock to jest.setup.js for testing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-31 17:14:44 -08:00

192 lines
5.1 KiB
TypeScript

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import {
AppColors,
BorderRadius,
FontSizes,
FontWeights,
Spacing,
} from '@/constants/theme';
export type SetupStep = 'name' | 'beneficiary' | 'purchase' | 'activate';
interface SetupProgressIndicatorProps {
currentStep: SetupStep;
variant?: 'default' | 'compact';
}
interface StepConfig {
key: SetupStep;
label: string;
shortLabel: string;
icon: keyof typeof Ionicons.glyphMap;
}
const STEPS: StepConfig[] = [
{ key: 'name', label: 'Your Name', shortLabel: 'Name', icon: 'person-outline' },
{ key: 'beneficiary', label: 'Add Loved One', shortLabel: 'Person', icon: 'heart-outline' },
{ key: 'purchase', label: 'Get Equipment', shortLabel: 'Equipment', icon: 'hardware-chip-outline' },
{ key: 'activate', label: 'Connect', shortLabel: 'Connect', icon: 'wifi-outline' },
];
function getStepIndex(step: SetupStep): number {
return STEPS.findIndex((s) => s.key === step);
}
export function SetupProgressIndicator({
currentStep,
variant = 'default',
}: SetupProgressIndicatorProps) {
const currentIndex = getStepIndex(currentStep);
const isCompact = variant === 'compact';
return (
<View style={styles.container}>
{/* Progress bar */}
<View style={styles.progressBarContainer}>
<View style={styles.progressBarTrack}>
<View
style={[
styles.progressBarFill,
{ width: `${((currentIndex + 1) / STEPS.length) * 100}%` },
]}
/>
</View>
</View>
{/* Step indicators */}
<View style={styles.stepsContainer}>
{STEPS.map((step, index) => {
const isCompleted = index < currentIndex;
const isCurrent = index === currentIndex;
const isPending = index > currentIndex;
return (
<View key={step.key} style={styles.stepWrapper}>
{/* Step circle */}
<View
style={[
styles.stepCircle,
isCompleted && styles.stepCircleCompleted,
isCurrent && styles.stepCircleCurrent,
isPending && styles.stepCirclePending,
]}
>
{isCompleted ? (
<Ionicons
name="checkmark"
size={isCompact ? 12 : 14}
color={AppColors.white}
/>
) : (
<Ionicons
name={step.icon}
size={isCompact ? 12 : 14}
color={isCurrent ? AppColors.white : AppColors.textMuted}
/>
)}
</View>
{/* Step label */}
{!isCompact && (
<Text
style={[
styles.stepLabel,
isCompleted && styles.stepLabelCompleted,
isCurrent && styles.stepLabelCurrent,
isPending && styles.stepLabelPending,
]}
numberOfLines={1}
>
{step.shortLabel}
</Text>
)}
</View>
);
})}
</View>
{/* Current step text */}
<Text style={styles.currentStepText}>
Step {currentIndex + 1} of {STEPS.length}: {STEPS[currentIndex].label}
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: Spacing.md,
paddingVertical: Spacing.md,
backgroundColor: AppColors.surface,
borderRadius: BorderRadius.lg,
marginBottom: Spacing.lg,
},
progressBarContainer: {
marginBottom: Spacing.md,
},
progressBarTrack: {
height: 4,
backgroundColor: AppColors.borderLight,
borderRadius: BorderRadius.full,
overflow: 'hidden',
},
progressBarFill: {
height: '100%',
backgroundColor: AppColors.primary,
borderRadius: BorderRadius.full,
},
stepsContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: Spacing.sm,
},
stepWrapper: {
alignItems: 'center',
flex: 1,
},
stepCircle: {
width: 28,
height: 28,
borderRadius: 14,
alignItems: 'center',
justifyContent: 'center',
marginBottom: Spacing.xs,
},
stepCircleCompleted: {
backgroundColor: AppColors.success,
},
stepCircleCurrent: {
backgroundColor: AppColors.primary,
},
stepCirclePending: {
backgroundColor: AppColors.backgroundSecondary,
borderWidth: 1,
borderColor: AppColors.border,
},
stepLabel: {
fontSize: FontSizes.xs,
textAlign: 'center',
},
stepLabelCompleted: {
color: AppColors.success,
fontWeight: FontWeights.medium,
},
stepLabelCurrent: {
color: AppColors.primary,
fontWeight: FontWeights.semibold,
},
stepLabelPending: {
color: AppColors.textMuted,
},
currentStepText: {
fontSize: FontSizes.sm,
color: AppColors.textSecondary,
textAlign: 'center',
fontWeight: FontWeights.medium,
},
});
export default SetupProgressIndicator;