mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Merge pull request #113 from Hestia-Homes/feature/book-a-survey-with-information-of-contact
Feature/book a survey with information of contact
This commit is contained in:
commit
040b13dd57
4 changed files with 199 additions and 51 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ export function Toolbar({
|
|||
const [openModal, setOpenModal] = useState(false);
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
|
||||
console.log(propertyId, "PropertyID")
|
||||
console.log(portfolioId, "porfolio id")
|
||||
console.log(propertyMeta, "property meta")
|
||||
console.log(decentHomes, "decent homes")
|
||||
|
||||
function handleClickSettings() {
|
||||
console.log("Settings were clicked, implement me");
|
||||
}
|
||||
|
|
@ -175,7 +180,7 @@ export function Toolbar({
|
|||
onOpenChange={setOpenModal}
|
||||
propertyId={BigInt(propertyId)}
|
||||
portfolioId={portfolioId}
|
||||
address={propertyMeta.address}
|
||||
propertyMeta={propertyMeta}
|
||||
onSuccess={() => setShowToast(true)}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export default async function DashboardLayout(props: {
|
|||
|
||||
const propertyId = params.propertyId ?? "";
|
||||
const portfolioId = params.slug ?? "";
|
||||
|
||||
|
||||
// The layout is a server component by default so we can fetch meta data here
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
|
|
|
|||
|
|
@ -12,24 +12,34 @@ import { Input } from "@/app/shadcn_components/ui/input";
|
|||
import { Label } from "@/app/shadcn_components/ui/label";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { PropertyMeta } from "@/app/db/schema/property";
|
||||
import { cache } from "react";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
|
||||
interface BookSurveyModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
propertyId: bigint;
|
||||
portfolioId: string;
|
||||
address: string;
|
||||
propertyMeta: PropertyMeta;
|
||||
onSuccess?: () => void; // ✅ fix: properly declare optional callback
|
||||
}
|
||||
|
||||
|
||||
export default function BookSurveyModal({
|
||||
open,
|
||||
onOpenChange,
|
||||
propertyId,
|
||||
portfolioId,
|
||||
address,
|
||||
propertyMeta,
|
||||
onSuccess, // ✅ fix: remove “?:” here, we already declared it optional in interface
|
||||
}: BookSurveyModalProps) {
|
||||
const { data: session, status } = useSession();
|
||||
|
||||
const user = session?.user;
|
||||
|
||||
|
||||
// 🧠 Simple mutation to call your HubSpot API
|
||||
const bookSurveyMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
|
|
@ -37,11 +47,12 @@ export default function BookSurveyModal({
|
|||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
dealName: address,
|
||||
pipelineId: "2400089278",
|
||||
dealStageId: "3660660975",
|
||||
propertyId: propertyId.toString(),
|
||||
portfolioId: portfolioId,
|
||||
userInfo: user,
|
||||
propertyMeta: propertyMeta,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue