diff --git a/src/routes/user/+page.svelte b/src/routes/user/+page.svelte index dc1d31c0ab774d973e75ec53b207e5eb05af864c..72210e6b5c5b62ab3a1a594a1e3eaed3ee9037f1 100644 --- a/src/routes/user/+page.svelte +++ b/src/routes/user/+page.svelte @@ -1,202 +1,203 @@ <script lang="ts"> - import { onMount } from 'svelte'; - import Card from '$lib/Card-style.svelte'; - import type { Implant } from '../../types/implant'; - import type { Purchase } from '../../types/purchase'; - - interface UserPurchase extends Purchase { - implant: Implant; - } + import { onMount } from 'svelte'; + import Card from '$lib/Card-style.svelte'; + import type { Implant } from '../../types/implant'; + import type { Purchase } from '../../types/purchase'; - let currentUser: { name: string; email: string; money: number; cyberpsychosis: number; cyberLimit: number } | null = null; - - let allPurchases: UserPurchase[] = []; - let displayedPurchases: UserPurchase[] = []; - let loading = true; - let error = ''; - let activeCategory = 'all'; - let categories: string[] = []; - let currentUserId = -1; - - let page = 1; - const perPage = 10; - - function getToken(): string | null { - return localStorage.getItem('token'); - } + interface UserPurchase extends Purchase { + implant: Implant; + } - onMount(async () => { - window.addEventListener('scroll', handleScroll); - try { - const token = getToken(); - if (!token) throw new Error('Usuário não autenticado'); - - currentUserId = parseInt(localStorage.getItem('user_id') || '-1'); - if (currentUserId === -1) throw new Error('ID de usuário não encontrado'); - - // Busca paralela das transações, implantes e dados do usuário - const [txRes, implantsRes, userRes] = await Promise.all([ - fetch('http://localhost:3000/getTransactionData', { - headers: { 'Authorization': `Bearer ${token}` } - }), - fetch('http://localhost:3000/getAllImplant', { - headers: { 'Authorization': `Bearer ${token}` } - }), - fetch(`http://localhost:3000/getUser/${currentUserId}`, { // Nova requisição para os dados do usuário - headers: { 'Authorization': `Bearer ${token}` } - }) - ]); - - if (!txRes.ok) throw new Error('Erro ao carregar transações'); - if (!implantsRes.ok) throw new Error('Erro ao carregar implantes'); - if (!userRes.ok) throw new Error('Erro ao carregar dados do usuário'); - - const transactions = await txRes.json() as Purchase[]; - const implants = await implantsRes.json() as Implant[]; - currentUser = await userRes.json(); // Armazena os dados do usuário - - // Filtra só as transações do usuário logado - const userTx = transactions.filter(t => t.user_id === currentUserId); - - // Junta detalhe de cada implante - allPurchases = userTx.map(t => ({ - ...t, - implant: implants.find(i => i.id === t.implant_id)! - })); - - // categorias para filtro - categories = [...new Set(allPurchases.map(p => p.implant.bodyPart))]; - - // página inicial - displayedPurchases = allPurchases.slice(0, perPage); - } catch (err) { - error = err instanceof Error ? err.message : String(err); - } finally { - loading = false; - } - - return () => window.removeEventListener('scroll', handleScroll); - }); - - // Carrega próxima “página” de items - function loadMore() { - const start = page * perPage; - const next = allPurchases.slice(start, start + perPage); - if (next.length > 0) { - displayedPurchases = [...displayedPurchases, ...next]; - page += 1; - } - } - - // Detecta fim da página e dispara loadMore - function handleScroll() { - if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 100) { - loadMore(); - } + let currentUser: { name: string; email: string; money: number; cyberpsychosis: number; cyberLimit: number } | null = null; + + let allPurchases: UserPurchase[] = []; + let displayedPurchases: UserPurchase[] = []; + let loading = true; + let error = ''; + let activeCategory = 'all'; + let categories: string[] = []; + let currentUserId = -1; + + let page = 1; + const perPage = 10; + + function getToken(): string | null { + return localStorage.getItem('token'); + } + + onMount(async () => { + window.addEventListener('scroll', handleScroll); + try { + const token = getToken(); + if (!token) throw new Error('Usuário não autenticado'); + + currentUserId = parseInt(localStorage.getItem('user_id') || '-1'); + if (currentUserId === -1) throw new Error('ID de usuário não encontrado'); + + // Busca paralela das transações, implantes e dados do usuário + const [txRes, implantsRes, userRes] = await Promise.all([ + fetch('http://localhost:3000/getTransactionData', { + headers: { 'Authorization': `Bearer ${token}` } + }), + fetch('http://localhost:3000/getAllImplant', { + headers: { 'Authorization': `Bearer ${token}` } + }), + fetch(`http://localhost:3000/getUser/${currentUserId}`, { + headers: { 'Authorization': `Bearer ${token}` } + }) + ]); + + if (!txRes.ok) throw new Error('Erro ao carregar transações'); + if (!implantsRes.ok) throw new Error('Erro ao carregar implantes'); + if (!userRes.ok) throw new Error('Erro ao carregar dados do usuário'); + + // Armazena dados resquitados + const transactions = await txRes.json() as Purchase[]; + const implants = await implantsRes.json() as Implant[]; + currentUser = await userRes.json(); + + // Filtra só as transações do usuário logado + const userTx = transactions.filter(t => t.user_id === currentUserId); + + // Junta detalhe de cada implante + allPurchases = userTx.map(t => ({ + ...t, + implant: implants.find(i => i.id === t.implant_id)! + })); + + // categorias para filtro + categories = [...new Set(allPurchases.map(p => p.implant.bodyPart))]; + + // página inicial + displayedPurchases = allPurchases.slice(0, perPage); + } catch (err) { + error = err instanceof Error ? err.message : String(err); + } finally { + loading = false; } - - // Filtra apenas o que vai ser mostrado - function getFiltered() { - return activeCategory === 'all' - ? displayedPurchases - : displayedPurchases.filter(p => p.implant.bodyPart === activeCategory); + + return () => window.removeEventListener('scroll', handleScroll); + }); + + // Carrega próxima “página” de items + function loadMore() { + const start = page * perPage; + const next = allPurchases.slice(start, start + perPage); + if (next.length > 0) { + displayedPurchases = [...displayedPurchases, ...next]; + page += 1; } - </script> - - <style> - - :global(body) { - background-image: url('/background.png'); - margin: 0; - padding: 0; - color: #00f7ff; - font-family: 'Rajdhani', 'Courier New', sans-serif; + } + + // Detecta fim da página e dispara loadMore + function handleScroll() { + if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 100) { + loadMore(); } + } + + // Filtra apenas o que vai ser mostrado + function getFiltered() { + return activeCategory === 'all' + ? displayedPurchases + : displayedPurchases.filter(p => p.implant.bodyPart === activeCategory); + } +</script> - .error { - color: #ff3e3e; - text-align: center; - } +<style> - /* Layout da janela principal */ - .window { - display: flex; - min-height: 100vh; - width: 100%; - } + :global(body) { + background-image: url('/background.png'); + margin: 0; + padding: 0; + color: #00f7ff; + font-family: 'Rajdhani', 'Courier New', sans-serif; + } - /* Estilização do menu lateral */ - .navegation { - width: 17%; - background: linear-gradient(145deg, #1a1a2e 0%, #16213e 100%); - border-right: 1px solid #00f7ff; - box-shadow: 2px 0 10px rgba(0, 247, 255, 0.2); - padding: 20px 0; - } + .error { + color: #ff3e3e; + text-align: center; + } - .nav-header h2 { - color: #ff073a; - text-align: center; - text-shadow: 0 0 10px #ff073a; - border-bottom: 1px solid #00f7ff; - padding-bottom: 15px; - margin: 0 15px 20px; - } + /* Layout da janela principal */ + .window { + display: flex; + min-height: 100vh; + width: 100%; + } - .nav-section { - margin: 20px 15px; - } + /* Estilização do menu lateral */ + .navegation { + width: 17%; + background: linear-gradient(145deg, #1a1a2e 0%, #16213e 100%); + border-right: 1px solid #00f7ff; + box-shadow: 2px 0 10px rgba(0, 247, 255, 0.2); + padding: 20px 0; + } - /* Botão Store */ - .nav-button { - display: block; - color: #00d0ff; - text-align: center; - text-shadow: 0 0 10px #9a9f17; - padding: 10px 15px; - margin: 0 15px 20px; - text-decoration: none; - border-radius: 5px; - transition: all 0.3s ease; - } + .nav-header h2 { + color: #ff073a; + text-align: center; + text-shadow: 0 0 10px #ff073a; + border-bottom: 1px solid #00f7ff; + padding-bottom: 15px; + margin: 0 15px 20px; + } - .nav-button:hover { - background-color: rgba(0, 208, 255, 0.2); - color: #ffffff; - } + .nav-section { + margin: 20px 15px; + } - /* Botões de filtro */ - .filter-btn { - display: block; - width: 100%; - background-color: #00d0ff; - color: #00060e; - border: none; - border-radius: 5px; - padding: 8px 15px; - margin-bottom: 8px; - cursor: pointer; - text-align: left; - } - - .filter-btn:hover { - background-color: #9a9f17; - } - - .filter-btn.active { - background-color: #9a9f17; - border-left: 3px solid #ff073a; - } + /* Botão Store */ + .nav-button { + display: block; + color: #00d0ff; + text-align: center; + text-shadow: 0 0 10px #9a9f17; + padding: 10px 15px; + margin: 0 15px 20px; + text-decoration: none; + border-radius: 5px; + transition: all 0.3s ease; + } + + .nav-button:hover { + background-color: rgba(0, 208, 255, 0.2); + color: #ffffff; + } + + /* Botões de filtro */ + .filter-btn { + display: block; + width: 100%; + background-color: #00d0ff; + color: #00060e; + border: none; + border-radius: 5px; + padding: 8px 15px; + margin-bottom: 8px; + cursor: pointer; + text-align: left; + } + + .filter-btn:hover { + background-color: #9a9f17; + } + + .filter-btn.active { + background-color: #9a9f17; + border-left: 3px solid #ff073a; + } .card-container { - display: flex; - justify-content: center; + display: flex; + justify-content: center; flex-direction: row; - flex-wrap: wrap; - gap: 10px; - padding: 1rem; - margin: 0.5rem; - } + flex-wrap: wrap; + gap: 10px; + padding: 1rem; + margin: 0.5rem; + } .main-content { flex: 1; @@ -207,176 +208,76 @@ p { margin-left: 10px; } - </style> - - <!-- - <h1>Meus implantes</h1> - - {#if loading} - <p>Carregando...</p> - {:else if error} - <p class="error">{error}</p> - {:else if allPurchases.length === 0} - <p>Você ainda não possui implantes comprados.</p> - {:else} - <div class="filter-container"> - <button - class="filter-btn" - class:active={activeCategory === 'all'} - on:click={() => activeCategory = 'all'}> - Todos - </button> - {#each categories as cat} - <button - class="filter-btn" - class:active={activeCategory === cat} - on:click={() => activeCategory = cat}> - {cat} - </button> - {/each} - <a href="/store"><strong>COMPRAR</strong></a> - </div> - - <div class="cards-container"> - {#each getFiltered() as p (p.implant_id)} - <Card - title={p.implant.name} - bodyPart={p.implant.bodyPart} - price={Number(p.implant.price)} - cyberCost={Number(p.implant.cyberCost)} - showButton={false} - id={p.implant_id} - boughtIds={[]} - /> - {/each} - </div> - {/if}--> - - <!-- - <div class="window"> - <div class="navegation"> - <div class="nav-header"> - <h2>MENU</h2> - </div> - - - <div class="nav-section"> - <a href="/store" class="nav-button"><strong>Store</strong></a> - </div> - - - <div class="nav-section"> - <h3>Filtrar implantes</h3> - <button - class="filter-btn" - class:active={activeCategory === 'all'} - on:click={() => activeCategory = 'all'}> - Todos - </button> - {#each categories as cat} - <button - class="filter-btn" - class:active={activeCategory === cat} - on:click={() => activeCategory = cat}> - {cat} - </button> - {/each} - </div> +</style> + + +<div class="window"> + <div class="navegation"> + <!-- Menu de navegação --> + <div class="nav-header"> + <h2>MENU</h2> </div> - - <div class="main-content"> - <h1>Meus implantes</h1> - {#if loading} - <p>Carregando...</p> - {:else if error} - <p class="error">{error}</p> - {:else if allPurchases.length === 0} - <p>Você ainda não possui implantes comprados.</p> - {:else} - <div class="cards-container"> - {#each getFiltered() as p (p.implant_id)} - <Card - title={p.implant.name} - bodyPart={p.implant.bodyPart} - price={Number(p.implant.price)} - cyberCost={Number(p.implant.cyberCost)} - showButton={false} - id={p.implant_id} - boughtIds={[]} - /> - {/each} - </div> - {/if} + <!-- Botão de comprar --> + <div class="nav-section"> + <a href="/store" class="nav-button"><strong>STORE</strong></a> </div> - </div>--> - - <div class="window"> - <div class="navegation"> - <!-- Menu de navegação --> - <div class="nav-header"> - <h2>MENU</h2> - </div> - - <!-- Botão de comprar --> - <div class="nav-section"> - <a href="/store" class="nav-button"><strong>STORE</strong></a> - </div> - - <p> - {#if currentUser} - Nome: {currentUser.name}<br> - Email: {currentUser.email}<br> - Money: {currentUser.money}<br> - Cyber Limit: {currentUser.cyberLimit}<br> - Cyberpsychosis: {currentUser.cyberpsychosis}<br> - {:else if loading} - Carregando informações do usuário... - {:else if error} - Erro ao carregar informações do usuário. - {/if} - </p> + + <p> + {#if currentUser} + Nome: {currentUser.name}<br> + Email: {currentUser.email}<br> + Money: {currentUser.money}<br> + Cyber Limit: {currentUser.cyberLimit}<br> + Cyberpsychosis: {currentUser.cyberpsychosis}<br> + {:else if loading} + Carregando informações do usuário... + {:else if error} + Erro ao carregar informações do usuário. + {/if} + </p> - <!-- Filtros de categorias --> - <div class="nav-section"> - <button - class="filter-btn" - class:active={activeCategory === 'all'} - on:click={() => activeCategory = 'all'}> - Todos - </button> - {#each categories as cat} - <button - class="filter-btn" - class:active={activeCategory === cat} - on:click={() => activeCategory = cat}> - {cat} - </button> - {/each} - </div> - </div> + <!-- Filtros de categorias --> + <div class="nav-section"> + <button + class="filter-btn" + class:active={activeCategory === 'all'} + on:click={() => activeCategory = 'all'}> + Todos + </button> + {#each categories as cat} + <button + class="filter-btn" + class:active={activeCategory === cat} + on:click={() => activeCategory = cat}> + {cat} + </button> + {/each} + </div> + </div> - <div class="main-content"> - {#if loading} - <p>Carregando...</p> - {:else if error} - <p class="error">{error}</p> - {:else if allPurchases.length === 0} - <p>Você ainda não possui implantes comprados.</p> - {:else} - <div class="card-container"> - {#each getFiltered() as p (p.implant_id)} - <Card - title={p.implant.name} - bodyPart={p.implant.bodyPart} - price={Number(p.implant.price)} - cyberCost={Number(p.implant.cyberCost)} - showButton={false} - id={p.implant_id} - boughtIds={[]} - /> - {/each} - </div> - {/if} - </div> - </div> \ No newline at end of file + <!-- Cards dos Implantes --> + <div class="main-content"> + {#if loading} + <p>Carregando...</p> + {:else if error} + <p class="error">{error}</p> + {:else if allPurchases.length === 0} + <p>Você ainda não possui implantes comprados.</p> + {:else} + <div class="card-container"> + {#each getFiltered() as p (p.implant_id)} + <Card + title={p.implant.name} + bodyPart={p.implant.bodyPart} + price={Number(p.implant.price)} + cyberCost={Number(p.implant.cyberCost)} + showButton={false} + id={p.implant_id} + boughtIds={[]} + /> + {/each} + </div> + {/if} + </div> +</div> \ No newline at end of file