{hasCheckedInToday
? completedTaskCount > 0
- ? `Your bit reacts to today's quiz and ${completedTaskCount} completed task${completedTaskCount === 1 ? "" : "s"}. Meals, hydration, sleep, and relaxing habits boost health and mood.`
+ ? `Your bit reacts to today's check-in and ${completedTaskCount} completed task${completedTaskCount === 1 ? "" : "s"}. Meals, hydration, sleep, and relaxing habits boost health and mood.`
: "Your bit is reacting to today's wellness check-in. Complete habits to boost mood, energy, and health."
: completedTaskCount > 0
- ? "Complete today's quiz for a full wellness read, then keep completing habits to boost your bit."
- : "Complete today's quiz to update your bit's mood, energy, and health."}
+ ? "Complete today's check-in for a full wellness read, then keep completing habits to boost your bit."
+ : "Complete today's check-in to update your bit's mood, energy, and health."}
);
}
@@ -155,7 +155,7 @@ export function DailyQuizForm() {
- Today's quiz is complete
+ Today's check-in is complete
Your answers are saved below. Come back tomorrow for your next
@@ -264,7 +264,7 @@ export function DailyQuizForm() {
{!isCompleted ? (
) : null}
diff --git a/components/daily-quiz/daily-quiz-link-button.tsx b/components/daily-quiz/daily-quiz-link-button.tsx
index ab09384..a815a13 100644
--- a/components/daily-quiz/daily-quiz-link-button.tsx
+++ b/components/daily-quiz/daily-quiz-link-button.tsx
@@ -23,14 +23,14 @@ export function DailyQuizLinkButton() {
if (!isReady || isCompleted) {
return (
);
}
return (
);
}
diff --git a/components/habits/habit-tracker.tsx b/components/habits/habit-tracker.tsx
index 46e92dd..eeb2836 100644
--- a/components/habits/habit-tracker.tsx
+++ b/components/habits/habit-tracker.tsx
@@ -57,7 +57,7 @@ function DailyTaskList({
if (tasks.length === 0) {
return (
- No daily tasks yet. Complete your daily quiz or update your profile so
+ No daily tasks yet. Complete your daily check-in or update your profile so
AI can suggest habits for you.
);
@@ -428,7 +428,7 @@ export function HabitTracker({ mode = "daily" }: HabitTrackerProps) {
Today's tasks
Personalized from your focus topics
- {quizCompletedToday ? ", today's quiz," : ""} and custom habits.
+ {quizCompletedToday ? ", today's check-in," : ""} and custom habits.
@@ -485,17 +485,17 @@ export function HabitTracker({ mode = "daily" }: HabitTrackerProps) {
How daily tasks are picked
Your tasks combine focus preferences, custom habits, and today's
- quiz.
+ check-in.
- Suggested habits can appear when your quiz shows low energy, high
+ Suggested habits can appear when your check-in shows low energy, high
stress, or poor sleep.
@@ -548,7 +548,7 @@ export function HabitTracker({ mode = "daily" }: HabitTrackerProps) {
How daily tasks are picked
Your tasks combine custom habits and AI suggestions based on your
- profile, onboarding, daily quiz, and journal.
+ profile, onboarding, daily check-in, and journal.
@@ -557,7 +557,7 @@ export function HabitTracker({ mode = "daily" }: HabitTrackerProps) {
{focusTopic ?? "None selected"}
+ );
+}
diff --git a/components/profile/profile-preferences-form.tsx b/components/profile/profile-preferences-form.tsx
index f1b8b81..3fba700 100644
--- a/components/profile/profile-preferences-form.tsx
+++ b/components/profile/profile-preferences-form.tsx
@@ -247,13 +247,13 @@ export function ProfilePreferencesForm({ email }: ProfilePreferencesFormProps) {
try {
await resetTodaysDailyQuiz();
setQuizResetMessage(
- "Today's quiz was reset. Open the Quiz tab to take it again.",
+ "Today's check-in was reset. Open the Bit page to complete it again.",
);
} catch (resetError) {
setError(
resetError instanceof Error
? resetError.message
- : "Could not reset today's quiz.",
+ : "Could not reset today's check-in.",
);
} finally {
setIsResettingQuiz(false);
@@ -337,7 +337,7 @@ export function ProfilePreferencesForm({ email }: ProfilePreferencesFormProps) {
Notification preferences
- Control reminders for your daily quiz and habits.
+ Control reminders for your daily check-in and habits.
@@ -425,7 +425,7 @@ export function ProfilePreferencesForm({ email }: ProfilePreferencesFormProps) {
- Reset clears today's wellness quiz entry so you can complete it
+ Reset clears today's wellness check-in entry so you can complete it
again immediately. Demo points are for testing the shop only.
{quizResetMessage ? (
{quizResetMessage}
diff --git a/lib/daily-quiz-storage.ts b/lib/daily-quiz-storage.ts
index f4eac1c..28f4a79 100644
--- a/lib/daily-quiz-storage.ts
+++ b/lib/daily-quiz-storage.ts
@@ -48,7 +48,7 @@ export async function resetTodaysDailyQuiz() {
const userId = await getAuthenticatedUserId();
if (!userId) {
- throw new Error("You must be signed in to reset today's quiz.");
+ throw new Error("You must be signed in to reset today's check-in.");
}
const supabase = createClient();
@@ -197,6 +197,89 @@ export async function saveDailyQuizSubmission(
return saveDailyEntry(answers, journal);
}
+export type DailyEntrySummary = {
+ date: string;
+ hasJournal: boolean;
+};
+
+const DAILY_ENTRY_SELECT =
+ "entry_date, mood, stress, energy, sleep_hours, sleep_quality, journal";
+
+function formatDateKey(date: Date) {
+ return date.toLocaleDateString("en-CA");
+}
+
+function getMonthDateBounds(year: number, month: number) {
+ const monthStart = new Date(year, month, 1);
+ const monthEnd = new Date(year, month + 1, 0);
+
+ return {
+ startKey: formatDateKey(monthStart),
+ endKey: formatDateKey(monthEnd),
+ };
+}
+
+export async function getDailyEntrySummariesForMonth(
+ year: number,
+ month: number,
+): Promise {
+ const userId = await getAuthenticatedUserId();
+
+ if (!userId) {
+ return [];
+ }
+
+ const { startKey, endKey } = getMonthDateBounds(year, month);
+ const supabase = createClient();
+ const { data, error } = await supabase
+ .from("daily_entries")
+ .select("entry_date, journal")
+ .eq("user_id", userId)
+ .gte("entry_date", startKey)
+ .lte("entry_date", endKey)
+ .order("entry_date", { ascending: true });
+
+ if (error) {
+ throw new Error(error.message);
+ }
+
+ return (data ?? []).map((row) => ({
+ date: row.entry_date as string,
+ hasJournal: Boolean((row.journal as string | null)?.trim()),
+ }));
+}
+
+export async function getDailyEntryByDate(
+ dateKey: string,
+): Promise {
+ const userId = await getAuthenticatedUserId();
+
+ if (!userId) {
+ return null;
+ }
+
+ const supabase = createClient();
+ const { data, error } = await supabase
+ .from("daily_entries")
+ .select(DAILY_ENTRY_SELECT)
+ .eq("user_id", userId)
+ .eq("entry_date", dateKey)
+ .order("created_at", { ascending: false })
+ .limit(1);
+
+ if (error) {
+ throw new Error(error.message);
+ }
+
+ const row = data?.[0];
+
+ if (!row) {
+ return null;
+ }
+
+ return mapRowToSubmission(row as DailyEntryRow);
+}
+
export async function getAvatarConditionForToday(): Promise {
const [entry, completedHabitLabels] = await Promise.all([
getDailyEntryForToday(),
diff --git a/lib/daily-reminders.ts b/lib/daily-reminders.ts
index 761a2d4..ee676d8 100644
--- a/lib/daily-reminders.ts
+++ b/lib/daily-reminders.ts
@@ -121,7 +121,7 @@ export function buildDailyReminderNotification(status: DailyReminderStatus) {
if (!status.quizCompleted && status.incompleteTaskCount > 0) {
return {
title: "Time for your daily check-in",
- body: `Complete today's wellness quiz and ${status.incompleteTaskCount} remaining habit${status.incompleteTaskCount === 1 ? "" : "s"}.`,
+ body: `Complete today's wellness check-in and ${status.incompleteTaskCount} remaining habit${status.incompleteTaskCount === 1 ? "" : "s"}.`,
targetUrl,
};
}
@@ -129,7 +129,7 @@ export function buildDailyReminderNotification(status: DailyReminderStatus) {
if (!status.quizCompleted) {
return {
title: "Time for your daily check-in",
- body: "Complete today's wellness quiz to keep your bit in good spirits.",
+ body: "Complete today's wellness check-in to keep your bit in good spirits.",
targetUrl,
};
}
diff --git a/lib/routes.ts b/lib/routes.ts
index 0de94c2..0cb59fc 100644
--- a/lib/routes.ts
+++ b/lib/routes.ts
@@ -8,6 +8,7 @@ export const routes = {
avatar: "/avatar",
customize: "/customize",
habits: "/habits",
+ dailyCheckIn: "/daily/check-in",
dailyQuiz: "/daily/quiz",
shop: "/shop",
profile: "/profile",