From 7a57c5599a49a2acada3382612e6f85b4a4e1748 Mon Sep 17 00:00:00 2001 From: TroianoLuca Date: Wed, 26 Nov 2025 22:20:02 -0300 Subject: [PATCH 01/49] Hecha links paginas usuarios --- src/lib/components/PostCard.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte index 10d49b4..be5f55e 100644 --- a/src/lib/components/PostCard.svelte +++ b/src/lib/components/PostCard.svelte @@ -60,10 +60,12 @@
+ {post.authorDisplayName[0].toUpperCase()} +
{post.authorDisplayName} @{post.authorName} From 8e366b4645e2695860d45597937dd5a2c6ff55c7 Mon Sep 17 00:00:00 2001 From: TroianoLuca Date: Thu, 27 Nov 2025 00:45:43 -0300 Subject: [PATCH 02/49] Agregado simbolo carga al boton de Publicar --- src/lib/components/crear-post.svelte | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/components/crear-post.svelte b/src/lib/components/crear-post.svelte index 0e42575..dd40c7f 100644 --- a/src/lib/components/crear-post.svelte +++ b/src/lib/components/crear-post.svelte @@ -4,6 +4,7 @@ import InputGroupTextarea from './ui/input-group/input-group-textarea.svelte'; import InputGroup from './ui/input-group/input-group.svelte'; import ArrowUpIcon from '@lucide/svelte/icons/arrow-up'; + import Loader2Icon from '@lucide/svelte/icons/loader-2'; import Kbd from './ui/kbd/kbd.svelte'; import { apiBase } from '@/stores/url'; @@ -88,8 +89,13 @@ class="transform rounded-full transition-transform ease-in hover:scale-120" size="xs" > -

Publicar

