Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add markdown #67

Merged
merged 6 commits into from
Apr 14, 2023
Merged
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
3 changes: 3 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@heroicons/react": "v2",
"@reduxjs/toolkit": "^1.9.3",
"@tailwindcss/line-clamp": "^0.4.4",
"@tailwindcss/typography": "^0.5.9",
"@tanstack/react-query": "^4.20.4",
"@trpc/client": "10.7.0",
"@trpc/next": "10.7.0",
Expand All @@ -47,8 +48,10 @@
"prettier-plugin-tailwindcss": "^0.2.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"react-redux": "^8.0.5",
"react-toastify": "^9.1.1",
"remark-gfm": "^3.0.1",
"siwe": "^1.1.6",
"superjson": "1.12.1",
"wagmi": "^0.10.2",
Expand Down
37 changes: 34 additions & 3 deletions apps/web/src/components/Comment/Comment.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,52 @@ import {Provider} from "react-redux";
import {store} from "../../store";

describe("<Comment />", () => {
const upVote = jest.fn();
const downVote = jest.fn();
const props = {
onUpVote: upVote,
onDownVote: downVote,
comment: {id: "abc"},
}

beforeEach(() => jest.resetAllMocks());

const renderComponent = (ui) => {
return render(<Provider store={store}>{ui}</Provider>);
}

it("should render comment component with no issues", () => {
const result = renderComponent(<Comment comment={undefined} />);
const result = renderComponent(<Comment {...props} />);
expect(result.container).toBeInTheDocument();
});

it("should dispatch profile id on profile icon click", async () => {
dispatchMock.mockReset();
renderComponent(<Comment comment={undefined} />);
renderComponent(<Comment {...props} />);
await act(async () => {
fireEvent.click(document.getElementById("profile"));
});
expect(dispatchMock).toBeCalledTimes(1);
});

it("should call upvote fn on upvote click", async () => {
renderComponent(<Comment {...props} />);
upVote.mockResolvedValue({});
expect(document.getElementById("up-vote")).toBeTruthy();
await act(async () => {
fireEvent.click(document.getElementById("up-vote"));
});
expect(upVote).toBeCalled();
expect(upVote).toBeCalledWith("abc");
});

it("should call downvote fn on downvote click", async () => {
renderComponent(<Comment {...props} />);
downVote.mockResolvedValue({});
expect(document.getElementById("down-vote")).toBeTruthy();
await act(async () => {
fireEvent.click(document.getElementById("down-vote"));
});
expect(downVote).toBeCalled();
expect(downVote).toBeCalledWith("abc");
});
});
40 changes: 35 additions & 5 deletions apps/web/src/components/Comment/Comment.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
import {FlexColumn, FlexRow} from "../Flex";
import Image from "next/image";
import {showUserProfile, useAppDispatch} from "../../store";
import {DownVote, Spinner, UpVote} from "../Icons";
import {useState} from "react";
import * as utils from "../../utils";
import {Markdown} from "../Markdown";

