diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/ActivityLog.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/ActivityLog.tsx
new file mode 100644
index 0000000..c43e2e1
--- /dev/null
+++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/ActivityLog.tsx
@@ -0,0 +1,82 @@
+"use client";
+
+import { useQuery } from "@tanstack/react-query";
+
+type AuditEvent = {
+ id: string;
+ hubspotDealId: string;
+ measureName: string;
+ action: string;
+ actedByEmail: string;
+ actedByName: string | null;
+ actedAt: string;
+};
+
+function formatDate(iso: string) {
+ return new Date(iso).toLocaleString("en-GB", {
+ day: "numeric",
+ month: "short",
+ year: "numeric",
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+}
+
+export function ActivityLog({
+ dealId,
+ portfolioId,
+}: {
+ dealId: string;
+ portfolioId: string;
+}) {
+ const { data, isLoading } = useQuery<{ events: AuditEvent[] }>({
+ queryKey: ["approvalEvents", portfolioId, dealId],
+ queryFn: async () => {
+ const res = await fetch(
+ `/api/portfolio/${portfolioId}/approvals?dealIds=${dealId}&include=events`,
+ );
+ if (!res.ok) throw new Error("Failed to fetch events");
+ return res.json();
+ },
+ staleTime: 30_000,
+ });
+
+ if (isLoading) {
+ return (
+
Loading activity…
+ );
+ }
+
+ const events = data?.events ?? [];
+
+ if (events.length === 0) {
+ return (
+ No activity yet.
+ );
+ }
+
+ return (
+
+ {events.map((e) => (
+
+
+ {e.action === "approved" ? "Approved" : "Unapproved"}
+
+ {e.measureName}
+ ·
+
+ {e.actedByName ?? e.actedByEmail}
+
+ ·
+ {formatDate(e.actedAt)}
+
+ ))}
+
+ );
+}
diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/MeasuresTable.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/MeasuresTable.tsx
index b25dd5d..89fc210 100644
--- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/MeasuresTable.tsx
+++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/MeasuresTable.tsx
@@ -2,7 +2,6 @@
import React, { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
-import { useQuery } from "@tanstack/react-query";
import {
Table,
TableBody,
@@ -17,16 +16,7 @@ import { Search, ChevronDown, ChevronRight } from "lucide-react";
import { STAGE_COLORS } from "./types";
import type { ClassifiedDeal, ApprovalsByDeal } from "./types";
import { parseMeasures } from "@/app/lib/parseMeasures";
-
-type AuditEvent = {
- id: string;
- hubspotDealId: string;
- measureName: string;
- action: string; // 'approved' | 'unapproved'
- actedByEmail: string;
- actedByName: string | null;
- actedAt: string; // ISO string
-};
+import { ActivityLog } from "./ActivityLog";
type Props = {
data: ClassifiedDeal[];
@@ -66,75 +56,6 @@ function ApprovalStatus({
);
}
-function formatDate(iso: string) {
- return new Date(iso).toLocaleString("en-GB", {
- day: "numeric",
- month: "short",
- year: "numeric",
- hour: "2-digit",
- minute: "2-digit",
- });
-}
-
-function ActivityLog({
- dealId,
- portfolioId,
-}: {
- dealId: string;
- portfolioId: string;
-}) {
- const { data, isLoading } = useQuery<{ events: AuditEvent[] }>({
- queryKey: ["approvalEvents", portfolioId, dealId],
- queryFn: async () => {
- const res = await fetch(
- `/api/portfolio/${portfolioId}/approvals?dealIds=${dealId}&include=events`,
- );
- if (!res.ok) throw new Error("Failed to fetch events");
- return res.json();
- },
- staleTime: 30_000,
- });
-
- if (isLoading) {
- return (
- Loading activity…
- );
- }
-
- const events = data?.events ?? [];
-
- if (events.length === 0) {
- return (
- No activity yet.
- );
- }
-
- return (
-
- {events.map((e) => (
-
-
- {e.action === "approved" ? "Approved" : "Unapproved"}
-
- {e.measureName}
- ·
-
- {e.actedByName ?? e.actedByEmail}
-
- ·
- {formatDate(e.actedAt)}
-
- ))}
-
- );
-}
-
export default function MeasuresTable({
data,
approvalsByDeal,
diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx
index 4f90bb7..469e037 100644
--- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx
+++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx
@@ -1,5 +1,6 @@
"use client";
+import { ActivityLog } from "./ActivityLog";
import { useEffect, useMemo, useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { X, CheckCircle2, Circle, AlertTriangle, ChevronRight, ChevronDown, Trash2, RotateCcw, Loader2 } from "lucide-react";
@@ -516,13 +517,7 @@ export function SurveyRequestSection({
);
}
-// -----------------------------------------------------------------------
-// Approval log placeholder (expand into a real implementation as needed)
-// -----------------------------------------------------------------------
-export function ApprovalLogSection({ dealId, portfolioId }: { dealId: string; portfolioId: string }) {
- void dealId; void portfolioId;
- return No approvals recorded.
;
-}
+export const ApprovalLogSection = ActivityLog;
function formatDateTime(d: string | Date | null | undefined): string {
if (!d) return "";