- + {#if cargando} + + Publicando... + {:else} + Publicar + + {/if} From 17addc8fcfc0f9960c843e6f3a3e2cc8a6663fd8 Mon Sep 17 00:00:00 2001 From: TroianoLuca Date: Thu, 27 Nov 2025 11:55:30 -0300 Subject: [PATCH 03/49] Agregado boton de carga el registrarse --- src/lib/components/signup-form.svelte | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/components/signup-form.svelte b/src/lib/components/signup-form.svelte index 4db6eaf..9469476 100644 --- a/src/lib/components/signup-form.svelte +++ b/src/lib/components/signup-form.svelte @@ -5,9 +5,12 @@ import { Input } from '$lib/components/ui/input/index.js'; import type { RegisterDto } from '../../types'; import { register } from '@/hooks/register'; + import Loader2Icon from '@lucide/svelte/icons/loader-2'; let {showAlert = $bindable() } = $props(); + let cargando = $state(false); + const setAlert = () => showAlert = true; let dto: RegisterDto = $state({password: "", username: "", email:"", displayName: ""}); @@ -48,7 +51,14 @@ - + Tenes una cuenta? Iniciar Sesion From 0b39cc6f2873d118ea430b0e4bf4018816fa87a0 Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 17:30:52 -0300 Subject: [PATCH 04/49] arreglado lo de usuario que no se veia el nombre de usuario --- src/lib/hooks/obtenerUsuario.ts | 27 +++++++++++++++++++++++++++ src/routes/[perfil]/+error.svelte | 20 ++++++++++++++++++++ src/routes/[perfil]/+page.server.ts | 11 +++++++++++ src/routes/[perfil]/+page.svelte | 6 ++---- src/types.d.ts | 12 ++++++++++++ 5 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/lib/hooks/obtenerUsuario.ts create mode 100644 src/routes/[perfil]/+error.svelte create mode 100644 src/routes/[perfil]/+page.server.ts diff --git a/src/lib/hooks/obtenerUsuario.ts b/src/lib/hooks/obtenerUsuario.ts new file mode 100644 index 0000000..40481bf --- /dev/null +++ b/src/lib/hooks/obtenerUsuario.ts @@ -0,0 +1,27 @@ +import { apiBase } from '@/stores/url'; +import type { UserResponseDto } from '../../types'; +import { get } from 'svelte/store'; +import { sesionStore } from '@/stores/usuario'; + +export async function obtenerUsuarioPorUsername(username: string): Promise { + try { + const response = await fetch(`${get(apiBase)}/api/users/username/${username}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + } + }); + + if (!response.ok) { + //console.error('Error fetching user data:', response.status); + return null; + } + + const user: UserResponseDto = await response.json(); + return user; + } catch (error) { + //console.error('Failed to reach the server while fetching user:', error); + return null; + } +} diff --git a/src/routes/[perfil]/+error.svelte b/src/routes/[perfil]/+error.svelte new file mode 100644 index 0000000..460a950 --- /dev/null +++ b/src/routes/[perfil]/+error.svelte @@ -0,0 +1,20 @@ + + +
+
+ + +

+ {page.status} +

+

+ {page.error!.message} +

+
+
+
+
diff --git a/src/routes/[perfil]/+page.server.ts b/src/routes/[perfil]/+page.server.ts new file mode 100644 index 0000000..641b412 --- /dev/null +++ b/src/routes/[perfil]/+page.server.ts @@ -0,0 +1,11 @@ +import { obtenerUsuarioPorUsername } from '@/hooks/obtenerUsuario.js'; +import type { User, UserResponseDto } from '../../types.js'; +import { error } from '@sveltejs/kit'; + +export async function load({ params }) { + const usuario: UserResponseDto | null = await obtenerUsuarioPorUsername(params.perfil); + if (usuario) { + return usuario; + } + error(404, 'No se encontro el usuario, ' + params.perfil); +} diff --git a/src/routes/[perfil]/+page.svelte b/src/routes/[perfil]/+page.svelte index e1160cc..189d37f 100644 --- a/src/routes/[perfil]/+page.svelte +++ b/src/routes/[perfil]/+page.svelte @@ -11,11 +11,9 @@ import { fade, slide } from 'svelte/transition'; import PostCard from '@/components/PostCard.svelte'; import { posts, setPosts, updatePostStore } from '@/stores/posts.js'; - import InputGroup from '@/components/ui/input-group/input-group.svelte'; - import InputGroupTextarea from '@/components/ui/input-group/input-group-textarea.svelte'; - import InputGroupAddon from '@/components/ui/input-group/input-group-addon.svelte'; import { updatePost } from '@/hooks/updatePost.js'; import ModalEditar from './modalEditar.svelte'; + import { page } from '$app/state'; let { params } = $props(); @@ -78,7 +76,7 @@

- {'test'} + {page.data.displayName}

@{params.perfil} diff --git a/src/types.d.ts b/src/types.d.ts index 16d437a..9d79673 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -74,3 +74,15 @@ export interface PostResponseDto { visibility: string; hashtags: string[]?; } + +export interface UserResponseDto { + id: string; + username: string; + displayName: string; + email: string; + bio: string; + profileImageUrl: string; + followersCount: number; + followingCount: number; + createdAt: string; +} From 6a2f524e6ad9c51c0d51969cb7fc0d919f4e2bde Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 17:34:08 -0300 Subject: [PATCH 05/49] skeleton de la interfaz para la pagina de admin --- src/lib/components/ui/table/index.ts | 28 +++++++++ src/lib/components/ui/table/table-body.svelte | 20 +++++++ .../components/ui/table/table-caption.svelte | 20 +++++++ src/lib/components/ui/table/table-cell.svelte | 23 ++++++++ .../components/ui/table/table-footer.svelte | 20 +++++++ src/lib/components/ui/table/table-head.svelte | 23 ++++++++ .../components/ui/table/table-header.svelte | 20 +++++++ src/lib/components/ui/table/table-row.svelte | 23 ++++++++ src/lib/components/ui/table/table.svelte | 22 +++++++ src/lib/head/AvatarButton.svelte | 5 ++ src/routes/(privado)/admin/+page.svelte | 59 +++++++++++++++++++ 11 files changed, 263 insertions(+) create mode 100644 src/lib/components/ui/table/index.ts create mode 100644 src/lib/components/ui/table/table-body.svelte create mode 100644 src/lib/components/ui/table/table-caption.svelte create mode 100644 src/lib/components/ui/table/table-cell.svelte create mode 100644 src/lib/components/ui/table/table-footer.svelte create mode 100644 src/lib/components/ui/table/table-head.svelte create mode 100644 src/lib/components/ui/table/table-header.svelte create mode 100644 src/lib/components/ui/table/table-row.svelte create mode 100644 src/lib/components/ui/table/table.svelte create mode 100644 src/routes/(privado)/admin/+page.svelte diff --git a/src/lib/components/ui/table/index.ts b/src/lib/components/ui/table/index.ts new file mode 100644 index 0000000..14695c8 --- /dev/null +++ b/src/lib/components/ui/table/index.ts @@ -0,0 +1,28 @@ +import Root from "./table.svelte"; +import Body from "./table-body.svelte"; +import Caption from "./table-caption.svelte"; +import Cell from "./table-cell.svelte"; +import Footer from "./table-footer.svelte"; +import Head from "./table-head.svelte"; +import Header from "./table-header.svelte"; +import Row from "./table-row.svelte"; + +export { + Root, + Body, + Caption, + Cell, + Footer, + Head, + Header, + Row, + // + Root as Table, + Body as TableBody, + Caption as TableCaption, + Cell as TableCell, + Footer as TableFooter, + Head as TableHead, + Header as TableHeader, + Row as TableRow, +}; diff --git a/src/lib/components/ui/table/table-body.svelte b/src/lib/components/ui/table/table-body.svelte new file mode 100644 index 0000000..29e9687 --- /dev/null +++ b/src/lib/components/ui/table/table-body.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-caption.svelte b/src/lib/components/ui/table/table-caption.svelte new file mode 100644 index 0000000..4696cff --- /dev/null +++ b/src/lib/components/ui/table/table-caption.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-cell.svelte b/src/lib/components/ui/table/table-cell.svelte new file mode 100644 index 0000000..2e1036f --- /dev/null +++ b/src/lib/components/ui/table/table-cell.svelte @@ -0,0 +1,23 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-footer.svelte b/src/lib/components/ui/table/table-footer.svelte new file mode 100644 index 0000000..b9b14eb --- /dev/null +++ b/src/lib/components/ui/table/table-footer.svelte @@ -0,0 +1,20 @@ + + +tr]:last:border-b-0", className)} + {...restProps} +> + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-head.svelte b/src/lib/components/ui/table/table-head.svelte new file mode 100644 index 0000000..b0fb68f --- /dev/null +++ b/src/lib/components/ui/table/table-head.svelte @@ -0,0 +1,23 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-header.svelte b/src/lib/components/ui/table/table-header.svelte new file mode 100644 index 0000000..f47d259 --- /dev/null +++ b/src/lib/components/ui/table/table-header.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/table/table-row.svelte b/src/lib/components/ui/table/table-row.svelte new file mode 100644 index 0000000..0df769e --- /dev/null +++ b/src/lib/components/ui/table/table-row.svelte @@ -0,0 +1,23 @@ + + +svelte-css-wrapper]:[&>th,td]:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", + className + )} + {...restProps} +> + {@render children?.()} + diff --git a/src/lib/components/ui/table/table.svelte b/src/lib/components/ui/table/table.svelte new file mode 100644 index 0000000..a334956 --- /dev/null +++ b/src/lib/components/ui/table/table.svelte @@ -0,0 +1,22 @@ + + +
+ + {@render children?.()} +
+
diff --git a/src/lib/head/AvatarButton.svelte b/src/lib/head/AvatarButton.svelte index 1d25635..c1e4c31 100644 --- a/src/lib/head/AvatarButton.svelte +++ b/src/lib/head/AvatarButton.svelte @@ -27,6 +27,11 @@ goto('/' + $sesionStore?.username)} >Mi Perfil + + {#if true} + goto('/admin')}>Menu Admin + {/if} + await logout(menuOpen)}>Cerrar Sesion diff --git a/src/routes/(privado)/admin/+page.svelte b/src/routes/(privado)/admin/+page.svelte new file mode 100644 index 0000000..52b6ce3 --- /dev/null +++ b/src/routes/(privado)/admin/+page.svelte @@ -0,0 +1,59 @@ + + +
+
+

+ Gestion Usuarios +

+ + + {#if usuarios.length === 0} + {#if error} + + Error al cargar usuarios. + + {:else if cargando} + + + Cargando usuarios... + + {:else} + No hay posts que mostar + {/if} + {:else} + + + + Usuario + Nombre + Cantidad de posts + Acciones + + + +
+ {/if} +
+
+
+
From 11dfe83aaafa1a8b8c18ddc40eb57b2b8cf6a80f Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 18:03:31 -0300 Subject: [PATCH 06/49] =?UTF-8?q?a=C3=B1adida=20funcionalidad=20de=20poste?= =?UTF-8?q?ar=20desde=20la=20pagina=20de=20perfil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/[perfil]/+page.svelte | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/routes/[perfil]/+page.svelte b/src/routes/[perfil]/+page.svelte index 189d37f..a421fc2 100644 --- a/src/routes/[perfil]/+page.svelte +++ b/src/routes/[perfil]/+page.svelte @@ -1,6 +1,7 @@ + + + + + Usuario + Nombre + Cantidad de posts + Fecha de Creacion + Acciones + + + + {#each usuarios as usuario} + + @{usuario.username} + {usuario.displayName} + ? + {usuario.createdAt.replace('Z', ' ').replace('T', ' | ')} + ? + + {/each} + +
diff --git a/src/lib/components/crear-post.svelte b/src/lib/components/crear-post.svelte index dd40c7f..19da76a 100644 --- a/src/lib/components/crear-post.svelte +++ b/src/lib/components/crear-post.svelte @@ -85,6 +85,7 @@ - import CardAction from '@/components/ui/card/card-action.svelte'; import CardContent from '@/components/ui/card/card-content.svelte'; - import CardHeader from '@/components/ui/card/card-header.svelte'; - import CardTitle from '@/components/ui/card/card-title.svelte'; import Card from '@/components/ui/card/card.svelte'; import TableBody from '@/components/ui/table/table-body.svelte'; import TableHead from '@/components/ui/table/table-head.svelte'; @@ -12,10 +9,11 @@ import type { User } from '../../../types'; import CardDescription from '@/components/ui/card/card-description.svelte'; import Spinner from '@/components/ui/spinner/spinner.svelte'; + import TableCell from '@/components/ui/table/table-cell.svelte'; + import { page } from '$app/state'; + import TablaUsuarios from '@/components/TablaUsuarios.svelte'; - let usuarios: User[] = $state([]); let cargando = $state(true); - let error = $state(true);
@@ -25,33 +23,18 @@ > Gestion Usuarios

- + - {#if usuarios.length === 0} - {#if error} + {#if page.data.usuarios.length === 0} + {#if page.data.error} Error al cargar usuarios. - {:else if cargando} - - - Cargando usuarios... - {:else} No hay posts que mostar {/if} {:else} - - - - Usuario - Nombre - Cantidad de posts - Acciones - - - -
+ {/if}
diff --git a/src/routes/(privado)/admin/+page.ts b/src/routes/(privado)/admin/+page.ts new file mode 100644 index 0000000..b253ba8 --- /dev/null +++ b/src/routes/(privado)/admin/+page.ts @@ -0,0 +1,29 @@ +import { apiBase } from '@/stores/url.js'; +import { sesionStore } from '@/stores/usuario'; +import { redirect } from '@sveltejs/kit'; +import { get } from 'svelte/store'; +import type { UserResponseDto } from '../../../types.js'; + +//para que solo se envie cuando se requiere +export const prerender = true; + +export async function load({}) { + const response = await fetch(get(apiBase) + '/api/admin/users', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + } + }); + + if (response.status === 401) { + throw redirect(302, '/'); + } + if (!response.ok) { + return { error: true }; + } + + const usuarios: UserResponseDto[] = await response.json(); + + return { usuarios, error: false }; +} From d38a223b12ecefc6d0a14e9dfd627e3a83cf50c4 Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 20:18:10 -0300 Subject: [PATCH 11/49] fetch de usuarios ya funcional junto con la ui de usurios --- src/routes/(privado)/admin/+page.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/(privado)/admin/+page.ts b/src/routes/(privado)/admin/+page.ts index b253ba8..953ccb1 100644 --- a/src/routes/(privado)/admin/+page.ts +++ b/src/routes/(privado)/admin/+page.ts @@ -4,8 +4,12 @@ import { redirect } from '@sveltejs/kit'; import { get } from 'svelte/store'; import type { UserResponseDto } from '../../../types.js'; +<<<<<<< HEAD //para que solo se envie cuando se requiere export const prerender = true; +======= +export const ssr = true; +>>>>>>> 354f43e (fetch de usuarios ya funcional junto con la ui de usurios) export async function load({}) { const response = await fetch(get(apiBase) + '/api/admin/users', { From 8d0fab49cd04f51b33a3c0520c8fb3bd3f4bf83e Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 20:20:31 -0300 Subject: [PATCH 12/49] resuelto un conflicto --- src/routes/(privado)/admin/+page.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/routes/(privado)/admin/+page.ts b/src/routes/(privado)/admin/+page.ts index 953ccb1..9adba4b 100644 --- a/src/routes/(privado)/admin/+page.ts +++ b/src/routes/(privado)/admin/+page.ts @@ -4,12 +4,7 @@ import { redirect } from '@sveltejs/kit'; import { get } from 'svelte/store'; import type { UserResponseDto } from '../../../types.js'; -<<<<<<< HEAD -//para que solo se envie cuando se requiere -export const prerender = true; -======= export const ssr = true; ->>>>>>> 354f43e (fetch de usuarios ya funcional junto con la ui de usurios) export async function load({}) { const response = await fetch(get(apiBase) + '/api/admin/users', { From 5a96152410ebf5355acb0031978c0fd560d3ce9a Mon Sep 17 00:00:00 2001 From: fede Date: Thu, 27 Nov 2025 21:30:50 -0300 Subject: [PATCH 13/49] correjida logica de refresh ahora si tiene en cuenta el .exp del jwt para saber cuando va a renovar --- src/lib/stores/usuario.ts | 41 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/lib/stores/usuario.ts b/src/lib/stores/usuario.ts index 4a7c5ac..c516de1 100644 --- a/src/lib/stores/usuario.ts +++ b/src/lib/stores/usuario.ts @@ -27,8 +27,43 @@ if (browser) { }); } if (browser) { + const decodeJWT = (token: string) => { + try { + const base64Url = token.split('.')[1]; + const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); + const jsonPayload = decodeURIComponent( + atob(base64) + .split('') + .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) + .join('') + ); + + return JSON.parse(jsonPayload); + } catch (error) { + console.error('Error decodificando JWT:', error); + return null; + } + }; + + const shouldRefreshToken = (sesion: Sesion | null): boolean => { + if (!sesion || !sesion.accessToken) return false; + + const decoded = decodeJWT(sesion.accessToken); + if (!decoded || !decoded.exp) return false; + + const expirationTime = decoded.exp * 1000; + const currentTime = Date.now(); + const timeUntilExpiration = expirationTime - currentTime; + + return timeUntilExpiration <= 60 * 1000; // 1 minuto + }; + const refreshAccessToken = async () => { try { + const sesion = get(currentSesion); + if (!shouldRefreshToken(sesion)) return; + + console.log('refrescando token'); const response = await fetch(get(apiBase) + '/api/auth/refresh', { method: 'POST', headers: { @@ -46,14 +81,14 @@ if (browser) { return sesion; }); } else { - console.error('Error refreshing token:', response.statusText); + console.error('Error refrescando token:', response.statusText); currentSesion.set(null); } } catch (error) { - console.error('Error refreshing token:', error); + console.error('Error refrescando token:', error); currentSesion.set(null); } }; - setInterval(refreshAccessToken, 10 * 60 * 1000); + setInterval(refreshAccessToken, 30 * 1000); // Check every 30 seconds } From 4db02b9fa82b4c4e4b6f96f591dee04f27a5e477 Mon Sep 17 00:00:00 2001 From: fede Date: Sat, 29 Nov 2025 12:06:02 -0300 Subject: [PATCH 14/49] no se refrescaba el token on load --- src/lib/stores/usuario.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/stores/usuario.ts b/src/lib/stores/usuario.ts index c516de1..aa1b2e5 100644 --- a/src/lib/stores/usuario.ts +++ b/src/lib/stores/usuario.ts @@ -91,4 +91,5 @@ if (browser) { }; setInterval(refreshAccessToken, 30 * 1000); // Check every 30 seconds + refreshAccessToken(); } From 8c69b808418f45ddc0f92134925019840d429527 Mon Sep 17 00:00:00 2001 From: fede Date: Sat, 29 Nov 2025 12:14:14 -0300 Subject: [PATCH 15/49] Fix: movi el tooltipProvider al layout global --- src/lib/components/crear-post.svelte | 48 +++++++++++++--------------- src/routes/+layout.svelte | 5 ++- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/lib/components/crear-post.svelte b/src/lib/components/crear-post.svelte index 19da76a..a49be4c 100644 --- a/src/lib/components/crear-post.svelte +++ b/src/lib/components/crear-post.svelte @@ -11,7 +11,7 @@ import { sesionStore } from '@/stores/usuario'; import type { CreatePostDto } from '../../types'; import { addPost } from '@/stores/posts'; - import { Tooltip, TooltipProvider } from './ui/tooltip'; + import { Tooltip } from './ui/tooltip'; import TooltipContent from './ui/tooltip/tooltip-content.svelte'; import TooltipTrigger from './ui/tooltip/tooltip-trigger.svelte'; @@ -80,30 +80,28 @@

/ 280 - - - - - {#if cargando} - - Publicando... - {:else} - Publicar - - {/if} - - - - Ctrl+Enter - - - + + + + {#if cargando} + + Publicando... + {:else} + Publicar + + {/if} + + + + Ctrl+Enter + +
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 718627a..a0ca932 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -3,6 +3,7 @@ import favicon from '$lib/assets/favicon.ico'; import { ModeWatcher } from 'mode-watcher'; import Header from '@/head/Header.svelte'; + import { TooltipProvider } from '@/components/ui/tooltip'; let { children } = $props(); @@ -13,4 +14,6 @@
-{@render children()} + + {@render children()} + From b60a2bb32f3edb8a5e5690b5c6b01ec2ecb1f706 Mon Sep 17 00:00:00 2001 From: fede Date: Sat, 29 Nov 2025 15:37:44 -0300 Subject: [PATCH 16/49] Fix: al ser ssr no podia leer el token porque se estaba ejecutando en el server --- src/routes/(privado)/admin/+page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(privado)/admin/+page.ts b/src/routes/(privado)/admin/+page.ts index 9adba4b..7d23379 100644 --- a/src/routes/(privado)/admin/+page.ts +++ b/src/routes/(privado)/admin/+page.ts @@ -4,7 +4,7 @@ import { redirect } from '@sveltejs/kit'; import { get } from 'svelte/store'; import type { UserResponseDto } from '../../../types.js'; -export const ssr = true; +export const ssr = false; export async function load({}) { const response = await fetch(get(apiBase) + '/api/admin/users', { From 3068280b82345cb19a2619b8a5726f700c3c3f49 Mon Sep 17 00:00:00 2001 From: fede Date: Sat, 29 Nov 2025 19:11:33 -0300 Subject: [PATCH 17/49] =?UTF-8?q?A=C3=B1adida=20implementacion=20de=20rese?= =?UTF-8?q?tear=20contrase=C3=B1a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/TablaUsuarios.svelte | 41 ++++++++- .../admin/RecuperarContraseña.svelte | 88 +++++++++++++++++++ src/lib/hooks/cambiarContraseña.ts | 24 +++++ src/routes/(privado)/admin/+page.svelte | 14 +-- 4 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 src/lib/components/admin/RecuperarContraseña.svelte create mode 100644 src/lib/hooks/cambiarContraseña.ts diff --git a/src/lib/components/TablaUsuarios.svelte b/src/lib/components/TablaUsuarios.svelte index 25ffd32..474a54b 100644 --- a/src/lib/components/TablaUsuarios.svelte +++ b/src/lib/components/TablaUsuarios.svelte @@ -5,15 +5,40 @@ import TableHeader from '@/components/ui/table/table-header.svelte'; import TableRow from '@/components/ui/table/table-row.svelte'; import Table from '@/components/ui/table/table.svelte'; - import type { UserResponseDto } from '../../../types'; + import type { UserResponseDto } from '../../types'; + import Button from './ui/button/button.svelte'; + import KeyIcon from '@lucide/svelte/icons/key'; + import { Tooltip } from './ui/tooltip'; + import TooltipTrigger from './ui/tooltip/tooltip-trigger.svelte'; + import TooltipContent from './ui/tooltip/tooltip-content.svelte'; + import RecuperarContraseña from './admin/RecuperarContraseña.svelte'; + import { Dialog } from './ui/dialog'; + import DialogContent from './ui/dialog/dialog-content.svelte'; interface Props { usuarios: UserResponseDto[]; } let { usuarios }: Props = $props(); + + let open = $state(false); + + //si ponia contraseña en español quedaba muy largo el nombre + let usuarioCambioPass: UserResponseDto | null = $state(null); + + $effect(() => { + if (!open) { + usuarioCambioPass = null; + } + }); + + function handleCambiarContraseña(usuario: UserResponseDto) { + open = true; + usuarioCambioPass = usuario; + } + @@ -31,8 +56,20 @@ {usuario.displayName} ? {usuario.createdAt.replace('Z', ' ').replace('T', ' | ')} - ? + + + + + + +

Recuperar Contraseña

+
+
+ + +
{/each}
+ diff --git a/src/lib/components/admin/RecuperarContraseña.svelte b/src/lib/components/admin/RecuperarContraseña.svelte new file mode 100644 index 0000000..b9e68b5 --- /dev/null +++ b/src/lib/components/admin/RecuperarContraseña.svelte @@ -0,0 +1,88 @@ + + +
+ (open = !open)}> + + +

Cambiar Contraseña

+
+
+ + + + +

= 8 + }} + > + {nuevapass.length} +

+ / 8 +
+
+
+ + +
+
+
+
+
+
+ (openMensaje = false)}> + {$inspect(error)} + {error === '' ? 'Se modificó el usuario' : error} + +
diff --git a/src/lib/hooks/cambiarContraseña.ts b/src/lib/hooks/cambiarContraseña.ts new file mode 100644 index 0000000..5721693 --- /dev/null +++ b/src/lib/hooks/cambiarContraseña.ts @@ -0,0 +1,24 @@ +import { apiBase } from '@/stores/url'; +import { get } from 'svelte/store'; +import type { UserResponseDto } from '../../types'; +import { sesionStore } from '@/stores/usuario'; + +export async function cambiarContraseña(usuario: UserResponseDto, newpass: string) { + try { + const req = await fetch(get(apiBase) + '/api/admin/password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + }, + body: JSON.stringify({ id: usuario.id, newpass }) + }); + if (req.ok) { + return ''; + } + const data = await req.json(); + return data.message; + } catch { + return 'No se pudo alcanzar el servidor'; + } +} diff --git a/src/routes/(privado)/admin/+page.svelte b/src/routes/(privado)/admin/+page.svelte index 1bdd3a4..29fdd2b 100644 --- a/src/routes/(privado)/admin/+page.svelte +++ b/src/routes/(privado)/admin/+page.svelte @@ -12,18 +12,22 @@ import TableCell from '@/components/ui/table/table-cell.svelte'; import { page } from '$app/state'; import TablaUsuarios from '@/components/TablaUsuarios.svelte'; + import CardTitle from '@/components/ui/card/card-title.svelte'; + import CardHeader from '@/components/ui/card/card-header.svelte'; let cargando = $state(true);
-

- Gestion Usuarios -

+ + +

+ Gestion Usuarios +

+
+
{#if page.data.usuarios.length === 0} {#if page.data.error} From 78e7df318e098ac0480e4afd12ee390dc78232ce Mon Sep 17 00:00:00 2001 From: fede Date: Sun, 30 Nov 2025 00:16:28 -0300 Subject: [PATCH 18/49] terminada logica de like + rework de la interfaz --- src/lib/components/PostCard.svelte | 62 ++++++++++++++++++++++++------ src/lib/hooks/likePublicacion.ts | 21 ++++++++++ src/types.d.ts | 1 + 3 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 src/lib/hooks/likePublicacion.ts diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte index be5f55e..2704294 100644 --- a/src/lib/components/PostCard.svelte +++ b/src/lib/components/PostCard.svelte @@ -1,6 +1,8 @@ @@ -61,10 +84,10 @@
- - - {post.authorDisplayName[0].toUpperCase()} - + + + {post.authorDisplayName[0].toUpperCase()} +
{post.authorDisplayName} @@ -74,7 +97,7 @@ {#if post.authorName === $sesionStore?.username} - + @@ -103,16 +126,31 @@
- -

{post.content}

+ +

{post.content}

{#if post.imageUrl} Post {/if}
-
- {post.likesCount} likes - {post.repliesCount} replies +
+ + + {post.createdAt.replace('T', ' ').split('.')[0]} @@ -122,7 +160,7 @@
-{#if mensajeError} +{#if mensajeError || errorLike} diff --git a/src/lib/hooks/likePublicacion.ts b/src/lib/hooks/likePublicacion.ts new file mode 100644 index 0000000..9c27855 --- /dev/null +++ b/src/lib/hooks/likePublicacion.ts @@ -0,0 +1,21 @@ +import { apiBase } from '@/stores/url'; +import { get } from 'svelte/store'; +import { sesionStore } from '@/stores/usuario'; +import type { Post } from '../../types'; + +export async function likePublicacion(post: Post) { + try { + const req = await fetch(get(apiBase) + `/api/posts/${post.id}/like`, { + method: post.isLiked ? 'DELETE' : 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + } + }); + + const data: { message: string } = await req.json(); + return { message: data.message, ok: req.ok }; + } catch { + return { message: 'No se pudo alcanzar el servidor', ok: false }; + } +} diff --git a/src/types.d.ts b/src/types.d.ts index 0fed13d..0f6f5f7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -15,6 +15,7 @@ export interface Post { isEdited: boolean; visibility: string; hashtags?: string[]; + isLiked: boolean; } export interface User { From 4fe210eab6adcdb09dbee639bcb3a4798a5980bd Mon Sep 17 00:00:00 2001 From: fede Date: Sun, 30 Nov 2025 00:29:23 -0300 Subject: [PATCH 19/49] =?UTF-8?q?A=C3=B1adida=20cantidad=20de=20post=20en?= =?UTF-8?q?=20el=20panel=20de=20admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/TablaUsuarios.svelte | 2 +- src/types.d.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/components/TablaUsuarios.svelte b/src/lib/components/TablaUsuarios.svelte index 474a54b..28e2423 100644 --- a/src/lib/components/TablaUsuarios.svelte +++ b/src/lib/components/TablaUsuarios.svelte @@ -54,7 +54,7 @@ @{usuario.username} {usuario.displayName} - ? + {usuario.postsCount} {usuario.createdAt.replace('Z', ' ').replace('T', ' | ')} diff --git a/src/types.d.ts b/src/types.d.ts index 0f6f5f7..a134d27 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -87,4 +87,5 @@ export interface UserResponseDto { followersCount: number; followingCount: number; createdAt: string; + postsCount: number; } From f15421b2e73ab2139e5c678fa9d6737fa6f3092f Mon Sep 17 00:00:00 2001 From: fede Date: Sun, 30 Nov 2025 00:29:47 -0300 Subject: [PATCH 20/49] =?UTF-8?q?a=C3=B1adido=20link=20a=20la=20pagina=20d?= =?UTF-8?q?el=20usuario=20desde=20el=20panel=20de=20admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/TablaUsuarios.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/components/TablaUsuarios.svelte b/src/lib/components/TablaUsuarios.svelte index 28e2423..b755996 100644 --- a/src/lib/components/TablaUsuarios.svelte +++ b/src/lib/components/TablaUsuarios.svelte @@ -52,7 +52,11 @@ {#each usuarios as usuario} - @{usuario.username} + @ + {usuario.username} + + {usuario.displayName} {usuario.postsCount} {usuario.createdAt.replace('Z', ' ').replace('T', ' | ')} From 64a6e4d9212f8f840ec59a9b161d1687f072000a Mon Sep 17 00:00:00 2001 From: TroianoLuca Date: Mon, 1 Dec 2025 16:56:50 -0300 Subject: [PATCH 21/49] Terminado boton de carga register --- src/lib/components/signup-form.svelte | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/components/signup-form.svelte b/src/lib/components/signup-form.svelte index 9469476..f5bf7c3 100644 --- a/src/lib/components/signup-form.svelte +++ b/src/lib/components/signup-form.svelte @@ -13,8 +13,14 @@ const setAlert = () => showAlert = true; + let dto: RegisterDto = $state({password: "", username: "", email:"", displayName: ""}); +const handleSubmit = async (e: Event) => { + cargando = true; + await register(e, dto, setAlert); + cargando = false; +} @@ -23,7 +29,7 @@
-
register(e, dto, setAlert)}> + Nombre de Usuario @@ -51,10 +57,10 @@ - + No tenes una cuenta? Registrate From cdf1760dfb7ae0b86b940e7d81f811cb1c670219 Mon Sep 17 00:00:00 2001 From: fede Date: Mon, 1 Dec 2025 19:30:45 -0300 Subject: [PATCH 23/49] =?UTF-8?q?fix:=20habia=20un=20log=20que=20quedo=20d?= =?UTF-8?q?e=20m=C3=A1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/admin/RecuperarContraseña.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/admin/RecuperarContraseña.svelte b/src/lib/components/admin/RecuperarContraseña.svelte index b9e68b5..829d8af 100644 --- a/src/lib/components/admin/RecuperarContraseña.svelte +++ b/src/lib/components/admin/RecuperarContraseña.svelte @@ -82,7 +82,7 @@
(openMensaje = false)}> - {$inspect(error)} + {error === '' ? 'Se modificó el usuario' : error}
From b15f08659fcc508733f32726f8e978200df1758b Mon Sep 17 00:00:00 2001 From: fede Date: Mon, 1 Dec 2025 19:31:04 -0300 Subject: [PATCH 24/49] skeleton del boton para modificar usuario --- src/lib/components/TablaUsuarios.svelte | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/components/TablaUsuarios.svelte b/src/lib/components/TablaUsuarios.svelte index b755996..1aa00ce 100644 --- a/src/lib/components/TablaUsuarios.svelte +++ b/src/lib/components/TablaUsuarios.svelte @@ -8,6 +8,7 @@ import type { UserResponseDto } from '../../types'; import Button from './ui/button/button.svelte'; import KeyIcon from '@lucide/svelte/icons/key'; + import UserPen from '@lucide/svelte/icons/user-pen'; import { Tooltip } from './ui/tooltip'; import TooltipTrigger from './ui/tooltip/tooltip-trigger.svelte'; import TooltipContent from './ui/tooltip/tooltip-content.svelte'; @@ -22,6 +23,7 @@ let { usuarios }: Props = $props(); let open = $state(false); + const openModificarUsuario = $state(false); //si ponia contraseña en español quedaba muy largo el nombre let usuarioCambioPass: UserResponseDto | null = $state(null); @@ -69,7 +71,14 @@

Recuperar Contraseña

- + + + + + +

Modificar Usuario

+
+
From 476c1308d0d8419b9ac4e3734e493e43e48ccc72 Mon Sep 17 00:00:00 2001 From: fede Date: Mon, 1 Dec 2025 22:33:39 -0300 Subject: [PATCH 25/49] arreglado acceso a la store --- src/lib/hooks/logout.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/hooks/logout.ts b/src/lib/hooks/logout.ts index 9fe4b4e..c22dfaf 100644 --- a/src/lib/hooks/logout.ts +++ b/src/lib/hooks/logout.ts @@ -1,14 +1,15 @@ import { goto } from '$app/navigation'; import { apiBase } from '@/stores/url'; import { sesionStore } from '@/stores/usuario'; +import { get } from 'svelte/store'; export async function logout(menuOpen: boolean) { try { - const req = await fetch($apiBase + '/api/auth/logout', { + const req = await fetch(get(apiBase) + '/api/auth/logout', { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${$sesionStore.accessToken}` + Authorization: `Bearer ${get(sesionStore)?.accessToken}` }, credentials: 'include' }); From c2c8bd58a889351e2b28bd5a3b994db3944f2438 Mon Sep 17 00:00:00 2001 From: fede Date: Mon, 1 Dec 2025 22:37:24 -0300 Subject: [PATCH 26/49] Arreglado error de ts --- src/lib/components/signup-form.svelte | 29 ++++++++++++++++----------- src/lib/hooks/register.ts | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/lib/components/signup-form.svelte b/src/lib/components/signup-form.svelte index f5bf7c3..f9e529c 100644 --- a/src/lib/components/signup-form.svelte +++ b/src/lib/components/signup-form.svelte @@ -7,20 +7,19 @@ import { register } from '@/hooks/register'; import Loader2Icon from '@lucide/svelte/icons/loader-2'; - let {showAlert = $bindable() } = $props(); + let { showAlert = $bindable() } = $props(); - let cargando = $state(false); + let cargando = $state(false); - const setAlert = () => showAlert = true; + const setAlert = () => (showAlert = true); + let dto: RegisterDto = $state({ password: '', username: '', email: '', displayName: '' }); - let dto: RegisterDto = $state({password: "", username: "", email:"", displayName: ""}); - -const handleSubmit = async (e: Event) => { - cargando = true; - await register(e, dto, setAlert); - cargando = false; -} + const handleSubmit = async (e: SubmitEvent) => { + cargando = true; + await register(e, dto, setAlert); + cargando = false; + }; @@ -29,7 +28,7 @@ const handleSubmit = async (e: Event) => {
- + Nombre de Usuario @@ -43,7 +42,13 @@ const handleSubmit = async (e: Event) => { Email - + Contraseña diff --git a/src/lib/hooks/register.ts b/src/lib/hooks/register.ts index 681959e..531b7dc 100644 --- a/src/lib/hooks/register.ts +++ b/src/lib/hooks/register.ts @@ -2,7 +2,7 @@ import { apiBase } from "@/stores/url"; import { goto } from "$app/navigation"; import type { RegisterDto } from "../../types"; -export async function register(e:FormDataEvent,dto: RegisterDto, callbackfn:()=>void){ +export async function register(e: SubmitEvent, dto: RegisterDto, callbackfn:()=>void){ e.preventDefault(); if (dto.password == "" || dto.username == "" || !dto.email?.includes("@") || dto.displayName=="") return; From 4b1f6c9f7a7f92a7a2ce09000c81a52d942fb356 Mon Sep 17 00:00:00 2001 From: fede Date: Mon, 1 Dec 2025 22:37:24 -0300 Subject: [PATCH 27/49] Arreglado error de ts --- src/lib/components/ui/login-form/login-form.svelte | 14 +++++++------- src/lib/hooks/login.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/components/ui/login-form/login-form.svelte b/src/lib/components/ui/login-form/login-form.svelte index 35d3f5e..52f83e7 100644 --- a/src/lib/components/ui/login-form/login-form.svelte +++ b/src/lib/components/ui/login-form/login-form.svelte @@ -6,19 +6,19 @@ import type { LoginDto } from '../../../../types'; import { login } from '@/hooks/login'; import Loader2Icon from '@lucide/svelte/icons/loader-2'; - let {id, showAlert = $bindable() } = $props(); + let { id, showAlert = $bindable() } = $props(); - let dto: LoginDto = $state({password: "", username: ""}); + let dto: LoginDto = $state({ password: '', username: '' }); - const setAlert = () => showAlert = true; + const setAlert = () => (showAlert = true); - let cargando = $state(false); + let cargando = $state(false); - const handleSubmit = async (e: Event) => { + const handleSubmit = async (e: SubmitEvent) => { cargando = true; await login(e, dto, setAlert); cargando = false; - } + }; @@ -27,7 +27,7 @@ ingrese su usuario para logearse en la cuenta - + Usuario diff --git a/src/lib/hooks/login.ts b/src/lib/hooks/login.ts index 9794a88..7d9dc2d 100644 --- a/src/lib/hooks/login.ts +++ b/src/lib/hooks/login.ts @@ -3,7 +3,7 @@ import type { LoginDto } from "../../types"; import { sesionStore } from "@/stores/usuario"; import { goto } from "$app/navigation"; -export async function login(e:FormDataEvent,dto: LoginDto, callbackfn:()=>void){ +export async function login(e:SubmitEvent, dto: LoginDto, callbackfn:()=>void){ e.preventDefault(); if (dto.password == "" || dto.username == "") return; try { From 4ba91dae210a76037c84a066803495c76d3781c8 Mon Sep 17 00:00:00 2001 From: fede Date: Tue, 2 Dec 2025 16:31:21 -0300 Subject: [PATCH 28/49] eliminados import innecesarios --- src/routes/(privado)/admin/+page.svelte | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/routes/(privado)/admin/+page.svelte b/src/routes/(privado)/admin/+page.svelte index 29fdd2b..be4b79d 100644 --- a/src/routes/(privado)/admin/+page.svelte +++ b/src/routes/(privado)/admin/+page.svelte @@ -1,15 +1,7 @@ - @@ -73,7 +81,7 @@ - +

Modificar Usuario

@@ -86,3 +94,4 @@
+ diff --git a/src/lib/components/admin/ModificarUsuario.svelte b/src/lib/components/admin/ModificarUsuario.svelte new file mode 100644 index 0000000..bf5cfd4 --- /dev/null +++ b/src/lib/components/admin/ModificarUsuario.svelte @@ -0,0 +1,101 @@ + + +
+ { + open = !open; + }} + > + + + Modificar Usuario + + +
+ + + Nombre + + + + Bio + +
+ + +
+
+
+ + +
+
+ +
+
+
+
+ (error = '')}> + + {error} + + +
diff --git a/src/lib/components/ui/checkbox/checkbox.svelte b/src/lib/components/ui/checkbox/checkbox.svelte new file mode 100644 index 0000000..1622e05 --- /dev/null +++ b/src/lib/components/ui/checkbox/checkbox.svelte @@ -0,0 +1,36 @@ + + + + {#snippet children({ checked, indeterminate })} +
+ {#if checked} + + {:else if indeterminate} + + {/if} +
+ {/snippet} +
diff --git a/src/lib/components/ui/checkbox/index.ts b/src/lib/components/ui/checkbox/index.ts new file mode 100644 index 0000000..6d92d94 --- /dev/null +++ b/src/lib/components/ui/checkbox/index.ts @@ -0,0 +1,6 @@ +import Root from "./checkbox.svelte"; +export { + Root, + // + Root as Checkbox, +}; diff --git a/src/lib/hooks/updateUsuario.ts b/src/lib/hooks/updateUsuario.ts new file mode 100644 index 0000000..2a2bfb3 --- /dev/null +++ b/src/lib/hooks/updateUsuario.ts @@ -0,0 +1,44 @@ +import { apiBase } from "@/stores/url" +import { sesionStore } from "@/stores/usuario" +import { get } from "svelte/store" + +export interface AdminUpdateUsuario { + id:string, + displayName: string, + bio: string, + profileImage:boolean, + oldImageUrl:string +} + +export async function updateUsuario(usuario: AdminUpdateUsuario) { + + const formData = new FormData(); + formData.append('displayName', usuario.displayName); + formData.append('bio', usuario.bio); + if (usuario.profileImage) { + formData.append('profileImageUrl', usuario.oldImageUrl); + } + + try { + const req = await fetch(get(apiBase) + "/api/users/"+usuario.id, { + method: "PUT", + headers: { + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + }, + body: formData, + }); + if (req.status === 204) { + let ret = { + // bio: usuario.bio, + displayName: usuario.displayName, + // oldImageUrl: usuario.oldImageUrl, + } + return ret; + } + const dataa = await req.json(); + + return dataa.message; + } catch { + return "No se pudo alcanzar el servidor" + } +} diff --git a/src/routes/(privado)/admin/+page.svelte b/src/routes/(privado)/admin/+page.svelte index be4b79d..956243c 100644 --- a/src/routes/(privado)/admin/+page.svelte +++ b/src/routes/(privado)/admin/+page.svelte @@ -8,6 +8,7 @@ import CardHeader from '@/components/ui/card/card-header.svelte'; let cargando = $state(true); + let usuarios = $state(page.data.usuarios);
@@ -22,15 +23,9 @@ {#if page.data.usuarios.length === 0} - {#if page.data.error} - - Error al cargar usuarios. - - {:else} - No hay posts que mostar - {/if} + No hay posts que mostar {:else} - + {/if} From 942f2704870f73a52918a279104a4afaa6d88b30 Mon Sep 17 00:00:00 2001 From: fede Date: Tue, 2 Dec 2025 20:27:00 -0300 Subject: [PATCH 31/49] Correjida inicial que se mostraba en el perfil --- src/routes/[perfil]/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/[perfil]/+page.svelte b/src/routes/[perfil]/+page.svelte index 4957000..d676b13 100644 --- a/src/routes/[perfil]/+page.svelte +++ b/src/routes/[perfil]/+page.svelte @@ -81,7 +81,7 @@
- {params.perfil[0].toUpperCase()} + {page.data.displayName[0].toUpperCase()}

Date: Tue, 2 Dec 2025 21:13:02 -0300 Subject: [PATCH 32/49] skeleton de la interfaz de seguidores y seguidos --- src/lib/components/ui/badge/badge.svelte | 50 ++++++++++++++ src/lib/components/ui/badge/index.ts | 2 + src/lib/hooks/obtenerSeguidoresPorUsuario.ts | 25 +++++++ src/lib/hooks/obtenerSeguidosPorUsuario.ts | 25 +++++++ src/routes/[perfil]/+page.server.ts | 14 ++-- src/routes/[perfil]/+page.svelte | 69 ++++++++++++++------ 6 files changed, 161 insertions(+), 24 deletions(-) create mode 100644 src/lib/components/ui/badge/badge.svelte create mode 100644 src/lib/components/ui/badge/index.ts create mode 100644 src/lib/hooks/obtenerSeguidoresPorUsuario.ts create mode 100644 src/lib/hooks/obtenerSeguidosPorUsuario.ts diff --git a/src/lib/components/ui/badge/badge.svelte b/src/lib/components/ui/badge/badge.svelte new file mode 100644 index 0000000..bfaa9c5 --- /dev/null +++ b/src/lib/components/ui/badge/badge.svelte @@ -0,0 +1,50 @@ + + + + + + {@render children?.()} + diff --git a/src/lib/components/ui/badge/index.ts b/src/lib/components/ui/badge/index.ts new file mode 100644 index 0000000..64e0aa9 --- /dev/null +++ b/src/lib/components/ui/badge/index.ts @@ -0,0 +1,2 @@ +export { default as Badge } from "./badge.svelte"; +export { badgeVariants, type BadgeVariant } from "./badge.svelte"; diff --git a/src/lib/hooks/obtenerSeguidoresPorUsuario.ts b/src/lib/hooks/obtenerSeguidoresPorUsuario.ts new file mode 100644 index 0000000..641aef3 --- /dev/null +++ b/src/lib/hooks/obtenerSeguidoresPorUsuario.ts @@ -0,0 +1,25 @@ +import { sesionStore } from "@/stores/usuario"; +import type { UserResponseDto } from "../../types"; +import { get } from "svelte/store"; +import { apiBase } from "@/stores/url"; + +export async function obtenerSeguidoresPorUsuario(Id: string): Promise { + try { + const response = await fetch(`${get(apiBase)}/api/users/${Id}/followers`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + } + }); + + if (!response.ok) { + return null; + } + + const followers: UserResponseDto[] = await response.json(); + return followers; + } catch (error) { + return null; + } +} diff --git a/src/lib/hooks/obtenerSeguidosPorUsuario.ts b/src/lib/hooks/obtenerSeguidosPorUsuario.ts new file mode 100644 index 0000000..2c1340a --- /dev/null +++ b/src/lib/hooks/obtenerSeguidosPorUsuario.ts @@ -0,0 +1,25 @@ +import { sesionStore } from "@/stores/usuario"; +import type { UserResponseDto } from "../../types"; +import { apiBase } from "@/stores/url"; +import { get } from "svelte/store"; + +export async function obtenerSeguidosPorUsuario(id: string): Promise { + try { + const response = await fetch(`${get(apiBase)}/api/users/${id}/following`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${get(sesionStore)?.accessToken}` + } + }); + + if (!response.ok) { + return null; + } + + const users: UserResponseDto[] = await response.json(); + return users; + } catch (error) { + return null; + } +} diff --git a/src/routes/[perfil]/+page.server.ts b/src/routes/[perfil]/+page.server.ts index 641b412..9c5399f 100644 --- a/src/routes/[perfil]/+page.server.ts +++ b/src/routes/[perfil]/+page.server.ts @@ -1,11 +1,15 @@ import { obtenerUsuarioPorUsername } from '@/hooks/obtenerUsuario.js'; import type { User, UserResponseDto } from '../../types.js'; import { error } from '@sveltejs/kit'; +import { obtenerSeguidosPorUsuario } from '@/hooks/obtenerSeguidosPorUsuario.js'; +import { obtenerSeguidoresPorUsuario } from '@/hooks/obtenerSeguidoresPorUsuario.js'; export async function load({ params }) { - const usuario: UserResponseDto | null = await obtenerUsuarioPorUsername(params.perfil); - if (usuario) { - return usuario; - } - error(404, 'No se encontro el usuario, ' + params.perfil); + const usuario: UserResponseDto | null = await obtenerUsuarioPorUsername(params.perfil); + if(!usuario) error(404, 'No se encontro el usuario, ' + params.perfil); + + const seguidos = await obtenerSeguidosPorUsuario(usuario.id); + const seguidores = await obtenerSeguidoresPorUsuario(usuario.id); + + return { ...usuario, seguidos, seguidores }; } diff --git a/src/routes/[perfil]/+page.svelte b/src/routes/[perfil]/+page.svelte index d676b13..52ecf28 100644 --- a/src/routes/[perfil]/+page.svelte +++ b/src/routes/[perfil]/+page.svelte @@ -22,6 +22,9 @@ import DialogHeader from '@/components/ui/dialog/dialog-header.svelte'; import DialogTitle from '@/components/ui/dialog/dialog-title.svelte'; import { sesionStore } from '@/stores/usuario.js'; + import CardHeader from '@/components/ui/card/card-header.svelte'; + import CardTitle from '@/components/ui/card/card-title.svelte'; + import Badge from '@/components/ui/badge/badge.svelte'; let { params } = $props(); @@ -62,7 +65,6 @@ async function handleEditar(e: SubmitEvent) { e.preventDefault(); - // post.content = 'test'; if (postAModificar == null) return; await updatePost( postAModificar, @@ -76,24 +78,53 @@
- - -
- - - {page.data.displayName[0].toUpperCase()} - -
-

- {page.data.displayName} -

-

- @{params.perfil} -

-
-
+
+ + +
+ + + {page.data.displayName?.[0]?.toUpperCase() || ''} + +
+

+ {page.data.displayName} +

+

+ @{params.perfil} +

+

+ {page.data.bio} +

+
+
+ +

Date: Wed, 3 Dec 2025 15:01:03 -0300 Subject: [PATCH 33/49] fix: que los usuarios sin auth no puedan dar like --- src/lib/components/PostCard.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte index 6cd772a..aa5d750 100644 --- a/src/lib/components/PostCard.svelte +++ b/src/lib/components/PostCard.svelte @@ -136,6 +136,7 @@
- +

From 43f9c9f5d888a06a2cce6f3c66b2ac2a658f3b75 Mon Sep 17 00:00:00 2001 From: fede Date: Wed, 3 Dec 2025 20:34:15 -0300 Subject: [PATCH 44/49] =?UTF-8?q?a=C3=B1adida=20validacion=20de=20email=20?= =?UTF-8?q?contra=20el=20back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/signup-form.svelte | 30 +++++++++++++++++++++++++-- src/lib/hooks/checkEmail.ts | 16 ++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/lib/hooks/checkEmail.ts diff --git a/src/lib/components/signup-form.svelte b/src/lib/components/signup-form.svelte index 2b102af..e21e58c 100644 --- a/src/lib/components/signup-form.svelte +++ b/src/lib/components/signup-form.svelte @@ -11,25 +11,39 @@ import Spinner from './ui/spinner/spinner.svelte'; import { checkUsername } from '@/hooks/checkUsername'; + import { checkEmail } from '@/hooks/checkEmail'; let { showAlert = $bindable() } = $props(); let cargando = $state(false); + let repetirContraseña = $state(''); + let checkeandoUsuario: boolean | null = $state(null); let esUsuarioValido = $state(false); + let checkeandoEmail: boolean | null = $state(null); + let esEmailValido = $state(false); + async function checkUsuario() { checkeandoUsuario = true; esUsuarioValido = await checkUsername(dto.username); checkeandoUsuario = false; } + async function checkEmaill() { + checkeandoEmail = true; + esEmailValido = await checkEmail(dto.email); + checkeandoEmail = false; + } const setAlert = () => (showAlert = true); let dto: RegisterDto = $state({ password: '', username: '', email: '', displayName: '' }); const handleSubmit = async (e: SubmitEvent) => { + if (esUsuarioValido == false) return; + if (repetirContraseña !== dto.password) return; + cargando = true; await register(e, dto, setAlert); cargando = false; @@ -73,13 +87,25 @@ - Email +
+ Email + {#if checkeandoEmail == null} + + {:else if checkeandoEmail == true} + + {:else if esEmailValido} + + {:else} + + {/if} +
@@ -89,7 +115,7 @@ Confirmar Contraseña - + Confirma la contraseña diff --git a/src/lib/hooks/checkEmail.ts b/src/lib/hooks/checkEmail.ts new file mode 100644 index 0000000..2bbc8e8 --- /dev/null +++ b/src/lib/hooks/checkEmail.ts @@ -0,0 +1,16 @@ +import { apiBase } from "@/stores/url"; +import { get } from "svelte/store"; + +export async function checkEmail(email: string) { + try { + const req = await fetch(`${get(apiBase)}/api/users/check-email/${email}`, { + method: "GET" + }); + if (req.ok){ + return (await req.json()).available; + } + return false; + } catch { + return false; + } +} From 5af062754aaa27fa94030b70e357a1cf299998f2 Mon Sep 17 00:00:00 2001 From: fede Date: Wed, 3 Dec 2025 21:48:29 -0300 Subject: [PATCH 45/49] =?UTF-8?q?ahora=20requiere=20que=20repitas=20la=20c?= =?UTF-8?q?ontrase=C3=B1a=20para=20que=20te=20deje=20enviar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/signup-form.svelte | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/lib/components/signup-form.svelte b/src/lib/components/signup-form.svelte index e21e58c..7ce02b0 100644 --- a/src/lib/components/signup-form.svelte +++ b/src/lib/components/signup-form.svelte @@ -25,6 +25,10 @@ let checkeandoEmail: boolean | null = $state(null); let esEmailValido = $state(false); + let dto: RegisterDto = $state({ password: '', username: '', email: '', displayName: '' }); + + let coinsidenLasPass = $derived(repetirContraseña == dto.password); + async function checkUsuario() { checkeandoUsuario = true; esUsuarioValido = await checkUsername(dto.username); @@ -38,11 +42,9 @@ } const setAlert = () => (showAlert = true); - let dto: RegisterDto = $state({ password: '', username: '', email: '', displayName: '' }); - const handleSubmit = async (e: SubmitEvent) => { if (esUsuarioValido == false) return; - if (repetirContraseña !== dto.password) return; + if (!coinsidenLasPass) return; cargando = true; await register(e, dto, setAlert); @@ -115,12 +117,18 @@ Confirmar Contraseña - + Confirma la contraseña -