export const Comment = ({comment}) => {
interface CommentProps {
comment: any;
onUpVote(commentId: string): Promise<void>;
onDownVote(commentId: string): Promise<void>;
}

export const Comment = (props: CommentProps) => {
const {comment, onUpVote, onDownVote} = props;
const userId = comment?.user?.id;
const user = comment?.user?.userPlatforms[0];
const absVotes = utils.getAbsVotes(comment?.votes);

const dispatch = useAppDispatch();
const [isUpVoting, setIsUpVoting] = useState(false);
const [isDownVoting, setIsDownVoting] = useState(false);

const handleUpVote = () => {
setIsUpVoting(true);
onUpVote(comment.id).finally(() => setIsUpVoting(false));
}

const handleDownVote = () => {
setIsDownVoting(true);
onDownVote(comment.id).finally(() => setIsDownVoting(false));
}

return (
<div className="flex flex-row space-x-4">
Expand All @@ -24,8 +49,8 @@ export const Comment = ({comment}) => {
alt={`${user?.platformUsername} avatar`}
/>
</div>
<FlexColumn>
<FlexRow classes="text-md text-gray-500 space-x-3">
<FlexColumn classes="space-y-3">
<FlexRow classes="text-md text-gray-500 space-x-2">
<div>{user?.platformUsername}</div>
<div>&#8226;</div>
<div>
Expand All @@ -39,9 +64,14 @@ export const Comment = ({comment}) => {
)}
</div>
</FlexRow>
<div className="text-md mt-3">
{comment?.text}
<div className="text-md">
<Markdown markdown={comment?.text} />
</div>
<FlexRow classes="space-x-2 text-sm text-gray-500">
{isUpVoting ? <Spinner/> : <UpVote onClick={handleUpVote}/>}
<span>{utils.formatNumber(absVotes)}</span>
{isDownVoting ? <Spinner/> : <DownVote onClick={handleDownVote}/>}
</FlexRow>
</FlexColumn>
</div>
);
Expand Down
49 changes: 48 additions & 1 deletion apps/web/src/components/Icons/Icons.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as utils from "../../utils";
import {IconProps} from "./types";
import {SVGProps} from "react";

export const Spinner = (props: IconProps) => {
return (
<svg
id="spinner"
className={utils.classNames(
"animate-spin mr-2 h-5 w-5",
"cursor-wait animate-spin mr-2 h-5 w-5",
props.color || "text-black",
)}
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -18,3 +19,49 @@ export const Spinner = (props: IconProps) => {
</svg>
);
};

export const UpVote = (props: SVGProps<any>) => {
return (
<svg
id="up-vote"
xmlns="http://www.w3.org/2000/svg"
className="cursor-pointer hover:fill-[#ff225b]"
width={18} height={18}
viewBox="0 0 20 20" fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_472_1110)">
<path
d="M12.877 19H7.123A1.125 1.125 0 016 17.877V11H2.126a1.114 1.114 0 01-1.007-.7 1.249 1.249 0 01.171-1.343L9.166.368a1.128 1.128 0 011.668.004l7.872 8.581a1.252 1.252 0 01.176 1.348 1.114 1.114 0 01-1.005.7H14v6.877A1.125 1.125 0 0112.877 19zM7.25 17.75h5.5v-8h4.934L10 1.31 2.258 9.75H7.25v8zM2.227 9.784l-.012.016c.01-.006.014-.01.012-.016z"></path>
</g>
<defs>
<clipPath id="clip0_472_1110">
<path d="M0 0h20v20H0z"></path>
</clipPath>
</defs>
</svg>
);
};

export const DownVote = (props: SVGProps<any>) => {
return (
<svg
id="down-vote"
xmlns="http://www.w3.org/2000/svg"
className="cursor-pointer rotate-180 hover:fill-[#ff225b]"
width={18} height={18}
viewBox="0 0 20 20" fill="currentColor"
{...props}
>
<g clipPath="url(#clip0_472_1110)">
<path
d="M12.877 19H7.123A1.125 1.125 0 016 17.877V11H2.126a1.114 1.114 0 01-1.007-.7 1.249 1.249 0 01.171-1.343L9.166.368a1.128 1.128 0 011.668.004l7.872 8.581a1.252 1.252 0 01.176 1.348 1.114 1.114 0 01-1.005.7H14v6.877A1.125 1.125 0 0112.877 19zM7.25 17.75h5.5v-8h4.934L10 1.31 2.258 9.75H7.25v8zM2.227 9.784l-.012.016c.01-.006.014-.01.012-.016z"></path>
</g>
<defs>
<clipPath id="clip0_472_1110">
<path d="M0 0h20v20H0z"></path>
</clipPath>
</defs>
</svg>
);
};
13 changes: 13 additions & 0 deletions apps/web/src/components/Markdown/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

export const Markdown = (props: {markdown: string}) => {
return (
<ReactMarkdown
className="prose prose-zinc"
remarkPlugins={[remarkGfm]}
>
{props.markdown}
</ReactMarkdown>
);
}
1 change: 1 addition & 0 deletions apps/web/src/components/Markdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Markdown";
3 changes: 2 additions & 1 deletion apps/web/src/components/Thread/Thread.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ThreadProps} from "./type";
import {FlexColumn, FlexRow} from "../Flex";
import Image from "next/image";
import {showUserProfile, useAppDispatch} from "../../store";
import {Markdown} from "../Markdown";

export const Thread = ({thread}: ThreadProps) => {
const userId = thread?.user?.id;
Expand Down Expand Up @@ -44,7 +45,7 @@ export const Thread = ({thread}: ThreadProps) => {
{thread?.title}
</div>
<div className="text-md mt-3 text-gray-500">
{thread?.body}
<Markdown markdown={thread?.body} />
</div>
</FlexColumn>
</FlexColumn>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/pages/community.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {useRouter} from "next/router";
import {useEffect, useState} from "react";
import {Loader} from "../components/Loader";
import {ThreadCard} from "../components/ThreadCard";
import {ThreadSection} from "../components/ThreadSection";
import {ThreadSection} from "../sections";
import {trpc} from "../utils/trpc";
import {Search} from "../components/Search";
import {CreateThread} from "../components/Thread";
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/pages/feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { Loader } from "../components/Loader";
import { ThreadCard } from "../components/ThreadCard";
import { ThreadSection } from "../components/ThreadSection";
import { ThreadSection } from "../sections";
import { trpc } from "../utils/trpc";
import { Search } from "../components/Search";
import {useAppSelector} from "../store";
Expand All @@ -20,7 +20,7 @@ const FeedPage = () => {
const threads: any[] = feedData.data && flatten(feedData.data.edges.map((relation) => {
return relation.node.community.threads.edges.map((thread) => thread);
}));

useEffect(() => {
if (threadId) setCurrentThread(threadId);
}, [threadId]);
Expand All @@ -36,7 +36,7 @@ const FeedPage = () => {
if (feedData.isLoading) {
return <Loader />;
}

return (
<div className="flex flex-row max-h-screen h-full overflow-y-hidden relative">
<div className="w-[30%] mx-4 flex flex-col">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "../../../test/setup";
import {ThreadSection} from "./ThreadSection";
import {Provider} from "react-redux";
import {store} from "../../store";
Expand Down Expand Up @@ -65,6 +66,12 @@ jest.mock('../../utils/trpc', () => ({
fetchCommentsByThreadId: {
useInfiniteQuery: () => mockFetchCommentsByThreadId,
},
upVoteComment: {
useMutation: () => ({mutateAsync: mutationMock}),
},
downVoteComment: {
useMutation: () => ({mutateAsync: mutationMock}),
}
},
},
}));
Expand Down
Loading