Files
vibn-frontend/app/api/vision/update/route.ts

121 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { adminDb } from "@/lib/firebase/admin";
import { getAuth } from "firebase-admin/auth";
interface VisionBoardUpdate {
vision?: {
problemSolving?: string;
changeCreated?: string;
};
targetUser?: {
who?: string;
whereTheyHangOut?: string;
};
needs?: {
problemSolved?: string;
benefitProvided?: string;
};
product?: {
description?: string;
differentiation?: string;
};
validationGoals?: {
firstUser?: string;
pathTo10Users?: string;
pricing?: string;
};
}
export async function POST(request: NextRequest) {
try {
const authHeader = request.headers.get("authorization");
if (!authHeader?.startsWith("Bearer ")) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const token = authHeader.split("Bearer ")[1];
const decodedToken = await getAuth().verifyIdToken(token);
const userId = decodedToken.uid;
const { projectId, updates } = (await request.json()) as {
projectId: string;
updates: VisionBoardUpdate;
};
if (!projectId || !updates) {
return NextResponse.json(
{ error: "Missing projectId or updates" },
{ status: 400 }
);
}
// Verify user has access to this project
const projectRef = adminDb.collection("projects").doc(projectId);
const projectSnap = await projectRef.get();
if (!projectSnap.exists) {
return NextResponse.json({ error: "Project not found" }, { status: 404 });
}
const projectData = projectSnap.data();
if (projectData?.userId !== userId) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
// Update vision board
const visionRef = projectRef.collection("visionBoard").doc("current");
const visionSnap = await visionRef.get();
const now = new Date();
if (visionSnap.exists()) {
// Merge updates
const currentData = visionSnap.data();
const mergedData = {
...currentData,
...updates,
vision: { ...currentData?.vision, ...updates.vision },
targetUser: { ...currentData?.targetUser, ...updates.targetUser },
needs: { ...currentData?.needs, ...updates.needs },
product: { ...currentData?.product, ...updates.product },
validationGoals: {
...currentData?.validationGoals,
...updates.validationGoals,
},
updatedAt: now,
};
await visionRef.update(mergedData);
return NextResponse.json({ success: true, data: mergedData });
} else {
// Create new vision board
const newData = {
vision: updates.vision || { problemSolving: "", changeCreated: "" },
targetUser: updates.targetUser || { who: "", whereTheyHangOut: "" },
needs: updates.needs || { problemSolved: "", benefitProvided: "" },
product: updates.product || { description: "", differentiation: "" },
validationGoals: updates.validationGoals || {
firstUser: "",
pathTo10Users: "",
pricing: "",
},
createdAt: now,
updatedAt: now,
};
await visionRef.set(newData);
return NextResponse.json({ success: true, data: newData });
}
} catch (error) {
console.error("Vision board update error:", error);
return NextResponse.json(
{
error: "Failed to update vision board",
details: error instanceof Error ? error.message : String(error),
},
{ status: 500 }
);
}
}