import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { useHabits } from '@/hooks/useHabits'
import { currentUserAtom, settingsAtom, usersAtom } from '@/lib/atoms'
import { Habit, User } from '@/lib/types'
import { convertMachineReadableFrequencyToHumanReadable, getCompletionsForToday, hasPermission, isTaskOverdue } from '@/lib/utils'
import { useAtom } from 'jotai'
import { Check, Coins, Edit, MoreVertical, Pin, Undo2 } from 'lucide-react'
import { useTranslations } from 'next-intl'
import { usePathname } from 'next/navigation'
import { useEffect, useState } from 'react'
import { HabitContextMenuItems } from './HabitContextMenuItems'
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'
interface HabitItemProps {
habit: Habit
onEdit: () => void
onDelete: () => void
}
const renderUserAvatars = (habit: Habit, currentUser: User | null, usersData: { users: User[] }) => {
if (!habit.userIds || habit.userIds.length <= 1) return null;
return (
{habit.userIds?.filter((u) => u !== currentUser?.id).map(userId => {
const user = usersData.users.find(u => u.id === userId)
if (!user) return null
return (
{user.username[0]}
)
})}
);
};
export default function HabitItem({ habit, onEdit, onDelete }: HabitItemProps) {
const { completeHabit, undoComplete } = useHabits()
const [settings] = useAtom(settingsAtom)
const completionsToday = getCompletionsForToday({ habit, timezone: settings.system.timezone })
const target = habit.targetCompletions || 1
const isCompletedToday = completionsToday >= target
const [isHighlighted, setIsHighlighted] = useState(false)
const t = useTranslations('HabitItem');
const [usersData] = useAtom(usersAtom)
const pathname = usePathname();
const [currentUser] = useAtom(currentUserAtom)
const canWrite = hasPermission(currentUser, 'habit', 'write')
const canInteract = hasPermission(currentUser, 'habit', 'interact')
useEffect(() => {
const params = new URLSearchParams(window.location.search)
const highlightId = params.get('highlight')
if (highlightId === habit.id) {
setIsHighlighted(true)
// Scroll the element into view after a short delay to ensure rendering
setTimeout(() => {
const element = document.getElementById(`habit-${habit.id}`)
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
}, 100)
// Remove highlight after animation
const timer = setTimeout(() => setIsHighlighted(false), 2000)
return () => clearTimeout(timer)
}
}, [habit.id])
return (
{habit.pinned && (
)}
{habit.name}
{isTaskOverdue(habit, settings.system.timezone) && (
{t('overdue')}
)}
{renderUserAvatars(habit, currentUser as User, usersData)}
{habit.description && (
{habit.description}
)}
{t('whenLabel', {
frequency: convertMachineReadableFrequencyToHumanReadable({
frequency: habit.frequency,
isRecurRule: pathname.includes("habits"),
timezone: settings.system.timezone
})
})}
{t('coinsPerCompletion', { count: habit.coinReward })}
{completionsToday > 0 && !habit.archived && (
)}
{!habit.archived && (
)}
)
}