Initial commit: SAPIENS Stock service
This commit is contained in:
254
components/watchlist.tsx
Normal file
254
components/watchlist.tsx
Normal file
@ -0,0 +1,254 @@
|
||||
"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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user