Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/components/item-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Link } from "@tanstack/react-router"
import { Package } from "lucide-react"
import type { ItemRead } from "@/api/generated/types"
import { ImageCarousel } from "@/components/image-carousel"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent } from "@/components/ui/card"

export function ItemCard({ item }: { item: ItemRead }) {
const images = item.images ?? []
return (
<Link to="/items/$itemId" params={{ itemId: item.id }} className="block">
<Card className="hover:border-primary/40 h-full overflow-hidden transition-colors">
{images.length > 0 ? (
<ImageCarousel
images={images}
aspectRatio="aspect-[4/3]"
showDots
showArrows
className="rounded-none"
/>
) : (
<div className="bg-muted flex aspect-[4/3] items-center justify-center">
<Package className="text-muted-foreground h-8 w-8" />
</div>
)}
<CardContent className="p-3">
<p className="truncate font-medium">{item.name}</p>
{item.description && (
<p className="text-muted-foreground mt-0.5 line-clamp-2 text-sm">
{item.description}
</p>
)}
<div className="text-muted-foreground mt-1 flex items-center gap-2 text-xs">
{item.estimated_value && (
<span>
$
{parseFloat(item.estimated_value).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</span>
)}
{item.estimated_value && item.created_at && <span>&middot;</span>}
<span>
{new Date(item.created_at).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
})}
</span>
</div>
<div className="mt-2 flex flex-wrap gap-1">
{item.collection_name && (
<Badge variant="default" className="text-xs">
{item.collection_name}
</Badge>
)}
{item.tags?.map((t) => (
<Badge key={t.id} variant="secondary" className="text-xs">
{t.name}
</Badge>
))}
{item.condition && item.condition !== "unknown" && (
<Badge variant="outline" className="text-xs capitalize">
{item.condition}
</Badge>
)}
</div>
</CardContent>
</Card>
</Link>
)
}
49 changes: 1 addition & 48 deletions src/pages/collections/collection-detail-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ import { useCreateItemNoteItemsItemIdNotesPost } from "@/api/generated/hooks/not
import type { ItemRead } from "@/api/generated/types"
import { getErrorMessage } from "@/lib/api-errors"
import { AppLayout } from "@/components/app-layout"
import { ImageCarousel } from "@/components/image-carousel"
import { ItemCard } from "@/components/item-card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
Expand Down Expand Up @@ -259,52 +258,6 @@ export function CollectionDetailPage() {
)
}

function ItemCard({ item }: { item: ItemRead }) {
const images = item.images ?? []
return (
<Link to="/items/$itemId" params={{ itemId: item.id }} className="block">
<Card className="hover:border-primary/40 h-full overflow-hidden transition-colors">
{images.length > 0 ? (
<ImageCarousel
images={images}
aspectRatio="aspect-[4/3]"
showDots
showArrows
className="rounded-none"
/>
) : (
<div className="bg-muted flex aspect-[4/3] items-center justify-center">
<Package className="text-muted-foreground h-8 w-8" />
</div>
)}
<CardContent className="p-3">
<p className="truncate font-medium">{item.name}</p>
{item.description && (
<p className="text-muted-foreground mt-0.5 line-clamp-2 text-sm">
{item.description}
</p>
)}
{((item.tags && item.tags.length > 0) ||
(item.condition && item.condition !== "unknown")) && (
<div className="mt-2 flex flex-wrap gap-1">
{item.tags?.map((t) => (
<Badge key={t.id} variant="secondary" className="text-xs">
{t.name}
</Badge>
))}
{item.condition && item.condition !== "unknown" && (
<Badge variant="outline" className="text-xs capitalize">
{item.condition}
</Badge>
)}
</div>
)}
</CardContent>
</Card>
</Link>
)
}

function CollectionHeaderSkeleton() {
return (
<div className="mb-6">
Expand Down
71 changes: 1 addition & 70 deletions src/pages/items/all-items-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import { ArrowLeft, Package, Search, ChevronsUpDown } from "lucide-react"
import { useListItemsItemsGet } from "@/api/generated/hooks/items/items"
import { useListCollectionsCollectionsGet } from "@/api/generated/hooks/collections/collections"
import { useListTagsTagsGet } from "@/api/generated/hooks/tags/tags"
import type { ItemRead } from "@/api/generated/types"
import { AppLayout } from "@/components/app-layout"
import { ImageCarousel } from "@/components/image-carousel"
import { ItemCard } from "@/components/item-card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Skeleton } from "@/components/ui/skeleton"
Expand Down Expand Up @@ -229,73 +227,6 @@ export function AllItemsPage() {
)
}

function ItemCard({ item }: { item: ItemRead }) {
const images = item.images ?? []
return (
<Link to="/items/$itemId" params={{ itemId: item.id }} className="block">
<Card className="hover:border-primary/40 h-full overflow-hidden transition-colors">
{images.length > 0 ? (
<ImageCarousel
images={images}
aspectRatio="aspect-[4/3]"
showDots
showArrows
className="rounded-none"
/>
) : (
<div className="bg-muted flex aspect-[4/3] items-center justify-center">
<Package className="text-muted-foreground h-8 w-8" />
</div>
)}
<CardContent className="p-3">
<p className="truncate font-medium">{item.name}</p>
{item.description && (
<p className="text-muted-foreground mt-0.5 line-clamp-2 text-sm">
{item.description}
</p>
)}
<div className="text-muted-foreground mt-1 flex items-center gap-2 text-xs">
{item.estimated_value && (
<span>
$
{parseFloat(item.estimated_value).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</span>
)}
{item.estimated_value && item.created_at && <span>&middot;</span>}
<span>
{new Date(item.created_at).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
})}
</span>
</div>
<div className="mt-2 flex flex-wrap gap-1">
{item.collection_name && (
<Badge variant="default" className="text-xs">
{item.collection_name}
</Badge>
)}
{item.tags?.map((t) => (
<Badge key={t.id} variant="secondary" className="text-xs">
{t.name}
</Badge>
))}
{item.condition && item.condition !== "unknown" && (
<Badge variant="outline" className="text-xs capitalize">
{item.condition}
</Badge>
)}
</div>
</CardContent>
</Card>
</Link>
)
}

function ItemsSkeleton() {
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
Expand Down