Ver código fonte

add insights page

Daniel Bohry 9 meses atrás
pai
commit
a04c20c572

+ 4 - 1
package.json

@@ -24,5 +24,8 @@
 		"svelte": "^4.2.7",
 		"vite": "^5.0.3"
 	},
-	"type": "module"
+	"type": "module",
+	"dependencies": {
+		"chart.js": "^4.4.8"
+	}
 }

+ 58 - 0
src/routes/Chart.svelte

@@ -0,0 +1,58 @@
+<script>
+	import { onMount } from 'svelte';
+	import { Chart, ArcElement, Tooltip, Legend, Title, DoughnutController } from 'chart.js';
+
+	export let data = {};
+
+	let chartContainer;
+
+	onMount(() => {
+		Chart.register(ArcElement, Tooltip, Legend, Title, DoughnutController);
+
+		if (data && data.stocks) {
+			const stockNames = data.stocks.map(stock => stock.name);
+			const stockTotals = data.stocks.map(stock => stock.total);
+
+			const chartData = {
+				labels: stockNames,
+				datasets: [{
+					label: 'Stock Distribution',
+					data: stockTotals,
+					backgroundColor: [
+						'#FF6F61', '#6B8E23', '#FFD700', '#20B2AA', '#87CEFA',
+						'#D2691E', '#FF6347', '#98FB98', '#D8BFD8', '#20B2AA',
+						'#FF4500', '#8A2BE2', '#A52A2A', '#DEB887', '#5F9EA0'
+					],
+					borderColor: '#fff',
+					borderWidth: 1,
+				}],
+			};
+
+			const chartOptions = {
+				responsive: true,
+				plugins: {
+					legend: {
+						position: 'top',
+					},
+					tooltip: {
+						callbacks: {
+							label: function(tooltipItem) {
+								return `${tooltipItem.label}: $${tooltipItem.raw.toFixed(2)}`;
+							},
+						},
+					},
+				},
+			};
+
+			new Chart(chartContainer, {
+				type: 'doughnut',
+				data: chartData,
+				options: chartOptions,
+			});
+		}
+	});
+</script>
+
+<div>
+	<canvas bind:this={chartContainer}></canvas>
+</div>

+ 3 - 0
src/routes/Header.svelte

@@ -46,6 +46,9 @@
                 <li aria-current={$page.url.pathname === '/portfolio' ? 'page' : undefined}>
                     <a href="/portfolio">Portfolio</a>
                 </li>
+                <li aria-current={$page.url.pathname === '/insights' ? 'page' : undefined}>
+                    <a href="/insights">Insights</a>
+                </li>
             {/if}
             <li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
                 <a href="/about">About</a>

+ 9 - 0
src/routes/insights/+page.js

@@ -0,0 +1,9 @@
+import { dev } from '$app/environment';
+
+// we don't need any JS on this page, though we'll load
+// it in dev so that we get hot module replacement
+export const csr = dev;
+
+// since there's no dynamic data here, we can prerender
+// it so that it gets served as a static asset in production
+export const prerender = true;

+ 53 - 0
src/routes/insights/+page.svelte

@@ -0,0 +1,53 @@
+<script>
+	import Chart from '../Chart.svelte';
+	import { onMount } from 'svelte';
+	import { authentication } from '../store.js';
+
+	let authToken;
+	let data = {};
+	let isLoading = true;
+
+	onMount(() => {
+		const unsubscribe = authentication.subscribe(async ({ token }) => {
+			if (token) {
+				authToken = token;
+				await fetchPortfolio();
+			}
+		});
+
+		return unsubscribe;
+	});
+
+	async function fetchPortfolio() {
+		try {
+			const response = await fetch(`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios`, {
+				headers: {
+					Authorization: `Bearer ${authToken}`,
+				},
+			});
+
+			if (!response.ok) {
+				const error = await response.json();
+				throw new Error(error.message || 'Unknown error');
+			}
+
+			const portfolio = await response.json();
+
+			if (portfolio?.length) {
+				data = portfolio[0];
+				data.stocks = data.stocks.sort((a, b) => a.total - b.total);
+			}
+		} catch (error) {
+			console.error('Failed to fetch portfolio:', error);
+			alert(`Error: ${error.message}`);
+		} finally {
+			isLoading = false;
+		}
+	}
+</script>
+
+{#if isLoading}
+	<p>Loading portfolio...</p>
+{:else}
+	<Chart {data} />
+{/if}

+ 4 - 4
src/routes/portfolio/+page.svelte

@@ -1,7 +1,7 @@
 <script>
-    import {authentication} from "../store.js";
-    import {onMount} from "svelte";
-    import {fade} from 'svelte/transition';
+    import { authentication } from '../store.js';
+    import { onMount } from 'svelte';
+    import { fade } from 'svelte/transition';
 
     let portfolioId = undefined;
     let result = [];
@@ -66,7 +66,7 @@
                 result = portfolio[0].stocks.sort((a, b) => a.total - b.total);
             }
 
-            result = portfolio[0].stocks;
+            data = portfolio[0];
             totalValue = portfolio[0].totalValue;
             totalAssets = portfolio[0].totalAssets;
             portfolioId = portfolio[0].id;