2eaac6b84a
- Add Owner, Contractor, Vendor, Subcontractor dashboards and role-based routing - Owner now has superuser access to all Admin pages (dashboard, schedule, leaderboard) - Redesign landing page mobile menu as slide-in sidebar (replaces broken Framer Motion overlay) - Add body scroll lock to app sidebar for mobile consistency - Fix Team Schedule to match Admin Dashboard design language (ambient glows, gradient header, SpotlightCard, zinc palette) - Fix login page tab overflow — use abbreviated labels and grid layout for 6 role tabs - Fix Recharts ResponsiveContainer warnings — replace height="100%" with fixed pixel heights - Fix lightbox image viewer — unified nav bar, touch swipe support, no more overlapping text - Add AI Assistant page, People/Vendor/Document management for Owner role - Expand mock data store with contractor, vendor, and subcontractor data
83 lines
3.9 KiB
React
83 lines
3.9 KiB
React
import React, { useMemo } from 'react';
|
|
import { ScatterChart, Scatter, XAxis, YAxis, Tooltip, ResponsiveContainer, ZAxis } from 'recharts';
|
|
import { SpotlightCard } from '../SpotlightCard';
|
|
import { InfoTooltip } from '../InfoTooltip';
|
|
|
|
const CustomTooltip = ({ active, payload }) => {
|
|
if (active && payload && payload.length) {
|
|
const data = payload[0].payload;
|
|
return (
|
|
<div className="bg-zinc-900/90 border border-zinc-700/50 p-3 rounded-lg shadow-xl backdrop-blur-md z-50">
|
|
<p className="text-zinc-100 font-bold mb-1">{data.address}</p>
|
|
<p className="text-zinc-400 text-xs">Built: {data.year}</p>
|
|
<p className="text-emerald-400 text-xs">Value: ${data.value.toLocaleString()}</p>
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const GoldenLeadsScatter = ({ properties }) => {
|
|
const data = useMemo(() => {
|
|
return properties.map(p => ({
|
|
x: p.propertyData.yearBuilt,
|
|
y: p.propertyData.currentEstimatedMarketValue,
|
|
z: 100, // bubble size
|
|
address: p.propertyData.propertyAddress.split(',')[0],
|
|
year: p.propertyData.yearBuilt,
|
|
value: p.propertyData.currentEstimatedMarketValue,
|
|
isGolden: p.propertyData.yearBuilt < 2000 && p.propertyData.currentEstimatedMarketValue > 400000
|
|
}));
|
|
}, [properties]);
|
|
|
|
return (
|
|
<SpotlightCard className="h-full flex flex-col">
|
|
<div className="p-6 flex-1 flex flex-col">
|
|
<div className="mb-4 flex justify-between items-start">
|
|
<div>
|
|
<h3 className="text-lg font-bold text-zinc-900 dark:text-white flex items-center">
|
|
Golden Leads
|
|
<InfoTooltip text="High-value properties built before 2000. These are prime candidates for renovation and modernization." />
|
|
</h3>
|
|
<p className="text-xs text-zinc-500 dark:text-zinc-400">High Value + Older Homes</p>
|
|
</div>
|
|
<div className="bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 text-[10px] px-2 py-1 rounded font-bold uppercase tracking-wider">
|
|
Opportunity Zone
|
|
</div>
|
|
</div>
|
|
|
|
<div className="w-full">
|
|
<ResponsiveContainer width="100%" height={200}>
|
|
<ScatterChart
|
|
margin={{ top: 20, right: 20, bottom: 20, left: 0 }}
|
|
>
|
|
<XAxis
|
|
type="number"
|
|
dataKey="x"
|
|
name="Year Built"
|
|
domain={['auto', 'auto']}
|
|
tick={{ fill: '#71717a', fontSize: 10 }}
|
|
tickCount={5}
|
|
axisLine={false}
|
|
tickLine={false}
|
|
/>
|
|
<YAxis
|
|
type="number"
|
|
dataKey="y"
|
|
name="Value"
|
|
unit="$"
|
|
tick={{ fill: '#71717a', fontSize: 10 }}
|
|
tickFormatter={(value) => `${value / 1000}k`}
|
|
axisLine={false}
|
|
tickLine={false}
|
|
/>
|
|
<Tooltip content={<CustomTooltip />} cursor={{ strokeDasharray: '3 3' }} />
|
|
<Scatter name="Properties" data={data} fill="#eab308" shape="circle" />
|
|
</ScatterChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</div>
|
|
</SpotlightCard>
|
|
);
|
|
};
|