feat(data): expand subcontractor task state machine constants + add category/assignedDate; audit cancel

This commit is contained in:
Satyam Rastogi
2026-05-29 19:31:26 +05:30
parent b0ad60c6f0
commit 42792a82ca
+42 -15
View File
@@ -6834,16 +6834,19 @@ export const SUBCONTRACTOR_TASK_PRIORITIES = [
]; ];
export const SUBCONTRACTOR_TASK_STATUSES = [ export const SUBCONTRACTOR_TASK_STATUSES = [
'Assigned', 'Assigned', 'Pre-Work Inspection', 'In Progress', 'On Hold',
'In Progress', 'Post-Work Review', 'Rework Needed', 'Completed', 'Cancelled',
'On Hold', ];
'Completed', // Statuses a subcontractor can set themselves (no review gate, no cancel):
'Cancelled', export const SUBCONTRACTOR_SELF_STATUSES = [
'Assigned', 'Pre-Work Inspection', 'In Progress', 'On Hold', 'Post-Work Review',
];
// Owner/admin-only transitions (the review gate + cancel):
export const SUBCONTRACTOR_REVIEW_STATUSES = ['Completed', 'Rework Needed', 'Cancelled'];
// Task categories (for the owner table + assignment):
export const SUBCONTRACTOR_TASK_CATEGORIES = [
'Roofing', 'Electrical', 'Plumbing', 'Siding', 'Gutters', 'Windows', 'Painting', 'Inspection', 'General',
]; ];
// Statuses the subcontractor themselves can set from the Task Detail page.
// Owner / admin can still flip a task to Cancelled from the admin page.
export const SUBCONTRACTOR_SELF_STATUSES = ['Assigned', 'In Progress', 'On Hold', 'Completed'];
export const SUBCONTRACTOR_EXPENSE_CATEGORIES = [ export const SUBCONTRACTOR_EXPENSE_CATEGORIES = [
'Materials', 'Materials',
@@ -6948,6 +6951,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Two ridge cap shingles missing on the south slope after wind storm. Replace with matching tile and seal. Inspect adjacent tiles for hairline cracks while you are up there.', description: 'Two ridge cap shingles missing on the south slope after wind storm. Replace with matching tile and seal. Inspect adjacent tiles for hairline cracks while you are up there.',
dueDate: '2026-05-25', dueDate: '2026-05-25',
priority: 'high', priority: 'high',
category: 'Roofing',
assignedDate: '2026-05-15T09:12:00Z',
status: 'In Progress', status: 'In Progress',
photos: [ photos: [
{ id: 'sct_001_p1', name: 'Roof_Damage.jpg', url: '/assets/images/properties/Hail_Damaged_Shingles.jpg', annotation: 'Repair this corner' }, { id: 'sct_001_p1', name: 'Roof_Damage.jpg', url: '/assets/images/properties/Hail_Damaged_Shingles.jpg', annotation: 'Repair this corner' },
@@ -7039,6 +7044,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Outdated 100A panel — upgrade to 200A. Permit pulled, materials staged on site. Coordinate Oncor disconnect for the morning of installation.', description: 'Outdated 100A panel — upgrade to 200A. Permit pulled, materials staged on site. Coordinate Oncor disconnect for the morning of installation.',
dueDate: '2026-05-22', dueDate: '2026-05-22',
priority: 'medium', priority: 'medium',
category: 'Electrical',
assignedDate: '2026-05-10T15:40:00Z',
status: 'In Progress', status: 'In Progress',
photos: [ photos: [
{ id: 'sct_002_p1', name: 'Old_Panel.jpg', url: '/assets/images/properties/Beige_Two_Story_House.jpg', annotation: 'Existing 100A panel — disconnect and remove' }, { id: 'sct_002_p1', name: 'Old_Panel.jpg', url: '/assets/images/properties/Beige_Two_Story_House.jpg', annotation: 'Existing 100A panel — disconnect and remove' },
@@ -7131,6 +7138,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Front fascia and side trim need fresh coat after siding repair. Match existing Sherwin-Williams color.', description: 'Front fascia and side trim need fresh coat after siding repair. Match existing Sherwin-Williams color.',
dueDate: '2026-05-18', dueDate: '2026-05-18',
priority: 'low', priority: 'low',
category: 'Painting',
assignedDate: '2026-05-05T11:00:00Z',
status: 'Completed', status: 'Completed',
photos: [ photos: [
{ id: 'sct_003_p1', name: 'Before.jpg', url: '/assets/images/properties/Brick_Front_Porch_Home.jpg', annotation: 'Before' }, { id: 'sct_003_p1', name: 'Before.jpg', url: '/assets/images/properties/Brick_Front_Porch_Home.jpg', annotation: 'Before' },
@@ -7149,6 +7158,7 @@ const MOCK_SUBCONTRACTOR_TASKS = [
fees: [ fees: [
{ id: 'sct_003_f1', description: 'Touch-up paint labour', type: 'Labour / Service Fee', amount: 180, createdAt: '2026-05-14T17:35:00Z' }, { id: 'sct_003_f1', description: 'Touch-up paint labour', type: 'Labour / Service Fee', amount: 180, createdAt: '2026-05-14T17:35:00Z' },
], ],
activities: [],
projectId: 'PRJ-2026-006', projectId: 'PRJ-2026-006',
paymentStatus: 'Paid', paymentStatus: 'Paid',
paymentRequestedAt: '2026-05-14T17:35:00Z', paymentRequestedAt: '2026-05-14T17:35:00Z',
@@ -7173,6 +7183,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Hailstorm overnight; 34 ft section of decking exposed near chimney. Tarp ASAP to prevent further water intrusion. Permanent repair will be scheduled after insurance scope.', description: 'Hailstorm overnight; 34 ft section of decking exposed near chimney. Tarp ASAP to prevent further water intrusion. Permanent repair will be scheduled after insurance scope.',
dueDate: '2026-05-19', dueDate: '2026-05-19',
priority: 'high', priority: 'high',
category: 'Roofing',
assignedDate: '2026-05-18T22:40:00Z',
status: 'Assigned', status: 'Assigned',
photos: [ photos: [
{ id: 'sct_004_p1', name: 'Storm_Damage.jpg', url: '/assets/images/properties/Broken_Roof_Surface.jpg', annotation: 'Exposed decking near chimney' }, { id: 'sct_004_p1', name: 'Storm_Damage.jpg', url: '/assets/images/properties/Broken_Roof_Surface.jpg', annotation: 'Exposed decking near chimney' },
@@ -7188,6 +7200,7 @@ const MOCK_SUBCONTRACTOR_TASKS = [
], ],
expenses: [], expenses: [],
fees: [], fees: [],
activities: [],
projectId: 'PRJ-2026-001', projectId: 'PRJ-2026-001',
paymentStatus: 'Unpaid', paymentStatus: 'Unpaid',
paymentRequestedAt: null, paymentRequestedAt: null,
@@ -7211,6 +7224,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Customer reports unusually high attic temps. Check ridge vent, soffit airflow, and intake/exhaust balance. Recommend remediation.', description: 'Customer reports unusually high attic temps. Check ridge vent, soffit airflow, and intake/exhaust balance. Recommend remediation.',
dueDate: '2026-05-30', dueDate: '2026-05-30',
priority: 'medium', priority: 'medium',
category: 'Inspection',
assignedDate: '2026-05-12T10:00:00Z',
status: 'On Hold', status: 'On Hold',
photos: [ photos: [
{ id: 'sct_005_p1', name: 'Attic_View.jpg', url: '/assets/images/properties/Roof_Inspection_Angle.jpg', annotation: 'Access from south gable' }, { id: 'sct_005_p1', name: 'Attic_View.jpg', url: '/assets/images/properties/Roof_Inspection_Angle.jpg', annotation: 'Access from south gable' },
@@ -7280,6 +7295,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: '30 ft section of K-style gutter — pulling away from fascia after storm. Replace with new 6" oversized gutter, match existing bronze color.', 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', dueDate: '2026-06-02',
priority: 'low', priority: 'low',
category: 'Gutters',
assignedDate: '2026-05-17T14:00:00Z',
status: 'Assigned', status: 'Assigned',
photos: [], photos: [],
statusHistory: [ statusHistory: [
@@ -7288,6 +7305,7 @@ const MOCK_SUBCONTRACTOR_TASKS = [
thread: [], thread: [],
expenses: [], expenses: [],
fees: [], fees: [],
activities: [],
projectId: 'PRJ-2026-009', projectId: 'PRJ-2026-009',
paymentStatus: 'Unpaid', paymentStatus: 'Unpaid',
paymentRequestedAt: null, paymentRequestedAt: null,
@@ -7311,6 +7329,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Sheathing soft in two ~2x2 ft areas. Cut out, replace with matching OSB, re-felt and re-shingle.', description: 'Sheathing soft in two ~2x2 ft areas. Cut out, replace with matching OSB, re-felt and re-shingle.',
dueDate: '2026-05-08', dueDate: '2026-05-08',
priority: 'high', priority: 'high',
category: 'Roofing',
assignedDate: '2026-05-01T09:00:00Z',
status: 'Completed', status: 'Completed',
photos: [ photos: [
{ id: 'sct_007_p1', name: 'Deck_Repair.jpg', url: '/assets/images/properties/Cracked_Asphalt_Shingles.jpg', annotation: 'Soft section, top right' }, { id: 'sct_007_p1', name: 'Deck_Repair.jpg', url: '/assets/images/properties/Cracked_Asphalt_Shingles.jpg', annotation: 'Soft section, top right' },
@@ -7331,6 +7351,7 @@ const MOCK_SUBCONTRACTOR_TASKS = [
fees: [ fees: [
{ id: 'sct_007_f1', description: 'Labour — deck repair (2 days)', type: 'Labour / Service Fee', amount: 920, createdAt: '2026-05-07T16:50:00Z' }, { id: 'sct_007_f1', description: 'Labour — deck repair (2 days)', type: 'Labour / Service Fee', amount: 920, createdAt: '2026-05-07T16:50:00Z' },
], ],
activities: [],
projectId: 'PRJ-2026-001', projectId: 'PRJ-2026-001',
paymentStatus: 'Paid', paymentStatus: 'Paid',
paymentRequestedAt: '2026-05-07T16:50:00Z', paymentRequestedAt: '2026-05-07T16:50:00Z',
@@ -7355,6 +7376,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Replace 4 standard receptacles with GFCI: 2 kitchen counter outlets (left of sink + island), 1 master bath vanity, 1 powder room vanity. Code update required as part of insurance work. Use Leviton SmartlockPro 20A devices. Test all branches with plug-in tester before signing off.', description: 'Replace 4 standard receptacles with GFCI: 2 kitchen counter outlets (left of sink + island), 1 master bath vanity, 1 powder room vanity. Code update required as part of insurance work. Use Leviton SmartlockPro 20A devices. Test all branches with plug-in tester before signing off.',
dueDate: '2026-05-26', dueDate: '2026-05-26',
priority: 'medium', priority: 'medium',
category: 'Electrical',
assignedDate: '2026-05-16T13:00:00Z',
status: 'In Progress', status: 'In Progress',
photos: [ photos: [
{ id: 'sct_008_p1', name: 'Kitchen_Outlet.jpg', url: '/assets/images/properties/Modern_White_Suburban_Home.jpg', annotation: 'Kitchen — left of sink, current standard receptacle' }, { id: 'sct_008_p1', name: 'Kitchen_Outlet.jpg', url: '/assets/images/properties/Modern_White_Suburban_Home.jpg', annotation: 'Kitchen — left of sink, current standard receptacle' },
@@ -7437,6 +7460,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'Homeowner purchased a Tesla Wall Connector. Run a dedicated 60A 240V circuit from the main panel to the garage wall. Coordinate with homeowner for outage window. Permit required.', description: 'Homeowner purchased a Tesla Wall Connector. Run a dedicated 60A 240V circuit from the main panel to the garage wall. Coordinate with homeowner for outage window. Permit required.',
dueDate: '2026-05-29', dueDate: '2026-05-29',
priority: 'medium', priority: 'medium',
category: 'Electrical',
assignedDate: '2026-05-20T09:00:00Z',
status: 'Assigned', status: 'Assigned',
photos: [ photos: [
{ id: 'sct_010_p1', name: 'Garage_Wall.jpg', url: '/assets/images/properties/Modern_White_Suburban_Home.jpg', annotation: 'Wall Connector mounting location' }, { id: 'sct_010_p1', name: 'Garage_Wall.jpg', url: '/assets/images/properties/Modern_White_Suburban_Home.jpg', annotation: 'Wall Connector mounting location' },
@@ -7474,6 +7499,8 @@ const MOCK_SUBCONTRACTOR_TASKS = [
description: 'New ADU build — bathroom rough-in. Coordinate with framing inspection.', description: 'New ADU build — bathroom rough-in. Coordinate with framing inspection.',
dueDate: '2026-06-15', dueDate: '2026-06-15',
priority: 'medium', priority: 'medium',
category: 'Plumbing',
assignedDate: '2026-05-09T10:00:00Z',
status: 'On Hold', status: 'On Hold',
photos: [], photos: [],
statusHistory: [ statusHistory: [
@@ -7483,6 +7510,7 @@ const MOCK_SUBCONTRACTOR_TASKS = [
thread: [], thread: [],
expenses: [], expenses: [],
fees: [], fees: [],
activities: [],
projectId: null, projectId: null,
paymentStatus: 'Unpaid', paymentStatus: 'Unpaid',
paymentRequestedAt: null, paymentRequestedAt: null,
@@ -8102,6 +8130,8 @@ export const MockStoreProvider = ({ children }) => {
description: input.description || '', description: input.description || '',
dueDate: input.dueDate, dueDate: input.dueDate,
priority: input.priority || 'medium', priority: input.priority || 'medium',
category: input.category || 'General',
assignedDate: now,
status: 'Assigned', status: 'Assigned',
photos: (input.photos || []).map((p, i) => ({ photos: (input.photos || []).map((p, i) => ({
id: p.id || `${Date.now()}_${i}`, id: p.id || `${Date.now()}_${i}`,
@@ -8120,6 +8150,7 @@ export const MockStoreProvider = ({ children }) => {
thread: [], thread: [],
expenses: [], expenses: [],
fees: [], fees: [],
activities: [],
createdAt: now, createdAt: now,
updatedAt: now, updatedAt: now,
}; };
@@ -8401,12 +8432,8 @@ export const MockStoreProvider = ({ children }) => {
toast.success('Task updated'); toast.success('Task updated');
}; };
const cancelSubcontractorTask = (taskId) => { const cancelSubcontractorTask = (taskId, comment = 'Task cancelled', actor) => {
setSubcontractorTasks(prev => prev.map(t => t.id === taskId setSubcontractorTaskStatus(taskId, 'Cancelled', comment, actor);
? { ...t, status: 'Cancelled', updatedAt: new Date().toISOString() }
: t,
));
toast.success('Task cancelled');
}; };
const reassignSubcontractorTask = (taskId, newSubcontractorId) => { const reassignSubcontractorTask = (taskId, newSubcontractorId) => {