Files
ember-market-frontend/components/dashboard/product-peek.tsx
g fe01f31538
Some checks failed
Build Frontend / build (push) Failing after 7s
Refactor UI imports and update component paths
Replaces imports from 'components/ui' with 'components/common' across the app and dashboard pages, and updates model and API imports to use new paths under 'lib'. Removes redundant authentication checks from several dashboard pages. Adds new dashboard components and utility files, and reorganizes hooks and services into the 'lib' directory for improved structure.
2026-01-13 05:02:13 +00:00

192 lines
10 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription
} from "@/components/common/sheet"
import { clientFetch } from "@/lib/api"
import { Badge } from "@/components/common/badge"
import { Separator } from "@/components/common/separator"
import { ScrollArea } from "@/components/common/scroll-area"
import { ShoppingCart, TrendingUp, BarChart3, Package, History, ExternalLink, AlertCircle } from "lucide-react"
import { formatGBP } from "@/lib/utils/format"
import Link from "next/link"
import { Button } from "@/components/common/button"
import { Skeleton } from "@/components/common/skeleton"
interface ProductPeekProps {
productId: string | null
open: boolean
onOpenChange: (open: boolean) => void
}
export function ProductPeek({ productId, open, onOpenChange }: ProductPeekProps) {
const [product, setProduct] = useState<any>(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
if (open && productId) {
fetchProductDetails()
}
}, [open, productId])
const fetchProductDetails = async () => {
setLoading(true)
try {
// In this app, productId might be the ID used in the list,
// which corresponds to the mongo _id or a semantic ID.
const data = await clientFetch(`/products/${productId}`)
setProduct(data)
} catch (error) {
console.error("Failed to fetch product details for peek:", error)
} finally {
setLoading(false)
}
}
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent className="sm:max-w-md border-white/5 bg-[#0a0a0a]/80 backdrop-blur-2xl p-0 overflow-hidden flex flex-col">
<SheetHeader className="p-6 border-b border-white/5 bg-white/5">
<div className="flex items-center justify-between mb-2">
<SheetTitle className="text-xl font-bold flex items-center gap-2">
<ShoppingCart className="h-5 w-5 text-primary" />
Product Insight
</SheetTitle>
{product && (
<Link href={`/dashboard/stock`} onClick={() => onOpenChange(false)}>
<Button variant="ghost" size="sm" className="h-8 gap-1.5 text-xs text-muted-foreground hover:text-primary">
Manage <ExternalLink className="h-3 w-3" />
</Button>
</Link>
)}
</div>
<SheetDescription asChild>
<div className="flex items-center gap-2 text-white font-medium bg-white/5 px-2.5 py-1 rounded-lg border border-white/10 w-fit mt-1">
{loading ? <Skeleton className="h-4 w-32" /> : product ? product.name : "Loading..."}
</div>
</SheetDescription>
</SheetHeader>
<ScrollArea className="flex-1">
{loading ? (
<div className="p-6 space-y-6">
<div className="flex gap-4">
<Skeleton className="h-24 w-24 rounded-2xl" />
<div className="space-y-2 flex-1">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-2/3" />
</div>
</div>
<Separator className="bg-white/5" />
<div className="grid grid-cols-2 gap-4">
<Skeleton className="h-20 w-full rounded-2xl" />
<Skeleton className="h-20 w-full rounded-2xl" />
</div>
</div>
) : product ? (
<div className="p-6 space-y-8">
{/* Product Visual & Basic Info */}
<div className="flex gap-6 items-start">
<div
className="h-24 w-24 bg-muted bg-cover bg-center rounded-2xl border border-white/10 shadow-xl flex-shrink-0"
style={{
backgroundImage: product._id
? `url(/api/products/${product._id}/image)`
: 'none'
}}
/>
<div className="space-y-2">
<Badge variant="outline" className="bg-primary/10 text-primary border-primary/20 capitalize">
{product.type || "Physical"}
</Badge>
<h2 className="text-lg font-bold text-white leading-tight">{product.name}</h2>
</div>
</div>
{/* Inventory Stats */}
<div className="grid grid-cols-2 gap-4">
<div className="p-4 rounded-2xl bg-white/5 border border-white/5 space-y-1">
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Current Stock</span>
<div className="flex items-center gap-2">
<span className={`text-xl font-bold ${(product.currentStock || 0) <= 5 ? 'text-rose-500' : 'text-white'}`}>
{product.currentStock || 0}
</span>
{(product.currentStock || 0) <= 5 && <AlertCircle className="h-4 w-4 text-rose-500 animate-pulse" />}
</div>
</div>
<div className="p-4 rounded-2xl bg-white/5 border border-white/5 space-y-1">
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Unit Type</span>
<div className="text-lg font-bold text-white capitalize">
{product.unitType || "Units"}
</div>
</div>
</div>
{/* Analytics Section */}
<div className="space-y-4">
<h3 className="text-sm font-bold flex items-center gap-2 text-muted-foreground uppercase tracking-widest">
<BarChart3 className="h-4 w-4" /> Performance Metrics
</h3>
<div className="p-4 rounded-2xl bg-white/5 border border-white/5 space-y-4">
<div className="flex justify-between items-center text-sm">
<span className="text-muted-foreground">Type</span>
<span className="font-medium text-white">{product.type || "Physical"}</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="text-muted-foreground">Rating</span>
<div className="flex items-center gap-1.5">
<div className="flex text-amber-500">
{"★".repeat(Math.round(product.rating || 5))}
</div>
<span className="font-bold text-white">({product.rating || "5.0"})</span>
</div>
</div>
</div>
</div>
{/* Status & Settings */}
<div className="space-y-4">
<h3 className="text-sm font-bold flex items-center gap-2 text-muted-foreground uppercase tracking-widest">
<TrendingUp className="h-4 w-4" /> Market Visibility
</h3>
<div className="p-4 rounded-2xl bg-emerald-500/5 border border-emerald-500/20">
<div className="flex items-center gap-3">
<div className="p-2 rounded-full bg-emerald-500/20 text-emerald-500">
<TrendingUp className="h-4 w-4" />
</div>
<div>
<p className="text-sm font-bold text-emerald-500">Active Listing</p>
<p className="text-xs text-emerald-500/60">This product is currently visible to all buyers.</p>
</div>
</div>
</div>
</div>
{/* Quick Actions */}
<div className="grid grid-cols-1 gap-3">
<Link href={`/dashboard/stock`} onClick={() => onOpenChange(false)} className="w-full">
<Button variant="outline" className="w-full justify-start gap-3 h-12 border-white/5 bg-white/5 hover:bg-white/10 group">
<Package className="h-4 w-4 text-primary group-hover:scale-110 transition-transform" />
Update Inventory Levels
</Button>
</Link>
</div>
</div>
) : (
<div className="p-12 text-center text-muted-foreground">
Failed to load product details.
</div>
)}
</ScrollArea>
</SheetContent>
</Sheet>
)
}