From f7034116a3a4f86a99caf37f10dc3800c5c773cb Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Fri, 6 Mar 2026 22:47:32 +0100 Subject: [PATCH] fix: migrate atoms to normal functions --- components/DailyOverview.tsx | 13 +++++-------- components/HabitCalendar.tsx | 5 ++--- components/HabitStreak.tsx | 14 ++++---------- components/PomodoroTimer.tsx | 7 ++++--- hooks/useHabits.tsx | 12 ++++++++---- lib/atoms.ts | 34 +--------------------------------- lib/utils.ts | 15 +++++++++++++++ 7 files changed, 39 insertions(+), 61 deletions(-) diff --git a/components/DailyOverview.tsx b/components/DailyOverview.tsx index fe5a640..c836406 100644 --- a/components/DailyOverview.tsx +++ b/components/DailyOverview.tsx @@ -13,22 +13,22 @@ import { TooltipTrigger, } from "@/components/ui/tooltip" import { useHabits } from '@/hooks/useHabits' -import { browserSettingsAtom, completedHabitsMapAtom, hasTasksAtom, pomodoroAtom, settingsAtom } from '@/lib/atoms' +import { browserSettingsAtom, completedHabitsMapAtom, settingsAtom } from '@/lib/atoms' import { DESKTOP_DISPLAY_ITEM_COUNT } from '@/lib/constants' import { Habit, WishlistItemType } from '@/lib/types' import { cn, d2t, getNow, getTodayInTimezone, isHabitDue, isSameDate, isTaskOverdue, t2d } from '@/lib/utils' import { useAtom } from 'jotai' -import { AlertTriangle, ArrowRight, ChevronDown, ChevronUp, Circle, CircleCheck, Coins, Pin, Plus } from 'lucide-react'; // Removed unused icons +import { AlertTriangle, ArrowRight, ChevronDown, ChevronUp, Circle, CircleCheck, Coins, Pin, Plus } from 'lucide-react'; import { useTranslations } from 'next-intl' import Link from 'next/link' import { useState } from 'react' import AddEditHabitModal from './AddEditHabitModal' import CompletionCountBadge from './CompletionCountBadge' import ConfirmDialog from './ConfirmDialog' +import DrawingDisplay from './DrawingDisplay' import { HabitContextMenuItems } from './HabitContextMenuItems' import Linkify from './linkify' import { Button } from './ui/button' -import DrawingDisplay from './DrawingDisplay' interface UpcomingItemsProps { habits: Habit[] @@ -54,8 +54,7 @@ const ItemSection = ({ addNewItem, }: ItemSectionProps) => { const t = useTranslations('DailyOverview'); - const { completeHabit, undoComplete, saveHabit, deleteHabit, archiveHabit, habitFreqMap } = useHabits(); - const [_, setPomo] = useAtom(pomodoroAtom); + const { completeHabit, undoComplete, saveHabit, deleteHabit, habitFreqMap } = useHabits(); const [browserSettings, setBrowserSettings] = useAtom(browserSettingsAtom); const [settings] = useAtom(settingsAtom); const [completedHabitsMap] = useAtom(completedHabitsMapAtom); @@ -397,8 +396,6 @@ export default function DailyOverview({ return a.coinCost - b.coinCost }) - const [hasTasks] = useAtom(hasTasksAtom) - const [, setPomo] = useAtom(pomodoroAtom) const [modalConfig, setModalConfig] = useState<{ isOpen: boolean, isTask: boolean @@ -416,7 +413,7 @@ export default function DailyOverview({
{/* Tasks Section */} - {hasTasks && ( + {habits.some(habit => habit.isTask === true) && ( (getNow({ timezone: settings.system.timezone })) const selectedDate = selectedDateTime.toFormat("yyyy-MM-dd") const [habitsData] = useAtom(habitsAtom) - const [hasTasks] = useAtom(hasTasksAtom) const habits = habitsData.habits const [completedHabitsMap] = useAtom(completedHabitsMapAtom) @@ -83,7 +82,7 @@ export default function HabitCalendar() { {selectedDateTime && (
- {hasTasks && ( + {habits.some(habit => habit.isTask === true) && (

{t('tasksSectionTitle')}

diff --git a/components/HabitStreak.tsx b/components/HabitStreak.tsx index 87e6c2d..6e43143 100644 --- a/components/HabitStreak.tsx +++ b/components/HabitStreak.tsx @@ -1,22 +1,16 @@ 'use client' import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { completedHabitsMapAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms'; // Added completedHabitsMapAtom +import { completedHabitsMapAtom, settingsAtom } from '@/lib/atoms'; import { Habit } from '@/lib/types'; -import { d2s, getNow } from '@/lib/utils'; // Removed getCompletedHabitsForDate +import { d2s, getNow } from '@/lib/utils'; import { useAtom } from 'jotai'; import { useTranslations } from 'next-intl'; import { CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; - -interface HabitStreakProps { - habits: Habit[] -} - -export default function HabitStreak({ habits }: HabitStreakProps) { +export default function HabitStreak({ habits }: { habits: Habit[] }) { const t = useTranslations('HabitStreak'); const [settings] = useAtom(settingsAtom) - const [hasTasks] = useAtom(hasTasksAtom) const [completedHabitsMap] = useAtom(completedHabitsMapAtom) // Use the atom // Get the last 7 days of data @@ -72,7 +66,7 @@ export default function HabitStreak({ habits }: HabitStreakProps) { strokeWidth={2} dot={false} /> - {hasTasks && ( + {habits.some(habit => habit.isTask === true) && ( habit.id === selectedHabitId) : null const [timeLeft, setTimeLeft] = useState(PomoConfigs.focus.duration) const [state, setState] = useState<'started' | 'stopped' | 'paused'>(autoStart ? 'started' : 'stopped') const wakeLock = useRef(null) - const [todayCompletions] = useAtom(pomodoroTodayCompletionsAtom) + const todayCompletions = getTodayCompletions(pomo, habitsData, settingsData); const currentTimerRef = useRef(PomoConfigs.focus) const [currentLabel, setCurrentLabel] = useState(() => { const labels = currentTimerRef.current.getLabels(); diff --git a/hooks/useHabits.tsx b/hooks/useHabits.tsx index 347d34a..2a60bbc 100644 --- a/hooks/useHabits.tsx +++ b/hooks/useHabits.tsx @@ -1,12 +1,13 @@ import { addCoins, removeCoins, saveHabitsData } from '@/app/actions/data' import { ToastAction } from '@/components/ui/toast' import { toast } from '@/hooks/use-toast' -import { coinsAtom, currentUserAtom, habitFreqMapAtom, habitsAtom, settingsAtom, usersAtom } from '@/lib/atoms' -import { Habit } from '@/lib/types' +import { coinsAtom, currentUserAtom, habitsAtom, settingsAtom } from '@/lib/atoms' +import { Freq, Habit } from '@/lib/types' import { d2s, d2t, getCompletionsForDate, + getHabitFreq, getISODate, getNow, getTodayInTimezone, @@ -23,12 +24,15 @@ import { useTranslations } from 'next-intl' export function useHabits() { const t = useTranslations('useHabits'); const tCommon = useTranslations('Common'); - const [usersData] = useAtom(usersAtom) const [currentUser] = useAtom(currentUserAtom) const [habitsData, setHabitsData] = useAtom(habitsAtom) const [coins, setCoins] = useAtom(coinsAtom) const [settings] = useAtom(settingsAtom) - const [habitFreqMap] = useAtom(habitFreqMapAtom) + // const [habitFreqMap] = useAtom(habitFreqMapAtom) + const habitFreqMap = new Map(); + habitsData.habits.forEach(habit => { + habitFreqMap.set(habit.id, getHabitFreq(habit)); + }) const completeHabit = async (habit: Habit) => { if (!handlePermissionCheck(currentUser, 'habit', 'interact', tCommon)) return diff --git a/lib/atoms.ts b/lib/atoms.ts index 423a127..e8e4730 100644 --- a/lib/atoms.ts +++ b/lib/atoms.ts @@ -114,7 +114,7 @@ export const coinsBalanceAtom = atom((get) => { }); /* transient atoms */ -interface PomodoroAtom { +export interface PomodoroAtom { show: boolean selectedHabitId: string | null autoStart: boolean @@ -191,38 +191,6 @@ export const completedHabitsMapAtom = atom((get) => { return map; }); -// Derived atom for habit frequency map -export const habitFreqMapAtom = atom((get) => { - const habits = get(habitsAtom).habits; - const map = new Map(); - habits.forEach(habit => { - map.set(habit.id, getHabitFreq(habit)); - }); - return map; -}); - -export const pomodoroTodayCompletionsAtom = atom((get) => { - const pomo = get(pomodoroAtom) - const habits = get(habitsAtom) - const settings = get(settingsAtom) - - if (!pomo.selectedHabitId) return 0 - - const selectedHabit = habits.habits.find(h => h.id === pomo.selectedHabitId!) - if (!selectedHabit) return 0 - - return getCompletionsForToday({ - habit: selectedHabit, - timezone: settings.system.timezone - }) -}) - -// Derived atom to check if any habits are tasks -export const hasTasksAtom = atom((get) => { - const habits = get(habitsAtom) - return habits.habits.some(habit => habit.isTask === true) -}) - // Atom family for habits by specific date export const habitsByDateFamily = atomFamily((dateString: string) => atom((get) => { diff --git a/lib/utils.ts b/lib/utils.ts index 8fb4df5..85e238a 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -6,6 +6,7 @@ import { DateTime, DateTimeFormatOptions } from "luxon" import { Formats } from "next-intl" import { datetime, RRule } from 'rrule' import { twMerge } from "tailwind-merge" +import { PomodoroAtom } from "./atoms" import { DUE_MAP, INITIAL_DUE, RECURRENCE_RULE_MAP } from "./constants" export function cn(...inputs: ClassValue[]) { @@ -84,6 +85,20 @@ export function getCompletionsForToday({ return getCompletionsForDate({ habit, date: getTodayInTimezone(timezone), timezone }) } +export function getTodayCompletions({ selectedHabitId }: PomodoroAtom, { habits }: HabitsData, { system: { timezone } }: Settings): number { + if (!selectedHabitId) + return 0; + + const selectedHabit = habits.find(h => h.id === selectedHabitId!); + if (!selectedHabit) + return 0; + + return getCompletionsForToday({ + habit: selectedHabit, + timezone: timezone + }); +} + export function getCompletedHabitsForDate({ habits, date,