mirror of
https://github.com/ManInDark/HabitTrove.git
synced 2026-01-20 22:24:28 +01:00
171 lines
5.8 KiB
TypeScript
171 lines
5.8 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect, useRef } from 'react'
|
|
import { useWishlist } from '@/hooks/useWishlist'
|
|
import { Plus, Gift } from 'lucide-react'
|
|
import EmptyState from './EmptyState'
|
|
import { Button } from '@/components/ui/button'
|
|
import WishlistItem from './WishlistItem'
|
|
import AddEditWishlistItemModal from './AddEditWishlistItemModal'
|
|
import ConfirmDialog from './ConfirmDialog'
|
|
import { WishlistItemType } from '@/lib/types'
|
|
|
|
export default function WishlistManager() {
|
|
const {
|
|
addWishlistItem,
|
|
editWishlistItem,
|
|
deleteWishlistItem,
|
|
redeemWishlistItem,
|
|
archiveWishlistItem,
|
|
unarchiveWishlistItem,
|
|
canRedeem,
|
|
wishlistItems
|
|
} = useWishlist()
|
|
|
|
const activeItems = wishlistItems.filter(item => !item.archived)
|
|
const archivedItems = wishlistItems.filter(item => item.archived)
|
|
|
|
const [highlightedItemId, setHighlightedItemId] = useState<string | null>(null)
|
|
const [recentlyRedeemedId, setRecentlyRedeemedId] = useState<string | null>(null)
|
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
const [editingItem, setEditingItem] = useState<WishlistItemType | null>(null)
|
|
const [deleteConfirmation, setDeleteConfirmation] = useState<{ isOpen: boolean, itemId: string | null }>({
|
|
isOpen: false,
|
|
itemId: null
|
|
})
|
|
|
|
const itemRefs = useRef<Record<string, HTMLDivElement | null>>({})
|
|
|
|
useEffect(() => {
|
|
// Check URL for highlight parameter
|
|
const params = new URLSearchParams(window.location.search)
|
|
const highlightId = params.get('highlight')
|
|
if (highlightId) {
|
|
setHighlightedItemId(highlightId)
|
|
// Scroll the element into view after a short delay to ensure rendering
|
|
setTimeout(() => {
|
|
const element = itemRefs.current[highlightId]
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
}
|
|
}, 100)
|
|
// Remove highlight after animation
|
|
setTimeout(() => setHighlightedItemId(null), 2000)
|
|
}
|
|
}, [])
|
|
|
|
|
|
const handleRedeem = async (item: WishlistItemType) => {
|
|
const success = await redeemWishlistItem(item)
|
|
if (success) {
|
|
setRecentlyRedeemedId(item.id)
|
|
setTimeout(() => {
|
|
setRecentlyRedeemedId(null)
|
|
}, 3000)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="flex justify-between items-center mb-6">
|
|
<h1 className="text-3xl font-bold">My Wishlist</h1>
|
|
<Button onClick={() => setIsModalOpen(true)}>
|
|
<Plus className="mr-2 h-4 w-4" /> Add Reward
|
|
</Button>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 items-stretch">
|
|
{activeItems.length === 0 ? (
|
|
<div className="col-span-2">
|
|
<EmptyState
|
|
icon={Gift}
|
|
title="Your wishlist is empty"
|
|
description="Add rewards that you'd like to earn with your coins"
|
|
/>
|
|
</div>
|
|
) : (
|
|
activeItems.map((item) => (
|
|
<div
|
|
key={item.id}
|
|
ref={(el) => {
|
|
if (el) {
|
|
itemRefs.current[item.id] = el
|
|
}
|
|
}}
|
|
>
|
|
<WishlistItem
|
|
item={item}
|
|
isHighlighted={item.id === highlightedItemId}
|
|
isRecentlyRedeemed={item.id === recentlyRedeemedId}
|
|
onEdit={() => {
|
|
setEditingItem(item)
|
|
setIsModalOpen(true)
|
|
}}
|
|
onDelete={() => setDeleteConfirmation({ isOpen: true, itemId: item.id })}
|
|
onRedeem={() => handleRedeem(item)}
|
|
onArchive={() => archiveWishlistItem(item.id)}
|
|
onUnarchive={() => unarchiveWishlistItem(item.id)}
|
|
canRedeem={canRedeem(item.coinCost)}
|
|
/>
|
|
</div>
|
|
))
|
|
)}
|
|
|
|
{archivedItems.length > 0 && (
|
|
<>
|
|
<div className="col-span-2 relative flex items-center my-6">
|
|
<div className="flex-grow border-t border-gray-300 dark:border-gray-600" />
|
|
<span className="mx-4 text-sm text-gray-500 dark:text-gray-400">Archived</span>
|
|
<div className="flex-grow border-t border-gray-300 dark:border-gray-600" />
|
|
</div>
|
|
{archivedItems.map((item) => (
|
|
<WishlistItem
|
|
key={item.id}
|
|
item={item}
|
|
onEdit={() => {
|
|
setEditingItem(item)
|
|
setIsModalOpen(true)
|
|
}}
|
|
onDelete={() => setDeleteConfirmation({ isOpen: true, itemId: item.id })}
|
|
onRedeem={() => handleRedeem(item)}
|
|
onArchive={() => archiveWishlistItem(item.id)}
|
|
onUnarchive={() => unarchiveWishlistItem(item.id)}
|
|
canRedeem={canRedeem(item.coinCost)}
|
|
/>
|
|
))}
|
|
</>
|
|
)}
|
|
</div>
|
|
<AddEditWishlistItemModal
|
|
isOpen={isModalOpen}
|
|
onClose={() => {
|
|
setIsModalOpen(false)
|
|
setEditingItem(null)
|
|
}}
|
|
onSave={(item) => {
|
|
if (editingItem) {
|
|
editWishlistItem({ ...item, id: editingItem.id })
|
|
} else {
|
|
addWishlistItem(item)
|
|
}
|
|
setIsModalOpen(false)
|
|
setEditingItem(null)
|
|
}}
|
|
item={editingItem}
|
|
/>
|
|
<ConfirmDialog
|
|
isOpen={deleteConfirmation.isOpen}
|
|
onClose={() => setDeleteConfirmation({ isOpen: false, itemId: null })}
|
|
onConfirm={() => {
|
|
if (deleteConfirmation.itemId) {
|
|
deleteWishlistItem(deleteConfirmation.itemId)
|
|
}
|
|
setDeleteConfirmation({ isOpen: false, itemId: null })
|
|
}}
|
|
title="Delete Reward"
|
|
message="Are you sure you want to delete this reward? This action cannot be undone."
|
|
confirmText="Delete"
|
|
/>
|
|
</div>
|
|
)
|
|
}
|