fix: null safety for market data components and backend CI
This commit is contained in:
parent
a14e24d8e8
commit
ca4a8b35f3
@ -3,11 +3,12 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "prisma generate",
|
||||||
"build": "nest build",
|
"build": "nest build",
|
||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:prod": "node dist/main",
|
"start:prod": "node dist/main",
|
||||||
"lint": "eslint \"{src,test}/**/*.ts\"",
|
"lint": "eslint \"{src,test}/**/*.ts\"",
|
||||||
"test": "vitest run",
|
"test": "VITE_CJS_IGNORE_WARNING=1 vitest run",
|
||||||
"test:watch": "vitest"
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -9,10 +9,10 @@ export interface ApiEnvelope<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface StockMarketData {
|
export interface StockMarketData {
|
||||||
price: number;
|
price: number | null;
|
||||||
change: number;
|
change: number | null;
|
||||||
changePercent: number;
|
changePercent: number | null;
|
||||||
open: number;
|
open: number | null;
|
||||||
high: number | null;
|
high: number | null;
|
||||||
low: number | null;
|
low: number | null;
|
||||||
volume: number;
|
volume: number;
|
||||||
@ -52,11 +52,11 @@ export interface ShareHistoryItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface BondMarketData {
|
export interface BondMarketData {
|
||||||
price: number;
|
price: number | null;
|
||||||
yieldToMaturity: number | null;
|
yieldToMaturity: number | null;
|
||||||
duration: number | null;
|
duration: number | null;
|
||||||
accruedInt: number;
|
accruedInt: number | null;
|
||||||
couponValue: number;
|
couponValue: number | null;
|
||||||
couponPercent: number | null;
|
couponPercent: number | null;
|
||||||
nextCouponDate: string | null;
|
nextCouponDate: string | null;
|
||||||
open: number;
|
open: number;
|
||||||
|
|||||||
@ -28,7 +28,9 @@ export function BondDetails({ bond }: BondDetailsProps) {
|
|||||||
<div style={{ fontSize: 14, color: 'var(--color-text-secondary)' }}>{bond.isin}</div>
|
<div style={{ fontSize: 14, color: 'var(--color-text-secondary)' }}>{bond.isin}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>{md.price.toFixed(2)}%</div>
|
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>
|
||||||
|
{md.price?.toFixed(2) ?? '—'}%
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: 16 }}>
|
<div style={{ marginTop: 16 }}>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
@ -44,7 +46,7 @@ export function BondDetails({ bond }: BondDetailsProps) {
|
|||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
<span>Купон</span>
|
<span>Купон</span>
|
||||||
<span>
|
<span>
|
||||||
{md.couponValue} ₽ {md.couponPercent != null ? `(${md.couponPercent}%)` : ''}
|
{md.couponValue ?? '—'} ₽ {md.couponPercent != null ? `(${md.couponPercent}%)` : ''}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
@ -57,7 +59,7 @@ export function BondDetails({ bond }: BondDetailsProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
<span>НКД</span>
|
<span>НКД</span>
|
||||||
<span>{md.accruedInt.toFixed(2)} ₽</span>
|
<span>{md.accruedInt?.toFixed(2) ?? '—'} ₽</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
<span>Доходность к погашению</span>
|
<span>Доходность к погашению</span>
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const rowStyle: React.CSSProperties = {
|
|||||||
|
|
||||||
export function StockDetails({ stock }: StockDetailsProps) {
|
export function StockDetails({ stock }: StockDetailsProps) {
|
||||||
const md = stock.marketData;
|
const md = stock.marketData;
|
||||||
const isPositive = md.change >= 0;
|
const isPositive = (md.change ?? 0) >= 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -34,7 +34,7 @@ export function StockDetails({ stock }: StockDetailsProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>
|
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>
|
||||||
{md.price.toLocaleString('ru-RU', { minimumFractionDigits: 2 })}{' '}
|
{md.price?.toLocaleString('ru-RU', { minimumFractionDigits: 2 }) ?? '—'}{' '}
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
@ -42,14 +42,14 @@ export function StockDetails({ stock }: StockDetailsProps) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isPositive ? '+' : ''}
|
{isPositive ? '+' : ''}
|
||||||
{md.change.toFixed(2)} ({md.changePercent.toFixed(2)}%)
|
{(md.change ?? 0).toFixed(2)} ({(md.changePercent ?? 0).toFixed(2)}%)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: 16 }}>
|
<div style={{ marginTop: 16 }}>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
<span>Открытие</span>
|
<span>Открытие</span>
|
||||||
<span>{md.open.toFixed(2)}</span>
|
<span>{md.open?.toFixed(2) ?? '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={rowStyle}>
|
<div style={rowStyle}>
|
||||||
<span>Максимум</span>
|
<span>Максимум</span>
|
||||||
|
|||||||
1
package-lock.json
generated
1
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"apps/backend": {
|
"apps/backend": {
|
||||||
"name": "@moex-vibe/backend",
|
"name": "@moex-vibe/backend",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@libsql/client": "^0.17.3",
|
"@libsql/client": "^0.17.3",
|
||||||
"@nestjs/axios": "^3.0.0",
|
"@nestjs/axios": "^3.0.0",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user