diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte new file mode 100644 index 0000000..b9fca16 --- /dev/null +++ b/src/lib/components/PostCard.svelte @@ -0,0 +1,68 @@ + + + + +
+
+ {post.authorId} + + + + + + + Opciones Publicación + + Editar + {}}> + +

Borrar

+
+
+
+
+
+
+
+ +

{post.content}

+ {#if post.imageUrl} + Post + {/if} +
+ +
+ {post.likesCount} likes + {post.repliesCount} replies + {post.createdAt.replace('T', ' ').split('.')[0]} + {#if post.isEdited} + Editado + {/if} +
+
+
diff --git a/src/lib/components/crear-post.svelte b/src/lib/components/crear-post.svelte new file mode 100644 index 0000000..a0df5c2 --- /dev/null +++ b/src/lib/components/crear-post.svelte @@ -0,0 +1,81 @@ + + +
handlePost(e)}> + + + + +
+ +

239}> + {mensaje.length} +

+ / 280 +
+ +

Publicar

+ +
+
+
+
+
diff --git a/src/lib/components/ui/avatar/avatar-fallback.svelte b/src/lib/components/ui/avatar/avatar-fallback.svelte new file mode 100644 index 0000000..249d4a4 --- /dev/null +++ b/src/lib/components/ui/avatar/avatar-fallback.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/avatar/avatar-image.svelte b/src/lib/components/ui/avatar/avatar-image.svelte new file mode 100644 index 0000000..2bb9db4 --- /dev/null +++ b/src/lib/components/ui/avatar/avatar-image.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/avatar/avatar.svelte b/src/lib/components/ui/avatar/avatar.svelte new file mode 100644 index 0000000..e37214d --- /dev/null +++ b/src/lib/components/ui/avatar/avatar.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/lib/components/ui/avatar/index.ts b/src/lib/components/ui/avatar/index.ts new file mode 100644 index 0000000..d06457b --- /dev/null +++ b/src/lib/components/ui/avatar/index.ts @@ -0,0 +1,13 @@ +import Root from "./avatar.svelte"; +import Image from "./avatar-image.svelte"; +import Fallback from "./avatar-fallback.svelte"; + +export { + Root, + Image, + Fallback, + // + Root as Avatar, + Image as AvatarImage, + Fallback as AvatarFallback, +}; diff --git a/src/lib/components/ui/input-group/index.ts b/src/lib/components/ui/input-group/index.ts new file mode 100644 index 0000000..fe1f55d --- /dev/null +++ b/src/lib/components/ui/input-group/index.ts @@ -0,0 +1,22 @@ +import Root from "./input-group.svelte"; +import Addon from "./input-group-addon.svelte"; +import Button from "./input-group-button.svelte"; +import Input from "./input-group-input.svelte"; +import Text from "./input-group-text.svelte"; +import Textarea from "./input-group-textarea.svelte"; + +export { + Root, + Addon, + Button, + Input, + Text, + Textarea, + // + Root as InputGroup, + Addon as InputGroupAddon, + Button as InputGroupButton, + Input as InputGroupInput, + Text as InputGroupText, + Textarea as InputGroupTextarea, +}; diff --git a/src/lib/components/ui/input-group/input-group-addon.svelte b/src/lib/components/ui/input-group/input-group-addon.svelte new file mode 100644 index 0000000..09f2b64 --- /dev/null +++ b/src/lib/components/ui/input-group/input-group-addon.svelte @@ -0,0 +1,55 @@ + + + + +
{ + if ((e.target as HTMLElement).closest("button")) { + return; + } + e.currentTarget.parentElement?.querySelector("input")?.focus(); + }} + {...restProps} +> + {@render children?.()} +
diff --git a/src/lib/components/ui/input-group/input-group-button.svelte b/src/lib/components/ui/input-group/input-group-button.svelte new file mode 100644 index 0000000..d38a71e --- /dev/null +++ b/src/lib/components/ui/input-group/input-group-button.svelte @@ -0,0 +1,49 @@ + + + + + diff --git a/src/lib/components/ui/input-group/input-group-input.svelte b/src/lib/components/ui/input-group/input-group-input.svelte new file mode 100644 index 0000000..ded2655 --- /dev/null +++ b/src/lib/components/ui/input-group/input-group-input.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/lib/components/ui/input-group/input-group-text.svelte b/src/lib/components/ui/input-group/input-group-text.svelte new file mode 100644 index 0000000..332f63d --- /dev/null +++ b/src/lib/components/ui/input-group/input-group-text.svelte @@ -0,0 +1,22 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/input-group/input-group-textarea.svelte b/src/lib/components/ui/input-group/input-group-textarea.svelte new file mode 100644 index 0000000..91850ff --- /dev/null +++ b/src/lib/components/ui/input-group/input-group-textarea.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/lib/head/AvatarButton.svelte b/src/lib/head/AvatarButton.svelte new file mode 100644 index 0000000..1d25635 --- /dev/null +++ b/src/lib/head/AvatarButton.svelte @@ -0,0 +1,35 @@ + + + + + + + {$sesionStore?.displayName[0]} + + + + + goto('/' + $sesionStore?.username)} + >Mi Perfil + + await logout(menuOpen)}>Cerrar Sesion + + + diff --git a/src/lib/head/Header.svelte b/src/lib/head/Header.svelte index 774035e..1791b52 100644 --- a/src/lib/head/Header.svelte +++ b/src/lib/head/Header.svelte @@ -7,42 +7,41 @@ import { sesionStore } from '@/stores/usuario'; import { onMount } from 'svelte'; import { apiBase } from '@/stores/url'; + import { goto } from '$app/navigation'; + import AvatarButton from './AvatarButton.svelte'; let menuOpen = $state(false); const toggleMenu = () => (menuOpen = !menuOpen); - let showCerrarSesion = $state(false); + let showCerrarSesion = $state(false); - onMount(()=>{ - sesionStore.subscribe((value)=>{ - showCerrarSesion = !!value?.accessToken; - }) + onMount(() => { + sesionStore.subscribe((value) => { + showCerrarSesion = !!value?.accessToken; + }); + }); - }); - - async function cerrarSesion(){ - try{ - const req = await fetch($apiBase+"/api/auth/logout", { - method: 'POST', - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${$sesionStore?.accessToken}` - - }, - credentials: "include" - }); - if(req.ok){ - - sesionStore.reset(); - menuOpen = false; - } - }catch{ - console.log("fallo el lougout") - } finally{ - sesionStore.reset(); - } - - } + async function cerrarSesion() { + try { + const req = await fetch($apiBase + '/api/auth/logout', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${$sesionStore?.accessToken}` + }, + credentials: 'include' + }); + if (req.ok) { + sesionStore.reset(); + menuOpen = false; + } + } catch { + console.log('fallo el lougout'); + } finally { + sesionStore.reset(); + goto('/'); + } + }
@@ -51,31 +50,38 @@

