import { FONTS, ROUNDNESS, SPACING } from "@/src/constants/Theme"; import { useAuth } from "@/src/hooks/useAuth"; import { useTheme } from "@/src/hooks/useTheme"; import { useData } from "@/src/hooks/useData"; import { performMutation } from "@/src/lib/sync"; import * as Haptics from "expo-haptics"; import { useRouter } from "expo-router"; import { Calendar, Clock, Repeat, Save, Sparkles, X, MapPin, Anchor, ChevronDown, } from "lucide-react-native"; import React, { useMemo, useState } from "react"; import { ActivityIndicator, Alert, ScrollView, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View, Modal, KeyboardAvoidingView, Platform } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { TimeInput } from "@/src/components/ui/TimeInput"; const FREQUENCIES = [ { label: "Daily", value: "daily" }, { label: "Weekly", value: "weekly" }, { label: "Monthly", value: "monthly" }, ]; const TIME_PRESETS = [ { label: "Morning", time: "08:00" }, { label: "Noon", time: "12:00" }, { label: "Evening", time: "18:00" }, { label: "Night", time: "22:00" }, ]; export default function AddHabitScreen() { const { colors } = useTheme(); const { user } = useAuth(); const styles = useMemo(() => createStyles(colors), [colors]); const router = useRouter(); const userId = user?.id || 'guest'; const { data: existingHabits } = useData<{id: string, title: string}>( 'SELECT id, title FROM habits WHERE is_active = 1 AND (user_id = ? OR user_id IS NULL)', [userId] ); const [title, setTitle] = useState(""); const [frequency, setFrequency] = useState("daily"); const [preferredTime, setPreferredTime] = useState("08:00"); const [location, setLocation] = useState(""); const [twoMinuteVersion, setTwoMinuteVersion] = useState(""); const [anchorHabitId, setAnchorHabitId] = useState(null); const [weekendFlexibility, setWeekendFlexibility] = useState(false); const [loading, setLoading] = useState(false); const [showAnchorModal, setShowAnchorModal] = useState(false); const selectedAnchor = useMemo(() => existingHabits.find(h => h.id === anchorHabitId), [existingHabits, anchorHabitId] ); const handleSave = async () => { if (!title) { Alert.alert("Error", "Please provide a title for your habit"); return; } setLoading(true); try { await performMutation("habits", "INSERT", { id: Math.random().toString(36).substring(7), user_id: userId, title, frequency, preferred_time: preferredTime, location: location, two_minute_version: twoMinuteVersion, anchor_habit_id: anchorHabitId, weekend_flexibility: weekendFlexibility ? 1 : 0, is_active: 1, }); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); router.back(); } catch (error) { console.error("Failed to save habit:", error); Alert.alert("Error", "Failed to save habit"); } finally { setLoading(false); } }; return ( router.back()}> New Habit {loading ? ( ) : ( )} HABIT ARCHITECT {/* Title */} WHAT IS THE HABIT? {/* Implementation Intentions: Location */} WHERE WILL YOU DO IT? (LOCATION) {/* Small Start: Two-Minute Version */} THE TWO-MINUTE VERSION (START SMALL) "Optimize for the starting line, not the finish line." {/* Habit Stacking: Anchor Habit */} STACK IT: AFTER I... { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setShowAnchorModal(true); }} > {selectedAnchor ? selectedAnchor.title : "Choose an anchor habit"} {/* Time */} {TIME_PRESETS.map((p) => ( { setPreferredTime(p.time); Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); }} > {p.label} ))} {/* Frequency */} FREQUENCY {FREQUENCIES.map((f) => ( setFrequency(f.value)} > {f.label} ))} {/* Weekend Flexibility */} Weekend Flexibility Allow skipping on weekends without breaking streaks. "Every action you take is a vote for the type of person you wish to become." {/* Anchor Habit Modal */} setShowAnchorModal(false)} > Select Anchor Habit setShowAnchorModal(false)}> { setAnchorHabitId(null); setShowAnchorModal(false); }} > No Anchor (Independent) {existingHabits.map((habit) => ( { setAnchorHabitId(habit.id); setShowAnchorModal(false); }} > {habit.title} ))} ); } const createStyles = (colors: any) => StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background, }, safeArea: { flex: 1, }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", padding: SPACING.lg, borderBottomWidth: 1, borderBottomColor: colors.outlineVariant + "4D", }, headerTitle: { fontFamily: FONTS.headline, fontSize: 20, color: colors.onSurface, }, content: { padding: SPACING.lg, }, section: { gap: SPACING.xl, }, sectionLabel: { fontFamily: FONTS.labelSm, fontSize: 11, color: colors.primary, letterSpacing: 1.5, marginBottom: 4, }, inputGroup: { gap: 8, }, label: { fontFamily: FONTS.labelSm, fontSize: 11, color: colors.outline, }, inputWrapper: { flexDirection: "row", alignItems: "center", backgroundColor: colors.surface, borderRadius: ROUNDNESS.md, borderWidth: 1, borderColor: colors.outlineVariant + "4D", paddingHorizontal: 12, }, inputIcon: { marginRight: 10, }, input: { flex: 1, height: 52, fontFamily: FONTS.body, fontSize: 16, color: colors.onSurface, }, hintText: { fontFamily: FONTS.body, fontSize: 12, color: colors.onSurfaceVariant, fontStyle: 'italic', marginTop: 2, }, presetsGrid: { flexDirection: "row", gap: 8, marginTop: 4, }, presetBtn: { flex: 1, paddingVertical: 8, borderRadius: ROUNDNESS.sm, backgroundColor: colors.surfaceVariant + "4D", alignItems: "center", borderWidth: 1, borderColor: colors.outlineVariant + "33", }, presetText: { fontFamily: FONTS.label, fontSize: 10, color: colors.onSurfaceVariant, }, frequencyGrid: { flexDirection: "row", gap: 10, }, frequencyOption: { flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 8, backgroundColor: colors.surface, paddingVertical: 12, borderRadius: ROUNDNESS.md, borderWidth: 1, borderColor: colors.outlineVariant + "4D", }, frequencyText: { fontFamily: FONTS.label, fontSize: 13, color: colors.onSurfaceVariant, }, switchRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", backgroundColor: colors.surface, padding: SPACING.lg, borderRadius: ROUNDNESS.lg, borderWidth: 1, borderColor: colors.outlineVariant + "4D", }, switchContent: { flex: 1, paddingRight: 16, }, rowAlign: { flexDirection: "row", alignItems: "center", marginBottom: 4, }, switchTitle: { fontFamily: FONTS.headline, fontSize: 16, color: colors.onSurface, }, switchDesc: { fontFamily: FONTS.body, fontSize: 13, color: colors.onSurfaceVariant, lineHeight: 18, }, infoCard: { backgroundColor: colors.primaryContainer + "40", padding: SPACING.lg, borderRadius: ROUNDNESS.lg, borderWidth: 1, borderColor: colors.primaryContainer, marginTop: SPACING.xxl, alignItems: "center", }, infoText: { fontFamily: FONTS.body, fontSize: 14, color: colors.onSurfaceVariant, fontStyle: "italic", textAlign: "center", }, modalOverlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end', }, modalContent: { borderTopLeftRadius: ROUNDNESS.xl, borderTopRightRadius: ROUNDNESS.xl, paddingBottom: 40, maxHeight: '70%', }, modalHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: SPACING.lg, borderBottomWidth: 1, borderBottomColor: colors.outlineVariant + '4D', }, modalTitle: { fontFamily: FONTS.headline, fontSize: 18, color: colors.onSurface, }, anchorList: { padding: SPACING.md, }, anchorItem: { padding: SPACING.lg, borderRadius: ROUNDNESS.lg, marginBottom: 8, }, anchorItemText: { fontFamily: FONTS.body, fontSize: 16, color: colors.onSurface, }, });