Untitled

 avatar
unknown
plain_text
a year ago
7.3 kB
14
Indexable
import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Search, TrendingUp, TrendingDown, Star, Plus } from 'lucide-react';

interface Asset {
  symbol: string;
  name: string;
  price: number;
  change: number;
  changePercent: number;
  type: 'stock' | 'crypto';
}

const AssetTracker = () => {
  const [searchTerm, setSearchTerm] = useState('');
  const [watchlist, setWatchlist] = useState<string[]>(['AAPL', 'BTC', 'TSLA']);
  const [assets] = useState<Asset[]>([
    { symbol: 'AAPL', name: 'Apple Inc.', price: 182.52, change: 2.43, changePercent: 1.35, type: 'stock' },
    { symbol: 'BTC', name: 'Bitcoin', price: 43250.00, change: -1250.30, changePercent: -2.81, type: 'crypto' },
    { symbol: 'TSLA', name: 'Tesla Inc.', price: 248.42, change: 5.23, changePercent: 2.15, type: 'stock' },
    { symbol: 'ETH', name: 'Ethereum', price: 2650.75, change: 125.40, changePercent: 4.97, type: 'crypto' },
    { symbol: 'GOOGL', name: 'Alphabet Inc.', price: 138.21, change: -0.87, changePercent: -0.62, type: 'stock' },
    { symbol: 'MSFT', name: 'Microsoft Corp.', price: 378.85, change: 3.21, changePercent: 0.85, type: 'stock' },
  ]);

  const filteredAssets = assets.filter(asset => 
    asset.symbol.toLowerCase().includes(searchTerm.toLowerCase()) ||
    asset.name.toLowerCase().includes(searchTerm.toLowerCase())
  );

  const watchlistAssets = assets.filter(asset => watchlist.includes(asset.symbol));

  const addToWatchlist = (symbol: string) => {
    if (!watchlist.includes(symbol)) {
      setWatchlist([...watchlist, symbol]);
    }
  };

  const removeFromWatchlist = (symbol: string) => {
    setWatchlist(watchlist.filter(s => s !== symbol));
  };

  return (
    <div className="space-y-6">
      <div className="text-center">
        <h2 className="text-3xl font-bold text-foreground mb-2">Market Tracker</h2>
        <p className="text-muted-foreground">Track stocks, crypto, and build your watchlist</p>
      </div>

      {/* Search */}
      <div className="relative max-w-md mx-auto">
        <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
        <Input
          placeholder="Search assets..."
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
          className="pl-10"
        />
      </div>

      {/* Watchlist */}
      {watchlistAssets.length > 0 && (
        <Card>
          <CardHeader>
            <CardTitle className="flex items-center gap-2">
              <Star className="h-5 w-5 text-accent" />
              Your Watchlist
            </CardTitle>
          </CardHeader>
          <CardContent>
            <div className="grid gap-4">
              {watchlistAssets.map((asset) => (
                <div key={asset.symbol} className="flex items-center justify-between p-4 rounded-lg bg-card border border-border hover:shadow-md transition-shadow">
                  <div className="flex items-center gap-4">
                    <div>
                      <div className="flex items-center gap-2">
                        <span className="font-semibold text-foreground">{asset.symbol}</span>
                        <Badge variant={asset.type === 'crypto' ? 'secondary' : 'outline'}>
                          {asset.type}
                        </Badge>
                      </div>
                      <span className="text-sm text-muted-foreground">{asset.name}</span>
                    </div>
                  </div>
                  <div className="flex items-center gap-4">
                    <div className="text-right">
                      <div className="font-semibold text-foreground">
                        ${asset.price.toLocaleString()}
                      </div>
                      <div className={`flex items-center gap-1 text-sm ${
                        asset.change >= 0 ? 'text-success' : 'text-destructive'
                      }`}>
                        {asset.change >= 0 ? <TrendingUp className="h-3 w-3" /> : <TrendingDown className="h-3 w-3" />}
                        {asset.changePercent >= 0 ? '+' : ''}{asset.changePercent.toFixed(2)}%
                      </div>
                    </div>
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => removeFromWatchlist(asset.symbol)}
                      className="text-muted-foreground hover:text-destructive"
                    >
                      <Star className="h-4 w-4 fill-current" />
                    </Button>
                  </div>
                </div>
              ))}
            </div>
          </CardContent>
        </Card>
      )}

      {/* All Assets */}
      <Card>
        <CardHeader>
          <CardTitle>All Assets</CardTitle>
        </CardHeader>
        <CardContent>
          <div className="grid gap-4">
            {filteredAssets.map((asset) => (
              <div key={asset.symbol} className="flex items-center justify-between p-4 rounded-lg bg-card border border-border hover:shadow-md transition-shadow">
                <div className="flex items-center gap-4">
                  <div>
                    <div className="flex items-center gap-2">
                      <span className="font-semibold text-foreground">{asset.symbol}</span>
                      <Badge variant={asset.type === 'crypto' ? 'secondary' : 'outline'}>
                        {asset.type}
                      </Badge>
                    </div>
                    <span className="text-sm text-muted-foreground">{asset.name}</span>
                  </div>
                </div>
                <div className="flex items-center gap-4">
                  <div className="text-right">
                    <div className="font-semibold text-foreground">
                      ${asset.price.toLocaleString()}
                    </div>
                    <div className={`flex items-center gap-1 text-sm ${
                      asset.change >= 0 ? 'text-success' : 'text-destructive'
                    }`}>
                      {asset.change >= 0 ? <TrendingUp className="h-3 w-3" /> : <TrendingDown className="h-3 w-3" />}
                      {asset.changePercent >= 0 ? '+' : ''}{asset.changePercent.toFixed(2)}%
                    </div>
                  </div>
                  {!watchlist.includes(asset.symbol) && (
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => addToWatchlist(asset.symbol)}
                      className="text-muted-foreground hover:text-accent"
                    >
                      <Plus className="h-4 w-4" />
                    </Button>
                  )}
                </div>
              </div>
            ))}
          </div>
        </CardContent>
      </Card>
    </div>
  );
};

export default AssetTracker;
Editor is loading...
Leave a Comment