From 2f1703870a8969415ef009c6c7a69e721d148259 Mon Sep 17 00:00:00 2001 From: Mayur Shinde Date: Thu, 4 Jun 2026 15:37:16 +0530 Subject: [PATCH] Owners box:navigate user to project details page when click on project from subcontractor table list --- .../owner/SubcontractorPaymentsPanel.jsx | 14 +- src/data/mockStore.jsx | 341 ------------------ src/pages/owner/OwnerProjectDetail.jsx | 17 +- src/pages/owner/OwnerSnapshot.jsx | 2 +- 4 files changed, 27 insertions(+), 347 deletions(-) diff --git a/src/components/owner/SubcontractorPaymentsPanel.jsx b/src/components/owner/SubcontractorPaymentsPanel.jsx index 4e4dde8..c33fa7c 100644 --- a/src/components/owner/SubcontractorPaymentsPanel.jsx +++ b/src/components/owner/SubcontractorPaymentsPanel.jsx @@ -1,4 +1,5 @@ import React, { useMemo, useState, useRef, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { Wallet, Users, Search, ChevronDown, ChevronRight, X, Check, FilterX } from 'lucide-react'; // ───────────────────────────────────────────────────────────────────────────── @@ -134,17 +135,25 @@ function StatusBadge({ status, colorMap }) { // Expanded detail view (project → requests hierarchy) // ───────────────────────────────────────────────────────────────────────────── function ContractorDetail({ projects }) { + const navigate = useNavigate(); + return (
{projects.map((proj, pi) => (
{/* Project header */} -
+
proj.projectId && navigate(`/owner/projects/${proj.projectId}?tab=budget`)} + className={`flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-2.5 bg-zinc-50 dark:bg-white/[0.03] border-b border-zinc-200 dark:border-white/[0.06] ${proj.projectId ? 'cursor-pointer hover:bg-zinc-100 dark:hover:bg-white/[0.06] transition-colors' : ''}`} + > Project - {proj.projectName} + {proj.projectName} {proj.projectAddress && ( {proj.projectAddress} )} + {proj.projectId && ( + + )}
{/* Requests — table on md+, cards on mobile */} @@ -298,6 +307,7 @@ const SubcontractorPaymentsPanel = ({ if (requested <= 0) continue; const sub = subById.get(task.subcontractorId); const project = task.projectId ? projectById.get(task.projectId) : null; + if (!project) continue; entries.push({ taskId: task.id, subId: task.subcontractorId, diff --git a/src/data/mockStore.jsx b/src/data/mockStore.jsx index b03932a..fd0a296 100644 --- a/src/data/mockStore.jsx +++ b/src/data/mockStore.jsx @@ -7612,139 +7612,6 @@ const MOCK_SUBCONTRACTOR_TASKS = [ updatedAt: '2026-05-18T23:10:00Z', }, - // ------------------------------------------------------------------- - // sct_005 — Maya (sub_002) — Attic ventilation inspection, On Hold - // ------------------------------------------------------------------- - { - id: 'sct_005', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_002', - subcontractorName: 'Maya Patel', - assignedBy: 'a1', - assignedByName: 'Wade Hollis', - title: 'Inspect attic ventilation', - location: '6909 Custer Rd, Plano, TX 75023', - description: 'Customer reports unusually high attic temps. Check ridge vent, soffit airflow, and intake/exhaust balance. Recommend remediation.', - dueDate: '2026-05-30', - priority: 'medium', - category: 'Inspection', - assignedDate: '2026-05-12T10:00:00Z', - status: 'On Hold', - photos: [ - { id: 'sct_005_p1', name: 'Attic_View.jpg', url: '/assets/images/properties/Roof_Inspection_Angle.jpg', annotation: 'Access from south gable' }, - ], - statusHistory: [ - { id: 'sct_005_h1', status: 'Assigned', actorId: 'a1', actorName: 'Wade Hollis', comment: 'Task created.', at: '2026-05-12T10:00:00Z' }, - { id: 'sct_005_h2', status: 'In Progress', actorId: 'sub_002', actorName: 'Maya Patel', comment: 'Initial pass done; baffles look blocked.', at: '2026-05-14T11:00:00Z' }, - { id: 'sct_005_h3', status: 'On Hold', actorId: 'sub_002', actorName: 'Maya Patel', comment: 'Waiting on homeowner to clear stored boxes from access path.', at: '2026-05-15T16:00:00Z' }, - ], - thread: [ - { id: 'sct_005_t1', channel: 'group', senderId: 'sub_002', senderName: 'Maya Patel', senderRole: 'Subcontractor', body: 'Access is blocked — homeowner needs to move some storage before I can complete the inspection.', at: '2026-05-15T15:55:00Z', mine: true }, - { id: 'sct_005_t2', channel: 'direct', senderId: 'a1', senderName: 'Wade Hollis', senderRole: 'Admin', body: 'I will reach out to the homeowner and reschedule.', at: '2026-05-15T16:20:00Z' }, - ], - expenses: [ - { id: 'sct_005_e1', description: 'Infrared thermometer (rental)', category: 'Equipment Rental', amount: 35.0, notes: '', receiptUrl: '', createdAt: '2026-05-14T10:30:00Z' }, - ], - fees: [ - { id: 'sct_005_f1', description: 'Inspection — initial visit', type: 'Inspection Fee', amount: 125, createdAt: '2026-05-14T13:00:00Z' }, - ], - activities: [ - { - id: 'sct_005_a1', type: 'status_change', status: 'Assigned', - note: 'Task created. Customer reports unusually high attic temps.', - photos: [], - actorId: 'a1', actorName: 'Wade Hollis', actorRole: 'Admin', - at: '2026-05-12T10:00:00Z', - }, - { - id: 'sct_005_a2', type: 'status_change', status: 'In Progress', - note: 'Initial inspection pass — soffit baffles appear blocked. Need attic access for confirmation.', - photos: [ - { id: 'sct_005_a2_p1', url: '/assets/images/properties/Roof_Inspection_Angle.jpg', name: 'south-gable.jpg' }, - ], - actorId: 'sub_002', actorName: 'Maya Patel', actorRole: 'Subcontractor', - at: '2026-05-14T11:00:00Z', - }, - { - id: 'sct_005_a3', type: 'status_change', status: 'On Hold', - note: 'Work stopped — homeowner needs to clear stored boxes blocking attic access before I can finish.', - photos: [ - { id: 'sct_005_a3_p1', url: '/assets/images/properties/Beige_Two_Story_House.jpg', name: 'access-blocked.jpg' }, - ], - actorId: 'sub_002', actorName: 'Maya Patel', actorRole: 'Subcontractor', - at: '2026-05-15T16:00:00Z', - }, - ], - projectId: 'PRJ-2026-007', - paymentStatus: 'Partially Paid', - paymentRequestedAt: '2026-05-14T13:00:00Z', - amountPaid: 80, - paidAt: '2026-05-18T09:00:00Z', - createdAt: '2026-05-12T10:00:00Z', - updatedAt: '2026-05-15T16:20:00Z', - }, - - // ------------------------------------------------------------------- - // sct_006 — Maya (sub_002) — Gutter replacement, Pre-Work Inspection - // ------------------------------------------------------------------- - { - id: 'sct_006', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_002', - subcontractorName: 'Maya Patel', - assignedBy: 'own_001', - assignedByName: 'Justin Johnson', - title: 'Replace gutter on south elevation', - location: '7224 Independence Pkwy, Plano, TX 75025', - description: '30 ft section of K-style gutter — pulling away from fascia after storm. Replace with new 6" oversized gutter, match existing bronze color.', - dueDate: '2026-06-02', - priority: 'low', - category: 'Gutters', - assignedDate: '2026-05-17T14:00:00Z', - status: 'Pre-Work Inspection', - photos: [ - { id: 'sct_006_p1', name: 'Gutter_Damage.jpg', url: '/assets/images/properties/Broken_Roof_Surface.jpg', annotation: 'Gutter pulling away from fascia — south elevation' }, - ], - statusHistory: [ - { id: 'sct_006_h1', status: 'Assigned', actorId: 'own_001', actorName: 'Justin Johnson', comment: 'Task created and assigned.', at: '2026-05-17T14:00:00Z' }, - { id: 'sct_006_h2', status: 'Pre-Work Inspection', actorId: 'sub_002', actorName: 'Maya Patel', comment: 'Site walk done — materials staged, access confirmed. Measured 32 ft run, bronze 6" gutter ordered.', at: '2026-05-26T10:00:00Z' }, - ], - thread: [ - { id: 'sct_006_t1', channel: 'group', senderId: 'sub_002', senderName: 'Maya Patel', senderRole: 'Subcontractor', body: 'On site for pre-work walkthrough. Gutter is pulling at four hangers — 32 ft run needs full replacement. Ordering materials now.', at: '2026-05-26T10:05:00Z', mine: true }, - { id: 'sct_006_t2', channel: 'group', senderId: 'own_001', senderName: 'Justin Johnson', senderRole: 'Owner', body: 'Perfect. Confirm when materials arrive and I will coordinate access with the homeowner.', at: '2026-05-26T10:30:00Z' }, - ], - expenses: [ - { id: 'sct_006_e1', description: '6" K-style gutter bronze (32 ft)', category: 'Materials', amount: 118.0, notes: 'Special order — delivery expected May 28.', receiptUrl: '', createdAt: '2026-05-26T11:00:00Z' }, - ], - fees: [], - activities: [ - { - id: 'sct_006_a1', type: 'status_change', status: 'Assigned', - note: 'Task created and assigned. 30 ft gutter section pulling away from fascia after storm damage.', - photos: [], - actorId: 'own_001', actorName: 'Justin Johnson', actorRole: 'Owner', - at: '2026-05-17T14:00:00Z', - }, - { - id: 'sct_006_a2', type: 'status_change', status: 'Pre-Work Inspection', - note: 'Site walk done — measured 32 ft run, confirmed bronze colour match, four failed hangers identified. Materials ordered, work scheduled for May 29.', - photos: [ - { id: 'sct_006_a2_p1', url: '/assets/images/properties/Broken_Roof_Surface.jpg', name: 'gutter-inspection.jpg' }, - ], - actorId: 'sub_002', actorName: 'Maya Patel', actorRole: 'Subcontractor', - at: '2026-05-26T10:00:00Z', - }, - ], - projectId: 'PRJ-2026-009', - paymentStatus: 'Unpaid', - paymentRequestedAt: null, - amountPaid: 0, - createdAt: '2026-05-17T14:00:00Z', - updatedAt: '2026-05-26T11:00:00Z', - }, - // ------------------------------------------------------------------- // sct_007 — Maya (sub_002) — completed earlier this month // ------------------------------------------------------------------- @@ -8011,60 +7878,6 @@ const MOCK_SUBCONTRACTOR_TASKS = [ updatedAt: '2026-05-27T11:05:00Z', }, - // ------------------------------------------------------------------- - // sct_009 — Jennifer Castillo (sub_004) — Cancelled plumbing - // ------------------------------------------------------------------- - { - id: 'sct_009', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_004', - subcontractorName: 'Jennifer Castillo', - assignedBy: 'own_001', - assignedByName: 'Justin Johnson', - title: 'Rough-in plumbing for ADU bathroom', - location: '6112 Roundrock Dr, Plano, TX 75025', - description: 'New ADU build — bathroom rough-in. Coordinate with framing inspection.', - dueDate: '2026-06-15', - priority: 'medium', - category: 'Plumbing', - assignedDate: '2026-05-09T10:00:00Z', - status: 'Cancelled', - photos: [], - statusHistory: [ - { id: 'sct_009_h1', status: 'Assigned', actorId: 'own_001', actorName: 'Justin Johnson', comment: 'Task created and assigned.', at: '2026-05-09T10:00:00Z' }, - { id: 'sct_009_h2', status: 'Cancelled', actorId: 'own_001', actorName: 'Justin Johnson', comment: 'Homeowner cancelled the ADU project — entire scope suspended. Task voided, no further work required.', at: '2026-05-20T15:00:00Z' }, - ], - thread: [ - { id: 'sct_009_t1', channel: 'group', senderId: 'own_001', senderName: 'Justin Johnson', senderRole: 'Owner', body: 'Jennifer — unfortunately the homeowner has decided to cancel the ADU build entirely. No further work needed on this task. Apologies for the inconvenience.', at: '2026-05-20T15:02:00Z' }, - { id: 'sct_009_t2', channel: 'group', senderId: 'sub_004', senderName: 'Jennifer Castillo', senderRole: 'Subcontractor', body: 'Understood — no work had been started so no impact on our end. Thanks for the heads-up.', at: '2026-05-20T15:30:00Z', mine: true }, - ], - expenses: [], - fees: [], - activities: [ - { - id: 'sct_009_a1', type: 'status_change', status: 'Assigned', - note: 'Task created. New ADU build — bathroom rough-in to coordinate with framing inspection.', - photos: [], - actorId: 'own_001', actorName: 'Justin Johnson', actorRole: 'Owner', - at: '2026-05-09T10:00:00Z', - }, - { - id: 'sct_009_a2', type: 'status_change', status: 'Cancelled', - note: 'Task cancelled — homeowner suspended the ADU project. No work was started.', - photos: [], - actorId: 'own_001', actorName: 'Justin Johnson', actorRole: 'Owner', - at: '2026-05-20T15:00:00Z', - }, - ], - projectId: null, - paymentStatus: 'Unpaid', - paymentRequestedAt: null, - amountPaid: 0, - createdAt: '2026-05-09T10:00:00Z', - updatedAt: '2026-05-20T15:30:00Z', - }, - // ------------------------------------------------------------------- // sct_011 — Maya Patel (sub_002) — full roof replacement PRJ-2026-001, PAID // ------------------------------------------------------------------- @@ -8238,51 +8051,6 @@ const MOCK_SUBCONTRACTOR_TASKS = [ updatedAt: '2026-04-28T16:00:00Z', }, - // ------------------------------------------------------------------- - // sct_015 — Jennifer Castillo (sub_004) — PRJ-2026-007, Partially Paid - // ------------------------------------------------------------------- - { - id: 'sct_015', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_004', - subcontractorName: 'Jennifer Castillo', - assignedBy: 'a1', - assignedByName: 'Wade Hollis', - title: 'Hot water heater replacement — PRJ-007', - location: '6909 Custer Rd, Plano, TX 75023', - description: 'Replace 40-gal gas water heater (unit failed). Install Bradford White 40-gal NG, reconnect supply & drain.', - dueDate: '2026-05-20', - priority: 'high', - category: 'Plumbing', - assignedDate: '2026-05-14T08:00:00Z', - status: 'Completed', - photos: [], - statusHistory: [ - { id: 'sct_015_h1', status: 'Assigned', actorId: 'a1', actorName: 'Wade Hollis', comment: 'Assigned.', at: '2026-05-14T08:00:00Z' }, - { id: 'sct_015_h2', status: 'Completed', actorId: 'sub_004', actorName: 'Jennifer Castillo', comment: 'Complete.', at: '2026-05-16T13:00:00Z' }, - ], - thread: [], - expenses: [ - { id: 'sct_015_e1', description: 'Bradford White 40-gal NG heater', category: 'Materials', amount: 680, notes: '', receiptUrl: '', createdAt: '2026-05-14T10:00:00Z' }, - { id: 'sct_015_e2', description: 'Gas flex connector + fittings', category: 'Materials', amount: 48, notes: '', receiptUrl: '', createdAt: '2026-05-14T10:05:00Z' }, - { id: 'sct_015_e3', description: 'Expansion tank + pressure relief', category: 'Materials', amount: 95, notes: '', receiptUrl: '', createdAt: '2026-05-14T10:10:00Z' }, - { id: 'sct_015_e4', description: 'Haul-away — old unit', category: 'Disposal / Dumpster', amount: 65, notes: '', receiptUrl: '', createdAt: '2026-05-16T14:00:00Z' }, - ], - fees: [ - { id: 'sct_015_f1', description: 'Labour — WHR install', type: 'Labour / Service Fee', amount: 420, createdAt: '2026-05-16T13:10:00Z' }, - { id: 'sct_015_f2', description: 'Mobilization', type: 'Mobilization Fee', amount: 75, createdAt: '2026-05-14T08:00:00Z' }, - ], - activities: [], - projectId: 'PRJ-2026-007', - paymentStatus: 'Partially Paid', - paymentRequestedAt: '2026-05-16T14:00:00Z', - amountPaid: 700, - paidAt: '2026-05-22T10:00:00Z', - createdAt: '2026-05-14T08:00:00Z', - updatedAt: '2026-05-16T14:00:00Z', - }, - // ------------------------------------------------------------------- // sct_016 — Dwayne Boudreaux (sub_003) — interior repaint PRJ-2026-004, Paid // ------------------------------------------------------------------- @@ -8325,47 +8093,6 @@ const MOCK_SUBCONTRACTOR_TASKS = [ updatedAt: '2026-05-03T16:00:00Z', }, - // ------------------------------------------------------------------- - // sct_017 — Dwayne Boudreaux (sub_003) — PRJ-2026-007 ceiling repaint, Unpaid - // ------------------------------------------------------------------- - { - id: 'sct_017', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_003', - subcontractorName: 'Dwayne Boudreaux', - assignedBy: 'a1', - assignedByName: 'Wade Hollis', - title: 'Ceiling repaint after water damage — PRJ-007', - location: '6909 Custer Rd, Plano, TX 75023', - description: 'Repaint ceilings in master bedroom and en-suite after remediation. Stain block primer + 2 coats flat white.', - dueDate: '2026-05-28', - priority: 'medium', - category: 'Painting', - assignedDate: '2026-05-18T10:00:00Z', - status: 'Completed', - photos: [], - statusHistory: [ - { id: 'sct_017_h1', status: 'Assigned', actorId: 'a1', actorName: 'Wade Hollis', comment: 'Assigned.', at: '2026-05-18T10:00:00Z' }, - { id: 'sct_017_h2', status: 'Completed', actorId: 'sub_003', actorName: 'Dwayne Boudreaux', comment: 'Complete.', at: '2026-05-25T14:00:00Z' }, - ], - thread: [], - expenses: [ - { id: 'sct_017_e1', description: 'Zinsser stain-block primer — 1 gal', category: 'Materials', amount: 52, notes: '', receiptUrl: '', createdAt: '2026-05-19T08:00:00Z' }, - { id: 'sct_017_e2', description: 'Ceiling flat white — 1 gal', category: 'Materials', amount: 42, notes: '', receiptUrl: '', createdAt: '2026-05-19T08:05:00Z' }, - ], - fees: [ - { id: 'sct_017_f1', description: 'Labour — ceiling repaint (1.5 days)', type: 'Labour / Service Fee', amount: 580, createdAt: '2026-05-25T14:10:00Z' }, - ], - activities: [], - projectId: 'PRJ-2026-007', - paymentStatus: 'Unpaid', - paymentRequestedAt: '2026-05-25T15:00:00Z', - amountPaid: 0, - createdAt: '2026-05-18T10:00:00Z', - updatedAt: '2026-05-25T15:00:00Z', - }, - // ------------------------------------------------------------------- // sct_018 — Greg Alston (sub_005) — window replacement PRJ-2026-003, Partially Paid // ------------------------------------------------------------------- @@ -8409,46 +8136,6 @@ const MOCK_SUBCONTRACTOR_TASKS = [ createdAt: '2026-05-03T09:00:00Z', updatedAt: '2026-05-13T16:00:00Z', }, - - // ------------------------------------------------------------------- - // sct_019 — Greg Alston (sub_005) — window sealing PRJ-2026-009, Unpaid - // ------------------------------------------------------------------- - { - id: 'sct_019', - companyId: 'lynkeduppro', - companyName: 'LynkedUp Pro Roofing', - subcontractorId: 'sub_005', - subcontractorName: 'Greg Alston', - assignedBy: 'a1', - assignedByName: 'Wade Hollis', - title: 'Re-seal & caulk all windows — PRJ-009', - location: '7224 Independence Pkwy, Plano, TX 75025', - description: 'Full perimeter re-seal on 8 windows. Remove old silicone, clean frames, apply new NP1 polyurethane sealant.', - dueDate: '2026-06-05', - priority: 'low', - category: 'Windows & Glazing', - assignedDate: '2026-05-22T09:00:00Z', - status: 'In Progress', - photos: [], - statusHistory: [ - { id: 'sct_019_h1', status: 'Assigned', actorId: 'a1', actorName: 'Wade Hollis', comment: 'Assigned.', at: '2026-05-22T09:00:00Z' }, - { id: 'sct_019_h2', status: 'In Progress', actorId: 'sub_005', actorName: 'Greg Alston', comment: 'In progress.', at: '2026-05-28T08:30:00Z' }, - ], - thread: [], - expenses: [ - { id: 'sct_019_e1', description: 'NP1 polyurethane sealant (6 tubes)', category: 'Materials', amount: 78, notes: '', receiptUrl: '', createdAt: '2026-05-23T07:00:00Z' }, - ], - fees: [ - { id: 'sct_019_f1', description: 'Labour — window sealing (1 day)', type: 'Labour / Service Fee', amount: 380, createdAt: '2026-05-28T12:00:00Z' }, - ], - activities: [], - projectId: 'PRJ-2026-009', - paymentStatus: 'Unpaid', - paymentRequestedAt: '2026-05-28T12:00:00Z', - amountPaid: 0, - createdAt: '2026-05-22T09:00:00Z', - updatedAt: '2026-05-28T12:00:00Z', - }, ]; const MOCK_NOTIFICATIONS = [ @@ -8470,20 +8157,6 @@ const MOCK_NOTIFICATIONS = [ taskId: 'sct_004', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', isRead: false, createdAt: '2026-05-18T22:40:00Z', }, - { - id: 'notif_003', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', - type: 'task_assigned', - message: 'You have been assigned a task by LynkedUp Pro Roofing — "Replace gutter on south elevation"', - taskId: 'sct_006', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', - isRead: false, createdAt: '2026-05-17T14:00:00Z', - }, - { - id: 'notif_004', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', - type: 'task_assigned', - message: 'You have been assigned a task by LynkedUp Pro Roofing — "Inspect attic ventilation"', - taskId: 'sct_005', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', - isRead: true, createdAt: '2026-05-12T10:00:00Z', - }, // -- Message Received -------------------------- { id: 'notif_005', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', @@ -8499,13 +8172,6 @@ const MOCK_NOTIFICATIONS = [ taskId: 'sct_004', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', isRead: false, createdAt: '2026-05-18T22:42:00Z', }, - { - id: 'notif_007', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', - type: 'message_received', - message: 'Wade Hollis added an internal note on sct_005 — "I will reach out to the homeowner…"', - taskId: 'sct_005', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', - isRead: true, createdAt: '2026-05-15T16:20:00Z', - }, // -- Task Updated ------------------------------ { id: 'notif_008', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', @@ -8536,13 +8202,6 @@ const MOCK_NOTIFICATIONS = [ taskId: 'sct_001', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', isRead: true, createdAt: '2026-05-16T08:30:00Z', }, - { - id: 'notif_012', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', - type: 'status_changed', - message: 'Status for sct_005 changed to On Hold by Maya Patel.', - taskId: 'sct_005', fromCompanyId: 'lynkeduppro', fromCompanyName: 'LynkedUp Pro Roofing', - isRead: true, createdAt: '2026-05-15T16:00:00Z', - }, { id: 'notif_013', recipientUserId: 'sub_002', recipientRole: 'SUBCONTRACTOR', type: 'status_changed', diff --git a/src/pages/owner/OwnerProjectDetail.jsx b/src/pages/owner/OwnerProjectDetail.jsx index bc7446a..20c1cf5 100644 --- a/src/pages/owner/OwnerProjectDetail.jsx +++ b/src/pages/owner/OwnerProjectDetail.jsx @@ -1,5 +1,5 @@ import React, { useState, useMemo, useRef, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; +import { useParams, useNavigate, useSearchParams } from 'react-router-dom'; import { useAuth } from '../../context/AuthContext'; import { useMockStore } from '../../data/mockStore'; import { LIFECYCLE_STAGES, REWORK_STAGE, nextStage, prevStage, stageToPct } from '../../data/lifecycle'; @@ -199,7 +199,15 @@ const OwnerProjectDetail = () => { } = useMockStore(); const navigate = useNavigate(); const { can } = usePermissions(); - const [activeTab, setActiveTab] = useState('overview'); + const [searchParams, setSearchParams] = useSearchParams(); + const [activeTab, setActiveTab] = useState(() => searchParams.get('tab') || 'overview'); + + useEffect(() => { + const tab = searchParams.get('tab'); + if (tab && tab !== activeTab) { + setActiveTab(tab); + } + }, [searchParams, activeTab]); const [selectedCO, setSelectedCO] = useState(null); const [selectedInvoice, setSelectedInvoice] = useState(null); const [selectedVersion, setSelectedVersion] = useState(null); @@ -554,7 +562,10 @@ const OwnerProjectDetail = () => { return (