feat(anotações): permite anexos em notas

This commit is contained in:
Felipe Coutinho
2026-06-21 11:54:05 -03:00
parent 129295d2e2
commit d363662548
17 changed files with 3942 additions and 90 deletions

View File

@@ -1,8 +1,8 @@
"use server";
import { and, eq } from "drizzle-orm";
import { and, eq, inArray } from "drizzle-orm";
import { z } from "zod";
import { notes } from "@/db/schema";
import { attachments, noteAttachments, notes } from "@/db/schema";
import {
handleActionError,
revalidateForEntity,
@@ -10,6 +10,7 @@ import {
import { getUser } from "@/shared/lib/auth/server";
import { db } from "@/shared/lib/db";
import { uuidSchema } from "@/shared/lib/schemas/common";
import { deleteS3Object } from "@/shared/lib/storage/presign";
import type { ActionResult } from "@/shared/lib/types/actions";
const taskSchema = z.object({
@@ -70,25 +71,42 @@ type NoteDeleteInput = z.infer<typeof deleteNoteSchema>;
export async function createNoteAction(
input: NoteCreateInput,
): Promise<ActionResult> {
): Promise<ActionResult<{ noteId: string }>> {
try {
const user = await getUser();
const data = createNoteSchema.parse(input);
await db.insert(notes).values({
title: data.title,
description: data.description,
type: data.type,
tasks:
data.tasks && data.tasks.length > 0 ? JSON.stringify(data.tasks) : null,
userId: user.id,
});
const [created] = await db
.insert(notes)
.values({
title: data.title,
description: data.description,
type: data.type,
tasks:
data.tasks && data.tasks.length > 0
? JSON.stringify(data.tasks)
: null,
userId: user.id,
})
.returning({ id: notes.id });
if (!created) {
return { success: false, error: "Não foi possível criar a anotação." };
}
revalidateForEntity("notes", user.id);
return { success: true, message: "Anotação criada com sucesso." };
return {
success: true,
message: "Anotação criada com sucesso.",
data: { noteId: created.id },
};
} catch (error) {
return handleActionError(error);
const result = handleActionError(error);
return {
success: false,
error: result.success ? "Ocorreu um erro inesperado." : result.error,
};
}
}
@@ -135,6 +153,25 @@ export async function deleteNoteAction(
const user = await getUser();
const data = deleteNoteSchema.parse(input);
const linkedAttachments = await db
.select({ id: attachments.id, fileKey: attachments.fileKey })
.from(noteAttachments)
.innerJoin(
attachments,
and(
eq(noteAttachments.attachmentId, attachments.id),
eq(attachments.userId, user.id),
),
)
.innerJoin(
notes,
and(
eq(noteAttachments.noteId, notes.id),
eq(notes.id, data.id),
eq(notes.userId, user.id),
),
);
const [deleted] = await db
.delete(notes)
.where(and(eq(notes.id, data.id), eq(notes.userId, user.id)))
@@ -147,6 +184,23 @@ export async function deleteNoteAction(
};
}
if (linkedAttachments.length > 0) {
await Promise.all(
linkedAttachments.map((attachment) =>
deleteS3Object(attachment.fileKey),
),
);
await db.delete(attachments).where(
and(
eq(attachments.userId, user.id),
inArray(
attachments.id,
linkedAttachments.map((attachment) => attachment.id),
),
),
);
}
revalidateForEntity("notes", user.id);
return { success: true, message: "Anotação removida com sucesso." };