浏览代码

add the jwt validator

gdias 2 周之前
父节点
当前提交
4f19f3b864
共有 3 个文件被更改,包括 97 次插入58 次删除
  1. 45 35
      src/lib/components/DashboardGuard.svelte
  2. 34 21
      src/lib/components/trading/TabelaOrdens.svelte
  3. 18 2
      src/routes/trading/+page.svelte

+ 45 - 35
src/lib/components/DashboardGuard.svelte

@@ -11,43 +11,53 @@
     const apiUrl = import.meta.env.VITE_API_URL;
     let intervalId = null;
 
-    // async function validate() {
-    //     if (!browser) return;
-    //     const m1 = document.cookie.match(/(?:^|; )auth_token=([^;]+)/);
-    //     const m2 = document.cookie.match(/(?:^|; )company_id=([^;]+)/);
-    //     const token = m1 ? decodeURIComponent(m1[1]) : null;
-    //     const v = m2 ? decodeURIComponent(m2[1]) : null;
-    //     const companyId = v && /^-?\d+$/.test(v) ? Number(v) : v;
-    //     if (!token || companyId == null) {
-    //         authorized.set(false);
-    //         goto('/');
-    //         return;
-    //     }
-    //     try {
-    //         const res = await fetch(`${apiUrl}/auth/validate-token`, {
-    //             method: 'POST',
-    //             headers: {
-    //                 'content-type': 'application/json',
-    //                 'Authorization': `Bearer ${token}`
-    //             },
-    //             body: JSON.stringify({ token, companyId })
-    //         });
-    //         if (!res.ok) throw new Error('invalid');
-    //         authorized.set(true);
-    //     } catch (e) {
-    //         authorized.set(false);
-    //         goto('/');
-    //     }
-    // }
+    async function validate() {
+        if (!browser) return;
+        const m1 = document.cookie.match(/(?:^|; )auth_token=([^;]+)/);
+        const m2 = document.cookie.match(/(?:^|; )company_id=([^;]+)/);
+        const token = m1 ? decodeURIComponent(m1[1]) : null;
+        const v = m2 ? decodeURIComponent(m2[1]) : null;
+        const companyId = v && /^-?\d+$/.test(v) ? Number(v) : v;
+        if (!token || companyId == null) {
+            authorized.set(false);
+            goto('/');
+            return;
+        }
+        try {
+            const res = await fetch(`${apiUrl}/verify/jwt`, {
+                method: 'POST',
+                headers: {
+                    'content-type': 'application/json',
+                    'Authorization': `Bearer ${token}`
+                },
+                body: JSON.stringify({ token, companyId })
+            });
+            const raw = await res.text();
+            let body = null;
+            if (raw) {
+                try {
+                    body = JSON.parse(raw);
+                } catch (err) {
+                    console.error('verify/jwt JSON parse error:', err);
+                }
+            }
+            const isActive = body?.status === 'ok' && body?.data?.status === 'active';
+            if (!res.ok || !isActive) throw new Error('inactive-token');
+            authorized.set(true);
+        } catch (e) {
+            authorized.set(false);
+            goto('/');
+        }
+    }
 
-    // onMount(() => {
-    //     validate();
-    //     intervalId = setInterval(validate, 60000);
-    // });
+    onMount(() => {
+        validate();
+        intervalId = setInterval(validate, 60000);
+    });
 
-    // onDestroy(() => {
-    //     if (intervalId) clearInterval(intervalId);
-    // });
+    onDestroy(() => {
+        if (intervalId) clearInterval(intervalId);
+    });
 </script>
 
 {#if $authorized}

+ 34 - 21
src/lib/components/trading/TabelaOrdens.svelte

@@ -3,6 +3,7 @@
   export let ordensCompra = [];
   export let ordensVenda = [];
   export let ultimaVenda = { valor: 0, quantidade: 0 };
+  export let emptyMessage = '';
   const dispatch = createEventDispatcher();
   function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n || 0)); }
   function formatQty(n) { return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(Number(n || 0)); }
@@ -84,16 +85,22 @@
         <div class="text-xs text-gray-500">VALOR · QUANTIDADE</div>
       </div>
       <div class="space-y-1">
-        {#each listaCompraView as o}
-        <div
-          class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 ${flashCompra.has(o.__idx) ? 'bg-green-100 dark:bg-green-900/30' : ''}`}
-          on:mouseenter={(event) => scheduleTooltip(event, o)}
-          on:mouseleave={hideTooltip}
-        >
-          <span class="text-green-600">{formatBRL(o.valor)}</span>
-          <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
-        </div>
-        {/each}
+        {#if listaCompraView.length === 0}
+          <div class="text-xs text-gray-500 dark:text-gray-400 text-center py-4 border border-dashed border-gray-200 dark:border-gray-700 rounded">
+            {emptyMessage || 'Nenhuma ordem de compra disponível.'}
+          </div>
+        {:else}
+          {#each listaCompraView as o}
+          <div
+            class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 ${flashCompra.has(o.__idx) ? 'bg-green-100 dark:bg-green-900/30' : ''}`}
+            on:mouseenter={(event) => scheduleTooltip(event, o)}
+            on:mouseleave={hideTooltip}
+          >
+            <span class="text-green-600">{formatBRL(o.valor)}</span>
+            <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
+          </div>
+          {/each}
+        {/if}
       </div>
     </div>
     <div class="p-4">
