tasks now update streaks in db

This commit is contained in:
masongga
2026-05-23 22:12:00 -06:00
parent f51b73bec4
commit 53f3cec385
3 changed files with 79 additions and 29 deletions

View File

@@ -69,17 +69,20 @@ export async function getDailyEntryForToday(): Promise<DailyQuizSubmission | nul
)
.eq("user_id", userId)
.eq("entry_date", entryDate)
.maybeSingle();
.order("created_at", { ascending: false })
.limit(1);
if (error) {
throw new Error(error.message);
}
if (!data) {
const row = data?.[0];
if (!row) {
return null;
}
return mapRowToSubmission(data as DailyEntryRow);
return mapRowToSubmission(row as DailyEntryRow);
}
export async function getDailyQuizSubmission() {

View File

@@ -50,12 +50,50 @@ function mapHabitRow(row: HabitRow): Habit {
id: row.id,
label: row.name,
catalogId: getCatalogIdByLabel(row.name),
streak: row.streak,
lastCompletedDate: row.last_completed_on,
streak: row.streak ?? 0,
lastCompletedDate: row.last_completed_on ?? null,
isCustom: !isCatalogLabel(row.name),
};
}
function getFirstRow<T>(rows: T[] | null | undefined) {
return rows?.[0] ?? null;
}
function dedupeHabitsByName(rows: HabitRow[]) {
const seen = new Map<string, HabitRow>();
for (const row of rows) {
const key = row.name.trim().toLowerCase();
if (!seen.has(key)) {
seen.set(key, row);
}
}
return Array.from(seen.values());
}
async function findActiveHabitByName(
userId: string,
name: string,
): Promise<HabitRow | null> {
const supabase = createClient();
const { data, error } = await supabase
.from("habits")
.select("id, name, streak, last_completed_on")
.eq("user_id", userId)
.eq("name", name)
.eq("active", true)
.order("created_at", { ascending: true });
if (error) {
throw new Error(error.message);
}
return getFirstRow(data as HabitRow[] | null);
}
async function getAuthenticatedUserId() {
const supabase = createClient();
const {
@@ -111,14 +149,13 @@ async function getPreviousCompletedDate(
.eq("habit_id", habitId)
.neq("completed_on", today)
.order("completed_on", { ascending: false })
.limit(1)
.maybeSingle();
.limit(1);
if (error) {
throw new Error(error.message);
}
return data?.completed_on ?? null;
return getFirstRow(data as { completed_on: string }[] | null)?.completed_on ?? null;
}
export function isHabitCompletedToday(habit: Habit, today = getTodayDateKey()) {
@@ -144,7 +181,9 @@ export async function getHabits(): Promise<Habit[]> {
throw new Error(error.message);
}
const rows = await reconcileMissedDayStreaks((data ?? []) as HabitRow[]);
const rows = await reconcileMissedDayStreaks(
dedupeHabitsByName((data ?? []) as HabitRow[]),
);
return rows.map(mapHabitRow);
}
@@ -163,19 +202,7 @@ export async function ensureCatalogHabit(catalogId: string): Promise<Habit | nul
}
const supabase = createClient();
const { data: existing, error: existingError } = await supabase
.from("habits")
.select("id, name, streak, last_completed_on")
.eq("user_id", userId)
.eq("name", entry.label)
.eq("active", true)
.maybeSingle();
if (existingError) {
throw new Error(existingError.message);
}
let row = existing as HabitRow | null;
let row = await findActiveHabitByName(userId, entry.label);
if (!row) {
const { data: inserted, error: insertError } = await supabase
@@ -190,10 +217,14 @@ export async function ensureCatalogHabit(catalogId: string): Promise<Habit | nul
.single();
if (insertError) {
throw new Error(insertError.message);
}
row = await findActiveHabitByName(userId, entry.label);
row = inserted as HabitRow;
if (!row) {
throw new Error(insertError.message);
}
} else {
row = inserted as HabitRow;
}
}
const [reconciledRow] = await reconcileMissedDayStreaks([row]);
@@ -228,23 +259,26 @@ export async function toggleHabitCompletion(habitId: string): Promise<Habit[]> {
const [reconciledHabit] = await reconcileMissedDayStreaks([habit as HabitRow]);
const currentStreak = reconciledHabit.streak;
const { data: existingLog, error: existingLogError } = await supabase
const { data: existingLogs, error: existingLogError } = await supabase
.from("habit_logs")
.select("id")
.eq("user_id", userId)
.eq("habit_id", habitId)
.eq("completed_on", today)
.maybeSingle();
.eq("completed_on", today);
if (existingLogError) {
throw new Error(existingLogError.message);
}
const existingLog = getFirstRow(existingLogs as { id: string }[] | null);
if (existingLog) {
const { error: deleteError } = await supabase
.from("habit_logs")
.delete()
.eq("id", existingLog.id);
.eq("user_id", userId)
.eq("habit_id", habitId)
.eq("completed_on", today);
if (deleteError) {
throw new Error(deleteError.message);