fix: resolved linting problems

This commit is contained in:
2025-05-14 11:01:05 +02:00
parent 8e6ddf0b9f
commit e908f1edec
32 changed files with 222 additions and 293 deletions

View File

@@ -1,36 +1,32 @@
'use server' 'use server'
import fs from 'fs/promises' import { getCurrentUser, saltAndHashPassword, verifyPassword } from "@/lib/server-helpers";
import path from 'path'
import { import {
HabitsData,
CoinsData, CoinsData,
CoinTransaction, CoinTransaction,
TransactionType,
WishlistItemType,
WishlistData,
Settings,
DataType,
DATA_DEFAULTS, DATA_DEFAULTS,
getDefaultSettings, DataType,
UserData,
getDefaultUsersData,
User,
getDefaultWishlistData,
getDefaultHabitsData,
getDefaultCoinsData, getDefaultCoinsData,
getDefaultHabitsData,
getDefaultSettings,
getDefaultUsersData,
getDefaultWishlistData,
HabitsData,
Permission, Permission,
ServerSettings ServerSettings,
} from '@/lib/types' Settings,
import { d2t, deepMerge, getNow, checkPermission, uuid } from '@/lib/utils'; TransactionType,
import { verifyPassword } from "@/lib/server-helpers"; User,
import { saltAndHashPassword } from "@/lib/server-helpers"; UserData,
WishlistData,
WishlistItemType
} from '@/lib/types';
import { d2t, getNow, uuid } from '@/lib/utils';
import { signInSchema } from '@/lib/zod'; import { signInSchema } from '@/lib/zod';
import { auth } from '@/auth'; import fs from 'fs/promises';
import _ from 'lodash'; 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 ResourceType = 'habit' | 'wishlist' | 'coins'
type ActionType = 'write' | 'interact' type ActionType = 'write' | 'interact'

View File

@@ -1,7 +1,4 @@
import Layout from '@/components/Layout'
import HabitCalendar from '@/components/HabitCalendar' import HabitCalendar from '@/components/HabitCalendar'
import { ViewToggle } from '@/components/ViewToggle'
import CompletionCountBadge from '@/components/CompletionCountBadge'
export default function CalendarPage() { export default function CalendarPage() {
return ( return (

View File

@@ -1,4 +1,3 @@
import Layout from '@/components/Layout'
import CoinsManager from '@/components/CoinsManager' import CoinsManager from '@/components/CoinsManager'
export default function CoinsPage() { export default function CoinsPage() {

View File

@@ -1,6 +1,5 @@
'use client' 'use client'
import { useHabits } from "@/hooks/useHabits";
import { habitsAtom, settingsAtom } from "@/lib/atoms"; import { habitsAtom, settingsAtom } from "@/lib/atoms";
import { Habit } from "@/lib/types"; import { Habit } from "@/lib/types";
import { useAtom } from "jotai"; import { useAtom } from "jotai";

View File

@@ -1,6 +1,4 @@
import Layout from '@/components/Layout'
import HabitList from '@/components/HabitList' import HabitList from '@/components/HabitList'
import { ViewToggle } from '@/components/ViewToggle'
export default function HabitsPage() { export default function HabitsPage() {
return ( return (

View File

@@ -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 { 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 Layout from '@/components/Layout'
import { Toaster } from '@/components/ui/toaster'
import { ThemeProvider } from "@/components/theme-provider" import { ThemeProvider } from "@/components/theme-provider"
import { Toaster } from '@/components/ui/toaster'
import { SessionProvider } from 'next-auth/react' 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) // Inter (clean, modern, excellent readability)

View File

@@ -1,22 +1,20 @@
'use client' 'use client'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { DynamicTimeNoSSR } from '@/components/DynamicTimeNoSSR';
import { Switch } from '@/components/ui/switch'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { DynamicTimeNoSSR } from '@/components/DynamicTimeNoSSR';
import { useAtom } from 'jotai';
import { settingsAtom } from '@/lib/atoms'; import { settingsAtom } from '@/lib/atoms';
import { Settings, WeekDay } from '@/lib/types' import { Settings, WeekDay } from '@/lib/types';
import { saveSettings, uploadAvatar } from '../actions/data' import { useAtom } from 'jotai';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Info } from 'lucide-react'; // Import Info icon
import { Button } from '@/components/ui/button'; import { saveSettings } from '../actions/data';
import { User, Info } from 'lucide-react'; // Import Info icon
export default function SettingsPage() { export default function SettingsPage() {
const [settings, setSettings] = useAtom(settingsAtom); const [settings, setSettings] = useAtom(settingsAtom);

View File

@@ -1,4 +1,3 @@
import Layout from '@/components/Layout'
import WishlistManager from '@/components/WishlistManager' import WishlistManager from '@/components/WishlistManager'
export default function WishlistPage() { export default function WishlistPage() {

View File

@@ -1,33 +1,24 @@
'use client' 'use client'
import { useState } from 'react' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
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 { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Switch } from '@/components/ui/switch'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' 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 { 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 data from '@emoji-mart/data'
import Picker from '@emoji-mart/react' import Picker from '@emoji-mart/react'
import { Habit, SafeUser } from '@/lib/types' import { useAtom } from 'jotai'
import { convertHumanReadableFrequencyToMachineReadable, convertMachineReadableFrequencyToHumanReadable, d2s, d2t, serializeRRule } from '@/lib/utils' import { SmilePlus, Zap } from 'lucide-react'
import { INITIAL_DUE, INITIAL_RECURRENCE_RULE, QUICK_DATES, RECURRENCE_RULE_MAP } from '@/lib/constants'
import * as chrono from 'chrono-node';
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import { import { useState } from 'react'
Select, import { RRule } from 'rrule'
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { useHelpers } from '@/lib/client-helpers'
interface AddEditHabitModalProps { interface AddEditHabitModalProps {
onClose: () => void onClose: () => void

View File

@@ -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 { Button } from '@/components/ui/button'
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { Textarea } from '@/components/ui/textarea'
import { SmilePlus, Info } from 'lucide-react' import { usersAtom } from '@/lib/atoms'
import { useHelpers } from '@/lib/client-helpers'
import { WishlistItemType } from '@/lib/types'
import data from '@emoji-mart/data' import data from '@emoji-mart/data'
import Picker from '@emoji-mart/react' 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 { interface AddEditWishlistItemModalProps {
isOpen: boolean isOpen: boolean

View File

@@ -18,7 +18,7 @@ export default function ClientWrapper({ children }: { children: ReactNode }) {
if (!currentUserId && !userSelect) { if (!currentUserId && !userSelect) {
setUserSelect(true) setUserSelect(true)
} }
}, [currentUserId, status, userSelect]) }, [currentUserId, status, userSelect, setUserSelect])
return ( return (
<> <>

View File

@@ -1,21 +1,21 @@
'use client' '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 { FormattedNumber } from '@/components/FormattedNumber'
import { History, Pencil } from 'lucide-react' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' import { Button } from '@/components/ui/button'
import EmptyState from './EmptyState'
import { Input } from '@/components/ui/input'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { settingsAtom, usersAtom } from '@/lib/atoms' import { Input } from '@/components/ui/input'
import Link from 'next/link'
import { useAtom } from 'jotai'
import { useCoins } from '@/hooks/useCoins' import { useCoins } from '@/hooks/useCoins'
import { TransactionNoteEditor } from './TransactionNoteEditor' import { settingsAtom, usersAtom } from '@/lib/atoms'
import { useHelpers } from '@/lib/client-helpers' 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() { export default function CoinsManager() {
const { currentUser } = useHelpers() 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 // 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 // Effect to scroll to highlighted transaction
useEffect(() => { useEffect(() => {

View File

@@ -1,9 +1,7 @@
import { Badge } from "@/components/ui/badge" import { Badge } from "@/components/ui/badge"
import { useAtom } from 'jotai' import { completedHabitsMapAtom, habitsByDateFamily, settingsAtom } from '@/lib/atoms'
import { completedHabitsMapAtom, habitsAtom, habitsByDateFamily } from '@/lib/atoms'
import { getTodayInTimezone } from '@/lib/utils' import { getTodayInTimezone } from '@/lib/utils'
import { useHabits } from '@/hooks/useHabits' import { useAtom } from 'jotai'
import { settingsAtom } from '@/lib/atoms'
interface CompletionCountBadgeProps { interface CompletionCountBadgeProps {
type: 'habits' | 'tasks' type: 'habits' | 'tasks'

View File

@@ -1,35 +1,31 @@
import { Circle, Coins, ArrowRight, CircleCheck, ChevronDown, ChevronUp, Plus, Pin, AlertTriangle } from 'lucide-react' // Removed unused icons import { Badge } from '@/components/ui/badge'
import CompletionCountBadge from './CompletionCountBadge' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { import {
ContextMenu, ContextMenu,
ContextMenuContent, ContextMenuContent,
ContextMenuItem, ContextMenuTrigger
ContextMenuSeparator,
ContextMenuTrigger,
} from "@/components/ui/context-menu" } from "@/components/ui/context-menu"
import { cn } from '@/lib/utils' import { Progress } from '@/components/ui/progress'
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 { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip" } 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 { 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 AddEditHabitModal from './AddEditHabitModal'
import CompletionCountBadge from './CompletionCountBadge'
import ConfirmDialog from './ConfirmDialog' import ConfirmDialog from './ConfirmDialog'
import { Button } from './ui/button'
import { HabitContextMenuItems } from './HabitContextMenuItems' import { HabitContextMenuItems } from './HabitContextMenuItems'
import Linkify from './linkify'
import { Button } from './ui/button'
interface UpcomingItemsProps { interface UpcomingItemsProps {
habits: Habit[] habits: Habit[]

View File

@@ -1,17 +1,15 @@
'use client' 'use client'
import { useCoins } from '@/hooks/useCoins'
import { habitsAtom, wishlistAtom } from '@/lib/atoms'
import { useAtom } from 'jotai' import { useAtom } from 'jotai'
import { wishlistAtom, habitsAtom, settingsAtom } from '@/lib/atoms' import CoinBalance from './CoinBalance'
import DailyOverview from './DailyOverview' import DailyOverview from './DailyOverview'
import HabitStreak from './HabitStreak' import HabitStreak from './HabitStreak'
import CoinBalance from './CoinBalance'
import { useHabits } from '@/hooks/useHabits'
import { useCoins } from '@/hooks/useCoins'
export default function Dashboard() { export default function Dashboard() {
const [habitsData] = useAtom(habitsAtom) const [habitsData] = useAtom(habitsAtom)
const habits = habitsData.habits const habits = habitsData.habits
const [settings] = useAtom(settingsAtom)
const { balance } = useCoins() const { balance } = useCoins()
const [wishlist] = useAtom(wishlistAtom) const [wishlist] = useAtom(wishlistAtom)
const wishlistItems = wishlist.items const wishlistItems = wishlist.items

View File

@@ -1,18 +1,17 @@
'use client' 'use client'
import { useState, useMemo, useCallback } from 'react' import CompletionCountBadge from '@/components/CompletionCountBadge'
import { Calendar } from '@/components/ui/calendar' import { Calendar } from '@/components/ui/calendar'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' 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 { useHabits } from '@/hooks/useHabits'
import { habitsAtom, settingsAtom, completedHabitsMapAtom, hasTasksAtom } from '@/lib/atoms' import { completedHabitsMapAtom, habitsAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms'
import { DateTime } from 'luxon'
import Linkify from './linkify'
import { Habit } from '@/lib/types' 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() { export default function HabitCalendar() {
const { completePastHabit } = useHabits() const { completePastHabit } = useHabits()

View File

@@ -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 { 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 { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuTrigger
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu' } from '@/components/ui/dropdown-menu'
import { useEffect, useState } from 'react'
import { useHabits } from '@/hooks/useHabits' import { useHabits } from '@/hooks/useHabits'
import { INITIAL_RECURRENCE_RULE, RECURRENCE_RULE_MAP } from '@/lib/constants' import { browserSettingsAtom, settingsAtom, usersAtom } from '@/lib/atoms'
import { DateTime } from 'luxon'
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'
import { useHelpers } from '@/lib/client-helpers' 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 { HabitContextMenuItems } from './HabitContextMenuItems'
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'
interface HabitItemProps { interface HabitItemProps {
habit: Habit habit: Habit
@@ -49,7 +45,6 @@ const renderUserAvatars = (habit: Habit, currentUser: User | null, usersData: {
export default function HabitItem({ habit, onEdit, onDelete }: HabitItemProps) { export default function HabitItem({ habit, onEdit, onDelete }: HabitItemProps) {
const { completeHabit, undoComplete, archiveHabit, unarchiveHabit, saveHabit } = useHabits() const { completeHabit, undoComplete, archiveHabit, unarchiveHabit, saveHabit } = useHabits()
const [settings] = useAtom(settingsAtom) const [settings] = useAtom(settingsAtom)
const [_, setPomo] = useAtom(pomodoroAtom)
const completionsToday = getCompletionsForToday({ habit, timezone: settings.system.timezone }) const completionsToday = getCompletionsForToday({ habit, timezone: settings.system.timezone })
const target = habit.targetCompletions || 1 const target = habit.targetCompletions || 1
const isCompletedToday = completionsToday >= target const isCompletedToday = completionsToday >= target

View File

@@ -1,23 +1,23 @@
'use client' '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 { 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 AddEditHabitModal from './AddEditHabitModal'
import ConfirmDialog from './ConfirmDialog' import ConfirmDialog from './ConfirmDialog'
import { Habit } from '@/lib/types' import EmptyState from './EmptyState'
import { useHabits } from '@/hooks/useHabits' import HabitItem from './HabitItem'
import { HabitIcon, TaskIcon } from '@/lib/constants'
import { ViewToggle } from './ViewToggle' 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() { export default function HabitList() {
const { saveHabit, deleteHabit } = useHabits() const { saveHabit, deleteHabit } = useHabits()

View File

@@ -1,11 +1,11 @@
'use client' 'use client'
import { Habit } from '@/lib/types'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { d2s, getNow, t2d } from '@/lib/utils' // Removed getCompletedHabitsForDate import { completedHabitsMapAtom, hasTasksAtom, settingsAtom } from '@/lib/atoms'; // Added completedHabitsMapAtom
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts' import { Habit } from '@/lib/types'
import { d2s, getNow } from '@/lib/utils'; // Removed getCompletedHabitsForDate
import { useAtom } from 'jotai' 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 { interface HabitStreakProps {
habits: Habit[] habits: Habit[]

View File

@@ -1,26 +1,15 @@
'use client' '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 { 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 { Logo } from '@/components/Logo'
import NotificationBell from './NotificationBell' import { useCoins } from '@/hooks/useCoins'
import { import { settingsAtom } from '@/lib/atoms'
DropdownMenu, import { useAtom } from 'jotai'
DropdownMenuContent, import { Coins } from 'lucide-react'
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 dynamic from 'next/dynamic' import dynamic from 'next/dynamic'
import Link from 'next/link'
import NotificationBell from './NotificationBell'
import { Profile } from './Profile' import { Profile } from './Profile'
import { useHelpers } from '@/lib/client-helpers'
interface HeaderProps { interface HeaderProps {
className?: string className?: string
@@ -30,7 +19,6 @@ const TodayEarnedCoins = dynamic(() => import('./TodayEarnedCoins'), { ssr: fals
export default function Header({ className }: HeaderProps) { export default function Header({ className }: HeaderProps) {
const [settings] = useAtom(settingsAtom) const [settings] = useAtom(settingsAtom)
const [browserSettings] = useAtom(browserSettingsAtom)
const { balance } = useCoins() const { balance } = useCoins()
return ( return (
<> <>

View File

@@ -1,4 +1,3 @@
import { Sparkles } from "lucide-react"
export function Logo() { export function Logo() {
return ( return (

View File

@@ -1,13 +1,13 @@
'use client' '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 { 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 { useEffect, useState } from 'react'
import AboutModal from './AboutModal' import AboutModal from './AboutModal'
import { HabitIcon, TaskIcon } from '@/lib/constants'
import { useHelpers } from '@/lib/client-helpers'
type ViewPort = 'main' | 'mobile' type ViewPort = 'main' | 'mobile'

View File

@@ -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 { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator'; 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 { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from '@/components/ui/tooltip'; } 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 { interface NotificationDropdownProps {
currentUser: User | null; currentUser: User | null;

View File

@@ -1,13 +1,13 @@
'use client'; '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 { toast } from '@/hooks/use-toast';
import { User } from '@/lib/types';
import { User as UserIcon } from 'lucide-react';
import { useState } from '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 { interface PasswordEntryFormProps {
user: User; user: User;

View File

@@ -1,14 +1,13 @@
'use client' 'use client'
import { useState, useEffect, useRef, useCallback } from 'react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress' 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 { 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 { interface PomoConfig {
labels: string[] labels: string[]
@@ -135,20 +134,6 @@ export default function PomodoroTimer() {
const remaining = Math.floor((targetEndTime - Date.now()) / 1000) const remaining = Math.floor((targetEndTime - Date.now()) / 1000)
if (remaining <= 0) { if (remaining <= 0) {
handleTimerEnd()
} else {
setTimeLeft(remaining)
}
}, 1000)
}
// return handles any other states
return () => {
if (interval) clearInterval(interval)
}
}, [state])
const handleTimerEnd = async () => {
setState("stopped") setState("stopped")
const currentTimerType = currentTimer.current.type const currentTimerType = currentTimer.current.type
currentTimer.current = currentTimerType === 'focus' ? PomoConfigs.break : PomoConfigs.focus currentTimer.current = currentTimerType === 'focus' ? PomoConfigs.break : PomoConfigs.focus
@@ -159,10 +144,20 @@ export default function PomodoroTimer() {
// update habits only after focus sessions // update habits only after focus sessions
if (selectedHabit && currentTimerType === 'focus') { if (selectedHabit && currentTimerType === 'focus') {
await completeHabit(selectedHabit) completeHabit(selectedHabit)
// The atom will automatically update with the new completions // The atom will automatically update with the new completions
} }
} else {
setTimeLeft(remaining)
} }
}, 1000)
}
// return handles any other states
return () => {
if (interval) clearInterval(interval)
}
}, [state, timeLeft, completeHabit, selectedHabit])
const toggleTimer = () => { const toggleTimer = () => {
setState(prev => prev === 'started' ? 'paused' : 'started') setState(prev => prev === 'started' ? 'paused' : 'started')

View File

@@ -1,20 +1,20 @@
'use client' 'use client'
import { signOut } from "@/app/actions/user"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" 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 { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog'
import UserForm from './UserForm' 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() { export function Profile() {
const [settings] = useAtom(settingsAtom) const [settings] = useAtom(settingsAtom)

View File

@@ -1,22 +1,21 @@
'use client'; '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 { 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 { Button } from './ui/button';
import { Input } from './ui/input';
import { Label } from './ui/label'; import { Label } from './ui/label';
import { Switch } from './ui/switch'; 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 { interface UserFormProps {
userId?: string; // if provided, we're editing; if not, we're creating userId?: string; // if provided, we're editing; if not, we're creating

View File

@@ -1,22 +1,19 @@
'use client'; '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 { useState } from 'react';
import PasswordEntryForm from './PasswordEntryForm'; import PasswordEntryForm from './PasswordEntryForm';
import UserForm from './UserForm'; import UserForm from './UserForm';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog';
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
import { Crown, Pencil, Plus, User as UserIcon, UserRoundPen } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog';
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';
function UserCard({ function UserCard({
user, user,

View File

@@ -1,12 +1,10 @@
'use client' '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 { browserSettingsAtom, habitsAtom, settingsAtom } from '@/lib/atoms'
import type { ViewType } from '@/lib/types'
import { HabitIcon, TaskIcon } from '@/lib/constants' 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' import { NotificationBadge } from './ui/notification-badge'
interface ViewToggleProps { interface ViewToggleProps {

View File

@@ -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 { 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 { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@@ -14,6 +7,12 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu' } 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 { interface WishlistItemProps {
item: WishlistItemType item: WishlistItemType

View File

@@ -1,7 +1,6 @@
"use client" "use client"
import * as React from "react" import { Moon, Sun } from "lucide-react"
import { Moon, MoonIcon, Sun } from "lucide-react"
import { useTheme } from "next-themes" import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"

View File

@@ -1,35 +1,30 @@
import { atom } from "jotai";
import { import {
getDefaultSettings,
getDefaultHabitsData,
getDefaultCoinsData,
getDefaultWishlistData,
Habit,
ViewType,
getDefaultUsersData,
CompletionCache,
getDefaultServerSettings,
User,
} from "./types";
import {
getTodayInTimezone,
isSameDate,
t2d,
calculateCoinsEarnedToday, calculateCoinsEarnedToday,
calculateCoinsSpentToday,
calculateTotalEarned, calculateTotalEarned,
calculateTotalSpent, calculateTotalSpent,
calculateCoinsSpentToday,
calculateTransactionsToday, calculateTransactionsToday,
getCompletionsForToday, getCompletionsForToday,
getISODate, getHabitFreq,
isHabitDueToday, getTodayInTimezone,
getNow,
isHabitDue, isHabitDue,
getHabitFreq t2d
} from "@/lib/utils"; } from "@/lib/utils";
import { atom } from "jotai";
import { atomFamily, atomWithStorage } from "jotai/utils"; import { atomFamily, atomWithStorage } from "jotai/utils";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { Freq } from "./types"; import {
CompletionCache,
Freq,
getDefaultCoinsData,
getDefaultHabitsData,
getDefaultServerSettings,
getDefaultSettings,
getDefaultUsersData,
getDefaultWishlistData,
Habit,
ViewType
} from "./types";
export interface BrowserSettings { export interface BrowserSettings {
viewType: ViewType viewType: ViewType