phase-10: ui code enhancements

This commit is contained in:
saikiranvella
2026-06-08 13:13:17 -04:00
parent 357dfb8249
commit 3c321a4a79
18 changed files with 179 additions and 182 deletions
+3
View File
@@ -0,0 +1,3 @@
export { default as CallForm } from './CallForm.svelte';
export { default as CallCard } from './CallCard.svelte';
export { default as CalendarSection } from './CalendarSection.svelte';
+2
View File
@@ -1,2 +1,4 @@
export * from './shared/index.js';
export * from './screener/index.js';
export * from './portfolio/index.js';
export * from './calls/index.js';
+3
View File
@@ -0,0 +1,3 @@
export { default as AddHoldingForm } from './AddHoldingForm.svelte';
export { default as AdviceTable } from './AdviceTable.svelte';
export { default as AccountsTable } from './AccountsTable.svelte';
+6 -170
View File
@@ -1,170 +1,6 @@
// ── UI type layer ─────────────────────────────────────────────────────────
// Shared domain types are imported from the server's canonical model files
// via the $types alias (→ server/types/). Only UI-specific types live here.
//
// All consumers should import from '$lib/types.js' as before — nothing changes
// at the call site.
// ── Re-export shared domain types ────────────────────────────────────────
export type {
Signal,
AssetType,
ScoreMode,
ScoreResult,
AssetResult,
ScreenerResult,
} from '$types/asset.model.js';
export type {
RateRegime,
VolatilityRegime,
Benchmarks,
MarketContext,
} from '$types/market.model.js';
export type { HoldingType, PortfolioHolding, PortfolioAdvice } from '$types/portfolio.model.js';
export type { TickerSnapshot, MarketCall } from '$types/calls.model.js';
export type { LLMAnalysis, CatalystStory, CalendarEvent } from '$types/finance.model.js';
// ── UI-only types (not on the server) ────────────────────────────────────
import type { AssetType } from '$types/asset.model.js';
import type { LLMAnalysis } from '$types/finance.model.js';
/** Detailed display metrics rendered per asset row in the screener table. */
export interface AssetDisplayMetrics {
// ── Common ──────────────────────────────────────────────────────────
Price?: string;
// ── Stock: classification ────────────────────────────────────────────
Sector?: string;
'Cap Tier'?: string; // Mega Cap / Large Cap / Mid Cap / Small Cap / Micro Cap
Style?: string; // High Growth / Growth / Stable / Value / Turnaround / Declining
// ── Stock: valuation ─────────────────────────────────────────────────
'P/E'?: string;
PEG?: string;
'P/B'?: string;
// ── Stock: quality ───────────────────────────────────────────────────
'GrossM%'?: string; // gross margin — key for tech/software moat
'ROE%'?: string;
'OpMgn%'?: string;
'NetMgn%'?: string;
'FCF Yld%'?: string;
'Div%'?: string;
// ── Stock: risk ───────────────────────────────────────────────────────
'D/E'?: string;
Quick?: string;
Beta?: string;
// ── Stock: 52-week movement ───────────────────────────────────────────
'52W Pos'?: string; // % position within the 52-week range
'52W Chg'?: string; // total price return over last 52 weeks (signed %)
'From High'?: string; // % below 52-week high (negative = drawdown)
'From Low'?: string; // % above 52-week low (positive = recovery)
// ── Stock: analyst consensus ──────────────────────────────────────────
Analyst?: string; // Strong Buy / Buy / Hold / Sell / Strong Sell
'# Analysts'?: string;
Target?: string; // analyst consensus price target
Upside?: string; // % upside to analyst target (signed %)
// ── Stock: DCF intrinsic value ────────────────────────────────────────
'DCF Value'?: string; // intrinsic value per share
'DCF Safety'?: string; // margin of safety % (positive = undervalued)
// ── Stock: REIT-specific ──────────────────────────────────────────────
'P/FFO'?: string;
// ── ETF ───────────────────────────────────────────────────────────────
'Exp Ratio%'?: string;
'Yield%'?: string;
AUM?: string;
'5Y Return%'?: string;
// ── Bond ──────────────────────────────────────────────────────────────
'YTM%'?: string;
Duration?: string;
Rating?: string;
[key: string]: string | null | undefined;
}
/** State object for the LLM analysis slide-over sidebar. */
export interface SidebarState {
open: boolean;
loading: boolean;
analysis: LLMAnalysis | null;
type: AssetType | null;
error: string | null;
}
/** Transient state for inline row editing in the portfolio table. */
export interface InlineEdit {
ticker: string;
shares: string;
costBasis: string;
type: string;
source: string;
}
// ── Portfolio component types ─────────────────────────────────────────────
import type { Signal } from '$types/asset.model.js';
/** A single row in the portfolio advice table. */
export interface AdviceRow {
ticker: string;
type: string;
source: string;
shares: number;
costBasis: number;
currentPrice: string | null;
marketValue: string | null;
gainLossPct: string | null;
signal: Signal | null;
advice: string;
reason: string;
}
/** Form data for adding or updating a holding. */
export interface HoldingFormData {
ticker: string;
shares: number;
costBasis: number;
type: 'stock' | 'etf' | 'bond' | 'crypto';
source: string;
}
interface SimpleFINAccount {
name: string;
type: string;
org: string;
balance: number;
}
interface CategoryBreakdown {
category: string;
amount: number;
pct: number;
}
/** Personal finance summary from SimpleFIN. */
export interface PersonalFinance {
netWorth: number;
totalAssets: number;
totalLiabilities: number;
totalCash: number;
totalInvestments: number;
totalIncome: number;
totalSpend: number;
cashPct: number;
investPct: number;
savingsRate: string | null;
accounts: SimpleFINAccount[];
categoryBreakdown: CategoryBreakdown[];
}
/**
* Backward-compatibility shim.
* Types have been split into lib/types/ subdirectory.
* Existing '$lib/types.js' imports continue to work unchanged.
*/
export * from './types/index.js';
+3
View File
@@ -0,0 +1,3 @@
export * from './shared.js';
export * from './ui.types.js';
export * from './portfolio.types.js';
+54
View File
@@ -0,0 +1,54 @@
import type { Signal } from '$types/asset.model.js';
/** A single row in the portfolio advice table. */
export interface AdviceRow {
ticker: string;
type: string;
source: string;
shares: number;
costBasis: number;
currentPrice: string | null;
marketValue: string | null;
gainLossPct: string | null;
signal: Signal | null;
advice: string;
reason: string;
}
/** Form data for adding or updating a holding. */
export interface HoldingFormData {
ticker: string;
shares: number;
costBasis: number;
type: 'stock' | 'etf' | 'bond' | 'crypto';
source: string;
}
interface SimpleFINAccount {
name: string;
type: string;
org: string;
balance: number;
}
interface CategoryBreakdown {
category: string;
amount: number;
pct: number;
}
/** Personal finance summary from SimpleFIN. */
export interface PersonalFinance {
netWorth: number;
totalAssets: number;
totalLiabilities: number;
totalCash: number;
totalInvestments: number;
totalIncome: number;
totalSpend: number;
cashPct: number;
investPct: number;
savingsRate: string | null;
accounts: SimpleFINAccount[];
categoryBreakdown: CategoryBreakdown[];
}
+21
View File
@@ -0,0 +1,21 @@
export type {
Signal,
AssetType,
ScoreMode,
ScoreResult,
AssetResult,
ScreenerResult,
} from '$types/asset.model.js';
export type {
RateRegime,
VolatilityRegime,
Benchmarks,
MarketContext,
} from '$types/market.model.js';
export type { HoldingType, PortfolioHolding, PortfolioAdvice } from '$types/portfolio.model.js';
export type { TickerSnapshot, MarketCall } from '$types/calls.model.js';
export type { LLMAnalysis, CatalystStory, CalendarEvent } from '$types/finance.model.js';
+81
View File
@@ -0,0 +1,81 @@
import type { AssetType } from '$types/asset.model.js';
import type { LLMAnalysis } from '$types/finance.model.js';
/** Detailed display metrics rendered per asset row in the screener table. */
export interface AssetDisplayMetrics {
// ── Common ──────────────────────────────────────────────────────────
Price?: string;
// ── Stock: classification ────────────────────────────────────────────
Sector?: string;
'Cap Tier'?: string;
Style?: string;
// ── Stock: valuation ─────────────────────────────────────────────────
'P/E'?: string;
PEG?: string;
'P/B'?: string;
// ── Stock: quality ───────────────────────────────────────────────────
'GrossM%'?: string;
'ROE%'?: string;
'OpMgn%'?: string;
'NetMgn%'?: string;
'FCF Yld%'?: string;
'Div%'?: string;
// ── Stock: risk ───────────────────────────────────────────────────────
'D/E'?: string;
Quick?: string;
Beta?: string;
// ── Stock: 52-week movement ───────────────────────────────────────────
'52W Pos'?: string;
'52W Chg'?: string;
'From High'?: string;
'From Low'?: string;
// ── Stock: analyst consensus ──────────────────────────────────────────
Analyst?: string;
'# Analysts'?: string;
Target?: string;
Upside?: string;
// ── Stock: DCF intrinsic value ────────────────────────────────────────
'DCF Value'?: string;
'DCF Safety'?: string;
// ── Stock: REIT-specific ──────────────────────────────────────────────
'P/FFO'?: string;
// ── ETF ───────────────────────────────────────────────────────────────
'Exp Ratio%'?: string;
'Yield%'?: string;
AUM?: string;
'5Y Return%'?: string;
// ── Bond ──────────────────────────────────────────────────────────────
'YTM%'?: string;
Duration?: string;
Rating?: string;
[key: string]: string | null | undefined;
}
/** State object for the LLM analysis slide-over sidebar. */
export interface SidebarState {
open: boolean;
loading: boolean;
analysis: LLMAnalysis | null;
type: AssetType | null;
error: string | null;
}
/** Transient state for inline row editing in the portfolio table. */
export interface InlineEdit {
ticker: string;
shares: string;
costBasis: string;
type: string;
source: string;
}
+3 -3
View File
@@ -1,9 +1,9 @@
<script lang="ts">
import { createCall, deleteCall } from '$lib/api.js';
import { invalidateAll } from '$app/navigation';
import CallForm from '$lib/calls/CallForm.svelte';
import CallCard from '$lib/calls/CallCard.svelte';
import CalendarSection from '$lib/calls/CalendarSection.svelte';
import CallForm from '$lib/components/calls/CallForm.svelte';
import CallCard from '$lib/components/calls/CallCard.svelte';
import CalendarSection from '$lib/components/calls/CalendarSection.svelte';
import type { CalendarEvent } from '$lib/types.js';
interface MarketCall {
+3 -3
View File
@@ -2,9 +2,9 @@
import { portfolioStore } from '$lib/stores/portfolio.store.svelte.js';
import MarketContext from '$lib/components/shared/MarketContext.svelte';
import Spinner from '$lib/components/shared/Spinner.svelte';
import AddHoldingForm from '$lib/portfolio/AddHoldingForm.svelte';
import AdviceTable from '$lib/portfolio/AdviceTable.svelte';
import AccountsTable from '$lib/portfolio/AccountsTable.svelte';
import AddHoldingForm from '$lib/components/portfolio/AddHoldingForm.svelte';
import AdviceTable from '$lib/components/portfolio/AdviceTable.svelte';
import AccountsTable from '$lib/components/portfolio/AccountsTable.svelte';
const p = portfolioStore;