aW1wb3J0IFJlYWN0LCB7IHVzZVN0YXRlLCB1c2VFZmZlY3QgfSBmcm9tICZxdW90O3JlYWN0JnF1b3Q7OwppbXBvcnQgeyBDYXJkLCBDYXJkQ29udGVudCB9IGZyb20gJnF1b3Q7QC9jb21wb25lbnRzL3VpL2NhcmQmcXVvdDs7CmltcG9ydCB7IElucHV0IH0gZnJvbSAmcXVvdDtAL2NvbXBvbmVudHMvdWkvaW5wdXQmcXVvdDs7CmltcG9ydCB7IEJ1dHRvbiB9IGZyb20gJnF1b3Q7QC9jb21wb25lbnRzL3VpL2J1dHRvbiZxdW90OzsKCmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFBvcnRmb2xpb1RyYWNrZXIoKSB7CiAgY29uc3QgW3N0b2Nrcywgc2V0U3RvY2tzXSA9IHVzZVN0YXRlKFtdKTsKICBjb25zdCBbc3ltYm9sLCBzZXRTeW1ib2xdID0gdXNlU3RhdGUoJnF1b3Q7JnF1b3Q7KTsKICBjb25zdCBbYW1vdW50LCBzZXRBbW91bnRdID0gdXNlU3RhdGUoJnF1b3Q7JnF1b3Q7KTsKICBjb25zdCBbY29zdCwgc2V0Q29zdF0gPSB1c2VTdGF0ZSgmcXVvdDsmcXVvdDspOwoKICAvLyDguYDguJ7guLTguYjguKHguKvguLjguYnguJnguYDguKPguLTguYjguKHguJXguYnguJkKICB1c2VFZmZlY3QoKCkgPSZndDsgewogICAgY29uc3QgaW5pdGlhbFN0b2NrcyA9IFsKICAgICAgeyBzeW1ib2w6ICZxdW90O08mcXVvdDssIGFtb3VudDogMSwgY29zdDogMzQwIH0sCiAgICAgIHsgc3ltYm9sOiAmcXVvdDtKTkomcXVvdDssIGFtb3VudDogMSwgY29zdDogMzMwIH0sCiAgICAgIHsgc3ltYm9sOiAmcXVvdDtNU0ZUJnF1b3Q7LCBhbW91bnQ6IDEsIGNvc3Q6IDMzMCB9LAogICAgXTsKICAgIHNldFN0b2Nrcyhpbml0aWFsU3RvY2tzKTsKICB9LCBbXSk7CgogIGNvbnN0IGFkZFN0b2NrID0gKCkgPSZndDsgewogICAgaWYgKCFzeW1ib2wgfHwgIWFtb3VudCB8fCAhY29zdCkgcmV0dXJuOwogICAgc2V0U3RvY2tzKFsKICAgICAgLi4uc3RvY2tzLAogICAgICB7IHN5bWJvbCwgYW1vdW50OiBOdW1iZXIoYW1vdW50KSwgY29zdDogTnVtYmVyKGNvc3QpIH0sCiAgICBdKTsKICAgIHNldFN5bWJvbCgmcXVvdDsmcXVvdDspOwogICAgc2V0QW1vdW50KCZxdW90OyZxdW90Oyk7CiAgICBzZXRDb3N0KCZxdW90OyZxdW90Oyk7CiAgfTsKCiAgY29uc3QgY2xlYXJQb3J0Zm9saW8gPSAoKSA9Jmd0OyB7CiAgICBzZXRTdG9ja3MoW10pOwogIH07CgogIGNvbnN0IHRvdGFsSW52ZXN0bWVudCA9IHN0b2Nrcy5yZWR1Y2UoCiAgICAoYWNjLCBzdG9jaykgPSZndDsgYWNjICsgc3RvY2suYW1vdW50ICogc3RvY2suY29zdCwKICAgIDAKICApOwoKICByZXR1cm4gKAogICAgJmx0O2RpdiBjbGFzc05hbWU9JnF1b3Q7bWF4LXctMnhsIG14LWF1dG8gcC00IHNwYWNlLXktNCZxdW90OyZndDsKICAgICAgJmx0O2gxIGNsYXNzTmFtZT0mcXVvdDt0ZXh0LXhsIGZvbnQtYm9sZCZxdW90OyZndDvguKPguLLguKLguIfguLLguJnguIHguLLguKPguKXguIfguJfguLjguJnguYHguJrguJogRENBJmx0Oy9oMSZndDsKICAgICAgJmx0O2RpdiBjbGFzc05hbWU9JnF1b3Q7Z3JpZCBncmlkLWNvbHMtMyBnYXAtMiZxdW90OyZndDsKICAgICAgICAmbHQ7SW5wdXQKICAgICAgICAgIHBsYWNlaG9sZGVyPSZxdW90O+C4q+C4uOC5ieC4mSAo4LmA4LiK4LmI4LiZIE1TRlQpJnF1b3Q7CiAgICAgICAgICB2YWx1ZT17c3ltYm9sfQogICAgICAgICAgb25DaGFuZ2U9eyhlKSA9Jmd0OyBzZXRTeW1ib2woZS50YXJnZXQudmFsdWUpfQogICAgICAgIC8mZ3Q7CiAgICAgICAgJmx0O0lucHV0CiAgICAgICAgICBwbGFjZWhvbGRlcj0mcXVvdDvguIjguLPguJnguKfguJnguKvguLjguYnguJkmcXVvdDsKICAgICAgICAgIHR5cGU9JnF1b3Q7bnVtYmVyJnF1b3Q7CiAgICAgICAgICB2YWx1ZT17YW1vdW50fQogICAgICAgICAgb25DaGFuZ2U9eyhlKSA9Jmd0OyBzZXRBbW91bnQoZS50YXJnZXQudmFsdWUpfQogICAgICAgIC8mZ3Q7CiAgICAgICAgJmx0O0lucHV0CiAgICAgICAgICBwbGFjZWhvbGRlcj0mcXVvdDvguKPguLLguITguLLguJXguYjguK3guKvguLjguYnguJkmcXVvdDsKICAgICAgICAgIHR5cGU9JnF1b3Q7bnVtYmVyJnF1b3Q7CiAgICAgICAgICB2YWx1ZT17Y29zdH0KICAgICAgICAgIG9uQ2hhbmdlPXsoZSkgPSZndDsgc2V0Q29zdChlLnRhcmdldC52YWx1ZSl9CiAgICAgICAgLyZndDsKICAgICAgJmx0Oy9kaXYmZ3Q7CiAgICAgICZsdDtkaXYgY2xhc3NOYW1lPSZxdW90O2ZsZXggZ2FwLTImcXVvdDsmZ3Q7CiAgICAgICAgJmx0O0J1dHRvbiBvbkNsaWNrPXthZGRTdG9ja30mZ3Q74LmA4Lie4Li04LmI4Lih4LiB4Liy4Lij4Lil4LiH4LiX4Li44LiZJmx0Oy9CdXR0b24mZ3Q7CiAgICAgICAgJmx0O0J1dHRvbiB2YXJpYW50PSZxdW90O2Rlc3RydWN0aXZlJnF1b3Q7IG9uQ2xpY2s9e2NsZWFyUG9ydGZvbGlvfSZndDsKICAgICAgICAgIOC4peC5ieC4suC4h+C4nuC4reC4o+C5jOC4lQogICAgICAgICZsdDsvQnV0dG9uJmd0OwogICAgICAmbHQ7L2RpdiZndDsKCiAgICAgICZsdDtDYXJkJmd0OwogICAgICAgICZsdDtDYXJkQ29udGVudCBjbGFzc05hbWU9JnF1b3Q7cC00JnF1b3Q7Jmd0OwogICAgICAgICAgJmx0O2gyIGNsYXNzTmFtZT0mcXVvdDt0ZXh0LWxnIGZvbnQtc2VtaWJvbGQgbWItMiZxdW90OyZndDvguKPguLLguKLguIHguLLguKPguKvguLjguYnguJkmbHQ7L2gyJmd0OwogICAgICAgICAge3N0b2Nrcy5sZW5ndGggPT09IDAgPyAoCiAgICAgICAgICAgICZsdDtwIGNsYXNzTmFtZT0mcXVvdDt0ZXh0LWdyYXktNTAwJnF1b3Q7Jmd0O+C4ouC4seC4h+C5hOC4oeC5iOC4oeC4teC4guC5ieC4reC4oeC4ueC4peC4geC4suC4o+C4peC4h+C4l+C4uOC4mSZsdDsvcCZndDsKICAgICAgICAgICkgOiAoCiAgICAgICAgICAgICZsdDt0YWJsZSBjbGFzc05hbWU9JnF1b3Q7dy1mdWxsIHRleHQtc20mcXVvdDsmZ3Q7CiAgICAgICAgICAgICAgJmx0O3RoZWFkJmd0OwogICAgICAgICAgICAgICAgJmx0O3RyIGNsYXNzTmFtZT0mcXVvdDt0ZXh0LWxlZnQgYm9yZGVyLWImcXVvdDsmZ3Q7CiAgICAgICAgICAgICAgICAgICZsdDt0aCBjbGFzc05hbWU9JnF1b3Q7cHktMSZxdW90OyZndDvguKvguLjguYnguJkmbHQ7L3RoJmd0OwogICAgICAgICAgICAgICAgICAmbHQ7dGggY2xhc3NOYW1lPSZxdW90O3B5LTEmcXVvdDsmZ3Q74LiI4Liz4LiZ4Lin4LiZJmx0Oy90aCZndDsKICAgICAgICAgICAgICAgICAgJmx0O3RoIGNsYXNzTmFtZT0mcXVvdDtweS0xJnF1b3Q7Jmd0O+C4o+C4suC4hOC4suC4leC5iOC4reC4q+C4uOC5ieC4mSZsdDsvdGgmZ3Q7CiAgICAgICAgICAgICAgICAgICZsdDt0aCBjbGFzc05hbWU9JnF1b3Q7cHktMSZxdW90OyZndDvguKHguLnguKXguITguYjguLLguKPguKfguKEmbHQ7L3RoJmd0OwogICAgICAgICAgICAgICAgJmx0Oy90ciZndDsKICAgICAgICAgICAgICAmbHQ7L3RoZWFkJmd0OwogICAgICAgICAgICAgICZsdDt0Ym9keSZndDsKICAgICAgICAgICAgICAgIHtzdG9ja3MubWFwKChzdG9jaywgaW5kZXgpID0mZ3Q7ICgKICAgICAgICAgICAgICAgICAgJmx0O3RyIGtleT17aW5kZXh9IGNsYXNzTmFtZT0mcXVvdDtib3JkZXItYiZxdW90OyZndDsKICAgICAgICAgICAgICAgICAgICAmbHQ7dGQgY2xhc3NOYW1lPSZxdW90O3B5LTEmcXVvdDsmZ3Q7e3N0b2NrLnN5bWJvbH0mbHQ7L3RkJmd0OwogICAgICAgICAgICAgICAgICAgICZsdDt0ZCBjbGFzc05hbWU9JnF1b3Q7cHktMSZxdW90OyZndDt7c3RvY2suYW1vdW50fSZsdDsvdGQmZ3Q7CiAgICAgICAgICAgICAgICAgICAgJmx0O3RkIGNsYXNzTmFtZT0mcXVvdDtweS0xJnF1b3Q7Jmd0O3tzdG9jay5jb3N0LnRvRml4ZWQoMil9Jmx0Oy90ZCZndDsKICAgICAgICAgICAgICAgICAgICAmbHQ7dGQgY2xhc3NOYW1lPSZxdW90O3B5LTEmcXVvdDsmZ3Q7CiAgICAgICAgICAgICAgICAgICAgICB7KHN0b2NrLmFtb3VudCAqIHN0b2NrLmNvc3QpLnRvRml4ZWQoMil9
import React, { useState, useEffect } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
export default function PortfolioTracker() {
const [stocks, setStocks] = useState([]);
const [symbol, setSymbol] = useState("");
const [amount, setAmount] = useState("");
const [cost, setCost] = useState("");
// เพิ่มหุ้นเริ่มต้น
useEffect(() => {
const initialStocks = [
{ symbol: "O", amount: 1, cost: 340 },
{ symbol: "JNJ", amount: 1, cost: 330 },
{ symbol: "MSFT", amount: 1, cost: 330 },
];
setStocks(initialStocks);
}, []);
const addStock = () => {
if (!symbol || !amount || !cost) return;
setStocks([
...stocks,
{ symbol, amount: Number(amount), cost: Number(cost) },
]);
setSymbol("");
setAmount("");
setCost("");
};
const clearPortfolio = () => {
setStocks([]);
};
const totalInvestment = stocks.reduce(
(acc, stock) => acc + stock.amount * stock.cost,
0
);
return (
<div className="max-w-2xl mx-auto p-4 space-y-4">
<h1 className="text-xl font-bold">รายงานการลงทุนแบบ DCA</h1>
<div className="grid grid-cols-3 gap-2">
<Input
placeholder="หุ้น (เช่น MSFT)"
value={symbol}
onChange={(e) => setSymbol(e.target.value)}
/>
<Input
placeholder="จำนวนหุ้น"
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<Input
placeholder="ราคาต่อหุ้น"
type="number"
value={cost}
onChange={(e) => setCost(e.target.value)}
/>
</div>
<div className="flex gap-2">
<Button onClick={addStock}>เพิ่มการลงทุน</Button>
<Button variant="destructive" onClick={clearPortfolio}>
ล้างพอร์ต
</Button>
</div>
<Card>
<CardContent className="p-4">
<h2 className="text-lg font-semibold mb-2">รายการหุ้น</h2>
{stocks.length === 0 ? (
<p className="text-gray-500">ยังไม่มีข้อมูลการลงทุน</p>
) : (
<table className="w-full text-sm">
<thead>
<tr className="text-left border-b">
<th className="py-1">หุ้น</th>
<th className="py-1">จำนวน</th>
<th className="py-1">ราคาต่อหุ้น</th>
<th className="py-1">มูลค่ารวม</th>
</tr>
</thead>
<tbody>
{stocks.map((stock, index) => (
<tr key={index} className="border-b">
<td className="py-1">{stock.symbol}</td>
<td className="py-1">{stock.amount}</td>
<td className="py-1">{stock.cost.toFixed(2)}</td>
<td className="py-1">
{(stock.amount * stock.cost).toFixed(2)}