Преглед изворни кода

add the endpoint e other changes

gdias пре 1 месец
родитељ
комит
a993f233b0

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

@@ -7,6 +7,7 @@
 	const authorized = writable(false);
 
     //TODO: When will has a token validation we need to validate the token here
+	//tenho que verificar se realmente vai ser feito essa validacao a cada minuto
 	let flag = 'approved';
 
 	onMount(async () => {
@@ -17,7 +18,7 @@
 		}
 		 setInterval(() => {
             console.log('passou pelo dashboard guard');
-		 }, 10000);
+		 }, 100000);
 	});
 </script>
 

+ 124 - 38
src/lib/components/users/UserCreateModal.svelte

@@ -7,27 +7,37 @@
   export let saveText = 'Criar usuário';
   export let cancelText = 'Cancelar';
 
-  let nome = '';
+  let name = '';
   let email = '';
-  let role = 'user';
   let password = '';
   let confirmPassword = '';
+  let phone = '';
+  let cpf = '';
+  let birthdate = '';
+  let address = '';
+  let city = '';
+  let state = '';
+  let zip = '';
+  let country = 'BR';
+  let kyc = false;
 
-  let errors = { nome: '', email: '', password: '', confirmPassword: '' };
+  let errors = { name: '', email: '', password: '', confirmPassword: '' };
 
   function validate() {
-    errors = { nome: '', email: '', password: '', confirmPassword: '' };
+    errors = { name: '', email: '', password: '', confirmPassword: '' };
     const emailRegex = /[^@\s]+@[^@\s]+\.[^@\s]+/;
-    if (!nome.trim()) errors.nome = 'Informe o nome';
+    if (!name.trim()) errors.name = 'Informe o nome';
     if (!email || !emailRegex.test(email)) errors.email = 'Informe um e-mail válido';
     if (!password || password.length < 6) errors.password = 'Senha mínima de 6 caracteres';
     if (confirmPassword !== password) errors.confirmPassword = 'Confirmação diferente da senha';
-    return !errors.nome && !errors.email && !errors.password && !errors.confirmPassword;
+    return !errors.name && !errors.email && !errors.password && !errors.confirmPassword;
   }
 
   function handleSave() {
     if (!validate()) return;
-    dispatch('submit', { nome, email, role, password });
+    const birthdateNum = birthdate ? Number(birthdate.replace(/-/g, '')) : undefined;
+    const kycNum = kyc ? 1 : 0;
+    dispatch('submit', { name, email, password, phone, address, city, state, zip, country, kyc: kycNum, birthdate: birthdateNum, cpf });
   }
 
   function handleCancel() {
@@ -48,12 +58,12 @@
           <div>
             <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nome</label>
             <input
-              bind:value={nome}
+              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"
             />
-            {#if errors.nome}
-              <p class="mt-1 text-sm text-red-600">{errors.nome}</p>
+            {#if errors.name}
+              <p class="mt-1 text-sm text-red-600">{errors.name}</p>
             {/if}
           </div>
           <div>
@@ -70,37 +80,113 @@
           </div>
         </div>
 
-        <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">Perfil</label>
-            <select bind:value={role} 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">
-              <option value="user">Usuário</option>
-              <option value="admin">Administrador</option>
-            </select>
+        <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>
+              <input
+                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"
+                placeholder="+55 11 99999-9999"
+              />
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">CPF</label>
+              <input
+                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>
+              <input
+                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"
+              />
+            </div>
           </div>
-          <div>
-            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Senha</label>
-            <input
-              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"
-              placeholder="********"
-            />
-            {#if errors.password}
-              <p class="mt-1 text-sm text-red-600">{errors.password}</p>
-            {/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">Endereço</label>
+              <input
+                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>
+              <input
+                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"
+              />
+            </div>
+          </div>
+
+          <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>
+              <input
+                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>
+              <input
+                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>
+              <input
+                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"
+              />
+            </div>
+          </div>
+
+          <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>
+              <input
+                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"
+                placeholder="********"
+              />
+              {#if errors.password}
+                <p class="mt-1 text-sm text-red-600">{errors.password}</p>
+              {/if}
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Confirmar senha</label>
+              <input
+                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"
+                placeholder="********"
+              />
+              {#if errors.confirmPassword}
+                <p class="mt-1 text-sm text-red-600">{errors.confirmPassword}</p>
+              {/if}
+            </div>
           </div>
+
           <div>
-            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Confirmar senha</label>
-            <input
-              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"
-              placeholder="********"
-            />
-            {#if errors.confirmPassword}
-              <p class="mt-1 text-sm text-red-600">{errors.confirmPassword}</p>
-            {/if}
+            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">KYC verificado</label>
+            <div class="mt-2">
+              <input type="checkbox" bind:checked={kyc} class="rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500" />
+            </div>
           </div>
         </div>
       </div>

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

@@ -18,6 +18,8 @@ function createDarkModeStore() {
 
 export const darkMode = createDarkModeStore();
 
+export const authToken = writable(null);
+
 if (browser) {
   // Inicializar com valor do localStorage
   const saved = localStorage.getItem('darkMode');
@@ -38,4 +40,8 @@ if (browser) {
       document.documentElement.classList.remove('dark');
     }
   });
+
+  // Inicializar authToken a partir do cookie
+  const m = document.cookie.match(/(?:^|; )auth_token=([^;]+)/);
+  if (m) authToken.set(decodeURIComponent(m[1]));
 }

+ 37 - 7
src/routes/+page.svelte

@@ -2,7 +2,9 @@
   import { goto } from '$app/navigation';
   import { browser } from '$app/environment';
   import { onMount, onDestroy } from 'svelte';
+  import { authToken } from '$lib/utils/stores';
 
+  const apiUrl = import.meta.env.VITE_API_URL;
   let email = '';
   let password = '';
   let remember = true;
@@ -45,17 +47,43 @@
         throw new Error('Preencha e-mail e senha.');
       }
 
-      if (browser) {
-        const token = 'demo-token';
-        localStorage.setItem('auth_token', token);
-        if (!remember) {
-          sessionStorage.setItem('auth_session', '1');
-        }
+      if (!browser) {
+        throw new Error('Ação disponível apenas no navegador.');
       }
 
+      const res = await fetch(`${apiUrl}/auth/login`, {
+        method: 'POST',
+        headers: { 'content-type': 'application/json' },
+        body: JSON.stringify({ email, password })
+      });
+
+      if (!res.ok) {
+        let msg = 'Credenciais inválidas.';
+        try {
+          const err = await res.json();
+          if (err?.message) msg = err.message;
+        } catch {}
+        throw new Error(msg);
+      }
+
+      const data = await res.json();
+      const token = data?.token;
+      if (!token) {
+        throw new Error('Resposta inválida do servidor.');
+      }
+
+      const attrs = [
+        'Path=/',
+        'SameSite=Lax',
+        (typeof location !== 'undefined' && location.protocol === 'https:') ? 'Secure' : null,
+        remember ? `Max-Age=${60 * 60 * 24 * 7}` : null
+      ].filter(Boolean).join('; ');
+      document.cookie = `auth_token=${encodeURIComponent(token)}; ${attrs}`;
+      authToken.set(token);
+
       await goto('/dashboard');
     } catch (err) {
-      error = err?.message ?? 'Falha ao entrar.';
+      error = err?.message ?? 'Falha ao autenticar, tente novamente.';
     } finally {
       loading = false;
     }
@@ -77,6 +105,7 @@
           <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" for="email">E-mail</label>
           <input
             id="email"
+            name="email"
             type="email"
             bind:value={email}
             class="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"
@@ -90,6 +119,7 @@
           <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" for="password">Senha</label>
           <input
             id="password"
+            name="password"
             type="password"
             bind:value={password}
             class="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"

+ 34 - 10
src/routes/users/+page.svelte

@@ -3,18 +3,19 @@
   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 } from '$lib/utils/stores';
+  const apiUrl = import.meta.env.VITE_API_URL;
   const breadcrumb = [{ label: 'Início' }, { label: 'Usuários', active: true }];
 
   // Tabela
   let columns = [
-    { key: 'nome', label: 'Nome' },
-    { key: 'email', label: 'E-mail' },
-    { key: 'role', label: 'Perfil' }
+    { key: 'name', label: 'Nome' },
+    { key: 'email', label: 'E-mail' }
   ];
 
   let data = [
-    { nome: 'Lucas Lumps', email: 'lucas@empresa.com', role: 'admin' },
-    { nome: 'Jorginho', email: 'jorginho@empresa.com', role: 'user' }
+    { name: 'Lucas Lumps', email: 'lucas@empresa.com' },
+    { name: 'Jorginho', email: 'jorginho@empresa.com' }
   ];
 
   // Modal criar usuário
@@ -28,12 +29,35 @@
     showCreate = true;
   }
 
-  function handleCreateSubmit(e) {
+  async function handleCreateSubmit(e) {
     const payload = e?.detail;
-    if (payload?.nome && payload?.email) {
-      data = [...data, { nome: payload.nome, email: payload.email, role: payload.role || 'user' }];
+    if (!payload) return;
+    try {
+      const res = await fetch(`${apiUrl}/users`, {
+        method: 'POST',
+        headers: {
+          'content-type': 'application/json',
+          ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
+        },
+        body: JSON.stringify(payload)
+      });
+      if (!res.ok) {
+        try {
+          const err = await res.json();
+          console.error('Falha ao criar usuário:', err);
+        } catch {}
+        // Fallback: ainda adiciona localmente para feedback imediato
+        data = [...data, { name: payload.name, email: payload.email }];
+      } else {
+        const created = await res.json();
+        data = [...data, { name: created?.name ?? payload.name, email: created?.email ?? payload.email }];
+      }
+    } catch (err) {
+      console.error('Erro na criação do usuário:', err);
+      data = [...data, { name: payload.name, email: payload.email }];
+    } finally {
+      showCreate = false;
     }
-    showCreate = false;
   }
 
   function handleCreateCancel() {
@@ -86,7 +110,7 @@
         on:confirm={confirmDelete}
         on:cancel={cancelDelete}
       >
-        <p>Tem certeza que deseja excluir o usuário "{rowToDelete?.nome}"?</p>
+        <p>Tem certeza que deseja excluir o usuário "{rowToDelete?.name}"?</p>
       </ConfirmModal>
     </div>
   </div>