8f9cb9dd48
- EstimatesPage: tabbed hub with Estimates and Templates tabs, KPI strip, search + filter - EstimateDetailModal: right-side drawer showing scope of work, computed line items, and financial summary from template + roof area - TemplateEditorModal: create/edit/duplicate templates with segmented mode toggle - Owner-only template management (create, edit, duplicate, delete); Admin/FA read-only view - Duplicate mode: toggle between 'Save as new copy' (default, editable name) and 'Replace original' - MASTER_TEMPLATES and MOCK_ESTIMATES moved into mockStore with full CRUD helpers - TemplateSelectionModal now reads from mockStore instead of local stub - Sidebar nav updated to point to /estimates hub for all roles - Routes added: /emp/fa/estimates, /admin/estimates, /owner/estimates
672 lines
35 KiB
React
672 lines
35 KiB
React
import React, { useState } from 'react';
|
|
import { useMockStore } from '../../data/mockStore';
|
|
|
|
const STUBBED_TEMPLATES = [
|
|
{
|
|
id: 'atlas_glassmaster',
|
|
name: 'Atlas GlassMaster',
|
|
category: 'Roofing',
|
|
brand: 'Atlas',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood. If bad or rotten wood is discovered, it will be replaced at a price of $50 per sheet.",
|
|
"Install 3' of Atlas WeatherMaster ice and water shield at all gutter lines, rakes edges, and valleys.",
|
|
"Install Atlas Summit 60 Synthetic underlayment.",
|
|
"Install Atlas Glassmaster AR Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'Atlas Glassmaster AR', baseUnitCost: 37.67, uom: 'SQ' },
|
|
{ desc: 'Atlas Pro-Cut Hip & Ridge', baseUnitCost: 78.50, uom: 'BD' },
|
|
{ desc: 'Atlas 6X Pro-Cut Starter', baseUnitCost: 70.80, uom: 'BD' },
|
|
{ desc: 'Atlas Summit 60 Synthetic Underlayment', baseUnitCost: 116.00, uom: 'RL' },
|
|
{ desc: 'Atlas WeatherMaster Ice & Water', baseUnitCost: 65.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'atlas_glassmaster_srs',
|
|
name: 'Atlas GlassMaster - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install 3' of Atlas WeatherMaster ice and water shield at all gutter lines, rakes edges, and valleys.",
|
|
"Install Atlas Summit 60 Synthetic underlayment.",
|
|
"Install Atlas Glassmaster AR Shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'Atlas Glassmaster AR', baseUnitCost: 37.67, uom: 'SQ' },
|
|
{ desc: 'Atlas Pro-Cut Hip & Ridge', baseUnitCost: 78.50, uom: 'BD' },
|
|
{ desc: 'Atlas 6X Pro-Cut Starter', baseUnitCost: 70.80, uom: 'BD' },
|
|
{ desc: 'Atlas Summit 60 Synthetic Underlayment', baseUnitCost: 116.00, uom: 'RL' },
|
|
{ desc: 'Atlas WeatherMaster Ice & Water', baseUnitCost: 65.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'atlas_pinnacle_pristine',
|
|
name: 'Atlas Pinnacle Pristine',
|
|
category: 'Roofing',
|
|
brand: 'Atlas',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install 3' of Atlas WeatherMaster ice and water shield.",
|
|
"Install Atlas Summit 60 Synthetic underlayment.",
|
|
"Install Atlas Pinnacle Pristine Lifetime Dimensional Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'Atlas Pinnacle Pristine', baseUnitCost: 42.50, uom: 'SQ' },
|
|
{ desc: 'Atlas Pro-Cut High Profile Hip & Ridge', baseUnitCost: 85.00, uom: 'BD' },
|
|
{ desc: 'Atlas Pro-Cut Starter', baseUnitCost: 72.00, uom: 'BD' },
|
|
{ desc: 'Atlas Summit 60 Synthetic Underlayment', baseUnitCost: 116.00, uom: 'RL' },
|
|
{ desc: 'Atlas WeatherMaster Ice & Water', baseUnitCost: 65.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'atlas_pinnacle_pristine_srs',
|
|
name: 'Atlas Pinnacle Pristine - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install 3' of Atlas WeatherMaster ice and water shield.",
|
|
"Install Atlas Summit 60 Synthetic underlayment.",
|
|
"Install Atlas Pinnacle Pristine Lifetime Dimensional Shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'Atlas Pinnacle Pristine', baseUnitCost: 42.50, uom: 'SQ' },
|
|
{ desc: 'Atlas Pro-Cut High Profile Hip & Ridge', baseUnitCost: 85.00, uom: 'BD' },
|
|
{ desc: 'Atlas Pro-Cut Starter', baseUnitCost: 72.00, uom: 'BD' },
|
|
{ desc: 'Atlas Summit 60 Synthetic Underlayment', baseUnitCost: 116.00, uom: 'RL' },
|
|
{ desc: 'Atlas WeatherMaster Ice & Water', baseUnitCost: 65.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'atlas_stormmaster_shake',
|
|
name: 'Atlas StormMaster Shake',
|
|
category: 'Roofing',
|
|
brand: 'Atlas',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install 3' of Atlas WeatherMaster ice and water shield at all eaves and valleys.",
|
|
"Install Atlas Summit 60 Synthetic underlayment.",
|
|
"Install Atlas StormMaster Shake Impact Resistant Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'Atlas StormMaster Shake', baseUnitCost: 55.00, uom: 'SQ' },
|
|
{ desc: 'Atlas Pro-Cut Hip & Ridge', baseUnitCost: 78.50, uom: 'BD' },
|
|
{ desc: 'Atlas 6X Pro-Cut Starter', baseUnitCost: 70.80, uom: 'BD' },
|
|
{ desc: 'Atlas Summit 60 Synthetic Underlayment', baseUnitCost: 116.00, uom: 'RL' },
|
|
{ desc: 'Atlas WeatherMaster Ice & Water', baseUnitCost: 65.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'certainteed_landmark',
|
|
name: 'CertainTeed Landmark AR',
|
|
category: 'Roofing',
|
|
brand: 'CertainTeed',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install CertainTeed WinterGuard ice and water shield.",
|
|
"Install CertainTeed RoofRunner Synthetic underlayment.",
|
|
"Install CertainTeed Landmark AR Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'CertainTeed Landmark AR', baseUnitCost: 44.00, uom: 'SQ' },
|
|
{ desc: 'CertainTeed ShadowRidge', baseUnitCost: 82.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed SwiftStart', baseUnitCost: 75.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed RoofRunner', baseUnitCost: 125.00, uom: 'RL' },
|
|
{ desc: 'CertainTeed WinterGuard', baseUnitCost: 70.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'certainteed_landmark_srs',
|
|
name: 'CertainTeed Landmark AR - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install CertainTeed WinterGuard ice and water shield.",
|
|
"Install CertainTeed RoofRunner Synthetic underlayment.",
|
|
"Install CertainTeed Landmark AR Shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'CertainTeed Landmark AR', baseUnitCost: 44.00, uom: 'SQ' },
|
|
{ desc: 'CertainTeed ShadowRidge', baseUnitCost: 82.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed SwiftStart', baseUnitCost: 75.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed RoofRunner', baseUnitCost: 125.00, uom: 'RL' },
|
|
{ desc: 'CertainTeed WinterGuard', baseUnitCost: 70.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'certainteed_presidential_shake',
|
|
name: 'CertainTeed Presidential Shake TL',
|
|
category: 'Roofing',
|
|
brand: 'CertainTeed',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install CertainTeed WinterGuard ice and water shield at all eaves and valleys.",
|
|
"Install CertainTeed RoofRunner Synthetic underlayment.",
|
|
"Install CertainTeed Presidential Shake TL triple-layer shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'CertainTeed Presidential Shake TL', baseUnitCost: 72.00, uom: 'SQ' },
|
|
{ desc: 'CertainTeed Presidential Ridge', baseUnitCost: 92.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed SwiftStart', baseUnitCost: 75.00, uom: 'BD' },
|
|
{ desc: 'CertainTeed RoofRunner', baseUnitCost: 125.00, uom: 'RL' },
|
|
{ desc: 'CertainTeed WinterGuard', baseUnitCost: 70.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'gaf_royal_sovereign',
|
|
name: 'GAF Royal Sovereign',
|
|
category: 'Roofing',
|
|
brand: 'GAF',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install GAF WeatherWatch ice and water shield at eaves and valleys.",
|
|
"Install GAF FeltBuster Synthetic underlayment.",
|
|
"Install GAF Royal Sovereign 3-tab shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'GAF Royal Sovereign', baseUnitCost: 32.00, uom: 'SQ' },
|
|
{ desc: 'GAF Seal-A-Ridge', baseUnitCost: 72.00, uom: 'BD' },
|
|
{ desc: 'GAF Pro-Start Starter Strip', baseUnitCost: 68.00, uom: 'BD' },
|
|
{ desc: 'GAF FeltBuster Synthetic Underlayment', baseUnitCost: 110.00, uom: 'RL' },
|
|
{ desc: 'GAF WeatherWatch Ice & Water', baseUnitCost: 68.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'gaf_timberline_hdz',
|
|
name: 'GAF Timberline HDZ',
|
|
category: 'Roofing',
|
|
brand: 'GAF',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install GAF WeatherWatch ice and water shield at eaves, rakes, and valleys.",
|
|
"Install GAF FeltBuster Synthetic underlayment.",
|
|
"Install GAF Timberline HDZ Laminated Architectural Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'GAF Timberline HDZ', baseUnitCost: 45.00, uom: 'SQ' },
|
|
{ desc: 'GAF TimberTex Premium Ridge Cap', baseUnitCost: 85.00, uom: 'BD' },
|
|
{ desc: 'GAF Pro-Start Starter Strip', baseUnitCost: 68.00, uom: 'BD' },
|
|
{ desc: 'GAF FeltBuster Synthetic Underlayment', baseUnitCost: 110.00, uom: 'RL' },
|
|
{ desc: 'GAF WeatherWatch Ice & Water', baseUnitCost: 68.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'gaf_timberline_ultra_hd',
|
|
name: 'GAF Timberline Ultra HD',
|
|
category: 'Roofing',
|
|
brand: 'GAF',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install GAF WeatherWatch ice and water shield at eaves, rakes, and valleys.",
|
|
"Install GAF FeltBuster Synthetic underlayment.",
|
|
"Install GAF Timberline Ultra HD extra-thick dimensional shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'GAF Timberline Ultra HD', baseUnitCost: 52.00, uom: 'SQ' },
|
|
{ desc: 'GAF TimberTex Premium Ridge Cap', baseUnitCost: 85.00, uom: 'BD' },
|
|
{ desc: 'GAF Pro-Start Starter Strip', baseUnitCost: 68.00, uom: 'BD' },
|
|
{ desc: 'GAF FeltBuster Synthetic Underlayment', baseUnitCost: 110.00, uom: 'RL' },
|
|
{ desc: 'GAF WeatherWatch Ice & Water', baseUnitCost: 68.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'gaf_timberline_hdz_srs',
|
|
name: 'GAF Timberline HDZ - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install GAF WeatherWatch ice and water shield at eaves, rakes, and valleys.",
|
|
"Install GAF FeltBuster Synthetic underlayment.",
|
|
"Install GAF Timberline HDZ Laminated Architectural Shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'GAF Timberline HDZ', baseUnitCost: 45.00, uom: 'SQ' },
|
|
{ desc: 'GAF TimberTex Premium Ridge Cap', baseUnitCost: 85.00, uom: 'BD' },
|
|
{ desc: 'GAF Pro-Start Starter Strip', baseUnitCost: 68.00, uom: 'BD' },
|
|
{ desc: 'GAF FeltBuster Synthetic Underlayment', baseUnitCost: 110.00, uom: 'RL' },
|
|
{ desc: 'GAF WeatherWatch Ice & Water', baseUnitCost: 68.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_armourshake',
|
|
name: 'IKO Armourshake',
|
|
category: 'Roofing',
|
|
brand: 'IKO',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield at eaves and valleys.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Armourshake heavyweight laminated shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Armourshake', baseUnitCost: 58.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_armourshake_srs',
|
|
name: 'IKO Armourshake - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield at eaves and valleys.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Armourshake heavyweight laminated shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Armourshake', baseUnitCost: 58.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_cambridge',
|
|
name: 'IKO Cambridge',
|
|
category: 'Roofing',
|
|
brand: 'IKO',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Cambridge Architectural Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Cambridge', baseUnitCost: 42.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_dynasty',
|
|
name: 'IKO Dynasty',
|
|
category: 'Roofing',
|
|
brand: 'IKO',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield at eaves, rakes, and valleys.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Dynasty Impact Resistant shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Dynasty', baseUnitCost: 54.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_dynasty_srs',
|
|
name: 'IKO Dynasty - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield at eaves, rakes, and valleys.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Dynasty Impact Resistant shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Dynasty', baseUnitCost: 54.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'iko_nordic_per_square',
|
|
name: 'IKO Nordic Per Square',
|
|
category: 'Roofing',
|
|
brand: 'IKO',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install IKO ArmourGard ice and water shield.",
|
|
"Install IKO RoofGard-SB Synthetic underlayment.",
|
|
"Install IKO Nordic Architectural Shingles (priced per square)."
|
|
],
|
|
materials: [
|
|
{ desc: 'IKO Nordic', baseUnitCost: 40.00, uom: 'SQ' },
|
|
{ desc: 'IKO Hip & Ridge 12', baseUnitCost: 80.00, uom: 'BD' },
|
|
{ desc: 'IKO Leading Edge Plus Starter Strip', baseUnitCost: 71.00, uom: 'BD' },
|
|
{ desc: 'IKO RoofGard-SB Synthetic Underlayment', baseUnitCost: 118.00, uom: 'RL' },
|
|
{ desc: 'IKO ArmourGard Ice & Water', baseUnitCost: 67.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'malarkey_vista_ar',
|
|
name: 'Malarkey Vista AR',
|
|
category: 'Roofing',
|
|
brand: 'Malarkey',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Re-nail any loose wood.",
|
|
"Install Malarkey EverGuard ice and water shield at eaves and valleys.",
|
|
"Install Malarkey UDL 40 Synthetic underlayment.",
|
|
"Install Malarkey Vista AR Architectural Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'Malarkey Vista AR', baseUnitCost: 46.00, uom: 'SQ' },
|
|
{ desc: 'Malarkey Ridglass Hip & Ridge', baseUnitCost: 83.00, uom: 'BD' },
|
|
{ desc: 'Malarkey Windsor Starter Strip', baseUnitCost: 73.00, uom: 'BD' },
|
|
{ desc: 'Malarkey UDL 40 Synthetic Underlayment', baseUnitCost: 122.00, uom: 'RL' },
|
|
{ desc: 'Malarkey EverGuard Ice & Water', baseUnitCost: 69.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'mulehide_epdm',
|
|
name: 'Mulehide .060 EPDM System',
|
|
category: 'Roofing',
|
|
brand: 'Mulehide',
|
|
description: [
|
|
"Remove existing flat roof membrane down to deck.",
|
|
"Inspect and repair decking as needed.",
|
|
"Install Mulehide .060 EPDM membrane fully adhered system.",
|
|
"Install Mulehide bonding adhesive.",
|
|
"Install drip edge and termination bars at perimeter."
|
|
],
|
|
materials: [
|
|
{ desc: 'Mulehide .060 EPDM Membrane', baseUnitCost: 85.00, uom: 'SQ' },
|
|
{ desc: 'Mulehide Bonding Adhesive', baseUnitCost: 48.00, uom: 'EA' },
|
|
{ desc: 'Mulehide EPDM Lap Sealant', baseUnitCost: 12.00, uom: 'EA' },
|
|
{ desc: 'Mulehide Termination Bar', baseUnitCost: 4.50, uom: 'LF' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'owens_corning_duration',
|
|
name: 'Owens Corning Duration',
|
|
category: 'Roofing',
|
|
brand: 'Owens Corning',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Inspect and re-nail decking.",
|
|
"Install Owens Corning WeatherLock G ice and water shield.",
|
|
"Install Owens Corning ProArmor Synthetic underlayment.",
|
|
"Install Owens Corning TruDefinition Duration Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'OC TruDefinition Duration', baseUnitCost: 46.50, uom: 'SQ' },
|
|
{ desc: 'OC ProEdge Hip & Ridge', baseUnitCost: 88.00, uom: 'BD' },
|
|
{ desc: 'OC Starter Strip Plus', baseUnitCost: 78.00, uom: 'BD' },
|
|
{ desc: 'OC ProArmor Underlayment', baseUnitCost: 130.00, uom: 'RL' },
|
|
{ desc: 'OC WeatherLock G', baseUnitCost: 75.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'owens_corning_duration_srs',
|
|
name: 'Owens Corning Duration - SRS',
|
|
category: 'Roofing',
|
|
brand: 'SRS',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Inspect and re-nail decking.",
|
|
"Install Owens Corning WeatherLock G ice and water shield.",
|
|
"Install Owens Corning ProArmor Synthetic underlayment.",
|
|
"Install Owens Corning TruDefinition Duration Shingles (SRS distribution)."
|
|
],
|
|
materials: [
|
|
{ desc: 'OC TruDefinition Duration', baseUnitCost: 46.50, uom: 'SQ' },
|
|
{ desc: 'OC ProEdge Hip & Ridge', baseUnitCost: 88.00, uom: 'BD' },
|
|
{ desc: 'OC Starter Strip Plus', baseUnitCost: 78.00, uom: 'BD' },
|
|
{ desc: 'OC ProArmor Underlayment', baseUnitCost: 130.00, uom: 'RL' },
|
|
{ desc: 'OC WeatherLock G', baseUnitCost: 75.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
},
|
|
{
|
|
id: 'owens_corning_oakridge',
|
|
name: 'Owens Corning Oakridge',
|
|
category: 'Roofing',
|
|
brand: 'Owens Corning',
|
|
description: [
|
|
"Remove existing shingles down to deck.",
|
|
"Inspect and re-nail decking.",
|
|
"Install Owens Corning WeatherLock G ice and water shield.",
|
|
"Install Owens Corning ProArmor Synthetic underlayment.",
|
|
"Install Owens Corning Oakridge Architectural Shingles."
|
|
],
|
|
materials: [
|
|
{ desc: 'OC Oakridge', baseUnitCost: 38.00, uom: 'SQ' },
|
|
{ desc: 'OC ProEdge Hip & Ridge', baseUnitCost: 88.00, uom: 'BD' },
|
|
{ desc: 'OC Starter Strip Plus', baseUnitCost: 78.00, uom: 'BD' },
|
|
{ desc: 'OC ProArmor Underlayment', baseUnitCost: 130.00, uom: 'RL' },
|
|
{ desc: 'OC WeatherLock G', baseUnitCost: 75.00, uom: 'RL' },
|
|
{ desc: 'Coil Nails 1 1/4"', baseUnitCost: 35.00, uom: 'BX' },
|
|
{ desc: 'Plastic Cap Nails', baseUnitCost: 28.50, uom: 'BX' },
|
|
{ desc: 'Geocel 2300 Clear Sealant', baseUnitCost: 8.95, uom: 'EA' }
|
|
]
|
|
}
|
|
];
|
|
|
|
export default function TemplateSelectionModal({ isOpen, onClose, onSelectTemplate }) {
|
|
const { templates } = useMockStore();
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [selected, setSelected] = useState(null);
|
|
|
|
const filtered = templates.filter(t =>
|
|
t.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
t.category.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
const handleNext = () => {
|
|
if (selected) {
|
|
onSelectTemplate(selected);
|
|
}
|
|
};
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm">
|
|
<div
|
|
className="bg-white dark:bg-zinc-900 w-full max-w-3xl rounded-2xl shadow-xl border border-zinc-200 dark:border-white/10 overflow-hidden flex flex-col max-h-[90vh]"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-6 border-b border-zinc-200 dark:border-white/10 shrink-0">
|
|
<div>
|
|
<h2 className="text-2xl font-display text-zinc-900 dark:text-white font-light tracking-tight">Select a Template</h2>
|
|
<p className="text-sm text-zinc-500 dark:text-zinc-400 mt-1">Choose a base template to calculate your item quantities.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Search Bar */}
|
|
<div className="px-6 py-4 border-b border-zinc-200 dark:border-white/5 bg-zinc-50 dark:bg-zinc-900/50 shrink-0">
|
|
<input
|
|
type="text"
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
placeholder="Search for a Template..."
|
|
className="w-full bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg px-4 py-2.5 text-sm outline-none focus:ring-2 focus:ring-blue-500 transition-shadow text-zinc-800 dark:text-zinc-200"
|
|
/>
|
|
</div>
|
|
|
|
{/* Templates List */}
|
|
<div className="p-6 overflow-y-auto custom-scrollbar flex-1 bg-zinc-50/50 dark:bg-zinc-900/20">
|
|
<div className="bg-white dark:bg-zinc-800/50 border border-zinc-200 dark:border-white/10 rounded-xl overflow-hidden">
|
|
|
|
{/* Category Header */}
|
|
<div className="px-4 py-3 bg-blue-50/50 dark:bg-blue-900/10 border-b border-zinc-200 dark:border-white/10">
|
|
<h3 className="text-sm font-semibold text-blue-600 dark:text-blue-400">
|
|
Templates ({filtered.length})
|
|
</h3>
|
|
</div>
|
|
|
|
{/* List items */}
|
|
<div className="divide-y divide-zinc-200 dark:divide-white/10 text-left">
|
|
{filtered.map((template) => {
|
|
const isSelected = selected?.id === template.id;
|
|
return (
|
|
<button
|
|
key={template.id}
|
|
onClick={() => setSelected(template)}
|
|
className={`w-full flex flex-col md:flex-row items-start md:items-center p-4 transition-colors text-left focus:outline-none ${isSelected
|
|
? 'bg-blue-50 dark:bg-blue-500/10 border-l-4 border-l-blue-500'
|
|
: 'hover:bg-blue-50/30 dark:hover:bg-blue-500/5 focus:bg-blue-50/50 dark:focus:bg-blue-500/10'
|
|
}`}
|
|
>
|
|
{/* Content */}
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
{/* Radio circle visual */}
|
|
<div className={`w-5 h-5 rounded-full border-2 flex items-center justify-center shrink-0 transition-colors ${isSelected ? 'border-orange-500' : 'border-orange-300 hover:border-blue-400'}`}>
|
|
{isSelected && (
|
|
<div className="w-2.5 h-2.5 rounded-full bg-orange-500"></div>
|
|
)}
|
|
</div>
|
|
<h4 className={`text-base font-medium transition-colors ${isSelected ? 'text-blue-700 dark:text-blue-300' : 'text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300'}`}>
|
|
{template.name}
|
|
</h4>
|
|
</div>
|
|
|
|
<ul className="pl-8 space-y-0.5">
|
|
{template.description.slice(0, 3).map((descLine, i) => (
|
|
<li key={i} className="text-sm text-zinc-500 dark:text-zinc-400 truncate max-w-xl flex items-start gap-2">
|
|
<span className="text-zinc-300 dark:text-zinc-600 mt-1 shrink-0">-</span>
|
|
<span className="truncate">{descLine}</span>
|
|
</li>
|
|
))}
|
|
{template.description.length > 3 && (
|
|
<li className="text-sm text-zinc-400 dark:text-zinc-500 pl-4">...</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Action Column */}
|
|
<div className="flex flex-col items-center justify-center ml-auto mt-4 md:mt-0 pl-8 md:pl-4 shrink-0 gap-2">
|
|
<span className="text-sm font-medium text-blue-500 hover:text-blue-600 hover:underline cursor-pointer">Preview</span>
|
|
<div className="text-xs font-bold text-zinc-500 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-700 px-2 py-0.5 rounded">
|
|
{template.brand}
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
})}
|
|
|
|
{filtered.length === 0 && (
|
|
<div className="px-4 py-8 text-center text-zinc-400 text-sm">
|
|
No templates match your search.
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="flex items-center gap-4 p-4 border-t border-zinc-200 dark:border-white/10 shrink-0 bg-white dark:bg-zinc-900 justify-start">
|
|
<button
|
|
onClick={onClose}
|
|
className="px-6 py-2.5 text-red-500 font-medium hover:bg-red-50 dark:hover:bg-red-500/10 rounded-lg transition-colors text-sm"
|
|
>
|
|
CANCEL
|
|
</button>
|
|
<button
|
|
onClick={handleNext}
|
|
disabled={!selected}
|
|
className={`ml-auto px-8 py-2.5 rounded-lg font-medium text-sm transition-colors ${selected
|
|
? 'bg-blue-500 hover:bg-blue-600 text-white shadow-sm cursor-pointer'
|
|
: 'bg-blue-100 dark:bg-blue-900/30 text-blue-300 dark:text-blue-500 cursor-not-allowed opacity-60'
|
|
}`}
|
|
>
|
|
NEXT
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|