← back to kjb135-coe__trackr-health

Function bodies 89 total

All specs Real LLM only Function bodies
ForgotPasswordScreen function · typescript · L21-L144 (124 LOC)
app/auth/forgot-password.tsx
export default function ForgotPasswordScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const [email, setEmail] = useState('');
  const [sent, setSent] = useState(false);

  const { sendPasswordReset, isLoading } = useAuthStore();

  const handleReset = async () => {
    if (!email.trim()) {
      Alert.alert('Error', 'Please enter your email address');
      return;
    }

    try {
      await sendPasswordReset(email.trim());
      setSent(true);
    } catch (err: unknown) {
      Alert.alert('Error', getAuthErrorMessage(err));
    }
  };

  if (sent) {
    return (
      <View style={styles.container}>
        <View style={styles.content}>
          <Animated.Text
            entering={FadeInDown.duration(ANIMATION_DURATION.screenEntrance).delay(
              STAGGER_DELAY.initialOffset,
            )}
            style={styles.title}
          >
            Check Your Email
          </Animated.Text>
          <Anima
LoginScreen function · typescript · L20-L156 (137 LOC)
app/auth/login.tsx
export default function LoginScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const { signIn, signInWithGoogle, isLoading } = useAuthStore();
  const { request, response, promptAsync } = useGoogleAuth();

  useEffect(() => {
    if (response && 'type' in response && response.type === 'success' && 'params' in response) {
      const idToken =
        typeof response.params?.['id_token'] === 'string' ? response.params['id_token'] : null;
      if (idToken) {
        signInWithGoogle(idToken).catch((err: unknown) => {
          Alert.alert('Error', getAuthErrorMessage(err));
        });
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [response]);

  const handleLogin = async () => {
    if (!email.trim() || !password) {
      Alert.alert('Error', 'Please enter both email and password');
      return;
   
SignUpScreen function · typescript · L21-L166 (146 LOC)
app/auth/signup.tsx
export default function SignUpScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');

  const { signUp, isLoading } = useAuthStore();

  const handleSignUp = async () => {
    if (!name.trim()) {
      Alert.alert('Error', 'Please enter your name');
      return;
    }
    if (!email.trim()) {
      Alert.alert('Error', 'Please enter your email');
      return;
    }
    if (!password) {
      Alert.alert('Error', 'Please enter a password');
      return;
    }
    if (password.length < 6) {
      Alert.alert('Error', 'Password must be at least 6 characters');
      return;
    }
    if (password !== confirmPassword) {
      Alert.alert('Error', 'Passwords do not match');
      return;
    }

    try {
      await signUp(email.trim(), passw
VerifyEmailScreen function · typescript · L12-L133 (122 LOC)
app/auth/verify-email.tsx
export default function VerifyEmailScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const [checking, setChecking] = useState(false);

  const { user, sendVerificationEmail, reloadUser, signOut, isLoading } = useAuthStore();

  useEffect(() => {
    const interval = setInterval(async () => {
      await reloadUser();
    }, EMAIL_VERIFICATION_POLL_MS);

    return () => clearInterval(interval);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (user?.emailVerified) {
      router.replace('/(tabs)');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user?.emailVerified]);

  const handleResend = async () => {
    try {
      await sendVerificationEmail();
      Alert.alert('Email Sent', 'A new verification email has been sent.');
    } catch {
      Alert.alert('Error', 'Could not send verification email. Please try again later.');
    }
  };

  const ha
LogExerciseScreen function · typescript · L103-L292 (190 LOC)
app/exercise/log.tsx
export default function LogExerciseScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const { createSession } = useExerciseStore();

  const [selectedType, setSelectedType] = useState<ExerciseType | null>(null);
  const [duration, setDuration] = useState(30);
  const [intensity, setIntensity] = useState(3);
  const [notes, setNotes] = useState('');
  const [saving, setSaving] = useState(false);

  const calories = estimateCalories(selectedType || 'other', duration, intensity);

  const handleSave = async () => {
    if (!selectedType) {
      Alert.alert('Error', 'Please select an exercise type');
      return;
    }

    setSaving(true);
    try {
      await createSession({
        date: getDateString(),
        type: selectedType,
        durationMinutes: duration,
        intensity: INTENSITY_MAP[intensity],
        caloriesBurned: calories,
        notes: notes.trim() || undefined,
        distance: undefined,
      });
      Haptics.notificationAsync(Hapt
Root function · typescript · L7-L28 (22 LOC)
app/+html.tsx
export default function Root({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />

        {/* 
          Disable body scrolling on web. This makes ScrollView components work closer to how they do on native. 
          However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
        */}
        <ScrollViewStyleReset />

        {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
        <style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
        {/* Add any additional <head> elements that you want globally available on web... */}
      </head>
      <body>{children}</body>
    </html>
  );
}
NewJournalEntryScreen function · typescript · L92-L266 (175 LOC)
app/journal/new.tsx
export default function NewJournalEntryScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const { createEntry } = useJournalStore();

  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');
  const [mood, setMood] = useState(3);
  const [selectedTags, setSelectedTags] = useState<string[]>([]);
  const [saving, setSaving] = useState(false);

  const MOOD_OPTIONS = [
    { value: 1, label: 'Terrible', Icon: Frown, color: colors.error },
    { value: 2, label: 'Bad', Icon: Frown, color: colors.warning },
    { value: 3, label: 'Okay', Icon: Meh, color: colors.textTertiary },
    { value: 4, label: 'Good', Icon: Smile, color: colors.info },
    { value: 5, label: 'Great', Icon: Smile, color: colors.success },
  ];

  const toggleTag = (tag: string) => {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    setSelectedTags((prev) =>
      prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag],
    );
  };

  con
About: code-quality intelligence by Repobility · https://repobility.com
RootLayout function · typescript · L55-L99 (45 LOC)
app/_layout.tsx
export default function RootLayout() {
  const [loaded, error] = useFonts({
    SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
    ...FontAwesome.font,
  });

  const { initialize, isInitialized } = useAuthStore();
  const { hasCompleted: hasCompletedOnboarding, initialize: initOnboarding } = useOnboardingStore();

  useEffect(() => {
    // Initialize database
    getDatabase();

    // Initialize auth listener
    const unsubscribe = initialize();

    // Initialize onboarding state
    initOnboarding();

    return unsubscribe;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (error) throw error;
  }, [error]);

  useEffect(() => {
    if (loaded && isInitialized && hasCompletedOnboarding !== null) {
      SplashScreen.hideAsync();
    }
  }, [loaded, isInitialized, hasCompletedOnboarding]);

  if (!loaded || !isInitialized || hasCompletedOnboarding === null) {
    return null;
  }

  return (
    <AppErrorBoundary>
    
RootLayoutNav function · typescript · L101-L280 (180 LOC)
app/_layout.tsx
function RootLayoutNav() {
  const { isDark, colors } = useTheme();
  const { user } = useAuthStore();
  const { hasCompleted: hasCompletedOnboarding } = useOnboardingStore();
  const segments = useSegments();
  const router = useRouter();
  const isNavigating = useRef(false);

  useEffect(() => {
    if (hasCompletedOnboarding === null) return;
    if (isNavigating.current) return;

    const inAuthGroup = segments[0] === 'auth';
    const inOnboarding = segments[0] === 'onboarding';

    let shouldNavigate = false;

    // First time user - show onboarding
    if (!hasCompletedOnboarding && !inOnboarding) {
      isNavigating.current = true;
      router.replace('/onboarding');
      shouldNavigate = true;
    } else if (!user && !inAuthGroup && !inOnboarding) {
      // User is not signed in, redirect to login
      // For now, let's allow unauthenticated access but show login option
      // router.replace('/auth/login');
    } else if (user && !user.emailVerified && !inAuthGroup) 
NotFoundScreen function · typescript · L5-L22 (18 LOC)
app/+not-found.tsx
export default function NotFoundScreen() {
  const { colors } = useTheme();

  return (
    <>
      <Stack.Screen options={{ title: 'Oops!' }} />
      <View style={[styles.container, { backgroundColor: colors.background }]}>
        <Text style={[styles.title, { color: colors.textPrimary }]}>
          {"This screen doesn't exist."}
        </Text>

        <Link href="/" style={styles.link}>
          <Text style={[styles.linkText, { color: colors.primary }]}>Go to home screen!</Text>
        </Link>
      </View>
    </>
  );
}
OnboardingScreen function · typescript · L20-L177 (158 LOC)
app/onboarding.tsx
export default function OnboardingScreen() {
  const router = useRouter();
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const [currentIndex, setCurrentIndex] = useState(0);
  const scrollX = useRef(new Animated.Value(0)).current;
  const flatListRef = useRef<FlatList>(null);
  const { setCompleted } = useOnboardingStore();

  const slides = useMemo(
    () => [
      {
        id: '1',
        title: 'Track Your Habits',
        description:
          'Build positive routines with streak tracking and daily reminders. Never miss a day again.',
        Icon: Target,
        color: colors.primary,
      },
      {
        id: '2',
        title: 'Sleep Better',
        description:
          'Log your sleep patterns and discover insights to improve your rest and energy levels.',
        Icon: Moon,
        color: colors.sleep,
      },
      {
        id: '3',
        title: 'Stay Active',
        description: 'Track workouts, monitor your progress, and reach 
SettingRow function · typescript · L64-L120 (57 LOC)
app/settings.tsx
function SettingRow({
  icon,
  iconBg,
  title,
  subtitle,
  onPress,
  rightElement,
  showChevron = true,
  danger = false,
}: SettingRowProps) {
  const { colors } = useTheme();
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = () => {
    if (onPress) {
      scale.value = withSpring(SCALE.settingRow, SPRING_CONFIG.pressIn);
    }
  };

  const handlePressOut = () => {
    scale.value = withSpring(1, SPRING_CONFIG.pressOut);
  };

  return (
    <Pressable
      onPress={() => {
        if (onPress) {
          Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
          onPress();
        }
      }}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      disabled={!onPress && !rightElement}
    >
      <Animated.View style={[styles.settingRow, animatedStyle]}>
        <View style={[styles.iconContainer, { backgroundColor: iconBg }]}>{icon}</View>
    
ThemePicker function · typescript · L122-L165 (44 LOC)
app/settings.tsx
function ThemePicker() {
  const { colors, mode, setMode } = useTheme();

  const options: { value: ThemeMode; label: string; icon: typeof Sun }[] = [
    { value: 'light', label: 'Light', icon: Sun },
    { value: 'dark', label: 'Dark', icon: Moon },
    { value: 'system', label: 'Auto', icon: Smartphone },
  ];

  return (
    <View style={styles.themePicker}>
      {options.map((option) => {
        const isSelected = mode === option.value;
        const Icon = option.icon;
        return (
          <Pressable
            key={option.value}
            onPress={() => {
              Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
              setMode(option.value);
            }}
            style={[
              styles.themeOption,
              {
                backgroundColor: isSelected ? colors.primary : colors.surfaceSecondary,
                borderColor: isSelected ? colors.primary : colors.border,
              },
            ]}
          >
            <Icon siz
LogSleepScreen function · typescript · L78-L257 (180 LOC)
app/sleep/log.tsx
export default function LogSleepScreen() {
  const router = useRouter();
  const { colors, isDark } = useTheme();
  const { createEntry } = useSleepStore();

  const [bedtime, setBedtime] = useState(new Date(new Date().setHours(22, 0, 0, 0)));
  const [wakeTime, setWakeTime] = useState(new Date(new Date().setHours(7, 0, 0, 0)));
  const [quality, setQuality] = useState(3);
  const [notes, setNotes] = useState('');
  const [selectedFactors, setSelectedFactors] = useState<string[]>([]);
  const [saving, setSaving] = useState(false);

  const calculateDuration = () => {
    let diff = wakeTime.getTime() - bedtime.getTime();
    if (diff < 0) diff += 24 * 60 * 60 * 1000;
    return Math.round(diff / 60000);
  };

  const formatDuration = (minutes: number) => {
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;
    return `${hours}h ${mins}m`;
  };

  const toggleFactor = (factor: string) => {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    setSelecte
DashboardCard function · typescript · L43-L77 (35 LOC)
app/(tabs)/index.tsx
function DashboardCard({
  title,
  value,
  subtitle,
  color,
  Icon,
  onPress,
  progress,
  delay = 0,
}: DashboardCardProps) {
  const { colors } = useTheme();

  return (
    <AnimatedCard style={styles.card} onPress={onPress} delay={delay} haptic>
      <View style={[styles.iconContainer, { backgroundColor: color + '20' }]}>
        <Icon color={color} size={24} />
      </View>
      <Text style={[styles.cardTitle, { color: colors.textSecondary }]}>{title}</Text>
      <Text style={[styles.cardValue, { color: colors.textPrimary }]}>{value}</Text>
      {subtitle && (
        <Text style={[styles.cardSubtext, { color: colors.textTertiary }]}>{subtitle}</Text>
      )}
      {progress !== undefined && (
        <View style={[styles.progressBar, { backgroundColor: colors.surfaceSecondary }]}>
          <Animated.View
            style={[
              styles.progressFill,
              { backgroundColor: color, width: `${Math.min(progress * 100, 100)}%` },
            ]}
        
Repobility · open methodology · https://repobility.com/research/
SettingsButton function · typescript · L19-L53 (35 LOC)
app/(tabs)/_layout.tsx
function SettingsButton() {
  const router = useRouter();
  const { colors } = useTheme();
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = () => {
    scale.value = withSpring(SCALE.quickActionPressIn, SPRING_CONFIG.pressIn);
  };

  const handlePressOut = () => {
    scale.value = withSpring(1, SPRING_CONFIG.pressOut);
  };

  const handlePress = () => {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    router.push('/settings');
  };

  return (
    <TouchableOpacity
      onPress={handlePress}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      style={{ marginRight: spacing.md }}
    >
      <Animated.View style={animatedStyle}>
        <Settings color={colors.textSecondary} size={24} />
      </Animated.View>
    </TouchableOpacity>
  );
}
AnimatedTabIcon function · typescript · L62-L81 (20 LOC)
app/(tabs)/_layout.tsx
function AnimatedTabIcon({ color, size, focused, Icon }: TabIconProps) {
  const scale = useSharedValue(focused ? SCALE.tabIconFocused : SCALE.tabIconUnfocused);

  React.useEffect(() => {
    scale.value = withSpring(
      focused ? SCALE.tabIconFocused : SCALE.tabIconUnfocused,
      SPRING_CONFIG.tabIcon,
    );
  }, [focused, scale]);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  return (
    <Animated.View style={animatedStyle}>
      <Icon color={color} size={size} strokeWidth={focused ? 2.5 : 2} />
    </Animated.View>
  );
}
TabLayout function · typescript · L83-L184 (102 LOC)
app/(tabs)/_layout.tsx
export default function TabLayout() {
  const { colors, isDark } = useTheme();

  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: colors.primary,
        tabBarInactiveTintColor: colors.textTertiary,
        tabBarStyle: {
          backgroundColor: isDark ? colors.surface : colors.surface,
          borderTopColor: colors.border,
          borderTopWidth: 0.5,
          height: Platform.OS === 'ios' ? 88 : 70,
          paddingBottom: Platform.OS === 'ios' ? 28 : 10,
          paddingTop: 10,
          position: 'absolute',
          elevation: 0,
          shadowColor: colors.black,
          shadowOffset: { width: 0, height: -2 },
          shadowOpacity: isDark ? 0.2 : 0.05,
          shadowRadius: 8,
        },
        tabBarLabelStyle: {
          fontSize: 11,
          fontWeight: '500',
          marginTop: 2,
        },
        headerStyle: {
          backgroundColor: colors.surface,
          elevation: 0,
          shadowOpacity: 0,
          borde
AICoaching function · typescript · L27-L222 (196 LOC)
src/components/dashboard/AICoaching.tsx
export function AICoaching({ onSetupApiKey }: AICoachingProps) {
  const { colors } = useTheme();
  const hasKey = useApiKeyExists();

  const { dailyCoaching, isLoadingCoaching, error, fetchDailyCoaching } = useAIInsightsStore();

  useEffect(() => {
    if (hasKey) {
      fetchDailyCoaching();
    }
  }, [hasKey, fetchDailyCoaching]);

  const handleRefresh = async () => {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    // Force refresh by clearing cache
    useAIInsightsStore.setState({ lastCoachingFetch: null });
    await fetchDailyCoaching();
  };

  const categoryIcons = useMemo<Record<string, React.ReactNode>>(
    () => ({
      habits: <TrendingUp color={colors.habits} size={16} />,
      sleep: <Moon color={colors.sleep} size={16} />,
      exercise: <Dumbbell color={colors.exercise} size={16} />,
      nutrition: <Apple color={colors.nutrition} size={16} />,
      journal: <BookOpen color={colors.journal} size={16} />,
    }),
    [colors],
  );

  const ca
QuickActionButton function · typescript · L25-L65 (41 LOC)
src/components/dashboard/QuickActions.tsx
function QuickActionButton({ label, Icon, color, onPress }: QuickActionButtonProps) {
  const { colors } = useTheme();
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = () => {
    scale.value = withSpring(SCALE.quickActionPressIn, SPRING_CONFIG.pressIn);
  };

  const handlePressOut = () => {
    scale.value = withSpring(1, SPRING_CONFIG.pressOut);
  };

  const handlePress = () => {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
    scale.value = withSequence(
      withSpring(SCALE.quickActionBounce, SPRING_CONFIG.pressIn),
      withSpring(1, SPRING_CONFIG.bounce),
    );
    onPress();
  };

  return (
    <AnimatedPressable
      style={[styles.actionButton, animatedStyle]}
      onPress={handlePress}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
    >
      <View style={[styles.iconContainer, { backgroundColor: color + '20' }]}>
        <
QuickActions function · typescript · L67-L114 (48 LOC)
src/components/dashboard/QuickActions.tsx
export function QuickActions() {
  const router = useRouter();
  const { colors } = useTheme();

  const actions = [
    {
      label: 'Log Sleep',
      Icon: Moon,
      color: colors.sleep,
      route: '/sleep/log',
    },
    {
      label: 'Workout',
      Icon: Dumbbell,
      color: colors.exercise,
      route: '/exercise/log',
    },
    {
      label: 'Scan Food',
      Icon: Camera,
      color: colors.nutrition,
      route: '/nutrition/camera',
    },
    {
      label: 'Journal',
      Icon: PenLine,
      color: colors.journal,
      route: '/journal/new',
    },
  ];

  return (
    <View style={styles.container}>
      <Text style={[styles.title, { color: colors.textPrimary }]}>Quick Actions</Text>
      <View style={[styles.actionsContainer, { backgroundColor: colors.surface }]}>
        {actions.map((action) => (
          <QuickActionButton
            key={action.route}
            label={action.label}
            Icon={action.Icon}
            color={action.colo
WeeklyInsights function · typescript · L22-L108 (87 LOC)
src/components/dashboard/WeeklyInsights.tsx
export function WeeklyInsights({ insights }: WeeklyInsightsProps) {
  const { colors } = useTheme();

  const getTrend = (current: number, previous: number, higherIsBetter: boolean) => {
    if (previous === 0) return { type: 'neutral', percent: 0 };
    const change = ((current - previous) / previous) * 100;

    if (Math.abs(change) < 5) return { type: 'neutral', percent: Math.round(change) };

    if (higherIsBetter) {
      return change > 0
        ? { type: 'positive', percent: Math.round(change) }
        : { type: 'negative', percent: Math.round(change) };
    } else {
      return change < 0
        ? { type: 'positive', percent: Math.round(Math.abs(change)) }
        : { type: 'negative', percent: Math.round(change) };
    }
  };

  const TrendIcon = ({ type }: { type: string }) => {
    switch (type) {
      case 'positive':
        return <TrendingUp size={14} color={colors.success} />;
      case 'negative':
        return <TrendingDown size={14} color={colors.error} />;
 
CreateHabitModal function · typescript · L32-L226 (195 LOC)
src/components/habits/CreateHabitModal.tsx
export function CreateHabitModal({ visible, onClose, editHabit }: CreateHabitModalProps) {
  const { colors } = useTheme();
  const insets = useSafeAreaInsets();
  const [newHabitName, setNewHabitName] = useState('');
  const [selectedColor, setSelectedColor] = useState(HABIT_COLORS[0]);
  const [reminderEnabled, setReminderEnabled] = useState(false);
  const [reminderHour, setReminderHour] = useState('09');
  const [reminderMinute, setReminderMinute] = useState('00');
  const [saving, setSaving] = useState(false);

  const { createHabit, updateHabit } = useHabitStore();

  React.useEffect(() => {
    if (editHabit) {
      setNewHabitName(editHabit.name);
      setSelectedColor(editHabit.color);
      if (editHabit.reminderTime) {
        setReminderEnabled(true);
        const [h, m] = editHabit.reminderTime.split(':');
        setReminderHour(h);
        setReminderMinute(m);
      } else {
        setReminderEnabled(false);
        setReminderHour('09');
        setReminderMinute('
Repobility · MCP-ready · https://repobility.com
HabitSuggestionsModal function · typescript · L28-L134 (107 LOC)
src/components/habits/HabitSuggestionsModal.tsx
export function HabitSuggestionsModal({ visible, onClose }: HabitSuggestionsModalProps) {
  const { colors } = useTheme();
  const insets = useSafeAreaInsets();
  const { createHabit } = useHabitStore();
  const { habitSuggestions, isLoadingHabits, fetchHabitSuggestions } = useAIInsightsStore();

  return (
    <Modal visible={visible} animationType="slide" transparent>
      <View style={[styles.modalOverlay, { backgroundColor: colors.overlay }]}>
        <Animated.View
          entering={FadeInDown.duration(300)}
          style={[
            styles.modalContent,
            {
              backgroundColor: colors.surface,
              paddingBottom: Math.max(spacing.xxl, insets.bottom + spacing.md),
            },
          ]}
        >
          <View style={styles.modalHeader}>
            <View style={styles.headerTitle}>
              <Sparkles color={colors.primary} size={20} />
              <Text
                style={[
                  styles.modalTitleText,
           
StreakBadge function · typescript · L11-L35 (25 LOC)
src/components/habits/StreakBadge.tsx
export function StreakBadge({ streak, size = 'md' }: StreakBadgeProps) {
  const { colors } = useTheme();
  const styles = createStyles(colors);

  const getStreakInfo = () => {
    if (streak >= 365) return { icon: Crown, color: colors.warning, label: 'Legendary' };
    if (streak >= 100) return { icon: Award, color: colors.primary, label: 'Champion' };
    if (streak >= 30) return { icon: Zap, color: colors.success, label: 'On Fire' };
    if (streak >= 7) return { icon: Flame, color: colors.error, label: 'Hot' };
    return { icon: Flame, color: colors.textTertiary, label: '' };
  };

  const { icon: Icon, color, label } = getStreakInfo();
  const iconSize = size === 'sm' ? 14 : size === 'lg' ? 24 : 18;

  if (streak === 0) return null;

  return (
    <View style={[styles.container, styles[size]]}>
      <Icon color={color} size={iconSize} fill={streak >= 7 ? color : 'none'} />
      <Text style={[styles.streakText, styles[`text_${size}`], { color }]}>{streak}</Text>
      {label &
StreakCelebration function · typescript · L26-L118 (93 LOC)
src/components/habits/StreakCelebration.tsx
export function StreakCelebration({ visible, streak, habitName, onClose }: StreakCelebrationProps) {
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const scaleValue = useSharedValue(0);
  const rotateValue = useSharedValue(0);

  useEffect(() => {
    if (visible) {
      Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
      scaleValue.value = withSpring(1, SPRING_CONFIG.celebration);
      rotateValue.value = withRepeat(
        withSequence(
          withTiming(5, { duration: 1000 }),
          withTiming(-5, { duration: 1000 }),
          withTiming(0, { duration: 1000 }),
        ),
        -1,
      );
    } else {
      scaleValue.value = 0;
      rotateValue.value = 0;
    }
  }, [visible, scaleValue, rotateValue]);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scaleValue.value }, { rotate: `${rotateValue.value}deg` }],
  }));

  const getStreakInfo = () => {
    if (streak >= 365)
      return {
    
getMoodEmoji function · typescript · L36-L51 (16 LOC)
src/components/journal/JournalEntryModal.tsx
function getMoodEmoji(mood: number): string {
  switch (mood) {
    case 1:
      return '😢';
    case 2:
      return '😕';
    case 3:
      return '😐';
    case 4:
      return '🙂';
    case 5:
      return '😄';
    default:
      return '😐';
  }
}
AnimatedButton function · typescript · L32-L182 (151 LOC)
src/components/ui/AnimatedButton.tsx
export function AnimatedButton({
  title,
  onPress,
  variant = 'primary',
  size = 'md',
  loading = false,
  disabled = false,
  icon,
  style,
  haptic = true,
  fullWidth = false,
}: AnimatedButtonProps) {
  const { colors } = useTheme();
  const scale = useSharedValue(1);
  const isDisabled = disabled || loading;

  const handlePressIn = () => {
    if (!isDisabled) {
      scale.value = withSpring(SCALE.buttonPressIn, SPRING_CONFIG.pressIn);
    }
  };

  const handlePressOut = () => {
    scale.value = withSpring(1, SPRING_CONFIG.pressOut);
  };

  const handlePress = () => {
    if (isDisabled) return;

    if (haptic) {
      Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
    }

    // Bounce animation on press
    scale.value = withSequence(
      withSpring(SCALE.buttonBounce, SPRING_CONFIG.pressIn),
      withSpring(1, SPRING_CONFIG.bounce),
    );

    onPress();
  };

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }
AnimatedCard function · typescript · L32-L134 (103 LOC)
src/components/ui/AnimatedCard.tsx
export function AnimatedCard({
  children,
  variant = 'elevated',
  padding = 'md',
  onPress,
  onLongPress,
  style,
  haptic = true,
  delay = 0,
  accessibilityLabel,
}: AnimatedCardProps) {
  const { colors, isDark } = useTheme();
  const scale = useSharedValue(1);

  const handlePressIn = () => {
    scale.value = withSpring(SCALE.cardPressIn, SPRING_CONFIG.pressIn);
  };

  const handlePressOut = () => {
    scale.value = withSpring(1, SPRING_CONFIG.pressOut);
  };

  const handlePress = () => {
    if (haptic) {
      Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    }
    onPress?.();
  };

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const paddingMap = {
    none: 0,
    sm: spacing.sm,
    md: spacing.md,
    lg: spacing.lg,
  };

  const getVariantStyle = (): ViewStyle => {
    switch (variant) {
      case 'elevated':
        return {
          backgroundColor: colors.surface,
          shadowColor: '#000',
Skeleton function · typescript · L22-L72 (51 LOC)
src/components/ui/animations/Skeleton.tsx
export function Skeleton({
  width,
  height,
  borderRadius: radius = borderRadius.md,
  style,
}: SkeletonProps) {
  const { colors, isDark } = useTheme();
  const shimmerProgress = useSharedValue(0);

  useEffect(() => {
    shimmerProgress.value = withRepeat(
      withTiming(1, { duration: 1200, easing: Easing.inOut(Easing.ease) }),
      -1,
      false,
    );
  }, [shimmerProgress]);

  const shimmerStyle = useAnimatedStyle(() => {
    const translateX = interpolate(shimmerProgress.value, [0, 1], [-200, 200]);
    return {
      transform: [{ translateX }],
    };
  });

  const baseColor = isDark ? colors.surfaceSecondary : colors.borderLight;
  const shimmerColor = colors.shimmer;

  return (
    <View
      style={[
        {
          width,
          height,
          borderRadius: radius,
          backgroundColor: baseColor,
          overflow: 'hidden',
        },
        style,
      ]}
    >
      <Animated.View style={[{ flex: 1 }, shimmerStyle]}>
        <LinearGrad
SkeletonCard function · typescript · L79-L100 (22 LOC)
src/components/ui/animations/Skeleton.tsx
export function SkeletonCard({ lines = 3, style }: SkeletonCardProps) {
  const { colors } = useTheme();

  return (
    <Animated.View
      style={[
        {
          backgroundColor: colors.surface,
          borderRadius: borderRadius.lg,
          padding: 16,
          gap: 12,
        },
        style,
      ]}
    >
      <Skeleton width="40%" height={20} />
      {Array.from({ length: lines }).map((_, i) => (
        <Skeleton key={i} width={i === lines - 1 ? '60%' : '100%'} height={16} />
      ))}
    </Animated.View>
  );
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
Button function · typescript · L19-L71 (53 LOC)
src/components/ui/Button.tsx
export function Button({
  title,
  onPress,
  variant = 'primary',
  size = 'md',
  loading = false,
  disabled = false,
  icon,
  style,
}: ButtonProps) {
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const isDisabled = disabled || loading;

  return (
    <TouchableOpacity
      onPress={onPress}
      disabled={isDisabled}
      accessibilityRole="button"
      accessibilityLabel={title}
      accessibilityState={{ disabled: isDisabled }}
      style={[
        styles.base,
        styles[variant],
        styles[`size_${size}`],
        isDisabled && styles.disabled,
        style,
      ]}
      activeOpacity={0.7}
    >
      {loading ? (
        <ActivityIndicator
          color={variant === 'primary' ? colors.white : colors.primary}
          size="small"
        />
      ) : (
        <>
          {icon}
          <Text
            style={[
              styles.text,
              styles[`text_${variant}`],
              styles[`text_${size}`],
  
Card function · typescript · L16-L37 (22 LOC)
src/components/ui/Card.tsx
export function Card({
  children,
  variant = 'elevated',
  padding = 'md',
  onPress,
  style,
}: CardProps) {
  const { colors } = useTheme();
  const styles = createStyles(colors);

  const cardStyle = [styles.base, styles[variant], styles[`padding_${padding}`], style];

  if (onPress) {
    return (
      <TouchableOpacity onPress={onPress} style={cardStyle} activeOpacity={0.7}>
        {children}
      </TouchableOpacity>
    );
  }

  return <View style={cardStyle}>{children}</View>;
}
EmptyState function · typescript · L12-L22 (11 LOC)
src/components/ui/EmptyState.tsx
export function EmptyState({ icon, title, subtitle }: EmptyStateProps) {
  const { colors } = useTheme();

  return (
    <View style={styles.container}>
      {icon}
      <Text style={[styles.title, { color: colors.textSecondary }]}>{title}</Text>
      <Text style={[styles.subtitle, { color: colors.textTertiary }]}>{subtitle}</Text>
    </View>
  );
}
ErrorBanner function · typescript · L12-L24 (13 LOC)
src/components/ui/ErrorBanner.tsx
export function ErrorBanner({ error, onDismiss }: ErrorBannerProps) {
  const { colors } = useTheme();

  return (
    <TouchableOpacity
      style={[styles.banner, { backgroundColor: colors.error + '15' }]}
      onPress={onDismiss}
    >
      <Text style={[styles.text, { color: colors.error }]}>{error}</Text>
      <X color={colors.error} size={16} />
    </TouchableOpacity>
  );
}
ErrorBoundary.render method · typescript · L40-L65 (26 LOC)
src/components/ui/ErrorBoundary.tsx
  render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      const colors = getColors();

      return (
        <View style={[styles.container, { backgroundColor: colors.background }]}>
          <Text style={[styles.title, { color: colors.textPrimary }]}>Something went wrong</Text>
          <Text style={[styles.message, { color: colors.textSecondary }]}>
            {this.state.error?.message || 'An unexpected error occurred.'}
          </Text>
          <TouchableOpacity
            style={[styles.button, { backgroundColor: colors.primary }]}
            onPress={this.handleRetry}
          >
            <Text style={[styles.buttonText, { color: colors.white }]}>Try Again</Text>
          </TouchableOpacity>
        </View>
      );
    }

    return this.props.children;
  }
FAB function · typescript · L26-L37 (12 LOC)
src/components/ui/FAB.tsx
export function FAB({ onPress, color, icon, grouped, accessibilityLabel }: FABProps) {
  return (
    <TouchableOpacity
      style={[styles.fab, !grouped && styles.positioned, { backgroundColor: color }]}
      onPress={onPress}
      accessibilityRole="button"
      accessibilityLabel={accessibilityLabel}
    >
      {icon}
    </TouchableOpacity>
  );
}
SecondaryFAB function · typescript · L39-L56 (18 LOC)
src/components/ui/FAB.tsx
export function SecondaryFAB({
  onPress,
  backgroundColor,
  borderColor,
  icon,
  accessibilityLabel,
}: SecondaryFABProps) {
  return (
    <TouchableOpacity
      style={[styles.fab, styles.secondary, { backgroundColor, borderColor }]}
      onPress={onPress}
      accessibilityRole="button"
      accessibilityLabel={accessibilityLabel}
    >
      {icon}
    </TouchableOpacity>
  );
}
Input function · typescript · L11-L27 (17 LOC)
src/components/ui/Input.tsx
export function Input({ label, error, containerStyle, style, ...props }: InputProps) {
  const { colors } = useTheme();
  const styles = createStyles(colors);

  return (
    <View style={containerStyle}>
      {label && <Text style={styles.label}>{label}</Text>}
      <TextInput
        accessibilityLabel={label || props.placeholder}
        style={[styles.input, error && styles.inputError, style]}
        placeholderTextColor={colors.textTertiary}
        {...props}
      />
      {error && <Text style={styles.error}>{error}</Text>}
    </View>
  );
}
About: code-quality intelligence by Repobility · https://repobility.com
ModalHeader function · typescript · L12-L23 (12 LOC)
src/components/ui/ModalHeader.tsx
export function ModalHeader({ title, onClose }: ModalHeaderProps) {
  const { colors } = useTheme();

  return (
    <View style={styles.container}>
      <Text style={[styles.title, { color: colors.textPrimary }]}>{title}</Text>
      <TouchableOpacity onPress={onClose} testID="modal-close">
        <X color={colors.textPrimary} size={24} />
      </TouchableOpacity>
    </View>
  );
}
getDatabase function · typescript · L5-L12 (8 LOC)
src/database/index.ts
export async function getDatabase(): Promise<SQLite.SQLiteDatabase> {
  if (db) return db;

  const database = await SQLite.openDatabaseAsync('trackr.db');
  await runMigrations(database);
  db = database;
  return db;
}
runMigrations function · typescript · L14-L37 (24 LOC)
src/database/index.ts
async function runMigrations(database: SQLite.SQLiteDatabase): Promise<void> {
  // Create migrations table if not exists
  await database.execAsync(`
    CREATE TABLE IF NOT EXISTS migrations (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL UNIQUE,
      applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
  `);

  // Check which migrations have been applied
  const appliedMigrations = await database.getAllAsync<{ name: string }>(
    'SELECT name FROM migrations',
  );
  const appliedSet = new Set(appliedMigrations.map((m) => m.name));

  // Run pending migrations
  for (const migration of migrations) {
    if (!appliedSet.has(migration.name)) {
      await database.execAsync(migration.sql);
      await database.runAsync('INSERT INTO migrations (name) VALUES (?)', migration.name);
    }
  }
}
closeDatabase function · typescript · L165-L170 (6 LOC)
src/database/index.ts
export async function closeDatabase(): Promise<void> {
  if (db) {
    await db.closeAsync();
    db = null;
  }
}
mapRowToSession function · typescript · L177-L194 (18 LOC)
src/database/repositories/exerciseRepository.ts
function mapRowToSession(row: ExerciseSessionRow): ExerciseSession {
  return {
    id: row.id,
    date: row.date,
    type: row.type as ExerciseSession['type'],
    customType: row.custom_type ?? undefined,
    durationMinutes: row.duration_minutes,
    intensity: row.intensity as ExerciseSession['intensity'],
    caloriesBurned: row.calories_burned ?? undefined,
    notes: row.notes ?? undefined,
    heartRateAvg: row.heart_rate_avg ?? undefined,
    heartRateMax: row.heart_rate_max ?? undefined,
    distance: row.distance ?? undefined,
    distanceUnit: (row.distance_unit as ExerciseSession['distanceUnit']) ?? undefined,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
mapRowToHabit function · typescript · L265-L278 (14 LOC)
src/database/repositories/habitRepository.ts
function mapRowToHabit(row: HabitRow): Habit {
  return {
    id: row.id,
    name: row.name,
    description: row.description ?? undefined,
    icon: row.icon ?? undefined,
    color: row.color,
    frequency: row.frequency,
    targetDaysPerWeek: row.target_days_per_week ?? undefined,
    reminderTime: row.reminder_time ?? undefined,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
mapRowToCompletion function · typescript · L280-L289 (10 LOC)
src/database/repositories/habitRepository.ts
function mapRowToCompletion(row: HabitCompletionRow): HabitCompletion {
  return {
    id: row.id,
    habitId: row.habit_id,
    date: row.date,
    completed: Boolean(row.completed),
    completedAt: row.completed_at ?? undefined,
    notes: row.notes ?? undefined,
  };
}
mapRowToEntry function · typescript · L180-L194 (15 LOC)
src/database/repositories/journalRepository.ts
function mapRowToEntry(row: JournalEntryRow): JournalEntry {
  return {
    id: row.id,
    date: row.date,
    title: row.title ?? undefined,
    content: row.content,
    mood: (row.mood as JournalEntry['mood']) ?? undefined,
    tags: safeJsonParse<string[]>(row.tags),
    isScanned: Boolean(row.is_scanned),
    originalImageUri: row.original_image_uri ?? undefined,
    ocrConfidence: row.ocr_confidence ?? undefined,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
Repobility · open methodology · https://repobility.com/research/
attachFoodsToMeals function · typescript · L294-L311 (18 LOC)
src/database/repositories/nutritionRepository.ts
async function attachFoodsToMeals(
  db: Awaited<ReturnType<typeof getDatabase>>,
  meals: Meal[],
): Promise<Meal[]> {
  if (meals.length === 0) return meals;

  const mealIds = meals.map((m) => m.id);
  const placeholders = mealIds.map(() => '?').join(',');
  const foodRows = await db.getAllAsync<FoodItemRow>(
    `SELECT * FROM food_items WHERE meal_id IN (${placeholders})`,
    ...mealIds,
  );
  const foodsByMeal = groupFoodsByMealId(foodRows);
  for (const meal of meals) {
    meal.foods = foodsByMeal.get(meal.id) ?? [];
  }
  return meals;
}
mapRowToMeal function · typescript · L313-L330 (18 LOC)
src/database/repositories/nutritionRepository.ts
function mapRowToMeal(row: MealRow): Meal {
  return {
    id: row.id,
    date: row.date,
    mealType: row.meal_type as Meal['mealType'],
    name: row.name ?? undefined,
    foods: [],
    totalCalories: row.total_calories,
    totalProtein: row.total_protein ?? undefined,
    totalCarbs: row.total_carbs ?? undefined,
    totalFat: row.total_fat ?? undefined,
    totalFiber: row.total_fiber ?? undefined,
    photoUri: row.photo_uri ?? undefined,
    aiAnalysis: safeJsonParse(row.ai_analysis),
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
groupFoodsByMealId function · typescript · L332-L344 (13 LOC)
src/database/repositories/nutritionRepository.ts
function groupFoodsByMealId(rows: FoodItemRow[]): Map<string, FoodItem[]> {
  const map = new Map<string, FoodItem[]>();
  for (const row of rows) {
    const food = mapRowToFoodItem(row);
    const existing = map.get(food.mealId);
    if (existing) {
      existing.push(food);
    } else {
      map.set(food.mealId, [food]);
    }
  }
  return map;
}
page 1 / 2next ›