Function bodies 89 total
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>
<AnimaLoginScreen 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(), passwVerifyEmailScreen 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 haLogExerciseScreen 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(HaptRoot 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],
);
};
conAbout: 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 sizLogSleepScreen 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);
setSelecteDashboardCard 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,
bordeAICoaching 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 caQuickActionButton 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.coloWeeklyInsights 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]}>
<LinearGradSkeletonCard 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 ›