Forráskód Böngészése

fix the more details and remove de company_id that frontend

gdias 1 hete
szülő
commit
9bf18cacaf

+ 2 - 5
src/lib/components/DashboardGuard.svelte

@@ -14,11 +14,8 @@
     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) {
+        if (!token) {
             authorized.set(false);
             goto('/');
             return;
@@ -30,7 +27,7 @@
                     'content-type': 'application/json',
                     'Authorization': `Bearer ${token}`
                 },
-                body: JSON.stringify({ token, companyId })
+                body: JSON.stringify({ token })
             });
             const raw = await res.text();
             let body = null;

+ 34 - 14
src/lib/components/users/UserCreateModal.svelte

@@ -58,6 +58,7 @@
   }
 
   function handleSave() {
+    if (loading) return;
     if (!validate()) return;
     let birthdateUnix = undefined;
     if (birthdate) {
@@ -85,6 +86,7 @@
   }
 
   function handleCancel() {
+    if (loading) return;
     resetForm();
     dispatch('cancel');
   }
@@ -99,10 +101,17 @@
       </div>
 
       <div class="p-6 space-y-4">
+        {#if errorMessage}
+          <div class="rounded border border-red-200 bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-200 px-3 py-2 text-sm">
+            {errorMessage}
+          </div>
+        {/if}
+
         <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
           <div>
-            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nome</label>
+            <label for="user-create-name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nome</label>
             <input
+              id="user-create-name"
               bind:value={name}
               class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
               placeholder="Nome completo"
@@ -112,8 +121,9 @@
             {/if}
           </div>
           <div>
-            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">E-mail</label>
+            <label for="user-create-email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">E-mail</label>
             <input
+              id="user-create-email"
               bind:value={email}
               type="email"
               class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
@@ -128,8 +138,9 @@
         <div class="space-y-4">
           <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Telefone</label>
+              <label for="user-create-phone" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Telefone</label>
               <input
+                id="user-create-phone"
                 bind:value={phone}
                 type="tel"
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
@@ -137,16 +148,18 @@
               />
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">CPF</label>
+              <label for="user-create-cpf" class="block text-sm font-medium text-gray-700 dark:text-gray-300">CPF</label>
               <input
+                id="user-create-cpf"
                 bind:value={cpf}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="123.456.789-00"
               />
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Data de Nascimento</label>
+              <label for="user-create-birthdate" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Data de Nascimento</label>
               <input
+                id="user-create-birthdate"
                 bind:value={birthdate}
                 type="date"
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
@@ -156,16 +169,18 @@
 
           <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Endereço</label>
+              <label for="user-create-address" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Endereço</label>
               <input
+                id="user-create-address"
                 bind:value={address}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="Av. Paulista, 1000"
               />
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Cidade</label>
+              <label for="user-create-city" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Cidade</label>
               <input
+                id="user-create-city"
                 bind:value={city}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="São Paulo"
@@ -175,24 +190,27 @@
 
           <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
+              <label for="user-create-state" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
               <input
+                id="user-create-state"
                 bind:value={state}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="SP"
               />
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">CEP</label>
+              <label for="user-create-zip" class="block text-sm font-medium text-gray-700 dark:text-gray-300">CEP</label>
               <input
+                id="user-create-zip"
                 bind:value={zip}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="01310-100"
               />
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">País</label>
+              <label for="user-create-country" class="block text-sm font-medium text-gray-700 dark:text-gray-300">País</label>
               <input
+                id="user-create-country"
                 bind:value={country}
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
                 placeholder="BR"
@@ -202,8 +220,9 @@
 
           <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Senha</label>
+              <label for="user-create-password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Senha</label>
               <input
+                id="user-create-password"
                 bind:value={password}
                 type="password"
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
@@ -214,8 +233,9 @@
               {/if}
             </div>
             <div>
-              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Confirmar senha</label>
+              <label for="user-create-confirm-password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Confirmar senha</label>
               <input
+                id="user-create-confirm-password"
                 bind:value={confirmPassword}
                 type="password"
                 class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
@@ -231,8 +251,8 @@
       </div>
 
       <div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end gap-2">
-        <button class="px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700" on:click={handleCancel}>{cancelText}</button>
-        <button class="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-700 text-white" on:click={handleSave}>{saveText}</button>
+        <button disabled={loading} class="px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700" on:click={handleCancel}>{cancelText}</button>
+        <button disabled={loading} class="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-700 text-white" on:click={handleSave}>{saveText}</button>
       </div>
     </div>
   </div>

+ 1 - 2
src/lib/layout/SideBar.svelte

@@ -13,7 +13,7 @@
   import settingsIcon from '$lib/assets/icons/sidebar/settings.svg?raw';
   import logo from '$lib/assets/logo2.png';
   import { onMount } from 'svelte';
-  import { easyCoinBalance, authToken, companyId } from '$lib/utils/stores.js';
+  import { easyCoinBalance, authToken } from '$lib/utils/stores.js';
 
   const navItems = [
     { id: 'dashboard', href: '/dashboard', label: 'Início', icon: dashboardIcon },
@@ -59,7 +59,6 @@
   function handleLogout() {
     clearAllCookies();
     authToken.set(null);
-    companyId.set(null);
     closeSidebar();
     goto('/');
   }

+ 0 - 8
src/lib/utils/stores.js

@@ -19,7 +19,6 @@ function createDarkModeStore() {
 export const darkMode = createDarkModeStore();
 
 export const authToken = writable(null);
-export const companyId = writable(null);
 
 if (browser) {
   // Inicializar com valor do localStorage
@@ -45,11 +44,4 @@ if (browser) {
   // Inicializar authToken a partir do cookie
   const m = document.cookie.match(/(?:^|; )auth_token=([^;]+)/);
   if (m) authToken.set(decodeURIComponent(m[1]));
-
-  // Inicializar companyId a partir do cookie
-  const m2 = document.cookie.match(/(?:^|; )company_id=([^;]+)/);
-  if (m2) {
-    const v = decodeURIComponent(m2[1]);
-    companyId.set(/^-?\d+$/.test(v) ? Number(v) : v);
-  }
 }

+ 1 - 6
src/routes/+page.svelte

@@ -2,7 +2,7 @@
   import { goto } from '$app/navigation';
   import { browser } from '$app/environment';
   import { onMount, tick } from 'svelte';
-  import { authToken, companyId as companyIdStore } from '$lib/utils/stores';
+  import { authToken } from '$lib/utils/stores';
 
   const apiUrl = import.meta.env.VITE_API_URL;
   let email = '';
@@ -367,7 +367,6 @@
       }
 
       const token = payload?.data?.token;
-      const companyIdFromApi = payload?.data?.company_id ?? payload?.data?.companyId;
       if (!token) {
         throw new Error('Resposta inválida do servidor.');
       }
@@ -379,10 +378,6 @@
         remember ? `Max-Age=${60 * 60 * 24 * 7}` : null
       ].filter(Boolean).join('; ');
       document.cookie = `auth_token=${encodeURIComponent(token)}; ${attrs}`;
-      if (companyIdFromApi != null) {
-        document.cookie = `company_id=${encodeURIComponent(companyIdFromApi)}; ${attrs}`;
-        companyIdStore.set(companyIdFromApi);
-      }
       authToken.set(token);
 
       clearPendingState();

+ 60 - 12
src/routes/cpr/+page.svelte

@@ -1,5 +1,6 @@
 <script>
   import { browser } from '$app/environment';
+  import { goto } from '$app/navigation';
   import { onDestroy, onMount, tick } from 'svelte';
   import { get } from 'svelte/store';
   import Header from '$lib/layout/Header.svelte';
@@ -8,7 +9,7 @@
   import ContractCpr from '$lib/components/commodities/cpr/ContractCpr.svelte';
   import EmissionCpr from '$lib/components/commodities/cpr/EmissionCpr.svelte';
   import CprDetailModal from '$lib/components/commodities/cpr/CprDetailModal.svelte';
-  import { authToken, companyId as companyIdStore } from '$lib/utils/stores';
+  import { authToken } from '$lib/utils/stores';
 
   const apiUrl = import.meta.env.VITE_API_URL;
 
@@ -296,6 +297,9 @@
   const breadcrumb = [{ label: 'Início' }, { label: 'CPR', active: true }];
   let activeTab = 4;
   const tabs = ['Contrato', 'Registro', 'Emissão'];
+  const B3_OFFLINE_START_HOUR = 20;
+  const B3_OFFLINE_END_HOUR = 8;
+  const B3_OFFLINE_POLL_INTERVAL_MS = 60_000;
 
   const historyEndpoint = `${apiUrl}/cpr/history`;
   const paymentConfirmEndpoint = `${apiUrl}/b3/payment/confirm`;
@@ -315,6 +319,8 @@
   let selectedDetailId = null;
   let showDetailModal = false;
   let historyInitialized = false;
+  let isB3OfflineWindow = false;
+  let b3OfflineIntervalId = null;
 
   function handleFieldChange(key, value) {
     submitError = '';
@@ -380,11 +386,7 @@
     if (!token) {
       throw new Error('Sessão expirada. Faça login novamente.');
     }
-    const company = Number(get(companyIdStore));
-    if (!company || Number.isNaN(company) || company <= 0) {
-      throw new Error('company_id inválido. Refaça o login.');
-    }
-    return { token, company_id: company };
+    return { token };
   }
 
   async function parseJsonResponse(res) {
@@ -569,14 +571,14 @@
     if (!paymentId) {
       return { state: 'error', message: 'Pagamento inválido. Gere um novo QR Code.' };
     }
-    const { token, company_id } = ensureAuthContext();
+    const { token } = ensureAuthContext();
     const res = await fetch(paymentConfirmEndpoint, {
       method: 'POST',
       headers: {
         'content-type': 'application/json',
         Authorization: `Bearer ${token}`
       },
-      body: JSON.stringify({ payment_id: paymentId, company_id })
+      body: JSON.stringify({ payment_id: paymentId })
     });
     const raw = await res.text();
     let body = null;
@@ -771,14 +773,14 @@
     detailError = '';
     detailLoading = false;
     try {
-      const { token, company_id } = ensureAuthContext();
+      const { token } = ensureAuthContext();
       const res = await fetch(historyEndpoint, {
         method: 'POST',
         headers: {
           'content-type': 'application/json',
           Authorization: `Bearer ${token}`
         },
-        body: JSON.stringify({ company_id })
+        body: JSON.stringify({})
       });
       const body = await parseJsonResponse(res);
       if (!res.ok) {
@@ -801,14 +803,14 @@
     detailLoading = true;
     detailError = '';
     try {
-      const { token, company_id } = ensureAuthContext();
+      const { token } = ensureAuthContext();
       const res = await fetch(historyEndpoint, {
         method: 'POST',
         headers: {
           'content-type': 'application/json',
           Authorization: `Bearer ${token}`
         },
-        body: JSON.stringify({ company_id, cpr_id: cprId })
+        body: JSON.stringify({ cpr_id: cprId })
       });
       const body = await parseJsonResponse(res);
       if (!res.ok) {
@@ -852,12 +854,20 @@
   onMount(() => {
     void fetchHistory();
     void restorePersistedPayment();
+    updateB3OfflineState();
+    if (browser) {
+      b3OfflineIntervalId = window.setInterval(updateB3OfflineState, B3_OFFLINE_POLL_INTERVAL_MS);
+    }
   });
 
   onDestroy(() => {
     stopPaymentPolling();
     stopPaymentCountdown();
     stopPaymentCopyTimeout();
+    if (b3OfflineIntervalId) {
+      clearInterval(b3OfflineIntervalId);
+      b3OfflineIntervalId = null;
+    }
   });
 
   function getMissingRequiredFields() {
@@ -984,8 +994,46 @@
       paymentLoadingVisible = false;
     }
   }
+
+  function isWithinB3OfflineWindow(date = new Date()) {
+    const hour = date.getHours();
+    return hour >= B3_OFFLINE_START_HOUR || hour < B3_OFFLINE_END_HOUR;
+  }
+
+  function updateB3OfflineState() {
+    if (!browser) {
+      isB3OfflineWindow = false;
+      return;
+    }
+    isB3OfflineWindow = isWithinB3OfflineWindow(new Date());
+  }
+
+  function handleB3OfflineRedirect() {
+    goto('/dashboard');
+  }
 </script>
 
+{#if isB3OfflineWindow}
+  <div class="fixed inset-0 z-50 flex items-center justify-center px-4 bg-black/70 backdrop-blur-sm">
+    <div class="w-full max-w-xl rounded-2xl bg-white shadow-2xl border border-red-200 dark:bg-gray-900 dark:border-red-800/40 overflow-hidden">
+      <div class="px-6 py-5 space-y-4 text-center">
+        <p class="text-sm uppercase tracking-[0.3em] text-red-500 font-semibold">Manutenção programada</p>
+        <h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">B3 indisponível entre 20h e 8h</h2>
+        <p class="text-base text-gray-600 dark:text-gray-300">
+          A emissão de novas CPRs fica temporariamente suspensa enquanto a B3 está offline. Retorne ao dashboard e tente novamente após as 08:00.
+        </p>
+        <button
+          type="button"
+          class="mt-2 inline-flex items-center justify-center rounded-lg bg-gray-900 text-white font-semibold px-6 py-3 hover:bg-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-900 dark:bg-white dark:text-gray-900"
+          on:click={handleB3OfflineRedirect}
+        >
+          Voltar para o dashboard
+        </button>
+      </div>
+    </div>
+  </div>
+{/if}
+
 <div>
   <Header title="CPR - Cédula de Produto Rural" subtitle="Gestão de contratos, emissão e registro de CPRs" breadcrumb={breadcrumb} />
   <div class="p-4">

+ 2 - 3
src/routes/dashboard/+page.svelte

@@ -7,7 +7,7 @@
 	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, companyId as companyIdStore } from '$lib/utils/stores';
+	import { authToken } from '$lib/utils/stores';
 
 	const apiUrl = import.meta.env.VITE_API_URL;
 	const breadcrumb = [{ label: 'Início', active: true }];
@@ -43,12 +43,11 @@
 		summaryError = '';
 		try {
 			const token = get(authToken);
-			const companyId = get(companyIdStore);
 			const headers = {
 				'content-type': 'application/json',
 				...(token ? { Authorization: `Bearer ${token}` } : {})
 			};
-			const bodyPayload = companyId ? { company_id: companyId } : {};
+			const bodyPayload = {};
 			const res = await fetch(`${apiUrl}/company/summary`, {
 				method: 'POST',
 				headers,

+ 0 - 1
src/routes/settings/+page.svelte

@@ -125,7 +125,6 @@
   function logoutAndRedirect() {
     if (typeof document === 'undefined') return;
     document.cookie = 'auth_token=; Max-Age=0; Path=/; SameSite=Lax';
-    document.cookie = 'company_id=; Max-Age=0; Path=/; SameSite=Lax';
     authToken.set(null);
     goto('/');
   }

+ 18 - 36
src/routes/users/+page.svelte

@@ -3,7 +3,7 @@
   import Tables from '$lib/components/Tables.svelte';
   import UserCreateModal from '$lib/components/users/UserCreateModal.svelte';
   import ConfirmModal from '$lib/components/ui/PopUpDelete.svelte';
-  import { authToken, companyId as companyIdStore } from '$lib/utils/stores';
+  import { authToken } from '$lib/utils/stores';
   import { onMount } from 'svelte';
   const apiUrl = import.meta.env.VITE_API_URL;
   const breadcrumb = [{ label: 'Início' }, { label: 'Usuários', active: true }];
@@ -38,19 +38,6 @@
     showCreate = true;
   }
 
-  function getCookie(name) {
-    const m = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]+)'));
-    return m ? decodeURIComponent(m[1]) : null;
-  }
-
-  function getCompanyIdValue() {
-    const fromStore = $companyIdStore;
-    if (fromStore != null && fromStore !== '') return fromStore;
-    const fromCookie = getCookie('company_id');
-    if (fromCookie == null || fromCookie === '') return null;
-    return /^-?\d+$/.test(fromCookie) ? Number(fromCookie) : fromCookie;
-  }
-
   onMount(loadUsers);
 
   async function loadUsers() {
@@ -58,10 +45,6 @@
     try {
       loadError = '';
       loadServerResponse = '';
-      //console.log('cookie company_id:', getCookie('company_id'));
-      const cid = getCompanyIdValue();
-      //console.log('resolved companyId:', cid);
-      if (!cid) throw new Error('company_id não encontrado.');
       const url = `${apiUrl}/user/get`;
       //console.log('fetch url:', url);
       const res = await fetch(url, {
@@ -70,7 +53,7 @@
           'content-type': 'application/json',
           ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
         },
-        body: JSON.stringify({ company_id: cid })
+        body: JSON.stringify({})
       });
       const raw = await res.text();
       loadServerResponse = raw?.trim() ?? '';
@@ -106,17 +89,11 @@
   async function handleCreateSubmit(e) {
     const payload = e?.detail;
     if (!payload) return;
-    const cid = getCompanyIdValue();
-    if (!cid) {
-      createError = 'company_id não encontrado.';
-      return;
-    }
     createLoading = true;
     createError = '';
     try {
       const requestBody = {
         ...payload,
-        company_id: cid,
         role_id: payload?.role_id ?? 1
       };
       const res = await fetch(`${apiUrl}/register`, {
@@ -190,13 +167,6 @@
       rowToDelete = null;
       return;
     }
-    const cid = getCompanyIdValue();
-    if (!cid) {
-      console.error('company_id não encontrado para exclusão de usuário.');
-      showDeleteConfirm = false;
-      rowToDelete = null;
-      return;
-    }
     try {
       const res = await fetch(`${apiUrl}/user/delete`, {
         method: 'POST',
@@ -204,7 +174,7 @@
           'content-type': 'application/json',
           ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
         },
-        body: JSON.stringify({ user_id: userId, company_id: cid })
+        body: JSON.stringify({ user_id: userId })
       });
       const raw = await res.text();
       //console.log('delete user raw body:', raw);
@@ -254,6 +224,9 @@
 
       <UserCreateModal
         visible={showCreate}
+        loading={createLoading}
+        errorMessage={createError}
+        resetToken={createResetToken}
         on:submit={handleCreateSubmit}
         on:cancel={handleCreateCancel}
       />
@@ -270,8 +243,18 @@
       </ConfirmModal>
 
       {#if showDetails}
-        <div class="fixed inset-0 bg-black/40 flex items-center justify-center z-50" on:click={() => showDetails = false}>
-          <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg w-full max-w-lg p-6" on:click|stopPropagation>
+        <div
+          class="fixed inset-0 bg-black/40 flex items-center justify-center z-50"
+          role="button"
+          tabindex="0"
+          on:click={(e) => {
+            if (e.target === e.currentTarget) showDetails = false;
+          }}
+          on:keydown={(e) => {
+            if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') showDetails = false;
+          }}
+        >
+          <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg w-full max-w-lg p-6" role="dialog" aria-modal="true">
             <div class="flex items-center justify-between mb-4">
               <h4 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Detalhes do usuário</h4>
               <button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200" on:click={() => showDetails = false}>✕</button>
@@ -279,7 +262,6 @@
             {#if selectedUser}
               <div class="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
                 <div><span class="text-gray-500">ID:</span> <span class="dark:text-gray-100">{selectedUser.userId}</span></div>
-                <div><span class="text-gray-500">Empresa:</span> <span class="dark:text-gray-100">{selectedUser.companyId}</span></div>
                 <div><span class="text-gray-500">Nome:</span> <span class="dark:text-gray-100">{selectedUser.userName}</span></div>
                 <div><span class="text-gray-500">E-mail:</span> <span class="dark:text-gray-100">{selectedUser.userEmail}</span></div>
                 <div><span class="text-gray-500">Telefone:</span> <span class="dark:text-gray-100">{selectedUser.userPhone}</span></div>