xtablo-source/apps/api/src/routers/notes.ts
2025-11-10 08:52:47 +01:00

82 lines
2.3 KiB
TypeScript

import type { Database } from "@xtablo/shared-types";
import { Hono } from "hono";
import { createFactory } from "hono/factory";
import { checkTabloMember } from "../helpers/helpers.js";
import type { AuthEnv } from "../types/app.types.js";
type Note = Database["public"]["Tables"]["notes"]["Row"];
const factory = createFactory<AuthEnv>();
/**
* Fetch notes shared with a specific tablo
*/
const getTabloNotes = factory.createHandlers(checkTabloMember, async (c) => {
const tabloId = c.req.param("tabloId");
if (!tabloId) {
return c.json({ error: "Tablo ID is required" }, 400);
}
const supabase = c.get("supabase");
// Find the tablo owner
const { data: tabloData, error: tabloError } = await supabase
.from("tablos")
.select("owner_id")
.eq("id", tabloId)
.single();
if (tabloError) {
console.error("Error fetching tablo:", tabloError);
return c.json({ error: "Failed to fetch tablo" }, 500);
}
if (!tabloData) {
return c.json({ error: "Tablo not found" }, 404);
}
const tabloOwnerId = tabloData.owner_id;
// Find notes shared with this specific tablo or all tablos
const { data, error } = await supabase
.from("note_access")
.select(`
note_id,
notes!inner (
id,
title,
content,
user_id,
created_at,
updated_at,
deleted_at
)
`)
.eq("is_active", true)
.eq("user_id", tabloOwnerId)
.or(`tablo_id.eq.${tabloId},tablo_id.is.null`)
.is("notes.deleted_at", null);
if (error) {
return c.json({ error: "An error occurred" }, 500);
}
// Extract notes from the join result and remove duplicates
type JoinedResult = { note_id: string; notes: Note[] };
const extractedNotes = (data as JoinedResult[])
.map((item) => (Array.isArray(item.notes) ? item.notes[0] : item.notes))
.filter((note) => note !== null && note !== undefined);
// Remove duplicates by note id (in case a note is shared both with all tablos and this specific tablo)
const uniqueNotes = Array.from(new Map(extractedNotes.map((note) => [note.id, note])).values());
return c.json({ notes: uniqueNotes });
});
export const getNotesRouter = () => {
const notesRouter = new Hono();
notesRouter.get("/:tabloId", ...getTabloNotes);
return notesRouter;
};