"use client";
import { useCallback, useEffect, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { HABIT_PET_DATA_UPDATED_EVENT } from "@/lib/app-events";
import {
getDailyTasks,
type DailyTask,
} from "@/lib/daily-tasks";
import {
addHabit,
getCustomHabits,
isHabitCompletedToday,
removeHabit,
toggleHabitCompletion,
type Habit,
} from "@/lib/habits-storage";
import { getProfilePreferences } from "@/lib/profile-preferences-storage";
import { hasCompletedDailyQuizToday } from "@/lib/daily-quiz-storage";
type HabitTrackerProps = {
mode?: "daily" | "manage";
};
const reasonLabels = {
custom: "Custom",
focus: "Your focus",
quiz: "Today's quiz",
} as const;
function DailyTaskList({
tasks,
onToggle,
}: {
tasks: DailyTask[];
onToggle: (habitId: string) => void;
}) {
if (tasks.length === 0) {
return (
No daily tasks yet. Set focus topics in Profile or complete the daily
quiz to personalize your list.
);
}
const sortedTasks = [...tasks].sort((a, b) => {
const aCompleted = isHabitCompletedToday(a);
const bCompleted = isHabitCompletedToday(b);
if (aCompleted === bCompleted) {
return 0;
}
return aCompleted ? 1 : -1;
});
return (
<>
{sortedTasks.map((habit) => {
const isCompleted = isHabitCompletedToday(habit);
return (
onToggle(habit.id)}
className="mt-0.5"
/>
{reasonLabels[habit.reason]}
{habit.streak} day streak
);
})}
>
);
}
function CustomHabitList({
habits,
onRemove,
}: {
habits: Habit[];
onRemove: (habitId: string) => void;
}) {
if (habits.length === 0) {
return (
No custom habits yet. Add one below to include it in your daily tasks.
);
}
return (
<>
{habits.map((habit) => (
{habit.label}
{habit.streak} day streak
))}
>
);
}
export function HabitTracker({ mode = "daily" }: HabitTrackerProps) {
const [dailyTasks, setDailyTasks] = useState([]);
const [customHabits, setCustomHabits] = useState([]);
const [newHabitLabel, setNewHabitLabel] = useState("");
const [focusTopics, setFocusTopics] = useState([]);
const [quizCompletedToday, setQuizCompletedToday] = useState(false);
const [error, setError] = useState(null);
const [isReady, setIsReady] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const refresh = useCallback(async () => {
try {
setError(null);
const [tasks, customs] = await Promise.all([
getDailyTasks(),
getCustomHabits(),
]);
setDailyTasks(tasks);
setCustomHabits(customs);
setFocusTopics(getProfilePreferences().focusTopics);
setQuizCompletedToday(hasCompletedDailyQuizToday());
setIsReady(true);
} catch (refreshError) {
setError(
refreshError instanceof Error
? refreshError.message
: "Could not load habits.",
);
setIsReady(true);
}
}, []);
useEffect(() => {
void refresh();
window.addEventListener(HABIT_PET_DATA_UPDATED_EVENT, refresh);
return () => {
window.removeEventListener(HABIT_PET_DATA_UPDATED_EVENT, refresh);
};
}, [refresh]);
const handleToggle = async (habitId: string) => {
try {
setIsSaving(true);
setError(null);
await toggleHabitCompletion(habitId);
} catch (toggleError) {
setError(
toggleError instanceof Error
? toggleError.message
: "Could not update habit.",
);
} finally {
setIsSaving(false);
}
};
const handleAddHabit = async () => {
try {
setIsSaving(true);
setError(null);
await addHabit(newHabitLabel);
setNewHabitLabel("");
} catch (addError) {
setError(
addError instanceof Error ? addError.message : "Could not add habit.",
);
} finally {
setIsSaving(false);
}
};
const handleRemoveHabit = async (habitId: string) => {
try {
setIsSaving(true);
setError(null);
await removeHabit(habitId);
} catch (removeError) {
setError(
removeError instanceof Error
? removeError.message
: "Could not remove habit.",
);
} finally {
setIsSaving(false);
}
};
if (!isReady) {
return (
Loading habits...
);
}
if (mode === "manage") {
return (
{error ?
{error}
: null}
Custom habits
Add your own habits. Custom habits always appear in your daily
task list.
setNewHabitLabel(event.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
event.preventDefault();
void handleAddHabit();
}
}}
/>
How daily tasks are picked
Your tasks combine focus preferences, custom habits, and today's
quiz.
Focus topics:{" "}
{focusTopics.length > 0 ? focusTopics.join(", ") : "None selected"}
Daily quiz today:{" "}
{quizCompletedToday ? "Completed" : "Not completed yet"}
Suggested habits can appear when your quiz shows low energy, high
stress, or poor sleep.
);
}
return (
Today's tasks
Personalized from your focus topics
{quizCompletedToday ? ", today's quiz," : ""} and custom habits.
{error ? {error}
: null}
);
}