From 5d6a8dca581dcc21e612cd4a2f4ae77a447eb991 Mon Sep 17 00:00:00 2001 From: Ruan Bueno Date: Tue, 30 Sep 2025 09:11:19 -0300 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20corrigindo=20p=C3=A1gina=20news?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.js | 2 +- src/app/(authenticated)/news/page.tsx | 6 +- src/components/content-feed.tsx | 55 +++++++++++++++++-- .../dashboard/birthdays-carousel.tsx | 2 +- src/components/dashboard/main-carousel.tsx | 2 +- src/components/ui/image-carousel.tsx | 6 +- src/components/ui/optimized-image.tsx | 55 +++++++++++++++---- 7 files changed, 105 insertions(+), 23 deletions(-) diff --git a/next.config.js b/next.config.js index 9cde5b1b..59822e99 100644 --- a/next.config.js +++ b/next.config.js @@ -23,7 +23,7 @@ const config = { headers: [ { key: 'Access-Control-Allow-Origin', - value: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000', + value: process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000', }, { key: 'Access-Control-Allow-Methods', diff --git a/src/app/(authenticated)/news/page.tsx b/src/app/(authenticated)/news/page.tsx index 58927624..290d6842 100644 --- a/src/app/(authenticated)/news/page.tsx +++ b/src/app/(authenticated)/news/page.tsx @@ -5,7 +5,11 @@ export default function NewsPage() { return (
- +
); diff --git a/src/components/content-feed.tsx b/src/components/content-feed.tsx index 51e0377c..21a10665 100644 --- a/src/components/content-feed.tsx +++ b/src/components/content-feed.tsx @@ -95,13 +95,25 @@ interface FlyerWithAuthor { // Dynamically import EmojiPicker to avoid SSR issues const EmojiPicker = dynamic(() => import("emoji-picker-react").then((mod) => mod.default), { ssr: false }) -export function ContentFeed({ className }: { className?: string }) { +interface ContentFeedProps { + className?: string + postsPerPage?: number + enablePagination?: boolean +} + +export function ContentFeed({ + className, + postsPerPage = 3, + enablePagination = false +}: ContentFeedProps) { const [open, setOpen] = useState(false) const [fileUrl] = useState(undefined) const [images, setImages] = useState([]) const [loading] = useState(false) + const [visiblePostsCount, setVisiblePostsCount] = useState(enablePagination ? postsPerPage : postsPerPage) const { toast } = useToast() const utils = api.useUtils() + const loadMoreRef = useRef(null) const { data: posts, isLoading: isLoadingPosts } = api.post.list.useQuery() const { data: events } = api.event.list.useQuery() @@ -112,6 +124,31 @@ export function ContentFeed({ className }: { className?: string }) { const eventsWithRoleConfig = events as EventWithAuthor[] | undefined const flyersWithRoleConfig = flyers as FlyerWithAuthor[] | undefined + // Intersection Observer para carregar mais posts + useEffect(() => { + if (!enablePagination || !postsWithRoleConfig || visiblePostsCount >= postsWithRoleConfig.length) return + + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting) { + setVisiblePostsCount(prev => Math.min(prev + postsPerPage, postsWithRoleConfig.length)) + } + }, + { threshold: 0.1 } + ) + + const currentRef = loadMoreRef.current + if (currentRef) { + observer.observe(currentRef) + } + + return () => { + if (currentRef) { + observer.unobserve(currentRef) + } + } + }, [enablePagination, postsWithRoleConfig, visiblePostsCount, postsPerPage]) + const createPost = api.post.create.useMutation({ onSuccess: async () => { toast({ @@ -206,7 +243,7 @@ export function ContentFeed({ className }: { className?: string }) { {isLoadingPosts ? (
- {Array.from({ length: 3 }).map((_, i) => ( + {Array.from({ length: enablePagination ? postsPerPage : 3 }).map((_, i) => (
@@ -217,9 +254,17 @@ export function ContentFeed({ className }: { className?: string }) {

Nenhum post publicado ainda.

) : (
- {postsWithRoleConfig?.map((post) => ( - - ))} + {postsWithRoleConfig + ?.slice(0, enablePagination ? visiblePostsCount : postsWithRoleConfig.length) + .map((post) => ( + + ))} + {/* Elemento de referência para carregar mais posts */} + {enablePagination && visiblePostsCount < (postsWithRoleConfig?.length || 0) && ( +
+
Carregando mais posts...
+
+ )}
)} diff --git a/src/components/dashboard/birthdays-carousel.tsx b/src/components/dashboard/birthdays-carousel.tsx index 5c3b6877..1743dfe5 100644 --- a/src/components/dashboard/birthdays-carousel.tsx +++ b/src/components/dashboard/birthdays-carousel.tsx @@ -58,7 +58,7 @@ export function BirthdaysCarousel({ itens, className }: BirthdayCarouselProps) { > {itens.map((item, index) => ( - +
{itens.map((item, index) => ( - +
( +
+ {/* Imagem de fundo borrada - sempre preenche todo o espaço */} + + + {/* Imagem principal */} + {alt} setIsLoaded(true)} + sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" + /> +
) } From 23556003ccea7d3fa178894d42bf315feb18b40a Mon Sep 17 00:00:00 2001 From: Ruan Bueno Date: Tue, 30 Sep 2025 09:16:45 -0300 Subject: [PATCH 2/2] fix: add optional chaining to IntersectionObserver entries check in ContentFeed component --- src/components/content-feed.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/content-feed.tsx b/src/components/content-feed.tsx index 21a10665..da88cdd7 100644 --- a/src/components/content-feed.tsx +++ b/src/components/content-feed.tsx @@ -130,7 +130,7 @@ export function ContentFeed({ const observer = new IntersectionObserver( (entries) => { - if (entries[0].isIntersecting) { + if (entries[0]?.isIntersecting) { setVisiblePostsCount(prev => Math.min(prev + postsPerPage, postsWithRoleConfig.length)) } },