feat: Add drawing annotation functionality to comments, including a new canvas component and API integration for creation, retrieval, and updates.

This commit is contained in:
Yusuf İpek
2026-02-21 20:23:15 +03:00
parent 4cb4089caa
commit d731c9434a
6 changed files with 424 additions and 16 deletions
+3 -2
View File
@@ -176,10 +176,10 @@ export async function PATCH(request: NextRequest, { params }: RouteParams) {
}
const body = await request.json();
const { content, isResolved, tagId } = body;
const { content, isResolved, tagId, annotationData } = body;
// Only author can edit content or tag
if ((content !== undefined || tagId !== undefined) && !isAuthor) {
if ((content !== undefined || tagId !== undefined || annotationData !== undefined) && !isAuthor) {
return apiErrors.forbidden('Only the author can edit comment content');
}
@@ -191,6 +191,7 @@ export async function PATCH(request: NextRequest, { params }: RouteParams) {
const updateData: Record<string, unknown> = {};
if (content !== undefined && typeof content === 'string') updateData.content = content.trim();
if (tagId !== undefined) updateData.tagId = tagId;
if (annotationData !== undefined) updateData.annotationData = annotationData;
if (isResolved !== undefined) {
updateData.isResolved = isResolved;
updateData.resolvedAt = isResolved ? new Date() : null;
@@ -44,6 +44,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
voiceUrl: true,
voiceDuration: true,
imageUrl: true,
annotationData: true,
parentId: true,
authorId: true,
tagId: true,
@@ -67,6 +68,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
voiceUrl: true,
voiceDuration: true,
imageUrl: true,
annotationData: true,
parentId: true,
authorId: true,
tagId: true,
@@ -83,6 +83,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
voiceUrl: true,
voiceDuration: true,
imageUrl: true,
annotationData: true,
parentId: true,
authorId: true,
tagId: true,
@@ -104,6 +105,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
voiceUrl: true,
voiceDuration: true,
imageUrl: true,
annotationData: true,
parentId: true,
authorId: true,
tagId: true,
@@ -184,7 +186,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
}
const body = await request.json();
const { content, timestamp, timestampEnd, parentId, voiceUrl, voiceDuration, guestName, guestEmail, tagId, imageUrl } = body;
const { content, timestamp, timestampEnd, parentId, voiceUrl, voiceDuration, guestName, guestEmail, tagId, imageUrl, annotationData } = body;
// Validate required fields
if (timestamp === undefined || timestamp === null) {
@@ -196,8 +198,8 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
return apiErrors.badRequest('Timestamp must be a valid number');
}
if (!content && !voiceUrl && !imageUrl) {
return apiErrors.badRequest('Either content, a voice recording, or an image attachment is required');
if (!content && !voiceUrl && !imageUrl && !annotationData) {
return apiErrors.badRequest('Either content, a voice recording, an image attachment, or an annotation is required');
}
// If replying, verify parent exists in same version
@@ -240,6 +242,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
voiceUrl: voiceUrl || null,
voiceDuration: voiceDuration || null,
imageUrl: imageUrl || null,
annotationData: annotationData || null,
authorId: session?.user?.id || null,
guestName: isGuest ? guestName : null,
guestEmail: isGuest ? guestEmail : null,