Files
at-mintel/packages/next-feedback/src/handlers/index.ts

132 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import {
createDirectus,
rest,
staticToken,
createItem,
readItems,
} from "@directus/sdk";
export interface CMSConfig {
url: string;
token: string;
}
export function createCMSClient(config: CMSConfig) {
return createDirectus(config.url)
.with(staticToken(config.token))
.with(rest());
}
export async function handleFeedbackRequest(
req: NextRequest,
config: CMSConfig,
) {
const client = createCMSClient(config);
if (req.method === "GET") {
try {
const items = await client.request(
readItems("visual_feedback", {
fields: ["*", { comments: ["*"] }],
sort: ["-date_created"],
}),
);
return NextResponse.json(items);
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
if (req.method === "POST") {
try {
const body = await req.json();
const { action, screenshot_base64, ...data } = body;
if (action === "reply") {
const reply = await client.request(
createItem("visual_feedback_comments", {
feedback_id: data.feedbackId,
user_name: data.userName,
text: data.text,
}),
);
return NextResponse.json(reply);
}
let screenshotId = null;
if (screenshot_base64) {
try {
const base64Data = screenshot_base64.split(";base64,").pop();
const buffer = Buffer.from(base64Data, "base64");
const formData = new FormData();
const blob = new Blob([buffer], { type: "image/png" });
formData.append("file", blob, `feedback-${Date.now()}.png`);
const fileRes = await fetch(`${config.url}/files`, {
method: "POST",
headers: { Authorization: `Bearer ${config.token}` },
body: formData,
});
if (fileRes.ok) {
const fileData = await fileRes.json();
screenshotId = fileData.data.id;
}
} catch (e) {
console.error("Failed to upload screenshot:", e);
}
}
const feedback = await client.request(
createItem("visual_feedback", {
project: data.project || req.headers.get("host") || "unknown",
url: data.url,
selector: data.selector,
x: data.x,
y: data.y,
type: data.type,
text: data.text,
user_name: data.userName,
user_identity: data.userIdentity,
status: "open",
screenshot: screenshotId,
company: data.companyId,
}),
);
return NextResponse.json(feedback);
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
return NextResponse.json({ error: "Method not allowed" }, { status: 405 });
}
export async function handleWhoAmIRequest(
req: NextRequest,
gatekeeperUrl: string,
) {
try {
const bypass = req.nextUrl.searchParams.get("gatekeeper_bypass");
const targetUrl = bypass
? `${gatekeeperUrl}/api/whoami?gatekeeper_bypass=${bypass}`
: `${gatekeeperUrl}/api/whoami`;
// Forward cookies
const cookieHeader = req.headers.get("cookie") || "";
const res = await fetch(targetUrl, {
headers: { Cookie: cookieHeader },
});
if (res.ok) {
return NextResponse.json(await res.json());
}
return NextResponse.json({ identity: "Guest" });
} catch (_e) {
return NextResponse.json({ identity: "Guest" });
}
}