mirror of
https://github.com/emailerfacu-spec/minix-front.git
synced 2026-04-01 13:10:44 -03:00
add pagination in profile
This commit is contained in:
@@ -16,9 +16,9 @@
|
||||
let {
|
||||
post,
|
||||
variant = 'icon-lg'
|
||||
}: { post: Omit<Partial<Post>, 'authorId'> & { authorId: string }; variant?: string } = $props();
|
||||
}: { post: Omit<Partial<Post>, 'authorId'> & { authorId: string; id: string }; variant?: 'icon-lg' | 'default' | 'sm' | 'lg' | 'icon' | 'icon-sm' } = $props();
|
||||
|
||||
let seguido: Boolean | null = $state(null);
|
||||
let seguido: boolean | null = $state(null);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('followCacheUpdated', ((
|
||||
@@ -40,9 +40,11 @@
|
||||
async function cargarSeguido() {
|
||||
let a = cacheSeguidos.get(post.authorId);
|
||||
if (a === undefined) {
|
||||
const seguidoStatus = await esSeguido(post);
|
||||
cacheSeguidos.set(post.authorId, seguidoStatus.isFollowing || false);
|
||||
seguido = seguidoStatus.isFollowing || false;
|
||||
const seguidoStatus = await esSeguido(post as Post);
|
||||
if (seguidoStatus) {
|
||||
cacheSeguidos.set(post.authorId, seguidoStatus.isFollowing || false);
|
||||
seguido = seguidoStatus.isFollowing || false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
seguido = a;
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</Card>
|
||||
{:else}
|
||||
{#each $posts as post (post.id)}
|
||||
<div animate:slide>
|
||||
<div transition:slide>
|
||||
<PostCard {post} bind:postAModificar />
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { apiBase } from '@/stores/url';
|
||||
import PenLine from '@lucide/svelte/icons/pen-line';
|
||||
import type { Post } from '../../types.js';
|
||||
import { fade, slide } from 'svelte/transition';
|
||||
import PostCard from '@/components/PostCard.svelte';
|
||||
@@ -9,7 +8,7 @@
|
||||
import ModalEditar from './modalEditar.svelte';
|
||||
import { page } from '$app/state';
|
||||
import Button from '@/components/ui/button/button.svelte';
|
||||
import { Dialog } from '@/components/ui/dialog/index.js';
|
||||
import { Dialog } from '@/components/ui/dialog';
|
||||
import CrearPost from '@/components/crear-post.svelte';
|
||||
import DialogContent from '@/components/ui/dialog/dialog-content.svelte';
|
||||
import DialogTitle from '@/components/ui/dialog/dialog-title.svelte';
|
||||
@@ -19,88 +18,131 @@
|
||||
import CardPerfil from '@/components/CardPerfil.svelte';
|
||||
import DialogModificarUsuario from '@/components/DialogModificarUsuario.svelte';
|
||||
import BotonSeguir from '@/components/BotonSeguir.svelte';
|
||||
import UserPen from '@lucide/svelte/icons/user-pen';
|
||||
import DialogResetPassword from '@/components/DialogResetPassword.svelte';
|
||||
import Key from '@lucide/svelte/icons/key';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let { params } = $props();
|
||||
|
||||
let cargando = $state(true);
|
||||
let cargando = $state(false);
|
||||
let finished = $state(false);
|
||||
let pageNumber = $state(1);
|
||||
let sentinel: HTMLDivElement;
|
||||
|
||||
let mensajeError = $state('');
|
||||
let postAModificar: Post | null = $state(null);
|
||||
|
||||
let showCrearPost = $state(false);
|
||||
|
||||
let data = $derived(page.data);
|
||||
|
||||
$effect(() => {
|
||||
obtenerPosts();
|
||||
});
|
||||
let fetching = false;
|
||||
|
||||
async function obtenerPosts() {
|
||||
if (fetching || finished) return;
|
||||
|
||||
fetching = true;
|
||||
cargando = true;
|
||||
|
||||
try {
|
||||
const req = await fetch($apiBase + '/api/posts/user/' + params.perfil, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${$sesionStore?.accessToken}`
|
||||
}
|
||||
});
|
||||
if (req.ok) {
|
||||
setPosts(await req.json());
|
||||
|
||||
const res = await fetch(
|
||||
`${$apiBase}/api/posts/user/${params.perfil}?page=${pageNumber}&pageSize=20`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${$sesionStore?.accessToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
const nuevosPosts: Post[] = await res.json();
|
||||
|
||||
if (nuevosPosts.length === 0) {
|
||||
finished = true;
|
||||
return;
|
||||
}
|
||||
mensajeError = 'Fallo al obtener los datos';
|
||||
} catch {
|
||||
mensajeError = 'No se alcanzo el servidor';
|
||||
|
||||
posts.update((actuales = []) => [...actuales, ...nuevosPosts]);
|
||||
|
||||
pageNumber++;
|
||||
|
||||
if (nuevosPosts.length < 20) {
|
||||
finished = true;
|
||||
}
|
||||
} finally {
|
||||
fetching = false;
|
||||
cargando = false;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
params.perfil;
|
||||
|
||||
setPosts([]);
|
||||
pageNumber = 1;
|
||||
finished = false;
|
||||
mensajeError = '';
|
||||
|
||||
obtenerPosts();
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
obtenerPosts();
|
||||
}
|
||||
},
|
||||
{ rootMargin: '200px' }
|
||||
);
|
||||
|
||||
if (sentinel) observer.observe(sentinel);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
async function handleEditar(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
if (postAModificar == null) return;
|
||||
if (!postAModificar) return;
|
||||
|
||||
await updatePost(
|
||||
postAModificar,
|
||||
(postnuevo: Post) => updatePostStore(postAModificar!.id, postnuevo),
|
||||
|
||||
(postNuevo: Post) =>
|
||||
updatePostStore(postAModificar!.id, postNuevo),
|
||||
mensajeError
|
||||
);
|
||||
|
||||
postAModificar = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- {$inspect(data)} -->
|
||||
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
||||
<div class="w-full max-w-6xl">
|
||||
{#key data}
|
||||
<CardPerfil bind:data />
|
||||
{/key}
|
||||
<h1
|
||||
class="mt-10 flex scroll-m-20 justify-between text-3xl font-extrabold tracking-tight lg:text-3xl"
|
||||
>
|
||||
|
||||
<h1 class="mt-10 flex justify-between text-3xl font-extrabold">
|
||||
Posts:
|
||||
{#if params.perfil == $sesionStore?.username}
|
||||
{#if params.perfil === $sesionStore?.username}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
class="m-1 rounded-full bg-blue-600"
|
||||
onclick={() => {
|
||||
showCrearPost = true;
|
||||
}}
|
||||
class="rounded-full bg-blue-600"
|
||||
onclick={() => (showCrearPost = true)}
|
||||
>
|
||||
<PenLine />
|
||||
+
|
||||
</Button>
|
||||
{:else if $posts?.length == 0}
|
||||
<BotonSeguir post={{ authorId: data.id }} />
|
||||
{:else if $posts.length === 0}
|
||||
<BotonSeguir post={{ authorId: data.id, id: data.id }} />
|
||||
{/if}
|
||||
</h1>
|
||||
|
||||
<hr class="mb-8" />
|
||||
{#if cargando}
|
||||
|
||||
{#if cargando && $posts.length === 0}
|
||||
<CardCargando />
|
||||
{:else if mensajeError !== ''}
|
||||
{:else if mensajeError}
|
||||
<CardError {mensajeError} />
|
||||
{:else if $posts.length === 0}
|
||||
<CardError mensajeError="Este usuario no tiene posts" />
|
||||
{:else}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each $posts as post (post.id)}
|
||||
@@ -110,40 +152,37 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div bind:this={sentinel} class="h-1"></div>
|
||||
|
||||
{#if cargando && $posts.length > 0}
|
||||
<div class="flex justify-center py-4">
|
||||
<CardCargando />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if postAModificar}
|
||||
<div in:fade>
|
||||
<ModalEditar callbackfn={handleEditar} bind:post={postAModificar} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div transition:fade>
|
||||
<Dialog open={showCrearPost} onOpenChange={() => (showCrearPost = false)}>
|
||||
<DialogContent
|
||||
onkeydown={(e: KeyboardEvent) => {
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
showCrearPost = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle>Crear Publicacion</DialogTitle>
|
||||
<CrearPost />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<Dialog open={showCrearPost} onOpenChange={() => (showCrearPost = false)}>
|
||||
<DialogContent>
|
||||
<DialogTitle>Crear publicación</DialogTitle>
|
||||
<CrearPost />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{#if $sesionStore?.isAdmin || $sesionStore?.username == params.perfil}
|
||||
{#if $sesionStore?.isAdmin || $sesionStore?.username === params.perfil}
|
||||
<div class="fixed right-8 bottom-8 flex flex-col gap-2">
|
||||
<DialogModificarUsuario bind:data>
|
||||
<Button variant="default" size="icon-lg">
|
||||
<UserPen />
|
||||
</Button>
|
||||
<Button>Modificar Usuario</Button>
|
||||
</DialogModificarUsuario>
|
||||
<DialogResetPassword bind:data>
|
||||
<Button variant="default" size="icon-lg">
|
||||
<Key />
|
||||
</Button>
|
||||
<Button>Reset Password</Button>
|
||||
</DialogResetPassword>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -152,6 +191,5 @@
|
||||
<meta property="og:title" content="Mini-x" />
|
||||
<meta property="og:description" content={`viendo el perfil de @${data.username}`} />
|
||||
<meta property="og:image" content={data.imageUrl} />
|
||||
<meta property="og:url" content="https://minix-front.vercel.app/" />
|
||||
<meta property="og:type" content="website" />
|
||||
</svelte:head>
|
||||
</svelte:head>
|
||||
Reference in New Issue
Block a user