diff --git a/web/src/components/layout/AppShell.tsx b/web/src/components/layout/AppShell.tsx
index 3633a72..8ca03ed 100644
--- a/web/src/components/layout/AppShell.tsx
+++ b/web/src/components/layout/AppShell.tsx
@@ -4,6 +4,7 @@ import { Sidebar } from './Sidebar';
import { Header } from './Header';
import { RightPanel } from './RightPanel';
import { Button } from '../ui/button';
+import { getLegacySimpleRoute, getPlansRoute } from '../../views/tradePlansRoutes';
const HomeView = lazy(() => import('../../views/HomeView').then((mod) => ({ default: mod.HomeView })));
const PortfolioView = lazy(() => import('../../views/PortfolioView').then((mod) => ({ default: mod.PortfolioView })));
@@ -75,7 +76,7 @@ function NotFoundView() {
function SimpleAliasRedirect() {
const location = useLocation();
- return ;
+ return ;
}
export function AppShell() {
@@ -98,8 +99,8 @@ export function AppShell() {
} />
} />
} />
- } />
- } />
+ } />
+ } />
} />
} />
} />
diff --git a/web/src/components/layout/Sidebar.tsx b/web/src/components/layout/Sidebar.tsx
index ae349c1..3a48443 100644
--- a/web/src/components/layout/Sidebar.tsx
+++ b/web/src/components/layout/Sidebar.tsx
@@ -4,12 +4,13 @@ import {
SlidersHorizontal, Star, Bell, Settings,
} from 'lucide-react';
import { useAppContext } from '../../context/AppContext';
+import { getPlansRoute } from '../../views/tradePlansRoutes';
const NAV = [
{ to: '/', icon: Home, label: 'Home', end: true },
{ to: '/portfolio', icon: Briefcase, label: 'Portfolio', end: false },
{ to: '/research', icon: FlaskConical, label: 'Research', end: false },
- { to: '/plans', icon: Target, label: 'Plans', end: false },
+ { to: getPlansRoute(), icon: Target, label: 'Plans', end: false },
{ to: '/markets', icon: TrendingUp, label: 'Markets', end: false },
{ to: '/screener', icon: SlidersHorizontal, label: 'Screener', end: false },
{ to: '/watchlist', icon: Star, label: 'Watchlist', end: false },
diff --git a/web/src/views/PortfolioView.tsx b/web/src/views/PortfolioView.tsx
index 2621602..0f95545 100644
--- a/web/src/views/PortfolioView.tsx
+++ b/web/src/views/PortfolioView.tsx
@@ -4,6 +4,7 @@ import { useAppContext } from '../context/AppContext';
import { PositionsTab } from '../tabs/PositionsTab';
import { HistoryTab } from '../tabs/HistoryTab';
import { PageHeader } from '../components/ui/page-header';
+import { buildCreateExitPlanUrl, buildPlanDrillInUrl } from './tradePlansRoutes';
const TABS = ['Positions & Orders', 'Trade History'] as const;
type Tab = typeof TABS[number];
@@ -37,14 +38,10 @@ export function PortfolioView() {
{
- const params = action === 'open-plan' && position.planEntryId
- ? new URLSearchParams({ setupId: position.planEntryId })
- : new URLSearchParams({
- mode: 'sell',
- symbol: position.symbol,
- });
- if (action !== 'open-plan' && position.tradeId) params.set('tradeId', position.tradeId);
- navigate(`/plans?${params.toString()}`);
+ const target = action === 'open-plan' && position.planEntryId
+ ? buildPlanDrillInUrl(position.planEntryId)
+ : buildCreateExitPlanUrl(position.symbol, position.tradeId);
+ navigate(target);
}}
/>
)}
diff --git a/web/src/views/SimpleView.tsx b/web/src/views/SimpleView.tsx
index 5d2936f..f6bc258 100644
--- a/web/src/views/SimpleView.tsx
+++ b/web/src/views/SimpleView.tsx
@@ -705,7 +705,7 @@ export function SimpleView() {
setSavedSetups(normalizeSimpleEntries(entryRows));
} catch (err: any) {
if (cancelled) return;
- dispatch({ type: 'set-error', value: err?.message ?? 'Failed to load Simple setups' });
+ dispatch({ type: 'set-error', value: err?.message ?? 'Failed to load Trade Plans' });
}
}
@@ -884,13 +884,13 @@ export function SimpleView() {
if (editingSetupId) {
await updateManualEntry(editingSetupId, payload);
- dispatch({ type: 'set-message', value: `Updated ${normalizedSymbol} Simple setup.` });
+ dispatch({ type: 'set-message', value: `Updated ${normalizedSymbol} trade plan.` });
} else {
await createManualEntry({
...payload,
stock_instance_id: crypto.randomUUID(),
});
- dispatch({ type: 'set-message', value: `Saved ${normalizedSymbol} Simple setup.` });
+ dispatch({ type: 'set-message', value: `Saved ${normalizedSymbol} trade plan.` });
}
await refreshSetupList();
@@ -900,7 +900,7 @@ export function SimpleView() {
marketPriceSource: draft.currentMarketPrice ? marketPriceSource : null,
});
} catch (err: any) {
- dispatch({ type: 'set-error', value: err?.message ?? 'Failed to save Simple setup' });
+ dispatch({ type: 'set-error', value: err?.message ?? 'Failed to save Trade Plan' });
} finally {
setSubmitting(false);
}
@@ -915,7 +915,7 @@ export function SimpleView() {
}
async function handleDelete(entryId: string) {
- if (!window.confirm('Delete this Simple setup?')) return;
+ if (!window.confirm('Delete this Trade Plan?')) return;
try {
await deleteManualEntry(entryId);
if (editingSetupId === entryId) {
@@ -923,7 +923,7 @@ export function SimpleView() {
}
await refreshSetupList();
} catch (err: any) {
- dispatch({ type: 'set-error', value: err?.message ?? 'Failed to delete Simple setup' });
+ dispatch({ type: 'set-error', value: err?.message ?? 'Failed to delete Trade Plan' });
}
}
diff --git a/web/src/views/tradePlansRoutes.test.ts b/web/src/views/tradePlansRoutes.test.ts
new file mode 100644
index 0000000..1202c0c
--- /dev/null
+++ b/web/src/views/tradePlansRoutes.test.ts
@@ -0,0 +1,17 @@
+import { describe, expect, it } from 'vitest';
+import {
+ buildCreateExitPlanUrl,
+ buildPlanDrillInUrl,
+ getLegacySimpleRoute,
+ getPlansRoute,
+} from './tradePlansRoutes';
+
+describe('tradePlansRoutes', () => {
+ it('builds the canonical plans routes consistently', () => {
+ expect(getPlansRoute()).toBe('/plans');
+ expect(getLegacySimpleRoute()).toBe('/simple');
+ expect(buildPlanDrillInUrl('setup-1')).toBe('/plans?setupId=setup-1');
+ expect(buildCreateExitPlanUrl('MSFT', 'TRD-MSFT')).toBe('/plans?mode=sell&symbol=MSFT&tradeId=TRD-MSFT');
+ expect(buildCreateExitPlanUrl('AAPL')).toBe('/plans?mode=sell&symbol=AAPL');
+ });
+});
diff --git a/web/src/views/tradePlansRoutes.ts b/web/src/views/tradePlansRoutes.ts
new file mode 100644
index 0000000..3ecb66a
--- /dev/null
+++ b/web/src/views/tradePlansRoutes.ts
@@ -0,0 +1,23 @@
+const PLANS_ROUTE = '/plans';
+const LEGACY_SIMPLE_ROUTE = '/simple';
+
+export function getPlansRoute() {
+ return PLANS_ROUTE;
+}
+
+export function getLegacySimpleRoute() {
+ return LEGACY_SIMPLE_ROUTE;
+}
+
+export function buildPlanDrillInUrl(setupId: string) {
+ return `${PLANS_ROUTE}?${new URLSearchParams({ setupId }).toString()}`;
+}
+
+export function buildCreateExitPlanUrl(symbol: string, tradeId?: string | null) {
+ const params = new URLSearchParams({
+ mode: 'sell',
+ symbol,
+ });
+ if (tradeId) params.set('tradeId', tradeId);
+ return `${PLANS_ROUTE}?${params.toString()}`;
+}