mirror of
https://github.com/emailerfacu-spec/minix-front.git
synced 2026-04-01 13:10:44 -03:00
@@ -30,13 +30,16 @@
|
||||
import DialogDescription from './ui/dialog/dialog-description.svelte';
|
||||
import { sesionStore } from '@/stores/usuario';
|
||||
import { likePost } from '@/hooks/likePost';
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
|
||||
interface postProp {
|
||||
post: Post;
|
||||
postAModificar: Post | null;
|
||||
update?: Function;
|
||||
}
|
||||
|
||||
let { post, postAModificar = $bindable() }: postProp = $props();
|
||||
let { post, postAModificar = $bindable(), update }: postProp = $props();
|
||||
|
||||
let cargandoBorrar = $state(false);
|
||||
let mensajeError = $state('');
|
||||
@@ -82,7 +85,7 @@
|
||||
likePost(post),
|
||||
new Promise((resolve) => setTimeout(resolve, 300))
|
||||
]);
|
||||
console.log(1);
|
||||
// console.log(1);
|
||||
if (ok) {
|
||||
if (post.isLiked) {
|
||||
post.likesCount--;
|
||||
@@ -94,9 +97,10 @@
|
||||
errorLike = true;
|
||||
mensajeError = message;
|
||||
}
|
||||
console.log(1);
|
||||
updatePostStore(post.id, post);
|
||||
console.log(1);
|
||||
// console.log(2);
|
||||
if (update) update();
|
||||
else updatePostStore(post.id, post);
|
||||
// console.log(3);
|
||||
cargandoLike = false;
|
||||
}
|
||||
</script>
|
||||
@@ -157,7 +161,7 @@
|
||||
|
||||
{#if post.imageUrl}
|
||||
<div class="flex justify-center">
|
||||
<Content class="mx-5 max-w-[25%] rounded-4xl bg-accent p-6">
|
||||
<Content class="mx-5 max-w-[50%] rounded-4xl bg-accent p-6">
|
||||
<img src={post.imageUrl} alt="Post" class="mt-2 rounded-md" />
|
||||
</Content>
|
||||
</div>
|
||||
@@ -179,7 +183,12 @@
|
||||
<ThumbsUp />
|
||||
{/if}
|
||||
</Button>
|
||||
<Button variant="ghost" class="flex items-center gap-2 rounded-full bg-accent p-3 text-lg">
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="flex items-center gap-2 rounded-full bg-accent p-3 text-lg"
|
||||
onclick={() => goto(resolve('/post/[idpost]', { idpost: post.id }))}
|
||||
>
|
||||
<p>
|
||||
{post.repliesCount}
|
||||
</p>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
import TooltipTrigger from './ui/tooltip/tooltip-trigger.svelte';
|
||||
import { publicarPost } from '@/hooks/publicarPost';
|
||||
import { filtrarImagen } from '@/utils';
|
||||
import { invalidate } from '$app/navigation';
|
||||
|
||||
let { placeholder, parentPostId }: { placeholder?: string; parentPostId?: string } = $props();
|
||||
|
||||
let mensaje = $state('');
|
||||
let imagen: File | null = $state(null);
|
||||
@@ -29,13 +32,14 @@
|
||||
if (imagen) {
|
||||
formData.append('image', imagen);
|
||||
}
|
||||
// formData.append('parentPostId', '');
|
||||
if (parentPostId) formData.append('parentPostId', parentPostId);
|
||||
mostrarError = await publicarPost(formData);
|
||||
if (mostrarError == '') {
|
||||
mensaje = '';
|
||||
imagen = null;
|
||||
}
|
||||
cargando = false;
|
||||
if (parentPostId) invalidate('post:respuestas');
|
||||
}
|
||||
|
||||
function handleKeydown(e: KeyboardEvent) {
|
||||
@@ -73,7 +77,7 @@
|
||||
}}
|
||||
ondrop={handleDrop}
|
||||
maxlength={280}
|
||||
placeholder="Alguna novedad?"
|
||||
placeholder={placeholder ? placeholder : 'Alguna novedad?'}
|
||||
onkeydown={handleKeydown}
|
||||
></InputGroupTextarea>
|
||||
|
||||
|
||||
@@ -1,38 +1,30 @@
|
||||
import { apiBase } from "@/stores/url";
|
||||
import type { LoginDto } from "../../types";
|
||||
import { sesionStore } from "@/stores/usuario";
|
||||
import { goto } from "$app/navigation";
|
||||
import { apiBase } from '@/stores/url';
|
||||
import type { LoginDto } from '../../types';
|
||||
import { sesionStore } from '@/stores/usuario';
|
||||
import { goto } from '$app/navigation';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
export async function login(e:SubmitEvent, dto: LoginDto, callbackfn:()=>void){
|
||||
e.preventDefault();
|
||||
if (dto.password == "" || dto.username == "") return;
|
||||
try {
|
||||
|
||||
const { subscribe } = apiBase;
|
||||
let baseUrl: string = '';
|
||||
|
||||
subscribe((value) => {
|
||||
baseUrl = value;
|
||||
})();
|
||||
const req = await fetch(baseUrl + "/api/auth/login", {
|
||||
method: "POST",
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(dto)
|
||||
});
|
||||
if (req.ok) {
|
||||
const token = await req.json();
|
||||
sesionStore.set(token);
|
||||
goto("/")
|
||||
} else {
|
||||
callbackfn();
|
||||
}
|
||||
|
||||
} catch {
|
||||
callbackfn();
|
||||
console.error("fallo al intentar alcanzar el servidor")
|
||||
|
||||
}
|
||||
export async function login(e: SubmitEvent, dto: LoginDto, callbackfn: () => void) {
|
||||
e.preventDefault();
|
||||
if (dto.password == '' || dto.username == '') return;
|
||||
try {
|
||||
const req = await fetch(get(apiBase) + '/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(dto)
|
||||
});
|
||||
if (req.ok) {
|
||||
const token = await req.json();
|
||||
sesionStore.set(token);
|
||||
goto('/');
|
||||
} else {
|
||||
callbackfn();
|
||||
}
|
||||
} catch {
|
||||
callbackfn();
|
||||
console.error('fallo al intentar alcanzar el servidor');
|
||||
}
|
||||
}
|
||||
|
||||
30
src/lib/hooks/obtenerPostPorId.ts
Normal file
30
src/lib/hooks/obtenerPostPorId.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { apiBase } from '@/stores/url';
|
||||
import { sesionStore } from '@/stores/usuario';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Post } from '../../types';
|
||||
|
||||
export async function obtenerPostPorId(
|
||||
idpost: string,
|
||||
fetch2?: Function,
|
||||
depends?: Function
|
||||
): Promise<null | Post | string> {
|
||||
if (idpost == '') return null;
|
||||
if (depends) depends('post:post');
|
||||
const fetchFn = fetch2 ? fetch2 : fetch;
|
||||
|
||||
try {
|
||||
const req = await fetchFn(`${get(apiBase)}/api/posts/${idpost}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${get(sesionStore)?.accessToken}`
|
||||
}
|
||||
});
|
||||
let data = await req.json();
|
||||
if (req.ok) {
|
||||
return data;
|
||||
}
|
||||
return data.message;
|
||||
} catch {
|
||||
return 'No se pudo alcanzar el servidor.';
|
||||
}
|
||||
}
|
||||
28
src/lib/hooks/obtenerRespuestasPorId.ts
Normal file
28
src/lib/hooks/obtenerRespuestasPorId.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { apiBase } from '@/stores/url';
|
||||
import { sesionStore } from '@/stores/usuario';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Post } from '../../types';
|
||||
|
||||
export async function obtenerRespuestasPorId(
|
||||
id: string,
|
||||
fetch2?: Function,
|
||||
depends?: Function
|
||||
): Promise<string | Post[] | null> {
|
||||
if (depends) depends('post:respuestas');
|
||||
const fetchFn = fetch2 ? fetch2 : fetch;
|
||||
try {
|
||||
const req = await fetchFn(`${get(apiBase)}/api/posts/${id}/replies`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${get(sesionStore)?.accessToken}`
|
||||
}
|
||||
});
|
||||
if (req.ok) {
|
||||
const data = await req.json();
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
return 'No se pudo obtener del dato del servidor';
|
||||
}
|
||||
}
|
||||
160
src/routes/post/[idpost]/+page.svelte
Normal file
160
src/routes/post/[idpost]/+page.svelte
Normal file
@@ -0,0 +1,160 @@
|
||||
<script lang="ts">
|
||||
import Card from '@/components/ui/card/card.svelte';
|
||||
import { Content } from '@/components/ui/card';
|
||||
import Spinner from '@/components/ui/spinner/spinner.svelte';
|
||||
import type { Post } from '../../../types';
|
||||
import PostCard from '@/components/PostCard.svelte';
|
||||
import ModalEditar from '../../[perfil]/modalEditar.svelte';
|
||||
import { fade, slide } from 'svelte/transition';
|
||||
import { updatePost } from '@/hooks/updatePost';
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
import Separator from '@/components/ui/separator/separator.svelte';
|
||||
import CrearPost from '@/components/crear-post.svelte';
|
||||
import Button from '@/components/ui/button/button.svelte';
|
||||
import { resolve } from '$app/paths';
|
||||
import MessageCircleMore from '@lucide/svelte/icons/message-circle-more';
|
||||
import { sesionStore } from '@/stores/usuario';
|
||||
import { likePost } from '@/hooks/likePost';
|
||||
import ThumbsUp from '@lucide/svelte/icons/thumbs-up';
|
||||
import { TamañoPantalla } from './TamañoPantalla.svelte';
|
||||
|
||||
interface Prop {
|
||||
data: {
|
||||
post: Post;
|
||||
respuestas: Post[];
|
||||
};
|
||||
}
|
||||
|
||||
let tamaño = new TamañoPantalla();
|
||||
|
||||
let { data }: Prop = $props();
|
||||
// $inspect(data);
|
||||
let postAModificar: Post | null = $state(null);
|
||||
|
||||
async function handleEditar(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
if (postAModificar == null) return;
|
||||
await updatePost(postAModificar, (postnuevo: Post) => invalidate('post:post'), '');
|
||||
postAModificar = null;
|
||||
}
|
||||
|
||||
async function likeHandler(post) {
|
||||
//para que se vea el spinner
|
||||
let [{ message, ok }] = await Promise.all([
|
||||
likePost(post),
|
||||
new Promise((resolve) => setTimeout(resolve, 300))
|
||||
]);
|
||||
if (ok) {
|
||||
if (post.isLiked) {
|
||||
post.likesCount--;
|
||||
} else {
|
||||
post.likesCount++;
|
||||
}
|
||||
post.isLiked = !post.isLiked;
|
||||
} else {
|
||||
}
|
||||
invalidate('post:respuestas');
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title
|
||||
>@{data.post.authorName} - {data.post?.content.substring(0, 7) ?? 'Post'}{data.post?.content
|
||||
.length > 7
|
||||
? '...'
|
||||
: ''}
|
||||
</title>
|
||||
<meta name="og:description" content={data.post?.content?.slice(0, 150)} />
|
||||
<!-- <meta name="og:image" content=""> -->
|
||||
</svelte:head>
|
||||
|
||||
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
||||
<div class="w-full max-w-6xl">
|
||||
{#if data.post}
|
||||
<div class="sticky top-0 z-10 w-full rounded-xl bg-background p-2">
|
||||
<PostCard post={data.post} bind:postAModificar update={() => invalidate('post:post')} />
|
||||
</div>
|
||||
{:else}
|
||||
<Card>
|
||||
<Content class="flex items-center gap-2">
|
||||
<Spinner class="h-6 w-6" />
|
||||
<span>Cargando post…</span>
|
||||
</Content>
|
||||
</Card>
|
||||
{/if}
|
||||
<div class="my-4">
|
||||
<Separator></Separator>
|
||||
</div>
|
||||
<CrearPost placeholder={`Responder a @${data.post.authorName}`} parentPostId={data.post.id} />
|
||||
|
||||
<div class="my-4">
|
||||
<Separator></Separator>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each data.respuestas as respuesta (respuesta.id)}
|
||||
<!-- {#if tamaño.isMobile} -->
|
||||
<!-- {#if true} -->
|
||||
{@render Respuesta(respuesta)}
|
||||
<!-- {:else} -->
|
||||
<!-- <PostCard post={respuesta} bind:postAModificar update={() => invalidate('post:post')} /> -->
|
||||
<!-- {/if} -->
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if postAModificar}
|
||||
<div in:fade>
|
||||
<ModalEditar callbackfn={handleEditar} bind:post={postAModificar} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#snippet Respuesta(post: Post)}
|
||||
<div class="ml-2 flex-1">
|
||||
<div class="flex items-center space-x-1">
|
||||
{#if post.authorImageUrl}
|
||||
<img
|
||||
src={post.authorImageUrl}
|
||||
alt={post.authorDisplayName}
|
||||
class="h-8 w-8 shrink-0 rounded-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<div
|
||||
class="flex h-8 w-8 items-center justify-center rounded-full bg-gray-300 text-xs font-medium text-white"
|
||||
>
|
||||
{post.authorName?.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
{/if}
|
||||
<span class="text-sm font-semibold">@{post.authorName}</span>
|
||||
<span class="text-xs text-gray-500">{new Date(post.createdAt).toLocaleDateString()}</span>
|
||||
</div>
|
||||
<p class=" mt-1 line-clamp-2 rounded-md p-2 text-lg">
|
||||
{post.content}
|
||||
</p>
|
||||
{#if post.imageUrl}
|
||||
<img src={post.imageUrl} alt="Imagen de respuesta" class="mt-2 h-auto max-w-[50%] rounded" />
|
||||
{/if}
|
||||
<div class="mt-2 flex gap-2">
|
||||
<button
|
||||
disabled={!$sesionStore?.accessToken}
|
||||
class={`${post.isLiked ? 'bg-blue-500/30' : ''} flex items-center gap-1 rounded-full p-2! text-lg`}
|
||||
onclick={() => likeHandler(post)}
|
||||
>
|
||||
<p>
|
||||
{post.likesCount}
|
||||
</p>
|
||||
<ThumbsUp class="h-5 w-5" />
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-1 rounded-full p-2! text-lg"
|
||||
onclick={() => goto(resolve('/post/[idpost]', { idpost: post.id }))}
|
||||
>
|
||||
<p>
|
||||
{post.repliesCount}
|
||||
</p>
|
||||
<MessageCircleMore class="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Separator class="bg-white/50" />
|
||||
{/snippet}
|
||||
18
src/routes/post/[idpost]/+page.ts
Normal file
18
src/routes/post/[idpost]/+page.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { obtenerPostPorId } from '@/hooks/obtenerPostPorId.js';
|
||||
import { obtenerRespuestasPorId } from '@/hooks/obtenerRespuestasPorId';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export async function load({ params, fetch, depends }) {
|
||||
let ret = await obtenerPostPorId(params.idpost, fetch, depends);
|
||||
if (ret == null) return error(404, 'no existe un post con ese id.');
|
||||
if (typeof ret == 'string') return error(500, ret);
|
||||
|
||||
let respuestas = await obtenerRespuestasPorId(params.idpost, fetch, depends);
|
||||
if (respuestas == null) return error(404, 'no existe un post con ese id.');
|
||||
if (typeof respuestas == 'string') return error(500, respuestas);
|
||||
|
||||
return {
|
||||
post: ret,
|
||||
respuestas: respuestas
|
||||
};
|
||||
}
|
||||
5
src/routes/post/[idpost]/TamañoPantalla.svelte.ts
Normal file
5
src/routes/post/[idpost]/TamañoPantalla.svelte.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { innerWidth } from 'svelte/reactivity/window';
|
||||
export class TamañoPantalla {
|
||||
width = $derived(() => innerWidth.current || 1080);
|
||||
isMobile = $derived(this.width() < 768);
|
||||
}
|
||||
Reference in New Issue
Block a user