Skip to content

Commit

Permalink
feat: Added web implementation of code comments
Browse files Browse the repository at this point in the history
  • Loading branch information
MathisBurger committed Oct 30, 2024
1 parent 0a66673 commit 0cf1f92
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 1 deletion.
5 changes: 5 additions & 0 deletions web/app/solutions/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import NavigateBack from "@/components/NavigateBack";
import FileStructureDisplay from "@/components/FileStructureDisplay";
import QuestionAnswersDisplay from "@/components/solution/questions/QuestionAnswersDisplay";
import {useSpotlightStage2} from "@/hooks/spotlight/stage2";
import CommentTab from "@/components/solution/CommentTab";

// Every 30s
const REFETCH_INTERVAL = 1000 * 30;
Expand Down Expand Up @@ -120,6 +121,7 @@ const SolutionDetailsPage = ({ params }: { params: { id: string } }) => {
<Tabs.Tab value="code">Code</Tabs.Tab>
</>
)}
<Tabs.Tab value="comments">Comments</Tabs.Tab>
</Tabs.List>

{solution.assignment.language === AssignmentLanguage.QuestionBased ? (
Expand All @@ -144,6 +146,9 @@ const SolutionDetailsPage = ({ params }: { params: { id: string } }) => {
</Tabs.Panel>
</>
)}
<Tabs.Panel value="comments" mt={10}>
<CommentTab solution={solution} />
</Tabs.Panel>
</Tabs>
{executorModalOpen &&
solution.job !== undefined &&
Expand Down
53 changes: 53 additions & 0 deletions web/components/solution/CommentTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import useApiServiceClient from "@/hooks/useApiServiceClient";
import useClientQuery from "@/hooks/useClientQuery";
import { Solution } from "@/service/types/tasky";
import {Badge, Button, Card, Group, Stack, Title} from "@mantine/core";
import AssignmentDateDisplay from "@/components/assignments/AssignmentDateDisplay";
import RichTextDisplay from "@/components/display/RichTextDisplay";
import useCurrentUser from "@/hooks/useCurrentUser";
import {IconPlus} from "@tabler/icons-react";
import {useState} from "react";
import CreateCommentModal from "@/components/solution/CreateCommentModal";

interface CommentTabProps {
solution: Solution;
}

const CommentTab = ({solution}: CommentTabProps) => {

const api = useApiServiceClient();
const {user} = useCurrentUser();
const [createModalOpen, setCreateModalOpen] = useState(false);
const [comments, refetch] = useClientQuery(() => api.getCodeComments(solution.id));

return (
<>
<Stack gap={10}>
<Group justify="flex-end">
<Button onClick={() => setCreateModalOpen(true)}><IconPlus />
&nbsp;Create Comment</Button>
</Group>
{(comments ?? []).map((comment) => (
<Card shadow="sm" padding="lg" radius="md" withBorder key={comment.id}>
<Group>
<Title order={4}>{comment.title}</Title>
{comment.commentor === user?.id && (
<Badge color="green">Your comment</Badge>
)}
</Group>
<RichTextDisplay content={comment.content} fullSize={false} />
</Card>
))}
</Stack>
{createModalOpen && (
<CreateCommentModal
solution={solution}
refetch={refetch}
onClose={() => setCreateModalOpen(false)}
/>
)}
</>
);
}

export default CommentTab;
63 changes: 63 additions & 0 deletions web/components/solution/CreateCommentModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Solution } from "@/service/types/tasky";
import {Button, Divider, Group, Modal, Stack, TextInput} from "@mantine/core";
import {useForm} from "@mantine/form";
import RichTextInput from "@/components/form/RichTextInput";
import useApiServiceClient from "@/hooks/useApiServiceClient";
import {notifications} from "@mantine/notifications";


interface CreateCommentModalProps {
solution: Solution;
refetch: () => void;
onClose: () => void;
}

const CreateCommentModal = ({solution, refetch, onClose}: CreateCommentModalProps) => {

const form = useForm({
initialValues: {
title: '',
content: ''
}
});
const api = useApiServiceClient();

const onSubmit = form.onSubmit(async (values) => {
try {
await api.createCodeComment(solution.id, values.title, values.content);
refetch();
onClose();
} catch (e: any) {
notifications.show({
title: 'Error',
message: e?.message ?? "Failed to create comment",
})
}
});

return (
<Modal opened onClose={onClose} title="Create code comment" size="xl">
<form onSubmit={onSubmit}>
<Stack gap={10}>
<TextInput label="Title" key={form.key('title')} {...form.getInputProps('title')} />
<RichTextInput
key={form.key('content')}
content={form.getInputProps('content').value}
setContent={form.getInputProps('content').onChange}
/>
</Stack>
<Divider mt={10} />
<Group mt={10}>
<Button type="submit">
Create questions
</Button>
<Button onClick={onClose} color="gray">
Cancel
</Button>
</Group>
</form>
</Modal>
);
}

export default CreateCommentModal;
10 changes: 9 additions & 1 deletion web/service/ApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
Solution,
SolutionFilesResponse,
SolutionsResponse,
AssignmentWish
AssignmentWish, CodeComment
} from "@/service/types/tasky";
import { FileStructureTree } from "@/components/FileStructure";

Expand Down Expand Up @@ -219,6 +219,14 @@ class ApiService {
await this.delete<any>(`/tasky/groups/${groupId}/assignment_wishes/${wishId}`);
}

public async getCodeComments(solutionId: number): Promise<CodeComment[]> {
return await this.get<CodeComment[]>(`/tasky/solutions/${solutionId}/code_comments`);
}

public async createCodeComment(solutionId: number, title: string, content: string): Promise<CodeComment> {
return await this.post<CodeComment>(`/tasky/solutions/${solutionId}/code_comments`, {title, content});
}

public async createCodeTests(
groupId: number,
assignmentId: number,
Expand Down
7 changes: 7 additions & 0 deletions web/service/types/tasky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,10 @@ export interface AssignmentWish {
title: string;
description: string;
}

export interface CodeComment {
id: number;
title: string;
content: string;
commentor: number;
}

0 comments on commit 0cf1f92

Please sign in to comment.