mirror of
https://github.com/ManInDark/HabitTrove.git
synced 2026-03-08 03:29:49 +01:00
fix: migrate atoms to normal functions
This commit is contained in:
@@ -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({
|
||||
<CardContent>
|
||||
<div className="space-y-6">
|
||||
{/* Tasks Section */}
|
||||
{hasTasks && (
|
||||
{habits.some(habit => habit.isTask === true) && (
|
||||
<ItemSection
|
||||
title={t('dailyTasksTitle')}
|
||||
items={dailyTasks}
|
||||
|
||||
@@ -4,7 +4,7 @@ import CompletionCountBadge from '@/components/CompletionCountBadge'
|
||||
import { Calendar } from '@/components/ui/calendar'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { useHabits } from '@/hooks/useHabits'
|
||||
import { completedHabitsMapAtom, habitsAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms'
|
||||
import { completedHabitsMapAtom, habitsAtom, settingsAtom } from '@/lib/atoms'
|
||||
import { Habit } from '@/lib/types'
|
||||
import { d2s, getCompletionsForDate, getISODate, getNow, isHabitDue } from '@/lib/utils'
|
||||
import { useAtom } from 'jotai'
|
||||
@@ -29,7 +29,6 @@ export default function HabitCalendar() {
|
||||
const [selectedDateTime, setSelectedDateTime] = useState<DateTime>(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() {
|
||||
<CardContent>
|
||||
{selectedDateTime && (
|
||||
<div className="space-y-8">
|
||||
{hasTasks && (
|
||||
{habits.some(habit => habit.isTask === true) && (
|
||||
<div className="pt-2 border-t">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="font-medium text-sm text-muted-foreground uppercase tracking-wide">{t('tasksSectionTitle')}</h3>
|
||||
|
||||
@@ -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) && (
|
||||
<Line
|
||||
type="monotone"
|
||||
name={t('tooltipTasksLabel')}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { useHabits } from '@/hooks/useHabits'
|
||||
import { habitsAtom, pomodoroAtom, pomodoroTodayCompletionsAtom } from '@/lib/atoms'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { habitsAtom, pomodoroAtom, settingsAtom } from '@/lib/atoms'
|
||||
import { cn, getTodayCompletions } from '@/lib/utils'
|
||||
import { useAtom } from 'jotai'
|
||||
import { Clock, Minus, Pause, Play, RotateCw, SkipForward, X } from 'lucide-react'
|
||||
import { useTranslations } from 'next-intl'
|
||||
@@ -41,12 +41,13 @@ export default function PomodoroTimer() {
|
||||
const [pomo, setPomo] = useAtom(pomodoroAtom)
|
||||
const { show, selectedHabitId, autoStart, minimized } = pomo
|
||||
const [habitsData] = useAtom(habitsAtom)
|
||||
const [settingsData] = useAtom(settingsAtom)
|
||||
const { completeHabit } = useHabits()
|
||||
const selectedHabit = selectedHabitId ? habitsData.habits.find(habit => habit.id === selectedHabitId) : null
|
||||
const [timeLeft, setTimeLeft] = useState(PomoConfigs.focus.duration)
|
||||
const [state, setState] = useState<'started' | 'stopped' | 'paused'>(autoStart ? 'started' : 'stopped')
|
||||
const wakeLock = useRef<WakeLockSentinel | null>(null)
|
||||
const [todayCompletions] = useAtom(pomodoroTodayCompletionsAtom)
|
||||
const todayCompletions = getTodayCompletions(pomo, habitsData, settingsData);
|
||||
const currentTimerRef = useRef<PomoConfig>(PomoConfigs.focus)
|
||||
const [currentLabel, setCurrentLabel] = useState(() => {
|
||||
const labels = currentTimerRef.current.getLabels();
|
||||
|
||||
@@ -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<string, Freq>();
|
||||
habitsData.habits.forEach(habit => {
|
||||
habitFreqMap.set(habit.id, getHabitFreq(habit));
|
||||
})
|
||||
|
||||
const completeHabit = async (habit: Habit) => {
|
||||
if (!handlePermissionCheck(currentUser, 'habit', 'interact', tCommon)) return
|
||||
|
||||
34
lib/atoms.ts
34
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<string, Freq>();
|
||||
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) => {
|
||||
|
||||
15
lib/utils.ts
15
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,
|
||||
|
||||
Reference in New Issue
Block a user