| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- <script>
- import Header from '$lib/layout/Header.svelte';
- 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';
- import { onMount } from 'svelte';
- const apiUrl = import.meta.env.VITE_API_URL;
- const breadcrumb = [{ label: 'Início' }, { label: 'Usuários', active: true }];
- // Tabela
- let columns = [
- { key: 'name', label: 'Nome' },
- { key: 'email', label: 'E-mail' }
- ];
- let data = [];
- let loadError = '';
- let loadServerResponse = '';
- let successMessage = '';
- let isLoadingUsers = false;
- let createLoading = false;
- let createError = '';
- let createResetToken = 0;
- // Modal criar usuário
- let showCreate = false;
- // Confirmação de delete
- let showDeleteConfirm = false;
- let rowToDelete = null;
- let selectedUser = null;
- let showDetails = false;
- function handleAddTop() {
- showCreate = true;
- }
- onMount(loadUsers);
- async function loadUsers() {
- isLoadingUsers = true;
- try {
- loadError = '';
- loadServerResponse = '';
- const url = `${apiUrl}/user/get`;
- //console.log('fetch url:', url);
- const res = await fetch(url, {
- method: 'POST',
- headers: {
- 'content-type': 'application/json',
- ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
- },
- body: JSON.stringify({})
- });
- const raw = await res.text();
- loadServerResponse = raw?.trim() ?? '';
- //console.log('response raw body:', raw);
- let body = null;
- if (raw) {
- try {
- body = JSON.parse(raw);
- } catch (err) {
- console.error('Resposta inválida do endpoint /users:', err);
- throw new Error('Resposta inválida do servidor.');
- }
- }
- if (!res.ok || body?.status !== 'ok') {
- throw new Error(body?.msg ?? 'Falha ao carregar usuários.');
- }
- const list = Array.isArray(body?.data) ? body.data : [];
- //console.log('parsed users length:', list.length);
- data = list.map((u) => ({
- __raw: u,
- name: u?.name ?? u?.user_name ?? u?.userName ?? u?.fullName ?? '-',
- email: u?.email ?? u?.user_email ?? u?.userEmail ?? '-'
- }));
- } catch (e) {
- //console.log('fetch users error:', e);
- loadError = e?.message ?? 'Falha ao carregar usuários.';
- data = [];
- } finally {
- isLoadingUsers = false;
- }
- }
- async function handleCreateSubmit(e) {
- const payload = e?.detail;
- if (!payload) return;
- createLoading = true;
- createError = '';
- try {
- const requestBody = {
- ...payload,
- role_id: payload?.role_id ?? 1
- };
- const res = await fetch(`${apiUrl}/register`, {
- method: 'POST',
- headers: {
- 'content-type': 'application/json',
- ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
- },
- body: JSON.stringify(requestBody)
- });
- const raw = await res.text();
- //console.log('create user raw body:', raw);
- let body = null;
- if (raw) {
- try {
- body = JSON.parse(raw);
- } catch (err) {
- console.error('Resposta inválida do endpoint /register:', err);
- throw new Error('Resposta inválida do servidor.');
- }
- }
- const isSuccess = body?.status === 'success' || body?.status === 'ok' || body?.code === 'S_CREATED';
- if (!res.ok || !isSuccess) {
- throw new Error(body?.message ?? body?.msg ?? 'Falha ao criar usuário.');
- }
- successMessage = body?.message ?? body?.msg ?? 'Usuário criado com sucesso!';
- showCreate = false;
- createResetToken = Date.now();
- await loadUsers();
- } catch (err) {
- console.error('Erro na criação do usuário:', err);
- createError = err?.message ?? 'Falha ao criar usuário.';
- } finally {
- createLoading = false;
- }
- }
- function handleCreateCancel() {
- showCreate = false;
- createError = '';
- createResetToken = Date.now();
- }
- function handleDeleteRow(e) {
- const { row } = e?.detail || {};
- if (!row) return;
- rowToDelete = row;
- showDeleteConfirm = true;
- }
- function handleEditRow(e) {
- const { row } = e?.detail || {};
- if (!row) return;
- selectedUser = row.__raw ?? row;
- //console.log('clicked user details:', selectedUser);
- showDetails = true;
- }
- async function confirmDelete() {
- if (!rowToDelete) { showDeleteConfirm = false; return; }
- const userId =
- rowToDelete?.__raw?.user_id ??
- rowToDelete?.__raw?.userId ??
- rowToDelete?.__raw?.id ??
- rowToDelete?.user_id ??
- rowToDelete?.userId ??
- rowToDelete?.id;
- if (userId == null) {
- console.error('ID do usuário não encontrado para exclusão.');
- showDeleteConfirm = false;
- rowToDelete = null;
- return;
- }
- try {
- const res = await fetch(`${apiUrl}/user/delete`, {
- method: 'POST',
- headers: {
- 'content-type': 'application/json',
- ...( $authToken ? { Authorization: `Bearer ${$authToken}` } : {} )
- },
- body: JSON.stringify({ user_id: userId })
- });
- const raw = await res.text();
- //console.log('delete user raw body:', raw);
- let body = null;
- if (raw) {
- try {
- body = JSON.parse(raw);
- } catch (err) {
- console.error('Resposta inválida do endpoint /user/delete:', err);
- throw new Error('Resposta inválida do servidor.');
- }
- }
- const isSuccess = body?.status === 'success' || body?.status === 'ok' || body?.code === 'S_DELETED';
- if (!res.ok || !isSuccess) {
- throw new Error(body?.message ?? body?.msg ?? 'Falha ao excluir usuário.');
- }
- successMessage = body?.message ?? body?.msg ?? 'Usuário excluído com sucesso!';
- await loadUsers();
- } catch (e) {
- console.error('Erro ao excluir usuário:', e);
- } finally {
- showDeleteConfirm = false;
- rowToDelete = null;
- }
- }
- function cancelDelete() {
- showDeleteConfirm = false;
- rowToDelete = null;
- }
- </script>
- <div>
- <Header title="Usuários" subtitle="Gestão de usuários" breadcrumb={breadcrumb} />
- <div class="p-4">
- <div class="max-w-6xl mx-auto mt-4">
- <Tables
- title="Usuários"
- {columns}
- {data}
- on:addTop={handleAddTop}
- on:rowClick={handleEditRow}
- on:editRow={handleEditRow}
- on:deleteRow={handleDeleteRow}
- showEdit={false}
- />
- <UserCreateModal
- visible={showCreate}
- loading={createLoading}
- errorMessage={createError}
- resetToken={createResetToken}
- on:submit={handleCreateSubmit}
- on:cancel={handleCreateCancel}
- />
- <ConfirmModal
- visible={showDeleteConfirm}
- title="Confirmar exclusão"
- confirmText="Excluir"
- cancelText="Cancelar"
- on:confirm={confirmDelete}
- on:cancel={cancelDelete}
- >
- <p>Tem certeza que deseja excluir o usuário "{rowToDelete?.name}"?</p>
- </ConfirmModal>
- {#if showDetails}
- <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>
- </div>
- {#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">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>
- <div><span class="text-gray-500">CPF:</span> <span class="dark:text-gray-100">{selectedUser.userCpf}</span></div>
- <div><span class="text-gray-500">Data Nasc.:</span> <span class="dark:text-gray-100">{selectedUser.userBirthdate}</span></div>
- <div><span class="text-gray-500">KYC:</span> <span class="dark:text-gray-100">{selectedUser.userKyc}</span></div>
- <div><span class="text-gray-500">Papel (roleId):</span> <span class="dark:text-gray-100">{selectedUser.roleId}</span></div>
- <div><span class="text-gray-500">Status:</span> <span class="dark:text-gray-100">{selectedUser.userFlag}</span></div>
- <div class="sm:col-span-2"><span class="text-gray-500">Endereço:</span> <span class="dark:text-gray-100">{selectedUser.userAddress}</span></div>
- <div><span class="text-gray-500">Cidade:</span> <span class="dark:text-gray-100">{selectedUser.userCity}</span></div>
- <div><span class="text-gray-500">Estado:</span> <span class="dark:text-gray-100">{selectedUser.userState}</span></div>
- <div><span class="text-gray-500">CEP:</span> <span class="dark:text-gray-100">{selectedUser.userZip}</span></div>
- <div><span class="text-gray-500">País:</span> <span class="dark:text-gray-100">{selectedUser.userCountry}</span></div>
- </div>
- {/if}
- <div class="mt-5 flex justify-end">
- <button class="px-4 py-2 rounded bg-blue-600 hover:bg-blue-700 text-white" on:click={() => showDetails = false}>Fechar</button>
- </div>
- </div>
- </div>
- {/if}
- </div>
- </div>
- </div>
|