Mini-X

-
diff --git a/src/lib/hooks/deletePost.ts b/src/lib/hooks/deletePost.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/hooks/logout.ts b/src/lib/hooks/logout.ts new file mode 100644 index 0000000..9fe4b4e --- /dev/null +++ b/src/lib/hooks/logout.ts @@ -0,0 +1,25 @@ +import { goto } from '$app/navigation'; +import { apiBase } from '@/stores/url'; +import { sesionStore } from '@/stores/usuario'; + +export async function logout(menuOpen: boolean) { + try { + const req = await fetch($apiBase + '/api/auth/logout', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${$sesionStore.accessToken}` + }, + credentials: 'include' + }); + if (req.ok) { + sesionStore.reset(); + menuOpen = false; + } + } catch { + console.log('fallo el lougout'); + } finally { + sesionStore.reset(); + goto('/'); + } +} diff --git a/src/lib/hooks/updatePost.ts b/src/lib/hooks/updatePost.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/stores/posts.ts b/src/lib/stores/posts.ts new file mode 100644 index 0000000..bf1611f --- /dev/null +++ b/src/lib/stores/posts.ts @@ -0,0 +1,22 @@ +import { writable } from 'svelte/store'; +import type { Post } from '../../types'; + +export const posts = writable([]); + +export const setPosts = (newPosts: Post[]) => { + posts.set(newPosts); +}; + +export const addPost = (post: Post) => { + posts.update((currentPosts) => [post, ...currentPosts]); +}; + +export const updatePost = (postId: string, updatedData: Partial) => { + posts.update((currentPosts) => + currentPosts.map((post) => (post._id === postId ? { ...post, ...updatedData } : post)) + ); +}; + +export const removePost = (postId: string) => { + posts.update((currentPosts) => currentPosts.filter((post) => post._id !== postId)); +}; diff --git a/src/lib/stores/usuario.ts b/src/lib/stores/usuario.ts index 649b18b..f419c8d 100644 --- a/src/lib/stores/usuario.ts +++ b/src/lib/stores/usuario.ts @@ -1,7 +1,18 @@ import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; import type { Sesion } from '../../types'; +import { apiBase } from '@/stores/url'; -export const currentSesion = writable(null); +const { subscribe } = apiBase; +let baseUrl: string = ''; + +subscribe((value) => { + baseUrl = value; +})(); + +const initialValue = browser ? JSON.parse(localStorage.getItem('sesion') || 'null') : null; + +export const currentSesion = writable(initialValue); export const sesionStore = { subscribe: currentSesion.subscribe, @@ -9,3 +20,40 @@ export const sesionStore = { update: currentSesion.update, reset: () => currentSesion.set(null) }; + +if (browser) { + currentSesion.subscribe((value) => { + localStorage.setItem('sesion', JSON.stringify(value)); + }); +} +if (browser) { + const refreshAccessToken = async () => { + try { + const response = await fetch(baseUrl + '/api/auth/refresh', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'include' + }); + + if (response.ok) { + const data = await response.json(); + currentSesion.update((sesion) => { + if (sesion) { + return { ...sesion, accessToken: data.accessToken }; + } + return sesion; + }); + } else { + console.error('Error refreshing token:', response.statusText); + currentSesion.set(null); + } + } catch (error) { + console.error('Error refreshing token:', error); + currentSesion.set(null); + } + }; + + setInterval(refreshAccessToken, 10 * 60 * 1000); +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 03797f5..bcde02d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,66 +1,52 @@
-
- {#if posts.length <= 0} - - -

No hay Posts que mostrar

-
-
- {:else} - {#each posts as post} +
+
+ {#if $sesionStore !== null} + + {/if} +
+ + {#if $posts.length <= 0} -
-
- {post.authorId} - {post.createdAt.toLocaleDateString()} -
-

{post.content}

- {#if post.imageUrl} - Post - {/if} -
- {post.likesCount} likes - {post.repliesCount} replies - {#if post.isEdited} - Editado - {/if} -
-
+

No hay Posts que mostrar

- {/each} - {/if} + {:else} + {#each $posts as post} + + {/each} + {/if} +
diff --git a/src/routes/[perfil]/+page.svelte b/src/routes/[perfil]/+page.svelte new file mode 100644 index 0000000..ff7ad90 --- /dev/null +++ b/src/routes/[perfil]/+page.svelte @@ -0,0 +1,92 @@ + + +
+
+ + +
+ + + {params.perfil[0].toUpperCase()} + +
+

+ {'test'} +

+

+ @{params.perfil} +

+
+
+

Posts:

+
+ {#if cargando} +
+ + + +

Cargando

+
+
+
+ {:else if mensajeError !== ''} +
+ + + +

+ {mensajeError} +

+
+
+
+ {/if} +
+
diff --git a/src/types.d.ts b/src/types.d.ts index bc001ff..6305a56 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -6,12 +6,13 @@ export interface Post { parentPostId?: string; likesCount: number; repliesCount: number; - createdAt: Date; + createdAt: string; updatedAt?: Date; isEdited: boolean; visibility: string; hashtags?: string[]; } + export interface User { _id: string; displayName: string; @@ -27,20 +28,27 @@ export interface User { } export interface Sesion { - accessToken:string?; - message:string; - url:string; - displayname:string; + accessToken: string?; + message: string; + url: string; + displayName: string; + username: string; } export interface LoginDto { - username: string?; - password: string?; + username: string?; + password: string?; } export interface RegisterDto { - username: string?; - email: string?; - password: string?; - displayName: string?; + username: string?; + email: string?; + password: string?; + displayName: string?; +} + +export interface CreatePostDto { + content: string; + imageUrl: string?; + parentPostId: string?; }