| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- <script>
- import { onMount } from 'svelte';
- import { get } from 'svelte/store';
- import Header from '$lib/layout/Header.svelte';
- import StatsCard from '$lib/components/StatsCard.svelte';
- import commoditiesIcon from '$lib/assets/icons/sidebar/commodities.svg?raw';
- import operationsIcon from '$lib/assets/icons/sidebar/operations.svg?raw';
- import cprIcon from '$lib/assets/icons/sidebar/cpr.svg?raw';
- import usersIcon from '$lib/assets/icons/sidebar/users.svg?raw';
- import { authToken } from '$lib/utils/stores';
- const apiUrl = import.meta.env.VITE_API_URL;
- const breadcrumb = [{ label: 'Início', active: true }];
- let summaryLoading = false;
- let summaryError = '';
- let summary = null;
- const fallbackStats = [
- { title: 'Total em Commodities', value: '-', change: 'Carregando...', iconSvg: commoditiesIcon },
- { title: 'Operações Ativas', value: '—', change: 'Aguardando dados', iconSvg: operationsIcon },
- { title: 'CPRs Emitidas', value: '—', change: 'Aguardando dados', iconSvg: cprIcon },
- { title: 'Usuários Ativos', value: '—', change: 'Aguardando dados', iconSvg: usersIcon }
- ];
- onMount(() => {
- void fetchCompanySummary();
- });
- function formatCurrency(value) {
- return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(value || 0));
- }
- function formatInteger(value) {
- return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(
- Number(value || 0)
- );
- }
- async function fetchCompanySummary() {
- if (!apiUrl) return;
- summaryLoading = true;
- summaryError = '';
- try {
- const token = get(authToken);
- const headers = {
- 'content-type': 'application/json',
- ...(token ? { Authorization: `Bearer ${token}` } : {})
- };
- const bodyPayload = {};
- const res = await fetch(`${apiUrl}/company/summary`, {
- method: 'POST',
- headers,
- body: JSON.stringify(bodyPayload)
- });
- const raw = await res.text();
- const data = raw ? JSON.parse(raw) : null;
- if (!res.ok) {
- throw new Error(data?.msg ?? data?.message ?? 'Falha ao carregar resumo da empresa.');
- }
- const resolvedSummary = data?.summary ?? data?.data?.summary ?? data;
- if (!resolvedSummary || typeof resolvedSummary !== 'object') {
- throw new Error('Resposta inválida do resumo da empresa.');
- }
- summary = resolvedSummary;
- } catch (err) {
- console.error('[Dashboard] Erro ao buscar resumo da empresa:', err);
- summary = null;
- summaryError = err?.message ?? 'Não foi possível carregar o resumo da empresa.';
- } finally {
- summaryLoading = false;
- }
- }
- $: stats = summary
- ? [
- {
- title: 'Total em tokens disponíveis',
- value: formatInteger(summary.total_tokens),
- change: '',
- iconSvg: commoditiesIcon
- },
- {
- title: 'Operações Ativas',
- value: formatInteger(summary.active_operations),
- change: '',
- iconSvg: operationsIcon
- },
- {
- title: 'CPRs Emitidas',
- value: formatInteger(summary.total_cprs),
- change: '',
- iconSvg: cprIcon
- },
- {
- title: 'Usuários Ativos',
- value: formatInteger(summary.total_users),
- change: 'Usuários vinculados à empresa',
- iconSvg: usersIcon
- }
- ]
- : fallbackStats;
- </script>
- <Header title="Início" subtitle="Visão geral do sistema de commodities" breadcrumb={breadcrumb} />
- <div class="p-8 space-y-4">
- {#if summaryError}
- <div class="rounded border border-red-200 bg-red-50 text-red-700 px-3 py-2 text-sm">
- {summaryError}
- </div>
- {/if}
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
- {#each stats as stat}
- <StatsCard {...stat} loading={summaryLoading && !summary} />
- {/each}
- </div>
- </div>
|