From d2d7c9576aec239393457772d8ebee9912a43f24 Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Mon, 3 Nov 2025 19:08:05 +0000 Subject: [PATCH] push to develop --- src/app/api/book-survey/route.ts | 225 ++++++++++++++---- .../[slug]/components/BookSurveyModal.tsx | 15 +- 2 files changed, 184 insertions(+), 56 deletions(-) diff --git a/src/app/api/book-survey/route.ts b/src/app/api/book-survey/route.ts index 7f02909..995db4f 100644 --- a/src/app/api/book-survey/route.ts +++ b/src/app/api/book-survey/route.ts @@ -1,40 +1,33 @@ -// app/api/book-survey/route.ts import { NextResponse } from "next/server"; import { db } from "@/app/db/db"; import { propertyStatusTracker } from "@/app/db/schema/crm/property_status_tracker"; import { eq, and } from "drizzle-orm"; +import { user } from "@/app/db/schema/users"; export async function POST(req: Request) { + console.log("📩 Incoming POST /api/property-status request"); + try { - const { dealName, pipelineId, dealStageId, propertyId, portfolioId } = - await req.json(); + const { + pipelineId, + dealStageId, + propertyId, + portfolioId, + userInfo, + propertyMeta, + } = await req.json(); - - // 1️⃣ Create HubSpot deal - const hsRes = await fetch("https://api.hubapi.com/crm/v3/objects/deals", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`, - }, - body: JSON.stringify({ - properties: { - dealname: dealName, - pipeline: pipelineId, - dealstage: dealStageId, - }, - }), + console.log("🧠 Parsed body:", { + pipelineId, + dealStageId, + propertyId, + portfolioId, + userInfo, + propertyMeta, }); - if (!hsRes.ok) { - const err = await hsRes.text(); - throw new Error(`HubSpot error: ${err}`); - } - - const hsData = await hsRes.json(); - const hubspotDealId = hsData.id; - - // 2️⃣ Check if record exists for property + portfolio + // 1️⃣ Check if record exists first + console.log("🔍 Checking if record already exists in DB..."); const existing = await db .select() .from(propertyStatusTracker) @@ -45,32 +38,170 @@ export async function POST(req: Request) { ) ); + console.log("🗃️ Existing record check result:", existing); + if (existing.length > 0) { - // 3️⃣ Update existing record - await db - .update(propertyStatusTracker) - .set({ - hubspotDealId, - updatedAt: new Date(), - }) - .where( - and( - eq(propertyStatusTracker.propertyId, propertyId), - eq(propertyStatusTracker.portfolioId, portfolioId) - ) - ); - } else { - // 4️⃣ Create new record - await db.insert(propertyStatusTracker).values({ - hubspotDealId: hubspotDealId, - propertyId: propertyId, - portfolioId: portfolioId, + console.log("⚠️ Record already exists, skipping deal creation"); + return NextResponse.json({ + message: "Record already exists, no new deal created", + dealId: existing[0].hubspotDealId, }); } + // 2️⃣ Create HubSpot deal + console.log("🧱 Creating HubSpot deal..."); + const dealRes = await fetch("https://api.hubapi.com/crm/v3/objects/deals", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`, + }, + body: JSON.stringify({ + properties: { + dealname: propertyMeta?.address || "New Property Deal", + pipeline: pipelineId, + dealstage: dealStageId, + }, + }), + }); + + console.log("📡 HubSpot deal response status:", dealRes.status); + + if (!dealRes.ok) { + const err = await dealRes.text(); + console.error("❌ HubSpot Deal creation failed:", err); + throw new Error(`HubSpot Deal Error: ${err}`); + } + + const dealData = await dealRes.json(); + const hubspotDealId = dealData.id; + console.log("✅ Created HubSpot deal:", hubspotDealId); + + // 3️⃣ Retrieve user info from your DB + console.log("👤 Fetching user info from DB..."); + const userProfile = await db + .select() + .from(user) + .where(eq(user.id, userInfo.dbId)) + .limit(1); + + const userInfoFromDb = userProfile[0]; + console.log("📇 User info from DB:", userInfoFromDb); + + if (!userInfoFromDb?.email) { + console.error("❌ User email missing in DB for user:", userInfo.dbId); + throw new Error("User email not found; cannot create HubSpot contact."); + } + + // 4️⃣ Create or find contact in HubSpot + console.log("📞 Creating HubSpot contact..."); + const contactRes = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`, + }, + body: JSON.stringify({ + properties: { + email: userInfoFromDb.email, + }, + }), + }); + + let hubspotContactId: string | null = null; + + console.log("📡 HubSpot contact response status:", contactRes.status); + + if (contactRes.ok) { + const contactData = await contactRes.json(); + hubspotContactId = contactData.id; + console.log("✅ Created new HubSpot contact:", hubspotContactId); + } else { + console.warn("⚠️ HubSpot contact creation failed — checking if contact exists..."); + + // Check if contact already exists + const findContactRes = await fetch( + `https://api.hubapi.com/crm/v3/objects/contacts/search`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`, + }, + body: JSON.stringify({ + filterGroups: [ + { + filters: [ + { + propertyName: "email", + operator: "EQ", + value: userInfoFromDb.email, + }, + ], + }, + ], + }), + } + ); + + console.log("📡 HubSpot contact search response:", findContactRes.status); + + if (findContactRes.ok) { + const found = await findContactRes.json(); + console.log("🔎 Found contact results:", found.results); + if (found.results?.length > 0) { + hubspotContactId = found.results[0].id; + console.log("✅ Found existing HubSpot contact:", hubspotContactId); + } else { + console.error("❌ HubSpot contact creation and lookup both failed"); + throw new Error("HubSpot contact creation and lookup both failed."); + } + } else { + const findErr = await findContactRes.text(); + console.error("❌ HubSpot contact search failed:", findErr); + throw new Error("HubSpot contact lookup request failed."); + } + } + + // 5️⃣ Associate contact with deal + if (hubspotContactId) { + console.log("🔗 Associating HubSpot deal and contact..."); + const assocUrl = `https://api.hubapi.com/crm/v3/objects/deals/${hubspotDealId}/associations/contacts/${hubspotContactId}/deal_to_contact`; + + const assocRes = await fetch(assocUrl, { + method: "PUT", + headers: { + Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`, + "Content-Type": "application/json", + }, + }); + + console.log("📡 HubSpot association response:", assocRes.status); + + if (!assocRes.ok) { + const assocErr = await assocRes.text(); + console.warn("⚠️ HubSpot association failed:", assocErr); + } else { + console.log("✅ Successfully associated contact with deal"); + } + } + + // 6️⃣ Create DB record + console.log("🗄️ Inserting new tracker record into DB..."); + await db.insert(propertyStatusTracker).values({ + hubspotDealId, + propertyId, + portfolioId, + createdAt: new Date(), + updatedAt: new Date(), + }); + + console.log("✅ All done — returning success response"); + return NextResponse.json({ - message: existing.length > 0 ? "Updated existing tracker" : "Created new tracker", + message: "Created new tracker, HubSpot deal, and linked contact", dealId: hubspotDealId, + contactId: hubspotContactId, }); } catch (error: any) { console.error("❌ Error creating or updating HubSpot deal:", error); diff --git a/src/app/portfolio/[slug]/components/BookSurveyModal.tsx b/src/app/portfolio/[slug]/components/BookSurveyModal.tsx index 2b9deeb..2e72797 100644 --- a/src/app/portfolio/[slug]/components/BookSurveyModal.tsx +++ b/src/app/portfolio/[slug]/components/BookSurveyModal.tsx @@ -14,8 +14,8 @@ import { useState, useEffect } from "react"; import { useMutation } from "@tanstack/react-query"; import { PropertyMeta } from "@/app/db/schema/property"; import { cache } from "react"; -import { getServerSession } from "next-auth"; -import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { useSession } from "next-auth/react"; + interface BookSurveyModalProps { open: boolean; @@ -26,10 +26,6 @@ interface BookSurveyModalProps { onSuccess?: () => void; // ✅ fix: properly declare optional callback } -const getSession = cache(async () => { - const session = await getServerSession(AuthOptions); - return session; -}); export default function BookSurveyModal({ open, @@ -39,9 +35,9 @@ export default function BookSurveyModal({ propertyMeta, onSuccess, // ✅ fix: remove “?:” here, we already declared it optional in interface }: BookSurveyModalProps) { + const { data: session, status } = useSession(); - const user = getSession(); - console.log(user, "user details"); + const user = session?.user; // 🧠 Simple mutation to call your HubSpot API @@ -51,11 +47,12 @@ export default function BookSurveyModal({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - dealName: propertyMeta.address, pipelineId: "2400089278", dealStageId: "3660660975", propertyId: propertyId.toString(), portfolioId: portfolioId, + userInfo: user, + propertyMeta: propertyMeta, }), });