use jotai for all states (#19)

This commit is contained in:
Doh
2025-01-04 11:20:36 -05:00
committed by GitHub
parent 306242f2ec
commit ad05a46206
18 changed files with 212 additions and 243 deletions

View File

@@ -1,69 +1,47 @@
import { useState, useEffect } from 'react'
import { loadHabitsData, saveHabitsData, addCoins, removeCoins } from '@/app/actions/data'
import { useAtom } from 'jotai'
import { habitsAtom, coinsAtom, settingsAtom } from '@/lib/atoms'
import { addCoins, removeCoins, saveHabitsData } from '@/app/actions/data'
import { Habit } from '@/lib/types'
import { getNowInMilliseconds, getTodayInTimezone } from '@/lib/utils'
import { toast } from '@/hooks/use-toast'
import { ToastAction } from '@/components/ui/toast'
import { Undo2 } from 'lucide-react'
import { Habit } from '@/lib/types'
import { getNowInMilliseconds, getTodayInTimezone } from '@/lib/utils'
import { useAtom } from 'jotai'
import { settingsAtom } from '@/lib/atoms'
export function useHabits() {
const [habits, setHabits] = useState<Habit[]>([])
const [habitsData, setHabitsData] = useAtom(habitsAtom)
const [coins, setCoins] = useAtom(coinsAtom)
const [settings] = useAtom(settingsAtom)
useEffect(() => {
fetchHabits()
}, [])
const fetchHabits = async () => {
const data = await loadHabitsData()
setHabits(data.habits)
}
const addHabit = async (habit: Omit<Habit, 'id'>) => {
const newHabit = { ...habit, id: getNowInMilliseconds() }
const newHabits = [...habits, newHabit]
setHabits(newHabits)
await saveHabitsData({ habits: newHabits })
}
const editHabit = async (updatedHabit: Habit) => {
const newHabits = habits.map(habit =>
habit.id === updatedHabit.id ? updatedHabit : habit
)
setHabits(newHabits)
await saveHabitsData({ habits: newHabits })
}
const deleteHabit = async (id: string) => {
const newHabits = habits.filter(habit => habit.id !== id)
setHabits(newHabits)
await saveHabitsData({ habits: newHabits })
}
const completeHabit = async (habit: Habit) => {
const today = getTodayInTimezone(settings.system.timezone)
const timezone = settings.system.timezone
const today = getTodayInTimezone(timezone)
if (!habit.completions.includes(today)) {
const updatedHabit = {
...habit,
completions: [...habit.completions, today]
}
const updatedHabits = habits.map(h =>
const updatedHabits = habitsData.habits.map(h =>
h.id === habit.id ? updatedHabit : h
)
await saveHabitsData({ habits: updatedHabits })
const coinsData = await addCoins(habit.coinReward, `Completed habit: ${habit.name}`, 'HABIT_COMPLETION', habit.id)
setHabitsData({ habits: updatedHabits })
setHabits(updatedHabits)
const coinsData = await addCoins(habit.coinReward, `Completed habit: ${habit.name}`, 'HABIT_COMPLETION', habit.id)
setCoins(coinsData)
toast({
title: "Habit completed!",
description: `You earned ${habit.coinReward} coins.`,
action: <ToastAction altText="Undo" className="gap-2" onClick={() => undoComplete(habit)}><Undo2 className="h-4 w-4" />Undo</ToastAction>
action: <ToastAction altText="Undo" className="gap-2" onClick={() => undoComplete(habit)}>
<Undo2 className="h-4 w-4" />Undo
</ToastAction>
})
return coinsData.balance
return {
updatedHabits,
newBalance: coinsData.balance,
newTransactions: coinsData.transactions
}
} else {
toast({
title: "Habit already completed",
@@ -75,34 +53,61 @@ export function useHabits() {
}
const undoComplete = async (habit: Habit) => {
const today = getTodayInTimezone(settings.system.timezone)
const timezone = settings.system.timezone
const today = getTodayInTimezone(timezone)
const updatedHabit = {
...habit,
completions: habit.completions.filter(date => date !== today)
}
const updatedHabits = habits.map(h =>
const updatedHabits = habitsData.habits.map(h =>
h.id === habit.id ? updatedHabit : h
)
await saveHabitsData({ habits: updatedHabits })
const coinsData = await removeCoins(habit.coinReward, `Undid habit completion: ${habit.name}`, 'HABIT_UNDO', habit.id)
setHabitsData({ habits: updatedHabits })
setHabits(updatedHabits)
const coinsData = await removeCoins(habit.coinReward, `Undid habit completion: ${habit.name}`, 'HABIT_UNDO', habit.id)
setCoins(coinsData)
toast({
title: "Completion undone",
description: `${habit.coinReward} coins have been deducted.`,
action: <ToastAction altText="Redo" onClick={() => completeHabit(habit)}><Undo2 className="h-4 w-4" />Undo</ToastAction>
action: <ToastAction altText="Redo" onClick={() => completeHabit(habit)}>
<Undo2 className="h-4 w-4" />Undo
</ToastAction>
})
return coinsData.balance
return {
updatedHabits,
newBalance: coinsData.balance,
newTransactions: coinsData.transactions
}
}
const saveHabit = async (habit: Omit<Habit, 'id'> & { id?: string }) => {
const newHabit = {
...habit,
id: habit.id || getNowInMilliseconds().toString()
}
const updatedHabits = habit.id
? habitsData.habits.map(h => h.id === habit.id ? newHabit : h)
: [...habitsData.habits, newHabit]
await saveHabitsData({ habits: updatedHabits })
setHabitsData({ habits: updatedHabits })
return updatedHabits
}
const deleteHabit = async (id: string) => {
const updatedHabits = habitsData.habits.filter(h => h.id !== id)
await saveHabitsData({ habits: updatedHabits })
setHabitsData({ habits: updatedHabits })
return updatedHabits
}
return {
habits,
addHabit,
editHabit,
deleteHabit,
completeHabit,
undoComplete
undoComplete,
saveHabit,
deleteHabit
}
}