This commit is contained in:
Jun-te Kim 2025-10-31 12:52:37 +00:00
parent 276b23a900
commit 4d61224cf3
3 changed files with 114 additions and 36 deletions

View file

@ -50,7 +50,7 @@ export function Toolbar({ portfolioId, scenarios }: ToolbarProps) {
}
function handleClickProgressReport() {
router.push(`/portfolio/${portfolioId}/reports`);
router.push(`/portfolio/${portfolioId}/live-projects`);
}
const [modalIsOpen, setModalIsOpen] = useState(false);

View file

@ -9,7 +9,10 @@ interface ReportsProps {
deals: Record<string, any>[];
}
export default function Reports({ deals }: ReportsProps) {
// 🟩 Stage mapping: “Major Condition Issues” = dealstage 3061261536
const MAJOR_CONDITION_STAGE_ID = "3061261536";
export default function LiveTracker({ deals }: ReportsProps) {
const [openTable, setOpenTable] = useState<{
stage: string;
data: any[];
@ -39,46 +42,120 @@ export default function Reports({ deals }: ReportsProps) {
const [currentProjectCode, setCurrentProjectCode] = useState(projectCodes[0]);
const currentDeals = groupedDeals[currentProjectCode];
// 🔹 Compute overall summary (across all projects)
const totalProperties = deals.length;
const majorConditionDeals = deals.filter(
(d) => d.dealstage === MAJOR_CONDITION_STAGE_ID
);
const majorIssues = majorConditionDeals.length;
const majorPercent = ((majorIssues / totalProperties) * 100).toFixed(1);
// 🔹 Click handlers
const handleTotalClick = () => {
console.log("Opening all deals (global)");
handleOpenTable("All Properties", deals);
};
const handleMajorClick = () => {
console.log("Opening all Major Condition Issues (global)");
handleOpenTable("Major Condition Issues", majorConditionDeals);
};
return (
<div className="p-6 space-y-6">
{/* 🔹 Centered Dropdown Selector for Projects */}
<div className="flex flex-col items-center gap-4">
<h2 className="text-xl font-semibold text-gray-800">
Select Project
</h2>
<div className="p-6 space-y-8">
{/* 🔹 Global Overview Row */}
<div className="border rounded-xl bg-gray-50 shadow-sm p-6 space-y-4">
<h2 className="text-lg font-semibold text-gray-700 text-center uppercase tracking-wide">
🌍 Global Portfolio Overview
</h2>
<div className="relative w-full max-w-xs">
<select
value={currentProjectCode}
onChange={(e) => setCurrentProjectCode(e.target.value)}
className="w-full appearance-none px-4 py-2 pr-10 border border-gray-300 rounded-lg bg-white text-center text-gray-800 shadow-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
>
{projectCodes.map((code) => (
<option key={code} value={code}>
{code}
</option>
))}
</select>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 items-center text-center">
{/* Total Properties */}
<button
onClick={handleTotalClick}
className="group transition rounded-lg border border-transparent hover:border-blue-500 hover:bg-blue-50 p-4 cursor-pointer"
>
<p className="text-sm text-gray-500 uppercase tracking-wide">
Total Properties
</p>
<p className="text-2xl font-semibold text-gray-800 group-hover:text-blue-600">
{totalProperties}
</p>
</button>
{/* Custom dropdown arrow */}
<div className="pointer-events-none absolute inset-y-0 right-3 flex items-center text-gray-500">
</div>
</div>
</div>
{/* Major Condition Issues */}
<button
onClick={handleMajorClick}
className="group transition rounded-lg border border-transparent hover:border-red-500 hover:bg-red-50 p-4 cursor-pointer"
>
<p className="text-sm text-gray-500 uppercase tracking-wide">
Major Condition Issues
</p>
<p className="text-2xl font-semibold text-red-600 group-hover:text-red-700">
{majorIssues}{" "}
<span className="text-gray-500 text-base font-normal">
({majorPercent}%)
</span>
</p>
</button>
{/* Charts */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="border rounded-xl p-4 shadow-sm bg-white">
<DealStageChart deals={currentDeals} onOpenTable={handleOpenTable} />
</div>
<div className="border rounded-xl p-4 shadow-sm bg-white">
<SurveyedPieChart deals={currentDeals} onOpenTable={handleOpenTable} />
{/* Project Dropdown Selector */}
<div>
<label
htmlFor="projectSelect"
className="block text-sm font-medium text-gray-700 mb-1"
>
Select Project
</label>
<div className="relative max-w-xs mx-auto">
<select
id="projectSelect"
value={currentProjectCode}
onChange={(e) => setCurrentProjectCode(e.target.value)}
className="w-full appearance-none px-4 py-2 pr-10 border border-gray-300 rounded-lg bg-white text-gray-800 shadow-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
>
{projectCodes.map((code) => (
<option key={code} value={code}>
{code}
</option>
))}
</select>
{/* Custom dropdown arrow */}
<div className="pointer-events-none absolute inset-y-0 right-3 flex items-center text-gray-500">
</div>
</div>
</div>
</div>
</div>
<div className="text-center text-gray-500 text-sm">
Showing project <span className="font-medium">{currentProjectCode}</span>
{/* 🔹 Project-Level Section */}
<div className="border rounded-xl bg-gray-50 shadow-sm p-6 space-y-4">
<h2 className="text-lg font-semibold text-gray-700 text-center uppercase tracking-wide">
📊 Project-Level Insights
</h2>
<p className="text-center text-gray-500 text-sm -mt-2">
Showing data for{" "}
<span className="font-medium text-gray-700">
{currentProjectCode}
</span>
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="border rounded-xl p-4 shadow-sm bg-white">
<DealStageChart
deals={currentDeals}
onOpenTable={handleOpenTable}
/>
</div>
<div className="border rounded-xl p-4 shadow-sm bg-white">
<SurveyedPieChart
deals={currentDeals}
onOpenTable={handleOpenTable}
/>
</div>
</div>
</div>
{/* 🔹 Modal Table */}

View file

@ -5,6 +5,7 @@ import { surveyDB } from "../../../../db/surveyDB/connection";
import { hubspotDealData } from "../../../../db/schema/crm/hubspot_deal_table";
import { eq } from "drizzle-orm";
import Reports from "./Report";
import LiveTracker from "./Report";
const Demo = async () => {
const user = await getServerSession(AuthOptions);
@ -25,7 +26,7 @@ const Demo = async () => {
return (
<>
<Reports deals={deals} />
<LiveTracker deals={deals} />
</>
);
};