| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <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 PaymentMenu from '$lib/components/wallet/PaymentMenu.svelte';
- import SellMenu from '$lib/components/wallet/SellMenu.svelte';
- import tokensIcon from '$lib/assets/icons/sidebar/tokens.svg?raw';
- import walletIcon from '$lib/assets/icons/sidebar/wallet.svg?raw';
- import { authToken } from '$lib/utils/stores';
- const breadcrumb = [{ label: 'Início' }, { label: 'wallet', active: true }];
- const apiUrl = import.meta.env.VITE_API_URL;
- let walletTokens = [];
- let easyCoinBalance = 0;
- let tokensLoading = false;
- let tokensError = '';
- let isPaymentOpen = false;
- let isSellOpen = false;
- let rateBRLPerEasyCoin = 100;
- onMount(() => {
- void fetchWalletTokens();
- });
- function openPayment() {
- isPaymentOpen = true;
- }
- function closePayment() {
- isPaymentOpen = false;
- }
- function confirmPayment(method) {
- isPaymentOpen = false;
- }
- function openSell() {
- isSellOpen = true;
- }
- function closeSell() {
- isSellOpen = false;
- }
- function confirmSell(e) {
- isSellOpen = false;
- }
- async function parseResponse(res) {
- const raw = await res.text();
- return raw ? JSON.parse(raw) : null;
- }
- async function fetchWalletTokens() {
- if (!apiUrl) return;
- tokensLoading = true;
- tokensError = '';
- try {
- const token = get(authToken);
- if (!token) {
- throw new Error('Sessão expirada. Faça login novamente.');
- }
- const res = await fetch(`${apiUrl}/wallet/tokens`, {
- method: 'POST',
- headers: {
- 'content-type': 'application/json',
- Authorization: `Bearer ${token}`
- }
- });
- const body = await parseResponse(res);
- if (!res.ok || body?.status !== 'ok') {
- throw new Error(body?.msg ?? 'Falha ao carregar tokens da wallet.');
- }
- const payload = body?.data ?? {};
- walletTokens = Array.isArray(payload?.tokens) ? payload.tokens : [];
- easyCoinBalance = resolveEasyCoinBalance(payload);
- } catch (err) {
- console.error('[Wallet] Erro ao buscar tokens:', err);
- walletTokens = [];
- easyCoinBalance = 0;
- tokensError = err?.message ?? 'Não foi possível carregar os tokens.';
- } finally {
- tokensLoading = false;
- }
- }
- function resolveEasyCoinBalance(payload) {
- const candidates = [
- payload?.wallet?.easycoin_balance,
- payload?.wallet?.easyCoinBalance,
- payload?.wallet?.balance,
- payload?.easycoin_balance,
- payload?.easyCoinBalance,
- payload?.easycoin,
- payload?.balance
- ];
- const firstValue = candidates.find((value) => value !== undefined && value !== null && value !== '');
- return Number(firstValue ?? 0);
- }
- function formatToken(n) {
- return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 6 }).format(Number(n || 0));
- }
- function formatCoin(n) {
- return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(Number(n || 0));
- }
- function tokenCardLabel(token) {
- return token?.cpr_product_name ?? token?.token_content ?? token?.token_external_id ?? token?.token_id ?? 'EasyToken';
- }
- function tokenCardSubtitle(token) {
- if (token?.token_city && token?.token_uf) {
- return `${token.token_city}/${token.token_uf}`;
- }
- if (token?.token_external_id) {
- return `ID ${token.token_external_id}`;
- }
- return 'Saldo atual';
- }
- function tokenAmount(token) {
- const candidates = [
- token?.token_commodities_amount,
- token?.token_amount,
- token?.token_balance,
- token?.balance,
- token?.amount
- ];
- const value = candidates.find((item) => item !== undefined && item !== null && item !== '');
- return Number(value ?? 0);
- }
- </script>
- <div>
- <Header title="Wallet" subtitle="Saldos e operações" breadcrumb={breadcrumb} />
- <div class="p-4 space-y-6">
- {#if tokensError}
- <div class="rounded border border-red-200 bg-red-50 text-red-700 px-3 py-2 text-sm">{tokensError}</div>
- {/if}
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
- {#if tokensLoading && !walletTokens.length}
- <div class="rounded-lg border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-800/60 p-4 text-center text-sm text-gray-500">
- Carregando tokens...
- </div>
- {:else if walletTokens.length}
- {#each walletTokens as token (token?.token_external_id ?? token?.token_id ?? token?.cpr_id ?? token)}
- <div class="rounded-lg overflow-hidden">
- <StatsCard
- title={tokenCardLabel(token)}
- value={formatToken(tokenAmount(token))}
- change={tokenCardSubtitle(token)}
- iconSvg={tokensIcon}
- />
- </div>
- {/each}
- {:else}
- <div class="rounded-lg border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-800/60 p-4 text-center text-sm text-gray-500">
- Nenhum token encontrado para sua conta.
- </div>
- {/if}
- <div class="rounded-lg overflow-hidden">
- <StatsCard
- title="EasyCoin"
- value={formatCoin(easyCoinBalance)}
- change={tokensLoading ? 'Atualizando...' : 'Saldo atual'}
- iconSvg={walletIcon}
- />
- </div>
- </div>
- <div class="flex gap-3">
- <button
- class="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-700 text-white shadow"
- on:click={openPayment}
- >
- Comprar EasyCoins
- </button>
- <button
- class="inline-flex items-center gap-2 px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-800 dark:text-gray-100"
- on:click={openSell}
- >
- Vender EasyCoins
- </button>
- </div>
- </div>
- <PaymentMenu
- isOpen={isPaymentOpen}
- onClose={closePayment}
- onConfirm={confirmPayment}
- />
- <SellMenu
- isOpen={isSellOpen}
- onClose={closeSell}
- onConfirm={(e) => confirmSell(e.detail || e)}
- rateBRLPerEasyCoin={rateBRLPerEasyCoin}
- />
- </div>
|