Add notes module
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"use server";
|
||||
|
||||
import { and, desc, eq, or, sql } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { db } from "@/lib/db";
|
||||
import { getCurrentSession } from "@/lib/session";
|
||||
import { notes } from "../schema";
|
||||
|
||||
export type NoteDto = {
|
||||
id: string;
|
||||
householdId: string;
|
||||
authorId: string;
|
||||
title: string;
|
||||
body: string;
|
||||
pinned: boolean;
|
||||
remindAt: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export async function listNotes(): Promise<NoteDto[]> {
|
||||
const { household } = await getCurrentSession();
|
||||
const rows = await db
|
||||
.select()
|
||||
.from(notes)
|
||||
.where(eq(notes.householdId, household.id))
|
||||
.orderBy(desc(notes.pinned), desc(notes.updatedAt));
|
||||
|
||||
return rows.map(toNoteDto);
|
||||
}
|
||||
|
||||
export async function getNote(id: string): Promise<NoteDto> {
|
||||
const parsed = z.string().uuid().parse(id);
|
||||
const { household } = await getCurrentSession();
|
||||
const [note] = await db
|
||||
.select()
|
||||
.from(notes)
|
||||
.where(and(eq(notes.id, parsed), eq(notes.householdId, household.id)))
|
||||
.limit(1);
|
||||
|
||||
if (!note) throw new Error("Note not found");
|
||||
return toNoteDto(note);
|
||||
}
|
||||
|
||||
export async function canAccessNote(noteId: string, householdId: string) {
|
||||
const [note] = await db
|
||||
.select({ id: notes.id })
|
||||
.from(notes)
|
||||
.where(and(eq(notes.id, noteId), eq(notes.householdId, householdId)))
|
||||
.limit(1);
|
||||
|
||||
return !!note;
|
||||
}
|
||||
|
||||
export async function searchNotes(query: string, householdId: string) {
|
||||
const rows = await db
|
||||
.select({
|
||||
id: notes.id,
|
||||
title: notes.title,
|
||||
body: notes.body,
|
||||
})
|
||||
.from(notes)
|
||||
.where(
|
||||
and(
|
||||
eq(notes.householdId, householdId),
|
||||
or(sql`${notes.title} ilike ${`%${query}%`}`, sql`${notes.body} ilike ${`%${query}%`}`),
|
||||
),
|
||||
)
|
||||
.limit(10);
|
||||
|
||||
return rows.map((row) => ({
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
url: `/notes/${row.id}`,
|
||||
excerpt: row.body.slice(0, 160),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function listWidgetNotes(input: { filter: "pinned" | "all"; limit?: number }) {
|
||||
const parsed = z
|
||||
.object({
|
||||
filter: z.enum(["pinned", "all"]),
|
||||
limit: z.number().int().min(1).max(50).optional(),
|
||||
})
|
||||
.parse(input);
|
||||
const { household } = await getCurrentSession();
|
||||
const conditions = [eq(notes.householdId, household.id)];
|
||||
if (parsed.filter === "pinned") conditions.push(eq(notes.pinned, true));
|
||||
|
||||
const rows = await db
|
||||
.select()
|
||||
.from(notes)
|
||||
.where(and(...conditions))
|
||||
.orderBy(desc(notes.pinned), desc(notes.updatedAt))
|
||||
.limit(parsed.limit ?? 10);
|
||||
|
||||
return rows.map(toNoteDto);
|
||||
}
|
||||
|
||||
function toNoteDto(note: typeof notes.$inferSelect): NoteDto {
|
||||
return {
|
||||
id: note.id,
|
||||
householdId: note.householdId,
|
||||
authorId: note.authorId,
|
||||
title: note.title,
|
||||
body: note.body,
|
||||
pinned: note.pinned,
|
||||
remindAt: note.remindAt?.toISOString() ?? null,
|
||||
createdAt: note.createdAt.toISOString(),
|
||||
updatedAt: note.updatedAt.toISOString(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user