Files
LynkedUpPro_CRM/src/pages/owner/OwnerSnapshot.jsx
T
Satyam 2eaac6b84a feat: Multi-role platform expansion, mobile nav redesign, and UI polish
- 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
2026-02-17 01:23:06 +05:30

139 lines
7.8 KiB
React

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../context/AuthContext';
import FinancialKPICards from '../../components/owner/FinancialKPICards';
import UrgentItemsPanel from '../../components/owner/UrgentItemsPanel';
import FinancialDetailsModal from '../../components/owner/FinancialDetailsModal';
import ActionCenterModal from '../../components/owner/ActionCenterModal';
import { SpotlightCard } from '../../components/SpotlightCard';
const OwnerSnapshot = () => {
const { user } = useAuth();
const navigate = useNavigate();
// Modal States
const [financialModal, setFinancialModal] = useState({ isOpen: false, type: 'revenue' });
const [actionModal, setActionModal] = useState({ isOpen: false, filter: 'all' });
// Handlers
const handleFinancialClick = (type) => {
setFinancialModal({ isOpen: true, type });
};
const handleActionClick = (id) => {
// Map IDs to filter types
const filterMap = {
'docs': 'docs',
'vendors': 'vendors',
'invoices': 'invoices',
'all': 'all'
};
setActionModal({ isOpen: true, filter: filterMap[id] || 'all' });
};
// Get time of day for greeting
const hour = new Date().getHours();
const greeting = hour < 12 ? 'Good Morning' : hour < 18 ? 'Good Afternoon' : 'Good Evening';
return (
<div className="min-h-full bg-zinc-50 dark:bg-[#09090b] text-zinc-900 dark:text-white relative pb-20 transition-colors duration-300">
{/* Ambient Background Glows */}
<div className="fixed top-0 left-0 w-full h-full overflow-hidden pointer-events-none z-0">
<div className="absolute top-[-10%] left-[-10%] w-[50%] h-[50%] bg-purple-500/5 dark:bg-purple-900/10 rounded-full blur-[120px]" />
<div className="absolute bottom-[-10%] right-[-10%] w-[50%] h-[50%] bg-blue-500/5 dark:bg-blue-900/10 rounded-full blur-[120px]" />
</div>
<div className="relative z-10 p-8 max-w-7xl mx-auto space-y-8">
{/* Header Section */}
<header className="flex flex-col md:flex-row justify-between items-start md:items-center border-b border-zinc-200 dark:border-white/5 pb-6">
<div>
<h1 className="text-4xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-zinc-900 to-zinc-600 dark:from-white dark:to-white/60 tracking-tight">
{greeting}, {user?.name?.split(' ')[0] || 'Owner'}
</h1>
<p className="text-zinc-500 dark:text-zinc-400 mt-2 font-light">Here's your business snapshot for today.</p>
</div>
<div className="mt-4 md:mt-0 flex space-x-3">
<button className="px-4 py-2 bg-zinc-100 dark:bg-white/5 hover:bg-zinc-200 dark:hover:bg-white/10 rounded-xl text-sm font-bold text-zinc-700 dark:text-zinc-300 transition-colors border border-zinc-200 dark:border-white/5 shadow-sm">
Download Report
</button>
<button className="px-4 py-2 bg-amber-500 hover:bg-amber-600 text-black font-bold rounded-xl text-sm transition-colors shadow-lg shadow-amber-500/20">
Quick Action
</button>
</div>
</header>
{/* Financial KPIs */}
<section>
<h2 className="text-xl font-bold text-zinc-900 dark:text-white/90 mb-4 flex items-center">
<span className="w-2 h-8 bg-emerald-500 rounded-full mr-3"></span>
Financial Overview
</h2>
<FinancialKPICards onCardClick={handleFinancialClick} />
</section>
{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Urgent Items Panel (Takes up 2 columns on large screens) */}
<section className="lg:col-span-2">
<UrgentItemsPanel onActionClick={handleActionClick} />
</section>
{/* Activity Feed / Notifications Placeholder (Right Column) */}
<SpotlightCard className="h-full">
<div className="p-6">
<div className="flex items-center mb-6">
<div className="w-2 h-2 rounded-full bg-blue-500 mr-2 animate-pulse"></div>
<h3 className="text-lg font-bold text-zinc-900 dark:text-white">Recent Activity</h3>
</div>
<div className="space-y-3">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-start space-x-3 p-3 rounded-xl bg-zinc-50 dark:bg-white/5 border border-zinc-200 dark:border-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
<div className="w-2 h-2 mt-2 rounded-full bg-blue-400 shrink-0"></div>
<div>
<p className="text-sm text-zinc-600 dark:text-zinc-300">New invoice submitted by <span className="text-zinc-900 dark:text-white font-bold">Texas Builders LLC</span></p>
<span className="text-[10px] text-zinc-400 uppercase font-bold tracking-wider">2 hours ago</span>
</div>
</div>
))}
<div className="flex items-start space-x-3 p-3 rounded-xl bg-zinc-50 dark:bg-white/5 border border-zinc-200 dark:border-white/5 hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
<div className="w-2 h-2 mt-2 rounded-full bg-emerald-400 shrink-0"></div>
<div>
<p className="text-sm text-zinc-600 dark:text-zinc-300">Payment received for <span className="text-zinc-900 dark:text-white font-bold">Project P-2602</span></p>
<span className="text-[10px] text-zinc-400 uppercase font-bold tracking-wider">5 hours ago</span>
</div>
</div>
</div>
<button
onClick={() => navigate('/owner/vendors')}
className="w-full mt-6 py-2 text-xs font-bold uppercase tracking-wider text-zinc-500 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white border border-zinc-200 dark:border-white/10 hover:bg-zinc-100 dark:hover:bg-white/5 rounded-xl transition-all"
>
View All Activity
</button>
</div>
</SpotlightCard>
</div>
</div>
{/* Interactive Modals */}
<FinancialDetailsModal
isOpen={financialModal.isOpen}
onClose={() => setFinancialModal({ ...financialModal, isOpen: false })}
type={financialModal.type}
/>
<ActionCenterModal
isOpen={actionModal.isOpen}
onClose={() => setActionModal({ ...actionModal, isOpen: false })}
defaultFilter={actionModal.filter}
// Force re-render on filter change if needed, generally okay as props update
key={actionModal.filter}
/>
</div >
);
};
export default OwnerSnapshot;