- Delete shared/api/responses.ts, move type re-exports to index.ts - Update all 55+ imports from shared/api/responses to shared/api - Delete stale client.test.ts (tested deleted client.ts) - Run biome checks and fix import ordering - Update tasks.md and plan.md to reflect actual approach
83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import { Link } from '@tanstack/react-router'
|
||
import type { Portfolio } from '@/shared/api'
|
||
import { pluralize } from '@/shared/lib/formatters'
|
||
|
||
export function PortfolioCard({ portfolio }: { portfolio: Portfolio }) {
|
||
const chipStyle = (bg: string): React.CSSProperties => ({
|
||
background: bg,
|
||
padding: '4px 10px',
|
||
borderRadius: 6,
|
||
fontSize: 12,
|
||
color: '#fff',
|
||
fontWeight: 500,
|
||
})
|
||
|
||
return (
|
||
<Link
|
||
to={`/portfolios/${portfolio.id}`}
|
||
style={{
|
||
display: 'block',
|
||
padding: 20,
|
||
background: 'var(--color-surface)',
|
||
border: '1px solid #e0e0e0',
|
||
borderRadius: 'var(--border-radius)',
|
||
textDecoration: 'none',
|
||
color: 'inherit',
|
||
transition: 'box-shadow 0.2s',
|
||
}}
|
||
onMouseEnter={(e) => (e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)')}
|
||
onMouseLeave={(e) => (e.currentTarget.style.boxShadow = 'none')}
|
||
>
|
||
<div
|
||
style={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'flex-start',
|
||
marginBottom: 12,
|
||
}}
|
||
>
|
||
<h3 style={{ margin: 0, fontSize: 16, fontWeight: 600, flex: 1 }}>{portfolio.name}</h3>
|
||
<div style={{ textAlign: 'right' }}>
|
||
<div style={{ fontSize: 20, fontWeight: 700, lineHeight: 1.2 }}>
|
||
{portfolio.totalValue?.toLocaleString('ru-RU', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2,
|
||
})}
|
||
</div>
|
||
<div style={{ fontSize: 11, color: 'var(--color-text-secondary)' }}>
|
||
{portfolio.currency}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{portfolio.description && (
|
||
<p style={{ margin: '0 0 12px', fontSize: 13, color: 'var(--color-text-secondary)' }}>
|
||
{portfolio.description}
|
||
</p>
|
||
)}
|
||
|
||
<div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
|
||
{portfolio.shareCount > 0 && (
|
||
<span style={chipStyle('#1b5e20')}>
|
||
{portfolio.shareCount} {pluralize(portfolio.shareCount, 'акция', 'акции', 'акций')}
|
||
</span>
|
||
)}
|
||
{portfolio.bondCount > 0 && (
|
||
<span style={chipStyle('#0d47a1')}>
|
||
{portfolio.bondCount}{' '}
|
||
{pluralize(portfolio.bondCount, 'облигация', 'облигации', 'облигаций')}
|
||
</span>
|
||
)}
|
||
<span style={chipStyle('#424242')}>
|
||
{portfolio.positionCount}{' '}
|
||
{pluralize(portfolio.positionCount, 'позиция', 'позиции', 'позиций')}
|
||
</span>
|
||
</div>
|
||
|
||
<span style={{ fontSize: 12, color: 'var(--color-text-secondary)' }}>
|
||
обновлён {new Date(portfolio.updatedAt).toLocaleDateString('ru-RU')}
|
||
</span>
|
||
</Link>
|
||
)
|
||
}
|