fix(ui): light mode color corrections for LeadProjectPage and OwnerProjectDetail
- Replace hardcoded dark-only NEO_PANEL_CLASS bg with dark: prefixed variants so SpotlightCard's bg-white shows through in light mode - Add light mode fallbacks to all NEON color constants (sky/amber/orange/green/red solid colors replace neon glows) - Fix progress bar and stepper tracks from bg-black/80 to bg-zinc-200 dark:bg-black/80 - Update stepper node colors to use theme-aware border/text/bg classes - Fix all section header text-white → text-zinc-900 dark:text-white throughout NeoCard content - Replace bg-black/30, bg-white/[0.03], border-white/5, divide-white/5 inner elements with light mode equivalents - Fix table headers (bg-[#18181b]/80 → bg-zinc-100 dark:), row hover states, and body text colors - Fix action buttons, doc rows, timeline items, and activity feed for proper light mode rendering
This commit is contained in:
@@ -19,11 +19,11 @@ import {
|
||||
} from 'lucide-react';
|
||||
|
||||
// ── Neomorphic constants (mirrors OwnerProjectDetail) ─────────────────────────
|
||||
const NEO_PANEL_CLASS = "bg-zinc-900/60 backdrop-blur-3xl border border-white/5 shadow-[8px_8px_16px_rgba(0,0,0,0.6),-8px_-8px_16px_rgba(255,255,255,0.02)] rounded-3xl relative overflow-hidden transition-all duration-300";
|
||||
const NEON_GREEN = "text-[#39ff14] drop-shadow-[0_0_8px_rgba(57,255,20,0.4)]";
|
||||
const NEON_GOLD = "text-[#fda913] drop-shadow-[0_0_8px_rgba(253,169,19,0.4)]";
|
||||
const NEON_ORANGE = "text-[#ff4500] drop-shadow-[0_0_8px_rgba(255,69,0,0.4)]";
|
||||
const NEON_BLUE = "text-[#00f0ff] drop-shadow-[0_0_8px_rgba(0,240,255,0.4)]";
|
||||
const NEO_PANEL_CLASS = "dark:bg-zinc-900/60 dark:backdrop-blur-3xl border border-zinc-200 dark:border-white/5 dark:shadow-[8px_8px_16px_rgba(0,0,0,0.6),-8px_-8px_16px_rgba(255,255,255,0.02)] rounded-3xl relative overflow-hidden transition-all duration-300";
|
||||
const NEON_GREEN = "text-green-600 dark:text-[#39ff14] dark:drop-shadow-[0_0_8px_rgba(57,255,20,0.4)]";
|
||||
const NEON_GOLD = "text-amber-600 dark:text-[#fda913] dark:drop-shadow-[0_0_8px_rgba(253,169,19,0.4)]";
|
||||
const NEON_ORANGE = "text-orange-600 dark:text-[#ff4500] dark:drop-shadow-[0_0_8px_rgba(255,69,0,0.4)]";
|
||||
const NEON_BLUE = "text-sky-600 dark:text-[#00f0ff] dark:drop-shadow-[0_0_8px_rgba(0,240,255,0.4)]";
|
||||
|
||||
function formatCurrency(n) {
|
||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(n || 0);
|
||||
@@ -62,7 +62,7 @@ function NeoCard({ children, className = '', spotlightColor = 'rgba(255,255,255,
|
||||
// ── Animated progress bar ─────────────────────────────────────────────────────
|
||||
function NeoProgress({ pct, color = '#3B82F6', height = 'h-1.5' }) {
|
||||
return (
|
||||
<div className={`${height} w-full bg-black/80 rounded-full border border-white/5 relative overflow-hidden`}>
|
||||
<div className={`${height} w-full bg-zinc-200 dark:bg-black/80 rounded-full border border-zinc-200 dark:border-white/5 relative overflow-hidden`}>
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${Math.min(pct, 100)}%` }}
|
||||
@@ -83,7 +83,7 @@ function StageMoverDropdown({ lead, columns, onStageChange }) {
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setOpen(v => !v)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl border border-white/10 bg-white/5 hover:bg-white/10 text-zinc-200 text-sm font-semibold transition-colors"
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl border border-zinc-300 dark:border-white/10 bg-zinc-100 dark:bg-white/5 hover:bg-zinc-200 dark:hover:bg-white/10 text-zinc-700 dark:text-zinc-200 text-sm font-semibold transition-colors"
|
||||
>
|
||||
Move Stage <ChevronDown size={13} />
|
||||
</button>
|
||||
@@ -138,13 +138,13 @@ function StageActivityItem({ entry, isLast }) {
|
||||
isRegress ? <ArrowDownLeft size={13} style={{ color: dotColor }} /> :
|
||||
<ArrowUpRight size={13} style={{ color: dotColor }} />}
|
||||
</div>
|
||||
{!isLast && <div className="w-px flex-1 bg-white/5 my-2 min-h-[20px]" />}
|
||||
{!isLast && <div className="w-px flex-1 bg-zinc-200 dark:bg-white/5 my-2 min-h-[20px]" />}
|
||||
</div>
|
||||
<div className={`flex-1 min-w-0 ${!isLast ? 'pb-5' : ''}`}>
|
||||
<div className="bg-white/[0.03] border border-white/[0.07] rounded-xl px-4 py-3 hover:bg-white/[0.06] transition-colors">
|
||||
<div className="bg-zinc-50 dark:bg-white/[0.03] border border-zinc-200 dark:border-white/[0.07] rounded-xl px-4 py-3 hover:bg-zinc-100 dark:hover:bg-white/[0.06] transition-colors">
|
||||
<div className="mb-0.5">
|
||||
{entry.from ? (
|
||||
<p className="text-sm font-semibold text-zinc-200">
|
||||
<p className="text-sm font-semibold text-zinc-700 dark:text-zinc-200">
|
||||
<span className="text-zinc-500">{entry.from}</span>
|
||||
<ArrowRight size={12} className="inline mx-1.5 text-zinc-600" />
|
||||
<span style={{ color: dotColor }}>{entry.to}</span>
|
||||
@@ -154,7 +154,7 @@ function StageActivityItem({ entry, isLast }) {
|
||||
)}
|
||||
<p className="text-xs text-zinc-600 mt-0.5">by <span className="font-medium text-zinc-400">{entry.by}</span> · {formatDate(entry.date)}</p>
|
||||
</div>
|
||||
{entry.note && <p className="text-sm text-zinc-400 leading-relaxed mt-2 pt-2 border-t border-white/5">{entry.note}</p>}
|
||||
{entry.note && <p className="text-sm text-zinc-500 dark:text-zinc-400 leading-relaxed mt-2 pt-2 border-t border-zinc-200 dark:border-white/5">{entry.note}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -390,10 +390,10 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(0,240,255,0.1)" className="lg:col-span-2">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Milestone className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Project Progression</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Project Progression</h3>
|
||||
</div>
|
||||
<div className="relative pt-8 pb-4">
|
||||
<div className="absolute top-[38px] left-[5%] right-[5%] h-1 bg-zinc-800 rounded-full z-0" />
|
||||
<div className="absolute top-[38px] left-[5%] right-[5%] h-1 bg-zinc-200 dark:bg-zinc-800 rounded-full z-0" />
|
||||
<motion.div
|
||||
initial={{ width: 0 }} animate={{ width: `${completionPct}%` }} transition={{ duration: 1.5 }}
|
||||
className="absolute top-[38px] left-[5%] h-1 bg-gradient-to-r from-blue-600 to-[#00f0ff] rounded-full shadow-[0_0_10px_#00f0ff] z-0"
|
||||
@@ -403,10 +403,10 @@ export default function LeadProjectPage() {
|
||||
const isActive = (i * 25) <= completionPct;
|
||||
return (
|
||||
<div key={i} className="flex flex-col items-center gap-3 w-20">
|
||||
<div className={`w-8 h-8 rounded-full flex items-center justify-center border-2 shadow-lg transition-colors ${isActive ? 'bg-zinc-900 border-[#00f0ff] text-[#00f0ff] shadow-[0_0_15px_rgba(0,240,255,0.4)]' : 'bg-black border-zinc-700 text-zinc-600'}`}>
|
||||
{isActive ? <CheckCircle size={14} /> : <span className="w-2 h-2 rounded-full bg-zinc-700" />}
|
||||
<div className={`w-8 h-8 rounded-full flex items-center justify-center border-2 shadow-lg transition-colors ${isActive ? 'bg-zinc-50 dark:bg-zinc-900 border-sky-500 dark:border-[#00f0ff] text-sky-500 dark:text-[#00f0ff] dark:shadow-[0_0_15px_rgba(0,240,255,0.4)]' : 'bg-white dark:bg-black border-zinc-300 dark:border-zinc-700 text-zinc-400 dark:text-zinc-600'}`}>
|
||||
{isActive ? <CheckCircle size={14} /> : <span className="w-2 h-2 rounded-full bg-zinc-300 dark:bg-zinc-700" />}
|
||||
</div>
|
||||
<span className={`text-[10px] text-center font-bold tracking-wide uppercase leading-tight ${isActive ? 'text-white' : 'text-zinc-600'}`}>{step}</span>
|
||||
<span className={`text-[10px] text-center font-bold tracking-wide uppercase leading-tight ${isActive ? 'text-zinc-900 dark:text-white' : 'text-zinc-500 dark:text-zinc-600'}`}>{step}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -419,7 +419,7 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(253,169,19,0.08)">
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<User className={NEON_GOLD} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Contact & Contractor</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Contact & Contractor</h3>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{[
|
||||
@@ -431,11 +431,11 @@ export default function LeadProjectPage() {
|
||||
{ icon: Phone, label: 'Crew Phone', value: proj.contractorPhone },
|
||||
{ icon: Shield, label: 'Assigned Agent', value: lead.assignedAgentName },
|
||||
].map(({ icon: Icon, label, value }) => value ? (
|
||||
<div key={label} className="flex items-start gap-3 py-2 border-b border-white/[0.04] last:border-0">
|
||||
<div key={label} className="flex items-start gap-3 py-2 border-b border-zinc-100 dark:border-white/[0.04] last:border-0">
|
||||
<Icon size={13} className="text-zinc-600 shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<p className="text-[10px] text-zinc-600">{label}</p>
|
||||
<p className="text-sm text-zinc-200 font-medium">{value}</p>
|
||||
<p className="text-sm text-zinc-700 dark:text-zinc-200 font-medium">{value}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null)}
|
||||
@@ -445,7 +445,7 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(57,255,20,0.06)">
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<AlertCircle className={NEON_ORANGE} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Open Items</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Open Items</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3 mb-5">
|
||||
{[
|
||||
@@ -454,16 +454,16 @@ export default function LeadProjectPage() {
|
||||
{ label: 'Pending Invoices', count: (proj.invoices || []).filter(i => i.status === 'pending').length, color: '#00f0ff' },
|
||||
{ label: 'Milestones Done', count: (proj.milestones || []).filter(m => m.status === 'completed').length + '/' + (proj.milestones?.length || 0), color: '#39ff14' },
|
||||
].map(item => (
|
||||
<div key={item.label} className="bg-black/30 border border-white/5 rounded-2xl p-4 text-center">
|
||||
<div key={item.label} className="bg-zinc-100 dark:bg-black/30 border border-zinc-200 dark:border-white/5 rounded-2xl p-4 text-center">
|
||||
<p className="text-2xl font-black" style={{ color: item.color, fontFamily: 'Barlow Condensed, sans-serif' }}>{item.count}</p>
|
||||
<p className="text-[10px] text-zinc-600 mt-1">{item.label}</p>
|
||||
<p className="text-[10px] text-zinc-500 dark:text-zinc-600 mt-1">{item.label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{lead.notes && (
|
||||
<div className="p-4 bg-amber-500/5 border border-amber-500/10 rounded-2xl">
|
||||
<p className="text-[10px] font-bold text-amber-500/70 uppercase tracking-widest mb-1.5">Field Notes</p>
|
||||
<p className="text-sm text-zinc-300 leading-relaxed">{lead.notes}</p>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300 leading-relaxed">{lead.notes}</p>
|
||||
</div>
|
||||
)}
|
||||
</NeoCard>
|
||||
@@ -477,7 +477,7 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(59,130,246,0.08)">
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<User className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Contact</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Contact</h3>
|
||||
</div>
|
||||
{[
|
||||
{ icon: User, label: 'Name', value: lead.name },
|
||||
@@ -488,11 +488,11 @@ export default function LeadProjectPage() {
|
||||
{ icon: Shield, label: 'Category', value: lead.insuranceType },
|
||||
{ icon: User, label: 'Assigned Agent', value: lead.assignedAgentName },
|
||||
].map(({ icon: Icon, label, value }) => value ? (
|
||||
<div key={label} className="flex items-start gap-3 py-2.5 border-b border-white/[0.04] last:border-0">
|
||||
<div key={label} className="flex items-start gap-3 py-2.5 border-b border-zinc-100 dark:border-white/[0.04] last:border-0">
|
||||
<Icon size={13} className="text-zinc-600 shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<p className="text-[10px] text-zinc-600">{label}</p>
|
||||
<p className="text-sm text-zinc-200 font-medium">{value}</p>
|
||||
<p className="text-sm text-zinc-700 dark:text-zinc-200 font-medium">{value}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null)}
|
||||
@@ -501,24 +501,24 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(245,158,11,0.06)">
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<Activity className={NEON_GOLD} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Pipeline Position</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Pipeline Position</h3>
|
||||
</div>
|
||||
<NeoProgress pct={stagePct} color={currentStage?.color ?? '#3B82F6'} height="h-2" />
|
||||
<div className="flex items-center gap-0.5 flex-wrap mt-4 mb-5">
|
||||
{stageColumns.map((col, i) => (
|
||||
<React.Fragment key={col.id}>
|
||||
<span className="text-[10px] font-bold px-1.5 py-0.5 rounded transition-colors"
|
||||
style={i === stageIdx ? { color: col.color } : { color: i < stageIdx ? '#52525b' : '#27272a' }}>
|
||||
style={i === stageIdx ? { color: col.color } : { color: i < stageIdx ? '#71717a' : '#a1a1aa' }}>
|
||||
{col.name}
|
||||
</span>
|
||||
{i < stageColumns.length - 1 && <ChevronRight size={10} className="text-zinc-800 shrink-0" />}
|
||||
{i < stageColumns.length - 1 && <ChevronRight size={10} className="text-zinc-400 dark:text-zinc-800 shrink-0" />}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
{lead.notes && (
|
||||
<div className="p-4 bg-amber-500/5 border border-amber-500/10 rounded-2xl mt-auto">
|
||||
<p className="text-[10px] font-bold text-amber-500/70 uppercase tracking-widest mb-1.5">Notes</p>
|
||||
<p className="text-sm text-zinc-300 leading-relaxed">{lead.notes}</p>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300 leading-relaxed">{lead.notes}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4 p-3 bg-blue-500/5 border border-blue-500/10 rounded-xl">
|
||||
@@ -541,28 +541,28 @@ export default function LeadProjectPage() {
|
||||
{ icon: Mail, label: 'Email', value: lead.email },
|
||||
{ icon: MapPin, label: 'Address', value: lead.address },
|
||||
].map(({ icon: Icon, label, value }) => value ? (
|
||||
<div key={label} className="flex items-start gap-3 py-2.5 border-b border-white/[0.04] last:border-0">
|
||||
<div key={label} className="flex items-start gap-3 py-2.5 border-b border-zinc-100 dark:border-white/[0.04] last:border-0">
|
||||
<Icon size={13} className="text-zinc-600 shrink-0 mt-0.5" />
|
||||
<div><p className="text-[10px] text-zinc-600">{label}</p><p className="text-sm text-zinc-200 font-medium">{value}</p></div>
|
||||
<div><p className="text-[10px] text-zinc-600">{label}</p><p className="text-sm text-zinc-700 dark:text-zinc-200 font-medium">{value}</p></div>
|
||||
</div>
|
||||
) : null)}
|
||||
</NeoCard>
|
||||
<NeoCard spotlightColor="rgba(139,92,246,0.08)">
|
||||
<p className="text-[10px] font-bold text-zinc-600 uppercase tracking-widest mb-4">Quick Actions</p>
|
||||
{lead.phone && (
|
||||
<a href={`tel:${lead.phone}`} className="flex items-center gap-3 px-4 py-3 rounded-xl bg-white/5 hover:bg-white/10 border border-white/5 transition-colors mb-2">
|
||||
<Phone size={14} className="text-emerald-400" /><span className="text-sm text-zinc-300">Call {lead.phone}</span>
|
||||
<a href={`tel:${lead.phone}`} className="flex items-center gap-3 px-4 py-3 rounded-xl bg-zinc-50 dark:bg-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 border border-zinc-100 dark:border-white/5 transition-colors mb-2">
|
||||
<Phone size={14} className="text-emerald-400" /><span className="text-sm text-zinc-600 dark:text-zinc-300">Call {lead.phone}</span>
|
||||
</a>
|
||||
)}
|
||||
{lead.email && (
|
||||
<a href={`mailto:${lead.email}`} className="flex items-center gap-3 px-4 py-3 rounded-xl bg-white/5 hover:bg-white/10 border border-white/5 transition-colors mb-2">
|
||||
<Mail size={14} className="text-blue-400" /><span className="text-sm text-zinc-300">Email {lead.email}</span>
|
||||
<a href={`mailto:${lead.email}`} className="flex items-center gap-3 px-4 py-3 rounded-xl bg-zinc-50 dark:bg-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 border border-zinc-100 dark:border-white/5 transition-colors mb-2">
|
||||
<Mail size={14} className="text-blue-400" /><span className="text-sm text-zinc-600 dark:text-zinc-300">Email {lead.email}</span>
|
||||
</a>
|
||||
)}
|
||||
{lead.address && (
|
||||
<a href={`https://maps.google.com/?q=${encodeURIComponent(lead.address)}`} target="_blank" rel="noopener noreferrer"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-white/5 hover:bg-white/10 border border-white/5 transition-colors">
|
||||
<MapPin size={14} className="text-amber-400" /><span className="text-sm text-zinc-300">View on Maps</span>
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-zinc-50 dark:bg-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 border border-zinc-100 dark:border-white/5 transition-colors">
|
||||
<MapPin size={14} className="text-amber-400" /><span className="text-sm text-zinc-600 dark:text-zinc-300">View on Maps</span>
|
||||
</a>
|
||||
)}
|
||||
</NeoCard>
|
||||
@@ -592,7 +592,7 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(0,240,255,0.08)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<DollarSign className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase">Budget Breakdown</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Budget Breakdown</h3>
|
||||
</div>
|
||||
<div className="h-56">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
@@ -618,11 +618,11 @@ export default function LeadProjectPage() {
|
||||
|
||||
{/* Table */}
|
||||
<NeoCard spotlightColor="rgba(253,169,19,0.06)">
|
||||
<h3 className="text-sm font-mono font-bold text-white tracking-widest uppercase mb-5">Line Item Breakdown</h3>
|
||||
<h3 className="text-sm font-mono font-bold text-zinc-900 dark:text-white tracking-widest uppercase mb-5">Line Item Breakdown</h3>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-white/5 text-[10px] uppercase tracking-wider text-zinc-600">
|
||||
<tr className="border-b border-zinc-200 dark:border-white/5 text-[10px] uppercase tracking-wider text-zinc-500 dark:text-zinc-600">
|
||||
<th className="text-left pb-3 font-bold">Category</th>
|
||||
<th className="text-right pb-3 font-bold">Allocated</th>
|
||||
<th className="text-right pb-3 font-bold">Committed</th>
|
||||
@@ -630,12 +630,12 @@ export default function LeadProjectPage() {
|
||||
<th className="text-right pb-3 font-bold">Remaining</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/[0.04]">
|
||||
<tbody className="divide-y divide-zinc-100 dark:divide-white/[0.04]">
|
||||
{(proj.budgetBreakdown || []).map((b, i) => {
|
||||
const rem = b.allocated - b.actual;
|
||||
return (
|
||||
<tr key={i} className="hover:bg-white/[0.03] transition-colors">
|
||||
<td className="py-3 text-zinc-300 font-medium">{b.category}</td>
|
||||
<tr key={i} className="hover:bg-zinc-50 dark:hover:bg-white/[0.03] transition-colors">
|
||||
<td className="py-3 text-zinc-600 dark:text-zinc-300 font-medium">{b.category}</td>
|
||||
<td className="py-3 text-right font-mono text-zinc-400">{formatCurrency(b.allocated)}</td>
|
||||
<td className="py-3 text-right font-mono text-zinc-400">{formatCurrency(b.committed)}</td>
|
||||
<td className="py-3 text-right font-mono text-zinc-300">{formatCurrency(b.actual)}</td>
|
||||
@@ -645,11 +645,11 @@ export default function LeadProjectPage() {
|
||||
})}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr className="border-t border-white/10">
|
||||
<td className="py-3 font-bold text-white text-[11px] uppercase tracking-wider">Total</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-white">{formatCurrency(proj.estimatedAmount)}</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-white">{formatCurrency(proj.budgetBreakdown?.reduce((s, b) => s + b.committed, 0))}</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-white">{formatCurrency(proj.actualCost)}</td>
|
||||
<tr className="border-t border-zinc-200 dark:border-white/10">
|
||||
<td className="py-3 font-bold text-zinc-900 dark:text-white text-[11px] uppercase tracking-wider">Total</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-zinc-900 dark:text-white">{formatCurrency(proj.estimatedAmount)}</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-zinc-900 dark:text-white">{formatCurrency(proj.budgetBreakdown?.reduce((s, b) => s + b.committed, 0))}</td>
|
||||
<td className="py-3 text-right font-mono font-bold text-zinc-900 dark:text-white">{formatCurrency(proj.actualCost)}</td>
|
||||
<td className={`py-3 text-right font-mono font-bold ${(proj.estimatedAmount - proj.actualCost) >= 0 ? 'text-emerald-400' : 'text-red-400'}`}>
|
||||
{formatCurrency(proj.estimatedAmount - proj.actualCost)}
|
||||
</td>
|
||||
@@ -666,7 +666,7 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(57,255,20,0.08)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Milestone className={NEON_GREEN} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Project Milestones</h3>
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Project Milestones</h3>
|
||||
<span className="text-xs text-zinc-600 ml-auto">
|
||||
{(proj.milestones || []).filter(m => m.status === 'completed').length} / {proj.milestones?.length || 0} complete
|
||||
</span>
|
||||
@@ -675,15 +675,15 @@ export default function LeadProjectPage() {
|
||||
{(proj.milestones || []).map((m, i) => {
|
||||
const dotColor = m.status === 'completed' ? '#39ff14' : m.status === 'in_progress' ? '#00f0ff' : '#3f3f46';
|
||||
return (
|
||||
<div key={m.id} className="flex items-start gap-4 p-4 rounded-2xl bg-white/[0.03] border border-white/[0.06] hover:bg-white/[0.06] transition-colors">
|
||||
<div className={`w-4 h-4 rounded-full mt-0.5 shrink-0 shadow-[0_0_8px_currentColor]`} style={{ backgroundColor: dotColor, color: dotColor }} />
|
||||
<div key={m.id} className="flex items-start gap-4 p-4 rounded-2xl bg-zinc-50 dark:bg-white/[0.03] border border-zinc-100 dark:border-white/[0.06] hover:bg-zinc-100 dark:hover:bg-white/[0.06] transition-colors">
|
||||
<div className={`w-4 h-4 rounded-full mt-0.5 shrink-0`} style={{ backgroundColor: dotColor }} />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="font-semibold text-zinc-200 text-sm">{m.name}</p>
|
||||
<p className="font-semibold text-zinc-700 dark:text-zinc-200 text-sm">{m.name}</p>
|
||||
<span className={`text-[10px] font-bold uppercase px-2 py-0.5 rounded-full ${
|
||||
m.status === 'completed' ? 'bg-emerald-500/15 text-emerald-400' :
|
||||
m.status === 'in_progress' ? 'bg-blue-500/15 text-blue-400' :
|
||||
'bg-zinc-800 text-zinc-600'
|
||||
m.status === 'completed' ? 'bg-emerald-500/15 text-emerald-600 dark:text-emerald-400' :
|
||||
m.status === 'in_progress' ? 'bg-blue-500/15 text-blue-600 dark:text-blue-400' :
|
||||
'bg-zinc-200 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-600'
|
||||
}`}>{m.status.replace('_', ' ')}</span>
|
||||
</div>
|
||||
{m.date && <p className="text-xs text-zinc-600 mt-0.5">{formatDate(m.date)}</p>}
|
||||
@@ -701,8 +701,8 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(253,169,19,0.08)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<GitPullRequest className={NEON_GOLD} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Change Orders</h3>
|
||||
<span className="text-xs font-bold bg-white/5 border border-white/5 px-2 py-0.5 rounded-full text-zinc-400 ml-auto">
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Change Orders</h3>
|
||||
<span className="text-xs font-bold bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/5 px-2 py-0.5 rounded-full text-zinc-500 dark:text-zinc-400 ml-auto">
|
||||
{proj.changeOrders?.length || 0}
|
||||
</span>
|
||||
</div>
|
||||
@@ -714,9 +714,9 @@ export default function LeadProjectPage() {
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{proj.changeOrders.map(co => (
|
||||
<div key={co.id} className="p-4 rounded-2xl bg-white/[0.03] border border-white/[0.06] hover:bg-white/[0.06] transition-colors">
|
||||
<div key={co.id} className="p-4 rounded-2xl bg-zinc-50 dark:bg-white/[0.03] border border-zinc-100 dark:border-white/[0.06] hover:bg-zinc-100 dark:hover:bg-white/[0.06] transition-colors">
|
||||
<div className="flex items-start justify-between gap-2 mb-2">
|
||||
<p className="font-semibold text-zinc-200 text-sm">{co.title}</p>
|
||||
<p className="font-semibold text-zinc-700 dark:text-zinc-200 text-sm">{co.title}</p>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<span className={`text-[10px] font-bold px-2 py-0.5 rounded-full uppercase ${co.status === 'approved' ? 'bg-emerald-500/15 text-emerald-400' : co.status === 'rejected' ? 'bg-red-500/15 text-red-400' : 'bg-amber-500/15 text-amber-400'}`}>
|
||||
{co.status}
|
||||
@@ -738,8 +738,8 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(255,69,0,0.08)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<FileText className={NEON_ORANGE} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Requests for Information</h3>
|
||||
<span className="text-xs font-bold bg-white/5 border border-white/5 px-2 py-0.5 rounded-full text-zinc-400 ml-auto">
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Requests for Information</h3>
|
||||
<span className="text-xs font-bold bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/5 px-2 py-0.5 rounded-full text-zinc-500 dark:text-zinc-400 ml-auto">
|
||||
{proj.rfis?.length || 0}
|
||||
</span>
|
||||
</div>
|
||||
@@ -751,7 +751,7 @@ export default function LeadProjectPage() {
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="border-b border-white/5 text-[10px] uppercase tracking-wider text-zinc-600">
|
||||
<thead className="border-b border-zinc-200 dark:border-white/5 text-[10px] uppercase tracking-wider text-zinc-500 dark:text-zinc-600">
|
||||
<tr>
|
||||
<th className="text-left pb-3 font-bold">ID</th>
|
||||
<th className="text-left pb-3 font-bold">Subject</th>
|
||||
@@ -761,11 +761,11 @@ export default function LeadProjectPage() {
|
||||
<th className="text-left pb-3 font-bold">Closed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/[0.04]">
|
||||
<tbody className="divide-y divide-zinc-100 dark:divide-white/[0.04]">
|
||||
{proj.rfis.map((r, i) => (
|
||||
<tr key={r.id} className="hover:bg-white/[0.03] transition-colors">
|
||||
<tr key={r.id} className="hover:bg-zinc-50 dark:hover:bg-white/[0.03] transition-colors">
|
||||
<td className="py-3 font-mono text-zinc-500 text-xs">{r.id.toUpperCase()}</td>
|
||||
<td className="py-3 text-zinc-200 font-semibold">{r.subject}</td>
|
||||
<td className="py-3 text-zinc-700 dark:text-zinc-200 font-semibold">{r.subject}</td>
|
||||
<td className="py-3 text-center">
|
||||
<span className={`text-[10px] font-bold px-2 py-1 rounded-full uppercase ${r.status === 'closed' ? 'bg-emerald-500/15 text-emerald-400' : 'bg-amber-500/15 text-amber-400'}`}>
|
||||
{r.status}
|
||||
@@ -801,11 +801,11 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(0,240,255,0.06)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<DollarSign className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Invoice Schedule</h3>
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Invoice Schedule</h3>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="border-b border-white/5 text-[10px] uppercase tracking-wider text-zinc-600">
|
||||
<thead className="border-b border-zinc-200 dark:border-white/5 text-[10px] uppercase tracking-wider text-zinc-500 dark:text-zinc-600">
|
||||
<tr>
|
||||
<th className="text-left pb-3 font-bold">Description</th>
|
||||
<th className="text-right pb-3 font-bold">Amount</th>
|
||||
@@ -814,11 +814,11 @@ export default function LeadProjectPage() {
|
||||
<th className="text-left pb-3 font-bold">Paid</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/[0.04]">
|
||||
<tbody className="divide-y divide-zinc-100 dark:divide-white/[0.04]">
|
||||
{(proj.invoices || []).map(inv => (
|
||||
<tr key={inv.id} className="hover:bg-white/[0.03] transition-colors">
|
||||
<td className="py-3 text-zinc-300 font-medium">{inv.description}</td>
|
||||
<td className="py-3 text-right font-mono text-zinc-200 font-semibold">{formatCurrency(inv.amount)}</td>
|
||||
<tr key={inv.id} className="hover:bg-zinc-50 dark:hover:bg-white/[0.03] transition-colors">
|
||||
<td className="py-3 text-zinc-600 dark:text-zinc-300 font-medium">{inv.description}</td>
|
||||
<td className="py-3 text-right font-mono text-zinc-700 dark:text-zinc-200 font-semibold">{formatCurrency(inv.amount)}</td>
|
||||
<td className="py-3 text-center">
|
||||
<span className={`text-[10px] font-bold px-2 py-1 rounded-full uppercase ${
|
||||
inv.status === 'paid' ? 'bg-emerald-500/15 text-emerald-400' :
|
||||
@@ -843,8 +843,8 @@ export default function LeadProjectPage() {
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<FolderOpen className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Project Documents</h3>
|
||||
<span className="text-xs font-bold bg-white/5 border border-white/5 px-2 py-0.5 rounded-full text-zinc-400">{docs.length}</span>
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Project Documents</h3>
|
||||
<span className="text-xs font-bold bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/5 px-2 py-0.5 rounded-full text-zinc-500 dark:text-zinc-400">{docs.length}</span>
|
||||
</div>
|
||||
<button onClick={() => setUploadOpen(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold transition-colors">
|
||||
@@ -854,7 +854,7 @@ export default function LeadProjectPage() {
|
||||
{docs.length === 0 ? (
|
||||
<div className="text-center py-16">
|
||||
<FolderOpen size={48} className="mx-auto mb-4 text-zinc-700" />
|
||||
<p className="font-bold text-lg text-white">No documents yet</p>
|
||||
<p className="font-bold text-lg text-zinc-900 dark:text-white">No documents yet</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
@@ -862,13 +862,13 @@ export default function LeadProjectPage() {
|
||||
const cfg = getDocType(doc.name);
|
||||
const DocIcon = cfg.icon;
|
||||
return (
|
||||
<div key={doc.id} className="flex items-start gap-4 px-4 py-4 rounded-2xl bg-white/[0.03] border border-white/[0.06] hover:bg-white/[0.07] transition-colors group">
|
||||
<div key={doc.id} className="flex items-start gap-4 px-4 py-4 rounded-2xl bg-zinc-50 dark:bg-white/[0.03] border border-zinc-100 dark:border-white/[0.06] hover:bg-zinc-100 dark:hover:bg-white/[0.07] transition-colors group">
|
||||
<div className="w-10 h-10 rounded-xl flex items-center justify-center shrink-0 mt-0.5" style={{ backgroundColor: cfg.bg }}>
|
||||
<DocIcon size={18} style={{ color: cfg.color }} />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<p className="font-semibold text-white text-sm truncate">{doc.name}</p>
|
||||
<p className="font-semibold text-zinc-900 dark:text-white text-sm truncate">{doc.name}</p>
|
||||
<span className="text-[10px] font-bold px-1.5 py-0.5 rounded-md uppercase" style={{ backgroundColor: cfg.bg, color: cfg.color }}>{cfg.label}</span>
|
||||
</div>
|
||||
<p className="text-xs text-zinc-600 mt-0.5">{doc.size} · {doc.uploadedBy} · {doc.uploadedDate}</p>
|
||||
@@ -882,9 +882,9 @@ export default function LeadProjectPage() {
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button onClick={() => setViewDoc(doc)} className="p-1.5 rounded-lg bg-white/5 hover:bg-white/10 text-zinc-400 hover:text-[#00f0ff] transition-colors" title="View"><Eye size={14} /></button>
|
||||
<button onClick={() => setEditNoteDoc({ doc, noteText: doc.notes || '' })} className="p-1.5 rounded-lg bg-white/5 hover:bg-white/10 text-zinc-400 hover:text-amber-400 transition-colors" title="Edit note"><Pencil size={14} /></button>
|
||||
<button onClick={() => setDeleteDocId(doc.id)} className="p-1.5 rounded-lg bg-white/5 hover:bg-red-500/20 text-zinc-400 hover:text-red-400 transition-colors" title="Delete"><Trash2 size={14} /></button>
|
||||
<button onClick={() => setViewDoc(doc)} className="p-1.5 rounded-lg bg-zinc-100 dark:bg-white/5 hover:bg-zinc-200 dark:hover:bg-white/10 text-zinc-500 dark:text-zinc-400 hover:text-sky-500 dark:hover:text-[#00f0ff] transition-colors" title="View"><Eye size={14} /></button>
|
||||
<button onClick={() => setEditNoteDoc({ doc, noteText: doc.notes || '' })} className="p-1.5 rounded-lg bg-zinc-100 dark:bg-white/5 hover:bg-zinc-200 dark:hover:bg-white/10 text-zinc-500 dark:text-zinc-400 hover:text-amber-500 dark:hover:text-amber-400 transition-colors" title="Edit note"><Pencil size={14} /></button>
|
||||
<button onClick={() => setDeleteDocId(doc.id)} className="p-1.5 rounded-lg bg-zinc-100 dark:bg-white/5 hover:bg-red-50 dark:hover:bg-red-500/20 text-zinc-500 dark:text-zinc-400 hover:text-red-500 dark:hover:text-red-400 transition-colors" title="Delete"><Trash2 size={14} /></button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -902,23 +902,23 @@ export default function LeadProjectPage() {
|
||||
<NeoCard spotlightColor="rgba(0,240,255,0.06)">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Activity className={NEON_BLUE} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Work Timeline</h3>
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Work Timeline</h3>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="absolute left-6 top-0 bottom-0 w-px bg-white/10" />
|
||||
<div className="absolute left-6 top-0 bottom-0 w-px bg-zinc-200 dark:bg-white/10" />
|
||||
<div className="space-y-5">
|
||||
{proj.workTimeline.map((a, i) => (
|
||||
<div key={i} className="relative flex items-start gap-4 pl-12">
|
||||
<div className="absolute left-[21px] top-1.5 w-2.5 h-2.5 rounded-full bg-[#09090b] border-2 border-[#00f0ff] shadow-[0_0_8px_rgba(0,240,255,0.5)]" />
|
||||
<div className="flex-1 p-4 rounded-xl bg-white/5 border border-white/5 hover:bg-white/10 transition-colors">
|
||||
<div className="absolute left-[21px] top-1.5 w-2.5 h-2.5 rounded-full bg-white dark:bg-[#09090b] border-2 border-sky-400 dark:border-[#00f0ff]" />
|
||||
<div className="flex-1 p-4 rounded-xl bg-zinc-50 dark:bg-white/5 border border-zinc-100 dark:border-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="font-bold text-white text-sm">{a.action}</div>
|
||||
{a.details && <div className="text-xs text-zinc-400 mt-1">{a.details}</div>}
|
||||
<div className="font-bold text-zinc-900 dark:text-white text-sm">{a.action}</div>
|
||||
{a.details && <div className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">{a.details}</div>}
|
||||
</div>
|
||||
<div className="text-right shrink-0 ml-4">
|
||||
<div className="text-xs font-mono text-zinc-500">{a.date}</div>
|
||||
{a.user && <div className="text-[10px] uppercase tracking-wider text-[#00f0ff] mt-1">{a.user}</div>}
|
||||
{a.user && <div className="text-[10px] uppercase tracking-wider text-sky-500 dark:text-[#00f0ff] mt-1">{a.user}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -934,9 +934,9 @@ export default function LeadProjectPage() {
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<TrendingUp className={NEON_GREEN} size={20} />
|
||||
<h3 className="text-lg font-bold text-white tracking-widest uppercase">Stage Movement Log</h3>
|
||||
<h3 className="text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase">Stage Movement Log</h3>
|
||||
</div>
|
||||
<span className="text-xs font-bold text-zinc-600 bg-white/5 border border-white/5 px-2 py-0.5 rounded-full">
|
||||
<span className="text-xs font-bold text-zinc-500 dark:text-zinc-600 bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/5 px-2 py-0.5 rounded-full">
|
||||
{lead.activity?.length ?? 0} entries
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user