Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .env.local.example

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
97 changes: 69 additions & 28 deletions components/blog/PostPage.tsx
Original file line number Diff line number Diff line change
@@ -1,97 +1,138 @@
// app/page.tsx
'use client';
"use client";

import { Box, Container, Flex, Spinner } from '@chakra-ui/react';
import TweetList from '../homepage/TweetList';
import TweetComposer from '../homepage/TweetComposer';
import { useEffect, useState } from 'react';
import { Comment, Discussion } from '@hiveio/dhive'; // Ensure this import is consistent
import Conversation from '../homepage/Conversation';
import TweetReplyModal from '../homepage/TweetReplyModal';
import { getPost } from '@/lib/hive/client-functions';
import PostDetails from '@/components/blog/PostDetails';
import { useComments } from '@/hooks/useComments';
import { Box, Container, Flex, Spinner } from "@chakra-ui/react";
import TweetList from "../homepage/TweetList";
import TweetComposer from "../homepage/TweetComposer";
import { useEffect, useState } from "react";
import { Comment, Discussion } from "@hiveio/dhive";
import Conversation from "../homepage/Conversation";
import TweetReplyModal from "../homepage/TweetReplyModal";
import { getPost } from "@/lib/hive/client-functions";
import PostDetails from "@/components/blog/PostDetails";
import { useComments } from "@/hooks/useComments";

interface PostPageProps {
author: string
permlink: string
author: string;
permlink: string;
}

