Skip to content

Commit

Permalink
feat: answers and verified answer
Browse files Browse the repository at this point in the history
  • Loading branch information
vishalkondle-dev committed Jul 11, 2024
1 parent 397eb1a commit ba49700
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 77 deletions.
55 changes: 38 additions & 17 deletions app/(private)/forum/[forum]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ForumType } from '@/components/Forum/Forum.types';
import { FORUM_ANSWERS_SORT_OPTIONS } from '@/lib/constants';
import { ForumDocument } from '@/models/Forum';
import { apiCall } from '@/lib/client_functions';
import Skelton from '@/components/Skelton/Skelton';

const ForumPage = ({ params }: { params: { forum: string } }) => {
const [forum, setForum] = useState<ForumDocument | null | any>(null);
Expand All @@ -19,38 +20,52 @@ const ForumPage = ({ params }: { params: { forum: string } }) => {
const getForum = async () => {
const res: any | undefined = await apiCall(`/api/forums?_id=${params.forum}`);
if (res?.data) {
setForum(res?.data?.[0]);
setAnswers(res?.data?.[1]);
const { answers: Answers, ...rest } = res.data;
setForum(rest);
SortIt(Answers);
}
};

useEffect(() => {
getForum();
}, [params.forum]);

useEffect(() => {
if (!forum || !answers) {
const SortIt = (data: ForumType[]) => {
if (!data) {
return;
}
const sortIt = [...answers];
const sortIt = [...data];
switch (value) {
case 'newest':
sortIt.sort((a: any, b: any) => dayjs(b.updatedAt).diff(dayjs(a.updatedAt), 'seconds'));
sortIt.sort((a: any, b: any) => dayjs(b.createdAt).diff(dayjs(a.createdAt), 'seconds'));
break;
case 'oldest':
sortIt.sort((a: any, b: any) => dayjs(a.updatedAt).diff(dayjs(b.updatedAt), 'seconds'));
sortIt.sort((a: any, b: any) => dayjs(a.createdAt).diff(dayjs(b.createdAt), 'seconds'));
break;
default:
sortIt.sort(
(a: any, b: any) =>
b.upvotes.length - b.downvotes.length - (a.upvotes.length - a.downvotes.length)
);
sortIt.sort((a: any, b: any) => {
const aScore = a.upvotes.length - a.downvotes.length;
const bScore = b.upvotes.length - b.downvotes.length;
return bScore - aScore;
});
break;
}

setAnswers(sortIt);
};

useEffect(() => {
getForum();
}, [params.forum]);

useEffect(() => {
SortIt(answers);
}, [value]);

const onMarkAsAnswer = async (answer: string | null) => {
await apiCall('/api/forums', { ...forum, answer }, 'PUT');
getForum();
};

if (!forum) {
return <Skelton height={200} />;
}

return (
<>
<Group mb="md" justify="space-between">
Expand Down Expand Up @@ -87,7 +102,13 @@ const ForumPage = ({ params }: { params: { forum: string } }) => {
/>
</Group>
{answers?.map((forumItem: ForumType) => (
<Forum key={String(forumItem._id)} forum={forumItem} refetch={getForum} />
<Forum
key={String(forumItem._id)}
forum={forumItem}
answer={String(forum.answer)}
refetch={getForum}
onMarkAsAnswer={onMarkAsAnswer}
/>
))}
<ReplyToQuestion refetch={getForum} parent={forum?._id} />
</Stack>
Expand Down
6 changes: 4 additions & 2 deletions app/api/forums/reply/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ export async function POST(req: NextRequest) {
}
const body = await req.json();
await startDb();
const forum = await Forum.create({ ...body, user: session?.user._id });
return NextResponse.json(forum, { status: 200 });
const { parent, ...remainingBody } = body;
const reply = await Forum.create({ ...remainingBody, user: session?.user._id });
await Forum.findByIdAndUpdate(parent, { $push: { answers: reply._id } });
return NextResponse.json(reply, { status: 200 });
} catch (error: any) {
return NextResponse.json({ error: error?.message }, { status: 500 });
}
Expand Down
11 changes: 7 additions & 4 deletions app/api/forums/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ export async function GET(req: NextRequest) {
const tags = req.nextUrl.searchParams.get('tag')?.toString() ?? '';

if (_id) {
const forum = await Forum.findById(_id).populate({ path: 'user', select: 'name' });
const answers = await Forum.find({ parent: _id })
const forum = await Forum.findById(_id)
.populate({ path: 'user', select: 'name' })
.select('-question -__v -tags -parent -views -saved -answers');
.populate({
path: 'answers',
select: '-question -__v -tags -views -saved',
populate: { path: 'user', select: 'name' },
});
if (!forum?.views.includes(new mongoose.Types.ObjectId(session?.user._id))) {
await forum?.updateOne({ $push: { views: session?.user._id } }, { new: true });
}
return NextResponse.json([forum, answers], { status: 200 });
return NextResponse.json(forum, { status: 200 });
}

if (tags) {
Expand Down
86 changes: 40 additions & 46 deletions components/Forum/Forum.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { ActionIcon, Avatar, Badge, Button, Group, Paper, rem, Stack, Text } from '@mantine/core';
import {
ActionIcon,
Avatar,
Badge,
Button,
Group,
Paper,
rem,
Stack,
Text,
Tooltip,
} from '@mantine/core';
import { useSession } from 'next-auth/react';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
Expand All @@ -8,8 +19,8 @@ import {
IconBookmarkFilled,
IconCaretDownFilled,
IconCaretUpFilled,
IconMessageReply,
IconQuestionMark,
IconCheck,
IconX,
} from '@tabler/icons-react';
import { ForumType } from './Forum.types';
import { apiCall, openModal } from '@/lib/client_functions';
Expand All @@ -19,9 +30,11 @@ dayjs.extend(relativeTime);
interface Props {
forum: ForumType;
refetch: () => void;
answer?: string;
onMarkAsAnswer?: (answer: string | null) => void;
}

export const Forum = ({ forum, refetch }: Props) => {
export const Forum = ({ forum, refetch, answer, onMarkAsAnswer }: Props) => {
const session: any = useSession();
const router = useRouter();

Expand All @@ -35,6 +48,8 @@ export const Forum = ({ forum, refetch }: Props) => {
const removeFromDownVotes = forum?.downvotes?.filter((_id) => _id !== session?.data?.user?._id);
const removeFromSaved = forum?.saved?.filter((_id) => _id !== session?.data?.user?._id);

const isThisAnswer = forum._id === answer;

const onDelete = () =>
openModal('This forum will be deleted permanently', () => {
apiCall(`/api/forums?_id=${forum?._id}`, {}, 'DELETE').then(() => {
Expand Down Expand Up @@ -109,6 +124,18 @@ export const Forum = ({ forum, refetch }: Props) => {
{isSaved ? <IconBookmarkFilled /> : <IconBookmark />}
</ActionIcon>
)}
{!forum?.question && forum?.user?._id === session.data.user._id && (
<Tooltip label={`${isThisAnswer ? 'Remove as answer' : 'Mark as answer'}`}>
<ActionIcon
onClick={() => onMarkAsAnswer?.(isThisAnswer ? null : String(forum._id))}
radius="xl"
color={isThisAnswer ? 'red' : 'teal'}
variant="subtle"
>
{isThisAnswer ? <IconX /> : <IconCheck />}
</ActionIcon>
</Tooltip>
)}
</Stack>
<Stack w="100%">
<Text dangerouslySetInnerHTML={{ __html: String(forum?.description) }} />
Expand Down Expand Up @@ -148,48 +175,15 @@ export const Forum = ({ forum, refetch }: Props) => {
)}
</Group>
<Paper p="xs" withBorder>
<Stack gap={rem(4)}>
<Text c="dimmed" size={rem(12)}>
{forum?.question ? 'asked' : 'answered'} on{' '}
{dayjs(forum?.createdAt).format('MMM DD YYYY @ HH:mm')}
</Text>
<Group gap={rem(4)}>
<Avatar name={forum?.user?.name} color="initials" />
<Stack gap={rem(4)}>
<Text size="xs">{forum?.user?.name}</Text>
<Group gap="xs">
<Badge
variant="light"
color="red"
radius="xs"
title="Questions"
leftSection={
<IconQuestionMark
stroke={4}
style={{ width: rem(14), height: rem(14) }}
/>
}
>
0
</Badge>
<Badge
variant="light"
color="teal"
radius="xs"
title="Replies"
leftSection={
<IconMessageReply
stroke={3}
style={{ width: rem(14), height: rem(14) }}
/>
}
>
0
</Badge>
</Group>
</Stack>
</Group>
</Stack>
<Group wrap="nowrap" gap={rem(4)}>
<Avatar name={forum?.user?.name} color="initials" />
<Stack gap={rem(4)}>
<Text size="xs">{forum?.user?.name}</Text>
<Text c="dimmed" size={rem(12)}>
{dayjs(forum?.createdAt).format('MMM DD YYYY @ HH:mm')}
</Text>
</Stack>
</Group>
</Paper>
</Group>
</Stack>
Expand Down
7 changes: 3 additions & 4 deletions components/Forum/ForumItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Avatar, Badge, Flex, Group, Paper, rem, Stack, Text } from '@mantine/core';
import { IconCheck } from '@tabler/icons-react';
import dayjs from 'dayjs';
import { useRouter } from 'next/navigation';
import { ForumType } from './Forum.types';
Expand Down Expand Up @@ -32,11 +31,11 @@ export const ForumItem = ({ forum, isMobile, selectedTag }: Props) => {
</Badge>
<Badge
radius="xs"
variant="filled"
leftSection={<IconCheck style={{ width: rem(18), height: rem(18) }} />}
variant={forum?.answer ? 'filled' : 'transparent'}
color="teal"
px={0}
>
{forum?.answers} answers
{forum?.answers?.length} answers
</Badge>
<Badge radius="xs" color="brown" variant="transparent" px={0}>
{forum?.views?.length} views
Expand Down
8 changes: 4 additions & 4 deletions models/Forum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { UserDocument } from './User';
export interface ForumDocument extends Document {
question?: string;
description?: string;
parent?: Types.ObjectId;
user?: Types.ObjectId | UserDocument;
tags: string[];
upvotes: Types.ObjectId[];
downvotes: Types.ObjectId[];
views: Types.ObjectId[];
saved: Types.ObjectId[];
answers: number;
answers: Types.ObjectId[];
answer?: Types.ObjectId;
createdAt?: Date;
updatedAt?: Date;
}
Expand All @@ -20,14 +20,14 @@ const forumSchema = new Schema<ForumDocument>(
{
question: { type: String, required: false, trim: true },
description: { type: String, required: false, trim: true },
parent: { type: Types.ObjectId, ref: 'Forum', default: null },
user: { type: Types.ObjectId, required: true, ref: 'User' },
tags: [{ type: String }],
views: { type: [Types.ObjectId], default: [], ref: 'User' },
upvotes: { type: [Types.ObjectId], default: [], ref: 'User' },
downvotes: { type: [Types.ObjectId], default: [], ref: 'User' },
saved: { type: [Types.ObjectId], default: [], ref: 'User' },
answers: { type: Number, default: 0 },
answers: { type: [Types.ObjectId], default: [], ref: 'Forum' },
answer: { type: Types.ObjectId, default: null, ref: 'Forum' },
},
{ timestamps: true }
);
Expand Down

0 comments on commit ba49700

Please sign in to comment.