From e908f1edecbc0e06680a9271a5933661a611b6da Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Wed, 14 May 2025 11:01:05 +0200 Subject: [PATCH] fix: resolved linting problems --- app/actions/data.ts | 40 +++++++++++------------ app/calendar/page.tsx | 3 -- app/coins/page.tsx | 1 - app/debug/habits/page.tsx | 1 - app/habits/page.tsx | 2 -- app/layout.tsx | 13 ++++---- app/settings/page.tsx | 16 ++++----- app/wishlist/page.tsx | 1 - components/AddEditHabitModal.tsx | 33 +++++++------------ components/AddEditWishlistItemModal.tsx | 19 ++++++----- components/ClientWrapper.tsx | 2 +- components/CoinsManager.tsx | 26 +++++++-------- components/CompletionCountBadge.tsx | 6 ++-- components/DailyOverview.tsx | 32 ++++++++---------- components/Dashboard.tsx | 8 ++--- components/HabitCalendar.tsx | 17 +++++----- components/HabitItem.tsx | 23 ++++++------- components/HabitList.tsx | 28 ++++++++-------- components/HabitStreak.tsx | 8 ++--- components/Header.tsx | 24 ++++---------- components/Logo.tsx | 1 - components/Navigation.tsx | 10 +++--- components/NotificationDropdown.tsx | 13 ++++---- components/PasswordEntryForm.tsx | 12 +++---- components/PomodoroTimer.tsx | 43 +++++++++++-------------- components/Profile.tsx | 20 ++++++------ components/UserForm.tsx | 25 +++++++------- components/UserSelectModal.tsx | 23 ++++++------- components/ViewToggle.tsx | 8 ++--- components/WishlistItem.tsx | 15 ++++----- components/theme-toggle.tsx | 3 +- lib/atoms.ts | 39 ++++++++++------------ 32 files changed, 222 insertions(+), 293 deletions(-) diff --git a/app/actions/data.ts b/app/actions/data.ts index 22614df..43865ec 100644 --- a/app/actions/data.ts +++ b/app/actions/data.ts @@ -1,36 +1,32 @@ 'use server' -import fs from 'fs/promises' -import path from 'path' +import { getCurrentUser, saltAndHashPassword, verifyPassword } from "@/lib/server-helpers"; import { - HabitsData, CoinsData, CoinTransaction, - TransactionType, - WishlistItemType, - WishlistData, - Settings, - DataType, DATA_DEFAULTS, - getDefaultSettings, - UserData, - getDefaultUsersData, - User, - getDefaultWishlistData, - getDefaultHabitsData, + DataType, getDefaultCoinsData, + getDefaultHabitsData, + getDefaultSettings, + getDefaultUsersData, + getDefaultWishlistData, + HabitsData, Permission, - ServerSettings -} from '@/lib/types' -import { d2t, deepMerge, getNow, checkPermission, uuid } from '@/lib/utils'; -import { verifyPassword } from "@/lib/server-helpers"; -import { saltAndHashPassword } from "@/lib/server-helpers"; + ServerSettings, + Settings, + TransactionType, + User, + UserData, + WishlistData, + WishlistItemType +} from '@/lib/types'; +import { d2t, getNow, uuid } from '@/lib/utils'; import { signInSchema } from '@/lib/zod'; -import { auth } from '@/auth'; +import fs from 'fs/promises'; import _ from 'lodash'; -import { getCurrentUser, getCurrentUserId } from '@/lib/server-helpers' +import path from 'path'; -import { PermissionError } from '@/lib/exceptions' type ResourceType = 'habit' | 'wishlist' | 'coins' type ActionType = 'write' | 'interact' diff --git a/app/calendar/page.tsx b/app/calendar/page.tsx index 8993563..f025056 100644 --- a/app/calendar/page.tsx +++ b/app/calendar/page.tsx @@ -1,7 +1,4 @@ -import Layout from '@/components/Layout' import HabitCalendar from '@/components/HabitCalendar' -import { ViewToggle } from '@/components/ViewToggle' -import CompletionCountBadge from '@/components/CompletionCountBadge' export default function CalendarPage() { return ( diff --git a/app/coins/page.tsx b/app/coins/page.tsx index 50b8552..7dec4ae 100644 --- a/app/coins/page.tsx +++ b/app/coins/page.tsx @@ -1,4 +1,3 @@ -import Layout from '@/components/Layout' import CoinsManager from '@/components/CoinsManager' export default function CoinsPage() { diff --git a/app/debug/habits/page.tsx b/app/debug/habits/page.tsx index 9ae7e84..2647ff5 100644 --- a/app/debug/habits/page.tsx +++ b/app/debug/habits/page.tsx @@ -1,6 +1,5 @@ 'use client' -import { useHabits } from "@/hooks/useHabits"; import { habitsAtom, settingsAtom } from "@/lib/atoms"; import { Habit } from "@/lib/types"; import { useAtom } from "jotai"; diff --git a/app/habits/page.tsx b/app/habits/page.tsx index 1e551f0..45ee2b6 100644 --- a/app/habits/page.tsx +++ b/app/habits/page.tsx @@ -1,6 +1,4 @@ -import Layout from '@/components/Layout' import HabitList from '@/components/HabitList' -import { ViewToggle } from '@/components/ViewToggle' export default function HabitsPage() { return ( diff --git a/app/layout.tsx b/app/layout.tsx index 169bb47..c6b2cbb 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,14 +1,13 @@ -import './globals.css' -import { Inter } from 'next/font/google' -import { DM_Sans } from 'next/font/google' -import { JotaiProvider } from '@/components/jotai-providers' -import { Suspense } from 'react' import { JotaiHydrate } from '@/components/jotai-hydrate' -import { loadSettings, loadHabitsData, loadCoinsData, loadWishlistData, loadUsersData, loadServerSettings } from './actions/data' +import { JotaiProvider } from '@/components/jotai-providers' import Layout from '@/components/Layout' -import { Toaster } from '@/components/ui/toaster' import { ThemeProvider } from "@/components/theme-provider" +import { Toaster } from '@/components/ui/toaster' import { SessionProvider } from 'next-auth/react' +import { DM_Sans } from 'next/font/google' +import { Suspense } from 'react' +import { loadCoinsData, loadHabitsData, loadServerSettings, loadSettings, loadUsersData, loadWishlistData } from './actions/data' +import './globals.css' // Inter (clean, modern, excellent readability) diff --git a/app/settings/page.tsx b/app/settings/page.tsx index a4c84d1..06be617 100644 --- a/app/settings/page.tsx +++ b/app/settings/page.tsx @@ -1,22 +1,20 @@ 'use client' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Switch } from '@/components/ui/switch'; +import { DynamicTimeNoSSR } from '@/components/DynamicTimeNoSSR'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Label } from '@/components/ui/label'; +import { Switch } from '@/components/ui/switch'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; -import { DynamicTimeNoSSR } from '@/components/DynamicTimeNoSSR'; -import { useAtom } from 'jotai'; import { settingsAtom } from '@/lib/atoms'; -import { Settings, WeekDay } from '@/lib/types' -import { saveSettings, uploadAvatar } from '../actions/data' -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' -import { Button } from '@/components/ui/button'; -import { User, Info } from 'lucide-react'; // Import Info icon +import { Settings, WeekDay } from '@/lib/types'; +import { useAtom } from 'jotai'; +import { Info } from 'lucide-react'; // Import Info icon +import { saveSettings } from '../actions/data'; export default function SettingsPage() { const [settings, setSettings] = useAtom(settingsAtom); diff --git a/app/wishlist/page.tsx b/app/wishlist/page.tsx index cfc410c..38a2b0a 100644 --- a/app/wishlist/page.tsx +++ b/app/wishlist/page.tsx @@ -1,4 +1,3 @@ -import Layout from '@/components/Layout' import WishlistManager from '@/components/WishlistManager' export default function WishlistPage() { diff --git a/components/AddEditHabitModal.tsx b/components/AddEditHabitModal.tsx index 980ee19..49a016e 100644 --- a/components/AddEditHabitModal.tsx +++ b/components/AddEditHabitModal.tsx @@ -1,33 +1,24 @@ 'use client' -import { useState } from 'react' -import { RRule, RRuleSet, rrulestr } from 'rrule' -import { useAtom } from 'jotai' -import { settingsAtom, browserSettingsAtom, usersAtom } from '@/lib/atoms' -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Button } from '@/components/ui/button' -import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' -import { Switch } from '@/components/ui/switch' +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' -import { Textarea } from '@/components/ui/textarea' -import { Info, SmilePlus, Zap } from 'lucide-react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' +import { Textarea } from '@/components/ui/textarea' +import { settingsAtom, usersAtom } from '@/lib/atoms' +import { useHelpers } from '@/lib/client-helpers' +import { INITIAL_DUE, INITIAL_RECURRENCE_RULE, QUICK_DATES } from '@/lib/constants' +import { Habit } from '@/lib/types' +import { convertHumanReadableFrequencyToMachineReadable, convertMachineReadableFrequencyToHumanReadable, d2t, serializeRRule } from '@/lib/utils' import data from '@emoji-mart/data' import Picker from '@emoji-mart/react' -import { Habit, SafeUser } from '@/lib/types' -import { convertHumanReadableFrequencyToMachineReadable, convertMachineReadableFrequencyToHumanReadable, d2s, d2t, serializeRRule } from '@/lib/utils' -import { INITIAL_DUE, INITIAL_RECURRENCE_RULE, QUICK_DATES, RECURRENCE_RULE_MAP } from '@/lib/constants' -import * as chrono from 'chrono-node'; +import { useAtom } from 'jotai' +import { SmilePlus, Zap } from 'lucide-react' import { DateTime } from 'luxon' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { useHelpers } from '@/lib/client-helpers' +import { useState } from 'react' +import { RRule } from 'rrule' interface AddEditHabitModalProps { onClose: () => void diff --git a/components/AddEditWishlistItemModal.tsx b/components/AddEditWishlistItemModal.tsx index ea74788..d294a46 100644 --- a/components/AddEditWishlistItemModal.tsx +++ b/components/AddEditWishlistItemModal.tsx @@ -1,19 +1,18 @@ -import { useState, useEffect } from 'react' -import { useAtom } from 'jotai' -import { usersAtom } from '@/lib/atoms' -import { useHelpers } from '@/lib/client-helpers' -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' -import { Textarea } from '@/components/ui/textarea' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' -import { SmilePlus, Info } from 'lucide-react' +import { Textarea } from '@/components/ui/textarea' +import { usersAtom } from '@/lib/atoms' +import { useHelpers } from '@/lib/client-helpers' +import { WishlistItemType } from '@/lib/types' import data from '@emoji-mart/data' import Picker from '@emoji-mart/react' -import { WishlistItemType } from '@/lib/types' +import { useAtom } from 'jotai' +import { SmilePlus } from 'lucide-react' +import { useEffect, useState } from 'react' +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' interface AddEditWishlistItemModalProps { isOpen: boolean diff --git a/components/ClientWrapper.tsx b/components/ClientWrapper.tsx index 02cb251..9235c92 100644 --- a/components/ClientWrapper.tsx +++ b/components/ClientWrapper.tsx @@ -18,7 +18,7 @@ export default function ClientWrapper({ children }: { children: ReactNode }) { if (!currentUserId && !userSelect) { setUserSelect(true) } - }, [currentUserId, status, userSelect]) + }, [currentUserId, status, userSelect, setUserSelect]) return ( <> diff --git a/components/CoinsManager.tsx b/components/CoinsManager.tsx index 3111070..f973830 100644 --- a/components/CoinsManager.tsx +++ b/components/CoinsManager.tsx @@ -1,21 +1,21 @@ 'use client' -import { useState, useEffect, useRef } from 'react' // Import useEffect, useRef -import { useSearchParams } from 'next/navigation' // Import useSearchParams -import { t2d, d2s, getNow, isSameDate } from '@/lib/utils' -import { Button } from '@/components/ui/button' import { FormattedNumber } from '@/components/FormattedNumber' -import { History, Pencil } from 'lucide-react' -import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' -import EmptyState from './EmptyState' -import { Input } from '@/components/ui/input' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { Button } from '@/components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { settingsAtom, usersAtom } from '@/lib/atoms' -import Link from 'next/link' -import { useAtom } from 'jotai' +import { Input } from '@/components/ui/input' import { useCoins } from '@/hooks/useCoins' -import { TransactionNoteEditor } from './TransactionNoteEditor' +import { settingsAtom, usersAtom } from '@/lib/atoms' import { useHelpers } from '@/lib/client-helpers' +import { d2s, t2d } from '@/lib/utils' +import { useAtom } from 'jotai' +import { History } from 'lucide-react' +import Link from 'next/link' +import { useSearchParams } from 'next/navigation'; // Import useSearchParams +import { useEffect, useRef, useState } from 'react'; // Import useEffect, useRef +import EmptyState from './EmptyState' +import { TransactionNoteEditor } from './TransactionNoteEditor' export default function CoinsManager() { const { currentUser } = useHelpers() @@ -53,7 +53,7 @@ export default function CoinsManager() { } } // Only run when userIdFromQuery or currentUser changes, avoid re-running on selectedUser change within this effect - }, [userIdFromQuery, currentUser, usersData.users]); + }, [userIdFromQuery, currentUser, usersData.users, selectedUser]); // Effect to scroll to highlighted transaction useEffect(() => { diff --git a/components/CompletionCountBadge.tsx b/components/CompletionCountBadge.tsx index 688d1e4..d82593d 100644 --- a/components/CompletionCountBadge.tsx +++ b/components/CompletionCountBadge.tsx @@ -1,9 +1,7 @@ import { Badge } from "@/components/ui/badge" -import { useAtom } from 'jotai' -import { completedHabitsMapAtom, habitsAtom, habitsByDateFamily } from '@/lib/atoms' +import { completedHabitsMapAtom, habitsByDateFamily, settingsAtom } from '@/lib/atoms' import { getTodayInTimezone } from '@/lib/utils' -import { useHabits } from '@/hooks/useHabits' -import { settingsAtom } from '@/lib/atoms' +import { useAtom } from 'jotai' interface CompletionCountBadgeProps { type: 'habits' | 'tasks' diff --git a/components/DailyOverview.tsx b/components/DailyOverview.tsx index cfd49cf..69091f6 100644 --- a/components/DailyOverview.tsx +++ b/components/DailyOverview.tsx @@ -1,35 +1,31 @@ -import { Circle, Coins, ArrowRight, CircleCheck, ChevronDown, ChevronUp, Plus, Pin, AlertTriangle } from 'lucide-react' // Removed unused icons -import CompletionCountBadge from './CompletionCountBadge' +import { Badge } from '@/components/ui/badge' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { ContextMenu, ContextMenuContent, - ContextMenuItem, - ContextMenuSeparator, - ContextMenuTrigger, + ContextMenuTrigger } from "@/components/ui/context-menu" -import { cn } from '@/lib/utils' -import Link from 'next/link' -import { useState } from 'react' -import { useAtom } from 'jotai' -import { pomodoroAtom, settingsAtom, completedHabitsMapAtom, browserSettingsAtom, BrowserSettings, hasTasksAtom } from '@/lib/atoms' -import { getTodayInTimezone, isSameDate, t2d, d2t, getNow, isHabitDue, isTaskOverdue } from '@/lib/utils' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Badge } from '@/components/ui/badge' +import { Progress } from '@/components/ui/progress' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip" -import { Progress } from '@/components/ui/progress' -import { Settings, WishlistItemType } from '@/lib/types' -import { Habit } from '@/lib/types' -import Linkify from './linkify' import { useHabits } from '@/hooks/useHabits' +import { browserSettingsAtom, completedHabitsMapAtom, hasTasksAtom, pomodoroAtom, settingsAtom } from '@/lib/atoms' +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 Link from 'next/link' +import { useState } from 'react' import AddEditHabitModal from './AddEditHabitModal' +import CompletionCountBadge from './CompletionCountBadge' import ConfirmDialog from './ConfirmDialog' -import { Button } from './ui/button' import { HabitContextMenuItems } from './HabitContextMenuItems' +import Linkify from './linkify' +import { Button } from './ui/button' interface UpcomingItemsProps { habits: Habit[] diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx index 86899ec..51d7532 100644 --- a/components/Dashboard.tsx +++ b/components/Dashboard.tsx @@ -1,17 +1,15 @@ 'use client' +import { useCoins } from '@/hooks/useCoins' +import { habitsAtom, wishlistAtom } from '@/lib/atoms' import { useAtom } from 'jotai' -import { wishlistAtom, habitsAtom, settingsAtom } from '@/lib/atoms' +import CoinBalance from './CoinBalance' import DailyOverview from './DailyOverview' import HabitStreak from './HabitStreak' -import CoinBalance from './CoinBalance' -import { useHabits } from '@/hooks/useHabits' -import { useCoins } from '@/hooks/useCoins' export default function Dashboard() { const [habitsData] = useAtom(habitsAtom) const habits = habitsData.habits - const [settings] = useAtom(settingsAtom) const { balance } = useCoins() const [wishlist] = useAtom(wishlistAtom) const wishlistItems = wishlist.items diff --git a/components/HabitCalendar.tsx b/components/HabitCalendar.tsx index 48c22db..8510ea9 100644 --- a/components/HabitCalendar.tsx +++ b/components/HabitCalendar.tsx @@ -1,18 +1,17 @@ 'use client' -import { useState, useMemo, useCallback } from 'react' +import CompletionCountBadge from '@/components/CompletionCountBadge' import { Calendar } from '@/components/ui/calendar' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import CompletionCountBadge from '@/components/CompletionCountBadge' -import { Button } from '@/components/ui/button' -import { Check, Circle, CircleCheck } from 'lucide-react' -import { d2s, getNow, t2d, getCompletedHabitsForDate, isHabitDue, getISODate, getCompletionsForToday, getCompletionsForDate } from '@/lib/utils' -import { useAtom } from 'jotai' import { useHabits } from '@/hooks/useHabits' -import { habitsAtom, settingsAtom, completedHabitsMapAtom, hasTasksAtom } from '@/lib/atoms' -import { DateTime } from 'luxon' -import Linkify from './linkify' +import { completedHabitsMapAtom, habitsAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms' import { Habit } from '@/lib/types' +import { d2s, getCompletionsForDate, getISODate, getNow, isHabitDue } from '@/lib/utils' +import { useAtom } from 'jotai' +import { Circle, CircleCheck } from 'lucide-react' +import { DateTime } from 'luxon' +import { useCallback, useMemo, useState } from 'react' +import Linkify from './linkify' export default function HabitCalendar() { const { completePastHabit } = useHabits() diff --git a/components/HabitItem.tsx b/components/HabitItem.tsx index 4b6165f..21febf0 100644 --- a/components/HabitItem.tsx +++ b/components/HabitItem.tsx @@ -1,24 +1,20 @@ -import { Habit, SafeUser, User, Permission } from '@/lib/types' -import { useAtom } from 'jotai' -import { settingsAtom, pomodoroAtom, browserSettingsAtom, usersAtom } from '@/lib/atoms' -import { getTodayInTimezone, isSameDate, t2d, d2t, getNow, d2s, getCompletionsForToday, isTaskOverdue, convertMachineReadableFrequencyToHumanReadable } from '@/lib/utils' -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' -import { Coins, Edit, Check, Undo2, MoreVertical, Pin } from 'lucide-react' // Removed unused icons +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { DropdownMenu, DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenuTrigger } from '@/components/ui/dropdown-menu' -import { useEffect, useState } from 'react' import { useHabits } from '@/hooks/useHabits' -import { INITIAL_RECURRENCE_RULE, RECURRENCE_RULE_MAP } from '@/lib/constants' -import { DateTime } from 'luxon' -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' +import { browserSettingsAtom, settingsAtom, usersAtom } from '@/lib/atoms' import { useHelpers } from '@/lib/client-helpers' +import { Habit, User } from '@/lib/types' +import { convertMachineReadableFrequencyToHumanReadable, getCompletionsForToday, isTaskOverdue } from '@/lib/utils' +import { useAtom } from 'jotai' +import { Check, Coins, Edit, MoreVertical, Pin, Undo2 } from 'lucide-react'; // Removed unused icons +import { useEffect, useState } from 'react' import { HabitContextMenuItems } from './HabitContextMenuItems' +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' interface HabitItemProps { habit: Habit @@ -49,7 +45,6 @@ const renderUserAvatars = (habit: Habit, currentUser: User | null, usersData: { export default function HabitItem({ habit, onEdit, onDelete }: HabitItemProps) { const { completeHabit, undoComplete, archiveHabit, unarchiveHabit, saveHabit } = useHabits() const [settings] = useAtom(settingsAtom) - const [_, setPomo] = useAtom(pomodoroAtom) const completionsToday = getCompletionsForToday({ habit, timezone: settings.system.timezone }) const target = habit.targetCompletions || 1 const isCompletedToday = completionsToday >= target diff --git a/components/HabitList.tsx b/components/HabitList.tsx index 1b4af51..a19ccd1 100644 --- a/components/HabitList.tsx +++ b/components/HabitList.tsx @@ -1,23 +1,23 @@ 'use client' -import { useState, useMemo, useEffect } from 'react' // Added useMemo, useEffect -import { Plus, ArrowUpNarrowWide, ArrowDownWideNarrow, Search } from 'lucide-react' // Added sort icons, Search icon -import { useAtom } from 'jotai' -import { habitsAtom, settingsAtom, browserSettingsAtom } from '@/lib/atoms' -import EmptyState from './EmptyState' import { Button } from '@/components/ui/button' -import HabitItem from './HabitItem' +import { Input } from '@/components/ui/input'; // Added +import { Label } from '@/components/ui/label'; // Added +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; // Added +import { useHabits } from '@/hooks/useHabits' +import { browserSettingsAtom, habitsAtom } from '@/lib/atoms' +import { HabitIcon, TaskIcon } from '@/lib/constants' +import { Habit } from '@/lib/types' +import { getHabitFreq } from '@/lib/utils'; // Added +import { useAtom } from 'jotai' +import { ArrowDownWideNarrow, ArrowUpNarrowWide, Plus, Search } from 'lucide-react'; // Added sort icons, Search icon +import { DateTime } from 'luxon'; // Added +import { useEffect, useMemo, useState } from 'react'; // Added useMemo, useEffect import AddEditHabitModal from './AddEditHabitModal' import ConfirmDialog from './ConfirmDialog' -import { Habit } from '@/lib/types' -import { useHabits } from '@/hooks/useHabits' -import { HabitIcon, TaskIcon } from '@/lib/constants' +import EmptyState from './EmptyState' +import HabitItem from './HabitItem' import { ViewToggle } from './ViewToggle' -import { Input } from '@/components/ui/input' // Added -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' // Added -import { Label } from '@/components/ui/label' // Added -import { DateTime } from 'luxon' // Added -import { getHabitFreq } from '@/lib/utils' // Added export default function HabitList() { const { saveHabit, deleteHabit } = useHabits() diff --git a/components/HabitStreak.tsx b/components/HabitStreak.tsx index 9462283..ef273f4 100644 --- a/components/HabitStreak.tsx +++ b/components/HabitStreak.tsx @@ -1,11 +1,11 @@ 'use client' -import { Habit } from '@/lib/types' import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { d2s, getNow, t2d } from '@/lib/utils' // Removed getCompletedHabitsForDate -import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts' +import { completedHabitsMapAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms'; // Added completedHabitsMapAtom +import { Habit } from '@/lib/types' +import { d2s, getNow } from '@/lib/utils'; // Removed getCompletedHabitsForDate import { useAtom } from 'jotai' -import { settingsAtom, hasTasksAtom, completedHabitsMapAtom } from '@/lib/atoms' // Added completedHabitsMapAtom +import { CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts' interface HabitStreakProps { habits: Habit[] diff --git a/components/Header.tsx b/components/Header.tsx index fcbdd60..6b6caff 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,26 +1,15 @@ 'use client' -import { useEffect, useState } from 'react' -import { useAtom } from 'jotai' -import { coinsAtom, settingsAtom, browserSettingsAtom } from '@/lib/atoms' -import { useCoins } from '@/hooks/useCoins' import { FormattedNumber } from '@/components/FormattedNumber' -import { Menu, Settings, User, Info, Coins } from 'lucide-react' -import { Button } from '@/components/ui/button' import { Logo } from '@/components/Logo' -import NotificationBell from './NotificationBell' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' -import AboutModal from './AboutModal' -import Link from 'next/link' +import { useCoins } from '@/hooks/useCoins' +import { settingsAtom } from '@/lib/atoms' +import { useAtom } from 'jotai' +import { Coins } from 'lucide-react' import dynamic from 'next/dynamic' +import Link from 'next/link' +import NotificationBell from './NotificationBell' import { Profile } from './Profile' -import { useHelpers } from '@/lib/client-helpers' interface HeaderProps { className?: string @@ -30,7 +19,6 @@ const TodayEarnedCoins = dynamic(() => import('./TodayEarnedCoins'), { ssr: fals export default function Header({ className }: HeaderProps) { const [settings] = useAtom(settingsAtom) - const [browserSettings] = useAtom(browserSettingsAtom) const { balance } = useCoins() return ( <> diff --git a/components/Logo.tsx b/components/Logo.tsx index 0beafe4..8fb29b2 100644 --- a/components/Logo.tsx +++ b/components/Logo.tsx @@ -1,4 +1,3 @@ -import { Sparkles } from "lucide-react" export function Logo() { return ( diff --git a/components/Navigation.tsx b/components/Navigation.tsx index b869b3d..a800849 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -1,13 +1,13 @@ 'use client' -import Link from 'next/link' -import { Home, Calendar, List, Gift, Coins, Settings, Info, CheckSquare } from 'lucide-react' -import { useAtom } from 'jotai' import { browserSettingsAtom } from '@/lib/atoms' +import { useHelpers } from '@/lib/client-helpers' +import { HabitIcon, TaskIcon } from '@/lib/constants' +import { useAtom } from 'jotai' +import { Calendar, Coins, Gift, Home } from 'lucide-react' +import Link from 'next/link' import { useEffect, useState } from 'react' import AboutModal from './AboutModal' -import { HabitIcon, TaskIcon } from '@/lib/constants' -import { useHelpers } from '@/lib/client-helpers' type ViewPort = 'main' | 'mobile' diff --git a/components/NotificationDropdown.tsx b/components/NotificationDropdown.tsx index fbb1745..c75fcd9 100644 --- a/components/NotificationDropdown.tsx +++ b/components/NotificationDropdown.tsx @@ -1,18 +1,17 @@ -import React from 'react'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { DropdownMenuItem } from '@/components/ui/dropdown-menu'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { CoinsData, HabitsData, WishlistData, UserData, User, CoinTransaction } from '@/lib/types'; -import { t2d } from '@/lib/utils'; -import Link from 'next/link'; -import { DropdownMenuItem } from '@/components/ui/dropdown-menu'; -import { Info } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; +import { CoinTransaction, HabitsData, User, UserData, WishlistData } from '@/lib/types'; +import { t2d } from '@/lib/utils'; +import { Info } from 'lucide-react'; +import Link from 'next/link'; interface NotificationDropdownProps { currentUser: User | null; diff --git a/components/PasswordEntryForm.tsx b/components/PasswordEntryForm.tsx index 56a6eb1..532776a 100644 --- a/components/PasswordEntryForm.tsx +++ b/components/PasswordEntryForm.tsx @@ -1,13 +1,13 @@ 'use client'; -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; -import { Input } from './ui/input'; -import { Button } from './ui/button'; -import { Label } from './ui/label'; -import { User as UserIcon } from 'lucide-react'; -import { Permission, User } from '@/lib/types'; import { toast } from '@/hooks/use-toast'; +import { User } from '@/lib/types'; +import { User as UserIcon } from 'lucide-react'; import { useState } from 'react'; +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; +import { Button } from './ui/button'; +import { Input } from './ui/input'; +import { Label } from './ui/label'; interface PasswordEntryFormProps { user: User; diff --git a/components/PomodoroTimer.tsx b/components/PomodoroTimer.tsx index d492364..773e624 100644 --- a/components/PomodoroTimer.tsx +++ b/components/PomodoroTimer.tsx @@ -1,14 +1,13 @@ 'use client' -import { useState, useEffect, useRef, useCallback } from 'react' import { Button } from '@/components/ui/button' import { Progress } from '@/components/ui/progress' -import { Play, Pause, RotateCw, Minus, X, Clock, SkipForward } from 'lucide-react' -import { cn, getCompletionsForToday } from '@/lib/utils' -import { useAtom } from 'jotai' -import { settingsAtom, pomodoroAtom, habitsAtom, pomodoroTodayCompletionsAtom } from '@/lib/atoms' -import { getCompletionsForDate, getTodayInTimezone } from '@/lib/utils' import { useHabits } from '@/hooks/useHabits' +import { habitsAtom, pomodoroAtom, pomodoroTodayCompletionsAtom, settingsAtom } from '@/lib/atoms' +import { cn } from '@/lib/utils' +import { useAtom } from 'jotai' +import { Clock, Minus, Pause, Play, RotateCw, SkipForward, X } from 'lucide-react' +import { useEffect, useRef, useState } from 'react' interface PomoConfig { labels: string[] @@ -135,7 +134,19 @@ export default function PomodoroTimer() { const remaining = Math.floor((targetEndTime - Date.now()) / 1000) if (remaining <= 0) { - handleTimerEnd() + setState("stopped") + const currentTimerType = currentTimer.current.type + currentTimer.current = currentTimerType === 'focus' ? PomoConfigs.break : PomoConfigs.focus + setTimeLeft(currentTimer.current.duration) + setCurrentLabel( + currentTimer.current.labels[Math.floor(Math.random() * currentTimer.current.labels.length)] + ) + + // update habits only after focus sessions + if (selectedHabit && currentTimerType === 'focus') { + completeHabit(selectedHabit) + // The atom will automatically update with the new completions + } } else { setTimeLeft(remaining) } @@ -146,23 +157,7 @@ export default function PomodoroTimer() { return () => { if (interval) clearInterval(interval) } - }, [state]) - - const handleTimerEnd = async () => { - setState("stopped") - const currentTimerType = currentTimer.current.type - currentTimer.current = currentTimerType === 'focus' ? PomoConfigs.break : PomoConfigs.focus - setTimeLeft(currentTimer.current.duration) - setCurrentLabel( - currentTimer.current.labels[Math.floor(Math.random() * currentTimer.current.labels.length)] - ) - - // update habits only after focus sessions - if (selectedHabit && currentTimerType === 'focus') { - await completeHabit(selectedHabit) - // The atom will automatically update with the new completions - } - } + }, [state, timeLeft, completeHabit, selectedHabit]) const toggleTimer = () => { setState(prev => prev === 'started' ? 'paused' : 'started') diff --git a/components/Profile.tsx b/components/Profile.tsx index b421212..48f4a57 100644 --- a/components/Profile.tsx +++ b/components/Profile.tsx @@ -1,20 +1,20 @@ 'use client' +import { signOut } from "@/app/actions/user" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" -import { Settings, Info, User, Moon, Sun, Palette, ArrowRightLeft, LogOut, Crown } from "lucide-react" +import { toast } from "@/hooks/use-toast" +import { settingsAtom, userSelectAtom } from "@/lib/atoms" +import { useHelpers } from "@/lib/client-helpers" +import { useAtom } from "jotai" +import { ArrowRightLeft, Crown, Info, LogOut, Moon, Palette, Settings, Sun, User } from "lucide-react" +import { useTheme } from "next-themes" +import Link from "next/link" +import { useState } from "react" +import AboutModal from "./AboutModal" import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog' import UserForm from './UserForm' -import Link from "next/link" -import { useAtom } from "jotai" -import { settingsAtom, userSelectAtom } from "@/lib/atoms" -import AboutModal from "./AboutModal" -import { useEffect, useState } from "react" -import { useTheme } from "next-themes" -import { signOut } from "@/app/actions/user" -import { toast } from "@/hooks/use-toast" -import { useHelpers } from "@/lib/client-helpers" export function Profile() { const [settings] = useAtom(settingsAtom) diff --git a/components/UserForm.tsx b/components/UserForm.tsx index 06c0f65..47bb4c3 100644 --- a/components/UserForm.tsx +++ b/components/UserForm.tsx @@ -1,22 +1,21 @@ 'use client'; -import { useState } from 'react'; +import { createUser, updateUser, updateUserPassword, uploadAvatar } from '@/app/actions/data'; +import { toast } from '@/hooks/use-toast'; +import { serverSettingsAtom, usersAtom } from '@/lib/atoms'; +import { useHelpers } from '@/lib/client-helpers'; +import { Permission } from '@/lib/types'; import { passwordSchema, usernameSchema } from '@/lib/zod'; -import { Input } from './ui/input'; +import { useAtom, useAtomValue } from 'jotai'; +import _ from 'lodash'; +import { User as UserIcon } from 'lucide-react'; +import { useState } from 'react'; +import { PermissionSelector } from './PermissionSelector'; +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; import { Button } from './ui/button'; +import { Input } from './ui/input'; import { Label } from './ui/label'; import { Switch } from './ui/switch'; -import { Permission } from '@/lib/types'; -import { toast } from '@/hooks/use-toast'; -import { useAtom, useAtomValue } from 'jotai'; -import { serverSettingsAtom, usersAtom } from '@/lib/atoms'; -import { createUser, updateUser, updateUserPassword, uploadAvatar } from '@/app/actions/data'; -import { SafeUser, User } from '@/lib/types'; -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; -import { User as UserIcon } from 'lucide-react'; -import _ from 'lodash'; -import { PermissionSelector } from './PermissionSelector'; -import { useHelpers } from '@/lib/client-helpers'; interface UserFormProps { userId?: string; // if provided, we're editing; if not, we're creating diff --git a/components/UserSelectModal.tsx b/components/UserSelectModal.tsx index a841449..1d18d5c 100644 --- a/components/UserSelectModal.tsx +++ b/components/UserSelectModal.tsx @@ -1,22 +1,19 @@ 'use client'; +import { signIn } from '@/app/actions/user'; +import { toast } from '@/hooks/use-toast'; +import { usersAtom } from '@/lib/atoms'; +import { useHelpers } from '@/lib/client-helpers'; +import { SafeUser, User } from '@/lib/types'; +import { cn } from '@/lib/utils'; +import { Description } from '@radix-ui/react-dialog'; +import { useAtom } from 'jotai'; +import { Crown, Plus, User as UserIcon, UserRoundPen } from 'lucide-react'; import { useState } from 'react'; import PasswordEntryForm from './PasswordEntryForm'; import UserForm from './UserForm'; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog'; import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; -import { Crown, Pencil, Plus, User as UserIcon, UserRoundPen } from 'lucide-react'; -import { Input } from './ui/input'; -import { Button } from './ui/button'; -import { useAtom } from 'jotai'; -import { usersAtom } from '@/lib/atoms'; -import { signIn } from '@/app/actions/user'; -import { createUser } from '@/app/actions/data'; -import { toast } from '@/hooks/use-toast'; -import { Description } from '@radix-ui/react-dialog'; -import { SafeUser, User } from '@/lib/types'; -import { cn } from '@/lib/utils'; -import { useHelpers } from '@/lib/client-helpers'; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog'; function UserCard({ user, diff --git a/components/ViewToggle.tsx b/components/ViewToggle.tsx index ba659e1..b76bc92 100644 --- a/components/ViewToggle.tsx +++ b/components/ViewToggle.tsx @@ -1,12 +1,10 @@ 'use client' -import { cn } from '@/lib/utils' -import { useAtom } from 'jotai' -import { CheckSquare, ListChecks } from 'lucide-react' import { browserSettingsAtom, habitsAtom, settingsAtom } from '@/lib/atoms' -import type { ViewType } from '@/lib/types' import { HabitIcon, TaskIcon } from '@/lib/constants' -import { isHabitDueToday } from '@/lib/utils' +import type { ViewType } from '@/lib/types' +import { cn, isHabitDueToday } from '@/lib/utils' +import { useAtom } from 'jotai' import { NotificationBadge } from './ui/notification-badge' interface ViewToggleProps { diff --git a/components/WishlistItem.tsx b/components/WishlistItem.tsx index b30f5ff..4a8a09b 100644 --- a/components/WishlistItem.tsx +++ b/components/WishlistItem.tsx @@ -1,12 +1,5 @@ -import { WishlistItemType, User, Permission } from '@/lib/types' -import { useAtom } from 'jotai' -import { usersAtom } from '@/lib/atoms' -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' -import { useHelpers } from '@/lib/client-helpers' -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' -import ReactMarkdown from 'react-markdown' import { Button } from '@/components/ui/button' -import { Coins, Edit, Trash2, Gift, MoreVertical, Archive, ArchiveRestore } from 'lucide-react' +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { DropdownMenu, DropdownMenuContent, @@ -14,6 +7,12 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' +import { usersAtom } from '@/lib/atoms' +import { useHelpers } from '@/lib/client-helpers' +import { User, WishlistItemType } from '@/lib/types' +import { useAtom } from 'jotai' +import { Archive, ArchiveRestore, Coins, Edit, Gift, MoreVertical, Trash2 } from 'lucide-react' +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar' interface WishlistItemProps { item: WishlistItemType diff --git a/components/theme-toggle.tsx b/components/theme-toggle.tsx index 64aa8cc..3bbc205 100644 --- a/components/theme-toggle.tsx +++ b/components/theme-toggle.tsx @@ -1,7 +1,6 @@ "use client" -import * as React from "react" -import { Moon, MoonIcon, Sun } from "lucide-react" +import { Moon, Sun } from "lucide-react" import { useTheme } from "next-themes" import { Button } from "@/components/ui/button" diff --git a/lib/atoms.ts b/lib/atoms.ts index 2302d19..160c9b4 100644 --- a/lib/atoms.ts +++ b/lib/atoms.ts @@ -1,35 +1,30 @@ -import { atom } from "jotai"; import { - getDefaultSettings, - getDefaultHabitsData, - getDefaultCoinsData, - getDefaultWishlistData, - Habit, - ViewType, - getDefaultUsersData, - CompletionCache, - getDefaultServerSettings, - User, -} from "./types"; -import { - getTodayInTimezone, - isSameDate, - t2d, calculateCoinsEarnedToday, + calculateCoinsSpentToday, calculateTotalEarned, calculateTotalSpent, - calculateCoinsSpentToday, calculateTransactionsToday, getCompletionsForToday, - getISODate, - isHabitDueToday, - getNow, + getHabitFreq, + getTodayInTimezone, isHabitDue, - getHabitFreq + t2d } from "@/lib/utils"; +import { atom } from "jotai"; import { atomFamily, atomWithStorage } from "jotai/utils"; import { DateTime } from "luxon"; -import { Freq } from "./types"; +import { + CompletionCache, + Freq, + getDefaultCoinsData, + getDefaultHabitsData, + getDefaultServerSettings, + getDefaultSettings, + getDefaultUsersData, + getDefaultWishlistData, + Habit, + ViewType +} from "./types"; export interface BrowserSettings { viewType: ViewType