@@ -102,17 +109,23 @@
         <div class="text-xs text-gray-500">VALOR · QUANTIDADE</div>
       </div>
       <div class="space-y-1">
-        {#each listaVendaView as o}
-        <div
-          class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 cursor-pointer hover:bg-red-50 dark:hover:bg-red-900/40 ${flashVenda.has(o.__idx) ? 'bg-red-100 dark:bg-red-900/30' : ''}`}
-          on:mouseenter={(event) => scheduleTooltip(event, o)}
-          on:mouseleave={hideTooltip}
-          on:click={() => dispatch('selectSellOrder', { valor: o.valor, quantidade: o.quantidade })}
-        >
-          <span class="text-red-600">{formatBRL(o.valor)}</span>
-          <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
-        </div>
-        {/each}
+        {#if listaVendaView.length === 0}
+          <div class="text-xs text-gray-500 dark:text-gray-400 text-center py-4 border border-dashed border-gray-200 dark:border-gray-700 rounded">
+            {emptyMessage || 'Nenhuma ordem de venda disponível.'}
+          </div>
+        {:else}
+          {#each listaVendaView as o}
+          <div
+            class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 cursor-pointer hover:bg-red-50 dark:hover:bg-red-900/40 ${flashVenda.has(o.__idx) ? 'bg-red-100 dark:bg-red-900/30' : ''}`}
+            on:mouseenter={(event) => scheduleTooltip(event, o)}
+            on:mouseleave={hideTooltip}
+            on:click={() => dispatch('selectSellOrder', { valor: o.valor, quantidade: o.quantidade })}
+          >
+            <span class="text-red-600">{formatBRL(o.valor)}</span>
+            <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
+          </div>
+          {/each}
+        {/if}
       </div>
     </div>
   </div>

+ 18 - 2
src/routes/trading/+page.svelte

@@ -21,6 +21,7 @@
   let ultimaVenda = { valor: 0, quantidade: 0 };
   let orderbookLoading = false;
   let orderbookError = '';
+  let orderbookEmptyMessage = '';
   let initialized = false;
   let lastFetchKey = '';
 
@@ -98,6 +99,7 @@
     ordensCompra = [];
     ordensVenda = [];
     ultimaVenda = { valor: 0, quantidade: 0 };
+    orderbookEmptyMessage = '';
   };
 
   function commodityPayloadValue(tokenId) {
@@ -122,6 +124,7 @@
 
     orderbookLoading = true;
     orderbookError = '';
+    orderbookEmptyMessage = '';
 
     try {
       const token = get(authToken);
@@ -144,10 +147,18 @@
         console.error('Falha ao interpretar resposta de /token/get:', err);
       }
 
-      if (!res.ok || payload?.status !== 'ok') {
+      if (!res.ok) {
         throw new Error(payload?.msg ?? 'Falha ao carregar ordens.');
       }
 
+      if (payload?.status !== 'ok') {
+        orderbookEmptyMessage = payload?.msg ?? 'Nenhuma ordem disponível para os filtros selecionados.';
+        ordensCompra = [];
+        ordensVenda = [];
+        ultimaVenda = { valor: 0, quantidade: 0 };
+        return;
+      }
+
       const mapped = Array.isArray(payload?.data)
         ? payload.data
             .map((item) => ({
@@ -162,6 +173,11 @@
 
       ordensCompra = [];
       ordensVenda = mapped;
+      if (!mapped.length) {
+        orderbookEmptyMessage = 'Nenhuma ordem encontrada para os filtros selecionados.';
+      } else {
+        orderbookEmptyMessage = '';
+      }
       ultimaVenda = mapped.length
         ? { valor: mapped[mapped.length - 1].valor, quantidade: mapped[mapped.length - 1].quantidade }
         : { valor: 0, quantidade: 0 };
@@ -350,7 +366,7 @@ $: displayPendingSells = pendingSells.map((o) => ({
           <div class="rounded border border-gray-200 bg-gray-50 text-sm text-gray-700 px-3 py-2 dark:border-gray-700 dark:bg-gray-800/50 dark:text-gray-200">Carregando orderbook...</div>
         {/if}
 
-        <TabelaOrdens {ordensCompra} {ordensVenda} {ultimaVenda}
+        <TabelaOrdens {ordensCompra} {ordensVenda} {ultimaVenda} emptyMessage={orderbookEmptyMessage}
           on:selectSellOrder={(e) => { const { valor, quantidade } = e.detail; prefillBuy = { valorSaca: valor, quantidade }; showBuyModal = true; }}
         />
       </div>