UI: surface buying/selling suggestion and execution plan in portfolio and stock detail (show last saved suggestion)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { useLoaderData, useNavigate, useLocation } from "react-router";
|
||||
import TradingViewChart from "../components/TradingViewChart";
|
||||
import Navbar from "../components/Navbar";
|
||||
import JobHistory from "../components/JobHistory";
|
||||
import { useMemo } from "react";
|
||||
import type { TradingDecision, AnalystReport, DebateRound } from "../types/agents";
|
||||
|
||||
export const meta = () => [{ title: "Stock Detail - AITrader" }];
|
||||
@@ -103,6 +104,15 @@ export default function StockDetail() {
|
||||
// Cache key for this ticker
|
||||
const cacheKey = `tradinggraph-${ticker}`;
|
||||
|
||||
// Parsed last execution plan if present on stockRecord
|
||||
const lastExecutionPlan = useMemo(() => {
|
||||
try {
|
||||
return stockRecord?.lastExecutionPlan ? JSON.parse(stockRecord.lastExecutionPlan) : null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}, [stockRecord]);
|
||||
|
||||
// Load cached results on mount
|
||||
useEffect(() => {
|
||||
const cached = sessionStorage.getItem(cacheKey);
|
||||
@@ -299,6 +309,23 @@ export default function StockDetail() {
|
||||
|
||||
{/* Job history */}
|
||||
<JobHistory ticker={ticker} />
|
||||
|
||||
{/* Last persisted decision (if no live decision) */}
|
||||
{!decision && stockRecord?.lastDecision && (
|
||||
<div className="mt-3 bg-white rounded-lg p-3 border border-gray-200 text-gray-900">
|
||||
<h4 className="text-sm font-medium">Last Saved Suggestion</h4>
|
||||
<div className="mt-2 text-sm">
|
||||
<div>Action: <strong className={stockRecord.lastDecision === 'buy' ? 'text-green-600' : stockRecord.lastDecision === 'sell' ? 'text-red-600' : 'text-gray-800'}>{stockRecord.lastDecision?.toUpperCase()}</strong></div>
|
||||
{lastExecutionPlan && (
|
||||
<div className="mt-2 text-sm text-gray-700">
|
||||
{lastExecutionPlan.amount != null && (<div>Amount: <strong>{lastExecutionPlan.amount}</strong></div>)}
|
||||
{lastExecutionPlan.takeProfit != null && (<div>Take profit: <strong>${lastExecutionPlan.takeProfit}</strong></div>)}
|
||||
{lastExecutionPlan.riskManagement?.maxLossPercent != null && (<div>Risk: <strong>{lastExecutionPlan.riskManagement.maxLossPercent}%</strong></div>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
|
||||
<div className="mt-6 bg-white rounded-xl shadow-lg p-6 border border-gray-200">
|
||||
|
||||
@@ -352,8 +352,14 @@ export default function Analyze() {
|
||||
{stock.analysis.action.toUpperCase()}
|
||||
</span>
|
||||
<div className="text-xs text-gray-500">
|
||||
Confidence: {(stock.analysis.confidence * 100).toFixed(0)}%
|
||||
{stock.analysis.confidence ? `Confidence: ${(stock.analysis.confidence * 100).toFixed(0)}%` : "Saved suggestion"}
|
||||
</div>
|
||||
{stock.analysis.executionPlan && (
|
||||
<div className="text-xs text-gray-700 mt-1">
|
||||
{stock.analysis.executionPlan.amount != null && (<div>Amount: <strong>{stock.analysis.executionPlan.amount}</strong></div>)}
|
||||
{stock.analysis.executionPlan.takeProfit != null && (<div>Take profit: <strong>${stock.analysis.executionPlan.takeProfit}</strong></div>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : stock.loading ? (
|
||||
<span className="text-blue-600">Analyzing...</span>
|
||||
|
||||
Reference in New Issue
Block a user