mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
recovering from merge missing files, adding Hubspot sync capabilities
This commit is contained in:
parent
9a13e0bf3f
commit
6056214039
7 changed files with 174 additions and 1 deletions
|
|
@ -10,6 +10,7 @@ import { and, eq, inArray, sql } from "drizzle-orm";
|
|||
import { z } from "zod";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { syncMeasureApprovalsToHubSpot } from "@/app/lib/hubspot/dealSync";
|
||||
|
||||
async function getRequestingUserId(email: string): Promise<bigint | null> {
|
||||
const rows = await db
|
||||
|
|
@ -204,6 +205,31 @@ export async function POST(
|
|||
});
|
||||
}
|
||||
|
||||
const affectedDealIds = [...new Set(body.changes.map((c) => c.hubspotDealId))];
|
||||
for (const dealId of affectedDealIds) {
|
||||
const approvalRows = await db
|
||||
.select({
|
||||
measureName: dealMeasureApprovals.measureName,
|
||||
approvedByEmail: user.email,
|
||||
})
|
||||
.from(dealMeasureApprovals)
|
||||
.leftJoin(user, eq(user.id, dealMeasureApprovals.approvedBy))
|
||||
.where(
|
||||
and(
|
||||
eq(dealMeasureApprovals.hubspotDealId, dealId),
|
||||
eq(dealMeasureApprovals.isApproved, true),
|
||||
),
|
||||
);
|
||||
|
||||
void syncMeasureApprovalsToHubSpot({
|
||||
hubspotDealId: dealId,
|
||||
approvedMeasures: approvalRows.map((r) => ({
|
||||
measureName: r.measureName,
|
||||
approvedByEmail: r.approvedByEmail ?? "unknown",
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error("POST /approvals error:", err);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { and, eq, desc } from "drizzle-orm";
|
|||
import { z } from "zod";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { syncRemovalRequestToHubSpot } from "@/app/lib/hubspot/dealSync";
|
||||
|
||||
const WRITE_ROLES = ["creator", "admin", "write"] as const;
|
||||
|
||||
|
|
@ -204,6 +205,13 @@ export async function POST(
|
|||
})
|
||||
.returning();
|
||||
|
||||
void syncRemovalRequestToHubSpot({
|
||||
hubspotDealId,
|
||||
status: "pending",
|
||||
reason,
|
||||
requestedByEmail: requestingUser.email,
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, id: String(inserted.id) });
|
||||
} catch (err) {
|
||||
console.error("[removal-requests POST]", err);
|
||||
|
|
@ -258,8 +266,15 @@ export async function PATCH(
|
|||
|
||||
try {
|
||||
const target = await db
|
||||
.select({ id: propertyRemovalRequests.id, status: propertyRemovalRequests.status })
|
||||
.select({
|
||||
id: propertyRemovalRequests.id,
|
||||
status: propertyRemovalRequests.status,
|
||||
hubspotDealId: propertyRemovalRequests.hubspotDealId,
|
||||
reason: propertyRemovalRequests.reason,
|
||||
requestedByEmail: user.email,
|
||||
})
|
||||
.from(propertyRemovalRequests)
|
||||
.innerJoin(user, eq(user.id, propertyRemovalRequests.requestedBy))
|
||||
.where(eq(propertyRemovalRequests.id, BigInt(requestId)))
|
||||
.limit(1);
|
||||
|
||||
|
|
@ -283,6 +298,14 @@ export async function PATCH(
|
|||
})
|
||||
.where(eq(propertyRemovalRequests.id, BigInt(requestId)));
|
||||
|
||||
void syncRemovalRequestToHubSpot({
|
||||
hubspotDealId: target[0].hubspotDealId,
|
||||
status: action,
|
||||
reason: target[0].reason,
|
||||
requestedByEmail: target[0].requestedByEmail,
|
||||
reviewedByEmail: requestingUser.email,
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error("[removal-requests PATCH]", err);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { eq, inArray } from "drizzle-orm";
|
|||
import { z } from "zod";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { syncContractorDocUploadToHubSpot } from "@/app/lib/hubspot/dealSync";
|
||||
|
||||
// POST — record a contractor install document in uploaded_files (fileType optional — can be classified later)
|
||||
export async function POST(req: NextRequest) {
|
||||
|
|
@ -56,6 +57,15 @@ export async function POST(req: NextRequest) {
|
|||
})
|
||||
.returning({ id: uploadedFiles.id });
|
||||
|
||||
if (body.hubspotDealId) {
|
||||
void syncContractorDocUploadToHubSpot({
|
||||
hubspotDealId: body.hubspotDealId,
|
||||
fileType: body.fileType ?? null,
|
||||
measureName: body.measureName ?? null,
|
||||
uploadedByEmail: session.user.email,
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ id: inserted.id.toString() }, { status: 201 });
|
||||
} catch (err) {
|
||||
console.error("POST /upload/contractor-install error:", err);
|
||||
|
|
|
|||
14
src/app/lib/hubspot/client.ts
Normal file
14
src/app/lib/hubspot/client.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Client } from "@hubspot/api-client";
|
||||
|
||||
let _client: Client | null = null;
|
||||
|
||||
export function getHubSpotClient(): Client {
|
||||
if (!_client) {
|
||||
const accessToken = process.env.HUBSPOT_API_KEY;
|
||||
if (!accessToken) {
|
||||
throw new Error("HUBSPOT_API_KEY environment variable is not set");
|
||||
}
|
||||
_client = new Client({ accessToken });
|
||||
}
|
||||
return _client;
|
||||
}
|
||||
96
src/app/lib/hubspot/dealSync.ts
Normal file
96
src/app/lib/hubspot/dealSync.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import { getHubSpotClient } from "./client";
|
||||
|
||||
export async function syncRemovalRequestToHubSpot(params: {
|
||||
hubspotDealId: string;
|
||||
status: "pending" | "approved" | "declined";
|
||||
reason: string;
|
||||
requestedByEmail: string;
|
||||
reviewedByEmail?: string | null;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const client = getHubSpotClient();
|
||||
|
||||
const statusLabel =
|
||||
params.status === "pending"
|
||||
? "Removal Request In Progress"
|
||||
: params.status === "approved"
|
||||
? "Removed From Project"
|
||||
: "";
|
||||
|
||||
let log = `Requested by: ${params.requestedByEmail}\nReason: ${params.reason}`;
|
||||
if (params.reviewedByEmail) {
|
||||
const action = params.status === "approved" ? "Approved" : "Declined";
|
||||
log += `\n${action} by: ${params.reviewedByEmail}`;
|
||||
}
|
||||
|
||||
await client.crm.deals.basicApi.update(params.hubspotDealId, {
|
||||
properties: {
|
||||
project_removal_status: statusLabel,
|
||||
project_removal_request_log: log,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[HubSpot] syncRemovalRequestToHubSpot failed", {
|
||||
dealId: params.hubspotDealId,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncContractorDocUploadToHubSpot(params: {
|
||||
hubspotDealId: string;
|
||||
fileType: string | null;
|
||||
measureName: string | null;
|
||||
uploadedByEmail: string;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const client = getHubSpotClient();
|
||||
|
||||
const log = [
|
||||
`File type: ${params.fileType ?? "unclassified"}`,
|
||||
`Measure: ${params.measureName ?? "N/A"}`,
|
||||
`Uploaded by: ${params.uploadedByEmail}`,
|
||||
].join("\n");
|
||||
|
||||
await client.crm.deals.basicApi.update(params.hubspotDealId, {
|
||||
properties: {
|
||||
contractor_document_upload_log: log,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[HubSpot] syncContractorDocUploadToHubSpot failed", {
|
||||
dealId: params.hubspotDealId,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncMeasureApprovalsToHubSpot(params: {
|
||||
hubspotDealId: string;
|
||||
approvedMeasures: Array<{ measureName: string; approvedByEmail: string }>;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const client = getHubSpotClient();
|
||||
|
||||
const log =
|
||||
params.approvedMeasures.length === 0
|
||||
? "No measures currently approved"
|
||||
: [
|
||||
"Approved measures:",
|
||||
...params.approvedMeasures.map(
|
||||
(m) => `- ${m.measureName} (approved by ${m.approvedByEmail})`,
|
||||
),
|
||||
].join("\n");
|
||||
|
||||
await client.crm.deals.basicApi.update(params.hubspotDealId, {
|
||||
properties: {
|
||||
client_measures_approval_log: log,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[HubSpot] syncMeasureApprovalsToHubSpot failed", {
|
||||
dealId: params.hubspotDealId,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { UsersPermissionsCard } from "../UsersPermissionsCard";
|
||||
import { CapabilitiesCard } from "../CapabilitiesCard";
|
||||
|
||||
export default async function UserAccessPage(props: {
|
||||
params: Promise<{ slug: string }>;
|
||||
|
|
@ -8,6 +9,7 @@ export default async function UserAccessPage(props: {
|
|||
return (
|
||||
<div>
|
||||
<UsersPermissionsCard portfolioId={slug} />
|
||||
<CapabilitiesCard portfolioId={slug} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,6 +217,8 @@ export default function LiveTracker({
|
|||
data={currentProject?.allDeals ?? []}
|
||||
onOpenDrawer={handleOpenDrawer}
|
||||
docStatusMap={docStatusMap}
|
||||
portfolioId={portfolioId}
|
||||
userCapability={userCapability}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue