mirror of
https://github.com/harivansh-afk/Habit-Tracker.git
synced 2026-04-15 14:03:50 +00:00
138 lines
No EOL
3.3 KiB
TypeScript
138 lines
No EOL
3.3 KiB
TypeScript
import { useState } from 'react';
|
|
import { supabase } from '../lib/supabase';
|
|
import { Habit } from '../types';
|
|
import { calculateStreak } from '../utils/streakCalculator';
|
|
|
|
export const useHabits = () => {
|
|
const [habits, setHabits] = useState<Habit[]>([]);
|
|
|
|
const fetchHabits = async () => {
|
|
try {
|
|
const { data, error } = await supabase
|
|
.from('habits')
|
|
.select(`
|
|
id,
|
|
name,
|
|
created_at,
|
|
best_streak,
|
|
habit_completions (completion_date)
|
|
`);
|
|
|
|
if (error) throw error;
|
|
|
|
const formattedHabits = data.map(habit => ({
|
|
id: habit.id,
|
|
name: habit.name,
|
|
created_at: habit.created_at,
|
|
best_streak: habit.best_streak,
|
|
completedDates: habit.habit_completions.map(
|
|
(completion: { completion_date: string }) => completion.completion_date
|
|
)
|
|
}));
|
|
|
|
setHabits(formattedHabits);
|
|
} catch (error) {
|
|
console.error('Error fetching habits:', error);
|
|
setHabits([]);
|
|
}
|
|
};
|
|
|
|
const addHabit = async (name: string) => {
|
|
try {
|
|
const { error } = await supabase
|
|
.from('habits')
|
|
.insert([{
|
|
name,
|
|
best_streak: 0,
|
|
created_at: new Date().toISOString()
|
|
}])
|
|
.select()
|
|
.single();
|
|
|
|
if (error) throw error;
|
|
await fetchHabits();
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error adding habit:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const toggleHabit = async (id: number, date: string) => {
|
|
try {
|
|
const { data: existing } = await supabase
|
|
.from('habit_completions')
|
|
.select()
|
|
.eq('habit_id', id)
|
|
.eq('completion_date', date)
|
|
.single();
|
|
|
|
if (existing) {
|
|
await supabase
|
|
.from('habit_completions')
|
|
.delete()
|
|
.eq('habit_id', id)
|
|
.eq('completion_date', date);
|
|
} else {
|
|
await supabase
|
|
.from('habit_completions')
|
|
.insert([{ habit_id: id, completion_date: date }]);
|
|
}
|
|
|
|
// After toggling, recalculate streak
|
|
const habit = habits.find(h => h.id === id);
|
|
if (habit) {
|
|
const newCompletedDates = existing
|
|
? habit.completedDates.filter(d => d !== date)
|
|
: [...habit.completedDates, date];
|
|
|
|
const { bestStreak } = calculateStreak(newCompletedDates);
|
|
|
|
// Update best_streak if the new streak is higher
|
|
if (bestStreak > habit.best_streak) {
|
|
await supabase
|
|
.from('habits')
|
|
.update({ best_streak: bestStreak })
|
|
.eq('id', id);
|
|
}
|
|
}
|
|
|
|
await fetchHabits();
|
|
} catch (error) {
|
|
console.error('Error toggling habit:', error);
|
|
}
|
|
};
|
|
|
|
const updateHabit = async (id: number, name: string) => {
|
|
try {
|
|
await supabase
|
|
.from('habits')
|
|
.update({ name })
|
|
.eq('id', id);
|
|
await fetchHabits();
|
|
} catch (error) {
|
|
console.error('Error updating habit:', error);
|
|
}
|
|
};
|
|
|
|
const deleteHabit = async (id: number) => {
|
|
try {
|
|
await supabase
|
|
.from('habits')
|
|
.delete()
|
|
.eq('id', id);
|
|
await fetchHabits();
|
|
} catch (error) {
|
|
console.error('Error deleting habit:', error);
|
|
}
|
|
};
|
|
|
|
return {
|
|
habits,
|
|
fetchHabits,
|
|
addHabit,
|
|
toggleHabit,
|
|
updateHabit,
|
|
deleteHabit
|
|
};
|
|
};
|