From aeaf6558acfbd4b9e1984ae0543f920cc88297c6 Mon Sep 17 00:00:00 2001 From: Krao Hasanee Date: Fri, 27 Mar 2026 00:47:06 -0400 Subject: [PATCH] Fix dark mode light boxes, add client dashboard stats, reorder nav Co-Authored-By: Claude Sonnet 4.6 --- src/components/Layout.jsx | 2 +- src/pages/client/MyCompany.jsx | 76 ++++++++++++++++++++++++------ src/pages/client/RequestDetail.jsx | 6 +-- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx index 928189e..1324cf8 100755 --- a/src/components/Layout.jsx +++ b/src/components/Layout.jsx @@ -25,9 +25,9 @@ function ClientNav({ onNav }) {
My Work
{[ - { to: '/my-company', label: 'Company' }, { to: '/my-projects', label: 'Projects' }, { to: '/my-invoices', label: 'Invoices' }, + { to: '/my-company', label: 'Company' }, ].map(({ to, label }) => ( `sidebar-link${isActive ? ' active' : ''}`}> {label} diff --git a/src/pages/client/MyCompany.jsx b/src/pages/client/MyCompany.jsx index 27115ab..3256427 100644 --- a/src/pages/client/MyCompany.jsx +++ b/src/pages/client/MyCompany.jsx @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import Layout from '../../components/Layout'; +import StatusBadge from '../../components/StatusBadge'; import { supabase } from '../../lib/supabase'; import { useAuth } from '../../context/AuthContext'; @@ -8,21 +9,27 @@ export default function MyCompany() { const { currentUser } = useAuth(); const company = currentUser?.company; const [members, setMembers] = useState([]); - const [stats, setStats] = useState({ projects: 0, active: 0 }); + const [projects, setProjects] = useState([]); + const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { if (!company?.id) { setLoading(false); return; } async function load() { - const [{ data: m }, { data: p }, { data: t }] = await Promise.all([ + const [{ data: m }, { data: p }] = await Promise.all([ supabase.from('profiles').select('id, name, email').eq('company_id', company.id).eq('role', 'client'), - supabase.from('projects').select('id').eq('company_id', company.id), - supabase.from('tasks').select('id, status, project_id'), + supabase.from('projects').select('*').eq('company_id', company.id).order('created_at', { ascending: false }), ]); setMembers(m || []); - const projectIds = (p || []).map(pr => pr.id); - const activeTasks = (t || []).filter(task => projectIds.includes(task.project_id) && task.status !== 'client_approved'); - setStats({ projects: (p || []).length, active: activeTasks.length }); + const projectList = p || []; + setProjects(projectList); + + if (projectList.length > 0) { + const { data: t } = await supabase + .from('tasks').select('*') + .in('project_id', projectList.map(pr => pr.id)); + setTasks(t || []); + } setLoading(false); } load(); @@ -30,6 +37,11 @@ export default function MyCompany() { if (loading) return

Loading...

; + const notStarted = tasks.filter(t => t.status === 'not_started').length; + const inProgress = tasks.filter(t => ['in_progress', 'on_hold'].includes(t.status)).length; + const awaitingReview = tasks.filter(t => t.status === 'client_review').length; + const completed = tasks.filter(t => t.status === 'client_approved').length; + return (
@@ -39,25 +51,61 @@ export default function MyCompany() { {[company?.phone, company?.address].filter(Boolean).join(' · ') || 'No contact info on file'}
- + New Request {/* Stats */}
-
{stats.projects}
-
Projects
+
{notStarted}
+
Not Started
-
{stats.active}
-
Active Jobs
+
{inProgress}
+
In Progress
+
+
+
0 ? 'var(--accent)' : undefined }}>{awaitingReview}
+
Awaiting Review
-
{members.length}
-
Team Members
+
{completed}
+
Completed
+ {/* Projects */} + {projects.length > 0 && ( +
+
Projects
+
+ {projects.map(project => { + const projectTasks = tasks.filter(t => t.project_id === project.id); + const pendingReview = projectTasks.filter(t => t.status === 'client_review').length; + const active = projectTasks.filter(t => ['in_progress', 'on_hold', 'not_started'].includes(t.status)).length; + return ( + +
0 ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 8, background: 'var(--card-bg)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> +
+
{project.name}
+
+ {projectTasks.length} job{projectTasks.length !== 1 ? 's' : ''} + {active > 0 && <> · {active} active} + {pendingReview > 0 && · {pendingReview} awaiting review} +
+
+ +
+ + ); + })} +
+
+ )} + {/* Team members */}
People
diff --git a/src/pages/client/RequestDetail.jsx b/src/pages/client/RequestDetail.jsx index 47b9d65..1447188 100755 --- a/src/pages/client/RequestDetail.jsx +++ b/src/pages/client/RequestDetail.jsx @@ -244,7 +244,7 @@ export default function RequestDetail() { )} {canReview && !submitted && action !== 'confirm-delete' && action !== 'revision' && ( -
+
🎨 Your work is ready for review!

Please review the delivered work for {titleWithVersion} and let us know if you're happy or need changes. @@ -350,12 +350,12 @@ export default function RequestDetail() { ))} {delivery && delivery.files && delivery.files.length > 0 && ( -

+
✓ Delivered {new Date(delivery.sent_at).toLocaleDateString()}
{delivery.files.map((file, fi) => ( -
+
📄 {file.name}