Skip to content
4 changes: 2 additions & 2 deletions frontend/components/answer/AnswerBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
const AnswerBox = ({ answer }: AnswerBoxProps) => {
const theme = useTheme();
const [isExpanded, setIsExpanded] = useState(false);
const { id, text, createdAt, hearts, isAnonymous, comments } = answer;

Check failure on line 31 in frontend/components/answer/AnswerBox.tsx

View workflow job for this annotation

GitHub Actions / ESLint

frontend/components/answer/AnswerBox.tsx#L31

'hearts' is assigned a value but never used. Allowed unused vars must match /^_/u (@typescript-eslint/no-unused-vars)
const [hearted, setHearted] = useState(false);
const [heartCount, setHeartCount] = useState(answer.hearts);
const [heartLoading, setHeartLoading] = useState(false);
const { text, createdAt, isAnonymous, comments } = answer;

const handleHeart = useCallback(async () => {
if (heartLoading) return;
Expand Down Expand Up @@ -147,7 +147,7 @@
paddingLeft={majorScale(3)}
marginTop={majorScale(3)}
>
<CommentsPanel comments={comments} />
<CommentsPanel comments={comments} answerId={String(id)}/>
</Pane>
</Pane>
);
Expand Down
113 changes: 113 additions & 0 deletions frontend/components/comment/CommentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
'use client';

import React, { useState } from 'react';

import { Button, Checkbox, Pane, Textarea, useTheme } from 'evergreen-ui';

import { createNewComment } from '@/api/commentService';

interface CommentFormProps {
answerId: string;
}

/**
* Renders an "Add Comment" button that expands into a form
* with a textarea, anonymous toggle, and submit/cancel actions.
*/
export function CommentForm({ answerId }: CommentFormProps) {
const theme = useTheme();
const [isOpen, setIsOpen] = useState(false);
const [text, setText] = useState('');
const [isAnonymous, setIsAnonymous] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);

const handleSubmit = async () => {
if (!text.trim() || isSubmitting) return;

setIsSubmitting(true);
const result = await createNewComment(answerId, {
text: text.trim(),
is_anonymous: isAnonymous,
});
setIsSubmitting(false);

if (result) {
setText('');
setIsAnonymous(false);
setIsOpen(false);
// TODO: refresh comment list in AnswerBox after successful submission
}
// TODO: handle error for failed submissions
};

const handleCancel = () => {
setText('');
setIsAnonymous(false);
setIsOpen(false);
};

// If the form is not open, show the "Add Comment" button
if (!isOpen) {
return (
<Button
appearance='primary'
backgroundColor={theme.colors.red500}
color='white'
onClick={() => setIsOpen(true)}
>
Add Comment
</Button>
);
}

// If the form is open, show the comment form
return (
<Pane
display='flex'
flexDirection='column'
gap={12}
padding={16}
border
borderRadius={8}
borderColor={theme.colors.gray400}
backgroundColor={theme.colors.gray50}
>
{/* Comment text input */}
<Textarea
placeholder='Write a comment...'
value={text}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setText(e.target.value)}
rows={3}
/>

{/* Anonymous posting toggle */}
<Checkbox
label='Post anonymously'
checked={isAnonymous}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setIsAnonymous(e.target.checked)
}
margin={0}
/>

{/* Form action buttons */}
<Pane display='flex' alignItems='center' gap={8}>
<Button
appearance='primary'
backgroundColor={theme.colors.red500}
color='white'
onClick={handleSubmit}
isLoading={isSubmitting}
disabled={!text.trim()}
>
Submit
</Button>
<Button appearance='minimal' color={theme.colors.gray700} onClick={handleCancel}>
Cancel
</Button>
</Pane>
</Pane>
);
}

export default CommentForm;
8 changes: 7 additions & 1 deletion frontend/components/comment/CommentsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ import React from 'react';
import { Pane } from 'evergreen-ui';

import { CommentBox } from '@/components/comment/CommentBox';
import { CommentForm } from '@/components/comment/CommentForm';
import type { Comment } from '@/types';

type CommentsPanelProps = {
comments: Comment[];
answerId: string;
};

const CommentsPanel: React.FC<CommentsPanelProps> = ({ comments }) => {
const CommentsPanel: React.FC<CommentsPanelProps> = ({ comments, answerId }) => {
return (
<Pane className='comments-panel flex flex-col gap-6'>
{/* List of existing comments */}
{comments.map((comment, idx) => (
<Pane key={comment.id}>
<CommentBox comment={comment} showThreadLine={idx < comments.length - 1} />
</Pane>
))}

{/* Comment form */}
<CommentForm answerId={answerId} />
</Pane>
);
};
Expand Down
Loading