feat: p&l label in portfolio + fixed unnecessary calls to /total

This commit is contained in:
Face 2025-06-11 11:06:05 +03:00
parent 8cba222fe2
commit 99614f853e
10 changed files with 172 additions and 53 deletions

View file

@ -34,7 +34,7 @@
import { mode, setMode } from 'mode-watcher';
import type { HTMLAttributes } from 'svelte/elements';
import { USER_DATA } from '$lib/stores/user-data';
import { PORTFOLIO_DATA, fetchPortfolioData } from '$lib/stores/portfolio-data';
import { PORTFOLIO_SUMMARY, fetchPortfolioSummary } from '$lib/stores/portfolio-data';
import { useSidebar } from '$lib/components/ui/sidebar/index.js';
import SignInConfirmDialog from './SignInConfirmDialog.svelte';
import DailyRewards from './DailyRewards.svelte';
@ -44,6 +44,7 @@
import { formatValue, getPublicUrl } from '$lib/utils';
import { goto } from '$app/navigation';
import { liveTradesStore, isLoadingTrades } from '$lib/stores/websocket';
import { onMount } from 'svelte';
const data = {
navMain: [
@ -64,11 +65,11 @@
let showPromoCode = $state(false);
let showUserManual = $state(false);
$effect(() => {
onMount(() => {
if ($USER_DATA) {
fetchPortfolioData();
fetchPortfolioSummary();
} else {
PORTFOLIO_DATA.set(null);
PORTFOLIO_SUMMARY.set(null);
}
});
@ -208,7 +209,7 @@
<Sidebar.Group>
<Sidebar.GroupContent>
<div class="px-2 py-1">
{#if !$PORTFOLIO_DATA}
{#if !$PORTFOLIO_SUMMARY}
<div class="space-y-2">
<Skeleton class="h-8 w-full rounded" />
</div>
@ -318,7 +319,7 @@
<Sidebar.GroupLabel>Portfolio</Sidebar.GroupLabel>
<Sidebar.GroupContent>
<div class="space-y-2 px-2 py-1">
{#if !$PORTFOLIO_DATA}
{#if !$PORTFOLIO_SUMMARY}
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<Skeleton class="h-4 w-4 rounded" />
@ -343,19 +344,19 @@
<span class="text-sm font-medium">Total Value</span>
</div>
<Badge variant="secondary" class="font-mono">
${formatCurrency($PORTFOLIO_DATA.totalValue)}
${formatCurrency($PORTFOLIO_SUMMARY.totalValue)}
</Badge>
</div>
<div class="text-muted-foreground space-y-1 text-xs">
<div class="flex justify-between">
<span>Cash:</span>
<span class="font-mono"
>${formatCurrency($PORTFOLIO_DATA.baseCurrencyBalance)}</span
>${formatCurrency($PORTFOLIO_SUMMARY.baseCurrencyBalance)}</span
>
</div>
<div class="flex justify-between">
<span>Coins:</span>
<span class="font-mono">${formatCurrency($PORTFOLIO_DATA.totalCoinValue)}</span>
<span class="font-mono">${formatCurrency($PORTFOLIO_SUMMARY.totalCoinValue)}</span>
</div>
</div>
{/if}

View file

@ -2,7 +2,7 @@
import { Button } from '$lib/components/ui/button';
import { Gift, Clock, Loader2, CheckIcon } from 'lucide-svelte';
import { USER_DATA } from '$lib/stores/user-data';
import { fetchPortfolioData } from '$lib/stores/portfolio-data';
import { fetchPortfolioSummary } from '$lib/stores/portfolio-data';
import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation';
import { formatTimeRemaining } from '$lib/utils';
@ -81,7 +81,7 @@
});
if ($USER_DATA) {
await fetchPortfolioData();
await fetchPortfolioSummary();
}
await fetchRewardStatus();

View file

@ -1,26 +1,55 @@
import { writable } from 'svelte/store';
export interface PortfolioData {
export interface PortfolioSummary {
baseCurrencyBalance: number;
totalCoinValue: number;
totalValue: number;
currency: string;
}
export interface PortfolioData extends PortfolioSummary {
coinHoldings: Array<{
symbol: string;
quantity: number;
currentPrice: number;
value: number;
percentageChange: number;
change24h: number;
icon?: string;
portfolioPercent: number;
}>;
currency: string;
}
export const PORTFOLIO_SUMMARY = writable<PortfolioSummary | null>(null);
export const PORTFOLIO_DATA = writable<PortfolioData | null>(null);
export async function fetchPortfolioSummary() {
try {
const response = await fetch('/api/portfolio/summary');
if (response.ok) {
const data = await response.json();
PORTFOLIO_SUMMARY.set(data);
return data;
}
} catch (error) {
console.error('Failed to fetch portfolio summary:', error);
}
return null;
}
export async function fetchPortfolioData() {
try {
const response = await fetch('/api/portfolio/total');
if (response.ok) {
const data = await response.json();
PORTFOLIO_DATA.set(data);
PORTFOLIO_SUMMARY.set({
baseCurrencyBalance: data.baseCurrencyBalance,
totalCoinValue: data.totalCoinValue,
totalValue: data.totalValue,
currency: data.currency
});
return data;
}
} catch (error) {