export default function PostPage({ author, permlink }: PostPageProps) {

const [isLoading, setIsLoading] = useState(false);
const [post, setPost] = useState<Discussion | null>(null);
const [error, setError] = useState<string | null>(null);
const [conversation, setConversation] = useState<Comment | undefined>();
const [reply, setReply] = useState<Comment>();
const [isOpen, setIsOpen] = useState(false);
const [newComment, setNewComment] = useState<Comment | null>(null); // Define the state
const [newComment, setNewComment] = useState<Comment | null>(null);

const data = useComments(author, permlink, true);
const commentsData = {
...data,
loadNextPage: () => {},
hasMore: false,
...data,
loadNextPage: () => {},
hasMore: false,
};

useEffect(() => {
async function loadPost() {
setIsLoading(true);
setIsOpen(false);
setReply(undefined);
setConversation(undefined);
setNewComment(null);

try {
const post = await getPost(author, permlink);
setPost(post);
} catch (err) {
setError('Failed to load post');
setError("Failed to load post");
} finally {
setIsLoading(false);
}
}

loadPost();
}, [author, permlink]);

const onOpen = () => setIsOpen(true);
const onClose = () => setIsOpen(false);

const handleNewComment = (newComment: Partial<Comment> | CharacterData) => {
setNewComment(newComment as Comment); // Type assertion
setNewComment(newComment as Comment);
};

if (isLoading || (!post || !author || !permlink)) {
if (isLoading || !post || !author || !permlink) {
return (
<Box display="flex" justifyContent="center" alignItems="center" height="100vh">
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100vh"
>
<Spinner size="xl" color="primary" />
</Box>
);
}

console.log("RENDER:", {
isOpen,
reply: !!reply,
conversation: !!conversation,
});

return (
<Box bg="background" color="text" minH="100vh">
<Flex direction={{ base: 'column', md: 'row' }}>
<Flex direction={{ base: "column", md: "row" }}>
<Box flex="1" p={4}>
<Container maxW="container.sm">
<PostDetails post={post} />
{!conversation ? (
<>
<TweetComposer pa={author} pp={permlink} onNewComment={handleNewComment} post={true} onClose={() => {}} />
{/* Composer fixo: só se modal fechado */}
{!isOpen && (
<TweetComposer
pa={author}
pp={permlink}
onNewComment={handleNewComment}
onClose={onClose}
post={true} // "REPLY"
/>
)}

{/*da forma como está aqui, mostra o frame para responder como Reply e apenas 1 vez. O erro de mostrar 2 vezes
no blog foi corrigido*/}
<TweetList
author={author}
permlink={permlink}
setConversation={setConversation}
onOpen={onOpen}
setReply={setReply}
newComment={newComment} // Pass the newComment to TweetList
newComment={newComment}
post={true}
data={commentsData}
showComposer={false} // NÃO mostra composer aqui
/>
</>
) : (
<Conversation comment={conversation} setConversation={setConversation} onOpen={onOpen} setReply={setReply} />
<Conversation
comment={conversation}
setConversation={setConversation}
onOpen={onOpen}
setReply={setReply}
/>
)}
</Container>
</Box>
</Flex>
{isOpen && <TweetReplyModal isOpen={isOpen} onClose={onClose} comment={reply} onNewReply={handleNewComment} />}

{/* Modal: só se isOpen e reply existirem */}
{isOpen && reply && (
<TweetReplyModal
isOpen={isOpen}
onClose={onClose}
comment={reply}
onNewReply={handleNewComment}
/>
)}
</Box>
);
}
111 changes: 59 additions & 52 deletions components/homepage/TweetList.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import React from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
import { Box, Spinner, VStack, Text } from '@chakra-ui/react';
import Tweet from './Tweet';
import { ExtendedComment, useComments } from '@/hooks/useComments';
import { useSnaps } from '@/hooks/useSnaps';
import TweetComposer from './TweetComposer';
// components/homepage/TweetList.tsx
import React from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { Box, Spinner, VStack, Text } from "@chakra-ui/react";
import Tweet from "./Tweet";
import { ExtendedComment } from "@/hooks/useComments";
import TweetComposer from "./TweetComposer";

interface InfiniteScrollData {
comments: ExtendedComment[];
loadNextPage: () => void;
isLoading: boolean;
hasMore: boolean;
}

interface TweetListProps {
author: string
permlink: string
author: string;
permlink: string;
setConversation: (conversation: ExtendedComment) => void;
onOpen: () => void;
setReply: (reply: ExtendedComment) => void;
newComment: ExtendedComment | null;
post?: boolean;
data: InfiniteScrollData
data: InfiniteScrollData;
showComposer?: boolean; // NOVA PROP
}

interface InfiniteScrollData {
comments: ExtendedComment[];
loadNextPage: () => void; // Default can be an empty function in usage
isLoading: boolean;
hasMore: boolean; // Default can be `false` in usage
}

function handleNewComment() {
function handleNewComment() {}

}

export default function TweetList(
{
//showComposer = true significa que o composer será exibido no feed (homepage)
//sendo assim esse frame me permite postar um snap
export default function TweetList({
author,
permlink,
setConversation,
Expand All @@ -38,51 +38,58 @@ export default function TweetList(
newComment,
post = false,
data,
showComposer = true, // padrão: mostrar
}: TweetListProps) {
const { comments, loadNextPage, isLoading, hasMore } = data;

const { comments, loadNextPage, isLoading, hasMore } = data

// Ordena por data (mais recente primeiro)
comments.sort((a: ExtendedComment, b: ExtendedComment) => {
return new Date(b.created).getTime() - new Date(a.created).getTime();
});
// Handle new comment addition
//const updatedComments = newComment ? [newComment, ...comments] : comments;

if (isLoading && comments.length === 0) {
// Initial loading state
return (
<Box textAlign="center" mt={4}>
<Spinner size="xl" />
<Text>Loading posts...</Text>
<Text>Loading Snaps...</Text>
</Box>
);
}

return (
<InfiniteScroll
dataLength={comments.length}
next={loadNextPage}
hasMore={hasMore}
loader={
(<Box display="flex" justifyContent="center" alignItems="center" py={5}>
<Spinner size="xl" color="primary" />
</Box>
)}
scrollableTarget="scrollableDiv"
>
<VStack spacing={1} align="stretch" mx="auto">
<TweetComposer pa={author} pp={permlink} onNewComment={handleNewComment} onClose={() => null} />
{comments.map((comment: ExtendedComment) => (
<Tweet
key={comment.permlink}
comment={comment}
onOpen={onOpen}
setReply={setReply}
{...(!post ? { setConversation } : {})}
/>
))}
</VStack>
</InfiniteScroll>
<InfiniteScroll
dataLength={comments.length}
next={loadNextPage}
hasMore={hasMore}
loader={
<Box display="flex" justifyContent="center" alignItems="center" py={5}>
<Spinner size="xl" color="primary" />
</Box>
}
scrollableTarget="scrollableDiv"
>
<VStack spacing={1} align="stretch" mx="auto">
{/* CONDICIONAL: só mostra no feed (home) */}
{showComposer && (
<TweetComposer
pa={author}
pp={permlink}
onNewComment={handleNewComment}
onClose={() => null}
post={false} // "POST" no feed
/>
)}

{comments.map((comment: ExtendedComment) => (
<Tweet
key={comment.permlink}
comment={comment}
onOpen={onOpen}
setReply={setReply}
{...(!post ? { setConversation } : {})}
/>
))}
</VStack>
</InfiniteScroll>
);
}
Loading