Files
sapiens-stock/components/watchlist.tsx
2025-10-22 09:31:15 +09:00

255 lines
8.0 KiB
TypeScript

"use client"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Plus, Settings } from "lucide-react"
interface WatchlistProps {
onSelectStock: (symbol: string) => void
}
export function Watchlist({ onSelectStock }: WatchlistProps) {
const [activeTab, setActiveTab] = useState("active")
const watchlistStocks = [
{
symbol: "MSFT",
exchange: "NASDAQ",
name: "Microsoft Corporation",
price: 507.03,
changePercent: -0.61,
logo: "https://logo.clearbit.com/microsoft.com",
bgColor: "bg-orange-500",
},
{
symbol: "GOOG",
exchange: "NASDAQ",
name: "Alphabet Inc.",
price: 246.57,
changePercent: -0.51,
logo: "https://logo.clearbit.com/google.com",
bgColor: "bg-blue-500",
},
{
symbol: "AMZN",
exchange: "NASDAQ",
name: "Amazon.com, Inc.",
price: 218.15,
changePercent: -0.94,
logo: "https://logo.clearbit.com/amazon.com",
bgColor: "bg-orange-600",
},
{
symbol: "META",
exchange: "NASDAQ",
name: "Meta Platforms, Inc.",
price: 748.91,
changePercent: -1.54,
logo: "https://logo.clearbit.com/meta.com",
bgColor: "bg-blue-600",
},
]
const activeStocks = [
{
symbol: "OPEN",
exchange: "NASDAQ",
name: "Opendoor Technologies...",
price: 9.09,
changePercent: 10.45,
logo: "https://logo.clearbit.com/opendoor.com",
bgColor: "bg-purple-600",
},
{
symbol: "INTC",
exchange: "NASDAQ",
name: "Intel Corporation",
price: 33.99,
changePercent: 8.87,
logo: "https://logo.clearbit.com/intel.com",
bgColor: "bg-blue-700",
},
{
symbol: "SNAP",
exchange: "NYSE",
name: "Snap Inc.",
price: 8.33,
changePercent: 1.34,
logo: "https://logo.clearbit.com/snap.com",
bgColor: "bg-yellow-500",
},
{
symbol: "SOXS",
exchange: "AMEX",
name: "Direxion Daily Semicond...",
price: 5.34,
changePercent: 1.14,
logo: "",
bgColor: "bg-gray-600",
letter: "S",
},
]
const peersStocks = [
{
symbol: "TM",
exchange: "NYSE",
name: "Toyota Motor Corporation",
price: 197.28,
changePercent: -0.41,
logo: "https://logo.clearbit.com/toyota.com",
bgColor: "bg-red-600",
},
{
symbol: "BYDDY",
exchange: "OTC",
name: "BYD Company Limited",
price: 13.8,
changePercent: 2.53,
logo: "",
bgColor: "bg-gray-700",
letter: "B",
},
{
symbol: "GM",
exchange: "NYSE",
name: "General Motors Comp...",
price: 60.59,
changePercent: 0,
logo: "https://logo.clearbit.com/gm.com",
bgColor: "bg-blue-800",
},
]
const getCurrentStocks = () => {
switch (activeTab) {
case "gainers":
return activeStocks.filter((stock) => stock.changePercent > 0)
case "losers":
return watchlistStocks // All are negative in the watchlist
case "active":
default:
return activeStocks
}
}
const StockItem = ({ stock }: { stock: any }) => {
const isPositive = stock.changePercent > 0
return (
<div
className="flex items-center justify-between py-0.5 sm:py-1 hover:bg-accent/20 cursor-pointer transition-colors"
onClick={() => onSelectStock(stock.symbol)}
>
<div className="flex items-center space-x-2 sm:space-x-3">
<div className={`w-5 h-5 sm:w-6 sm:h-6 rounded-sm flex items-center justify-center ${stock.bgColor}`}>
{stock.logo ? (
<img src={stock.logo || "/placeholder.svg"} alt={stock.symbol} className="w-3 h-3 sm:w-4 sm:h-4" />
) : (
<span className="text-white font-bold text-xs">{stock.letter || stock.symbol[0]}</span>
)}
</div>
<div className="min-w-0">
<div className="text-xs sm:text-sm font-medium text-foreground truncate">{stock.name}</div>
<div className="text-xs text-muted-foreground">
{stock.symbol} · {stock.exchange}
</div>
</div>
</div>
<div className="text-right flex items-center space-x-1 sm:space-x-2">
<div className="text-xs sm:text-sm text-foreground">US${stock.price.toFixed(2)}</div>
<Button size="sm" variant="ghost" className="h-5 w-5 sm:h-6 sm:w-6 p-0 hover:bg-accent/50">
<Plus className="w-2.5 h-2.5 sm:w-3 sm:h-3 text-muted-foreground" />
</Button>
</div>
</div>
)
}
const StockItemWithChange = ({ stock }: { stock: any }) => {
const isPositive = stock.changePercent > 0
return (
<div
className="flex items-center justify-between py-0.5 sm:py-1 hover:bg-accent/20 cursor-pointer transition-colors"
onClick={() => onSelectStock(stock.symbol)}
>
<div className="flex items-center space-x-2 sm:space-x-3">
<div className={`w-5 h-5 sm:w-6 sm:h-6 rounded-sm flex items-center justify-center ${stock.bgColor}`}>
{stock.logo ? (
<img src={stock.logo || "/placeholder.svg"} alt={stock.symbol} className="w-3 h-3 sm:w-4 sm:h-4" />
) : (
<span className="text-white font-bold text-xs">{stock.letter || stock.symbol[0]}</span>
)}
</div>
<div className="min-w-0">
<div className="text-xs sm:text-sm font-medium text-foreground truncate">{stock.name}</div>
<div className="text-xs text-muted-foreground">
{stock.symbol} · {stock.exchange}
</div>
</div>
</div>
<div className="text-right">
<div className="text-xs sm:text-sm text-foreground">US${stock.price.toFixed(2)}</div>
<div className={`text-xs ${isPositive ? "text-green-400" : "text-red-400"}`}>
{isPositive ? "+" : ""}
{stock.changePercent.toFixed(2)}%
</div>
</div>
</div>
)
}
return (
<div className="space-y-2 sm:space-y-4">
<div className="border border-border/50 rounded-lg p-2 sm:p-3 md:p-4 space-y-2 sm:space-y-3">
<div className="flex items-center justify-between mb-2 sm:mb-3">
<h2 className="text-xs sm:text-sm font-medium text-foreground">Create Watchlist</h2>
<Button size="sm" variant="ghost" className="h-5 w-5 sm:h-6 sm:w-6 p-0 hover:bg-accent/50">
<Settings className="w-3 h-3 sm:w-4 sm:h-4 text-muted-foreground" />
</Button>
</div>
<div className="space-y-0.5 sm:space-y-1">
{watchlistStocks.map((stock) => (
<StockItemWithChange key={stock.symbol} stock={stock} />
))}
</div>
<div className="pt-2 sm:pt-3 border-t border-border/30">
<div className="flex border-b border-border">
{["Gainers", "Losers", "Active"].map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab.toLowerCase())}
className={`px-2 sm:px-4 py-1 sm:py-2 text-xs sm:text-sm font-medium transition-colors relative ${
activeTab === tab.toLowerCase()
? "text-foreground border-b-2 border-foreground"
: "text-muted-foreground hover:text-foreground"
}`}
>
{tab}
</button>
))}
</div>
<div className="space-y-0.5 sm:space-y-1 mt-2 sm:mt-3">
{getCurrentStocks().map((stock) => (
<StockItemWithChange key={stock.symbol} stock={stock} />
))}
</div>
</div>
<div className="pt-2 sm:pt-3 border-t border-border/30">
<h3 className="text-xs sm:text-sm font-medium text-foreground mb-1 sm:mb-2">Peers</h3>
<div className="space-y-0.5 sm:space-y-1">
{peersStocks.map((stock) => (
<StockItemWithChange key={stock.symbol} stock={stock} />
))}
</div>
</div>
</div>
</div>
)
}