diff --git a/index.html b/index.html index c2fe74f..b493745 100644 --- a/index.html +++ b/index.html @@ -12,21 +12,21 @@ - + - - + + - + - + diff --git a/public/assets/images/properties/Apartment_Complex.jpg b/public/assets/images/properties/Apartment_Complex.jpg new file mode 100644 index 0000000..63939b6 Binary files /dev/null and b/public/assets/images/properties/Apartment_Complex.jpg differ diff --git a/public/assets/images/properties/Beige_Two_Story_House.jpg b/public/assets/images/properties/Beige_Two_Story_House.jpg new file mode 100644 index 0000000..4842b7e Binary files /dev/null and b/public/assets/images/properties/Beige_Two_Story_House.jpg differ diff --git a/public/assets/images/properties/Brick_Front_Porch_Home.jpg b/public/assets/images/properties/Brick_Front_Porch_Home.jpg new file mode 100644 index 0000000..ba72501 Binary files /dev/null and b/public/assets/images/properties/Brick_Front_Porch_Home.jpg differ diff --git a/public/assets/images/properties/Broken_Roof_Surface.jpg b/public/assets/images/properties/Broken_Roof_Surface.jpg new file mode 100644 index 0000000..7867a6a Binary files /dev/null and b/public/assets/images/properties/Broken_Roof_Surface.jpg differ diff --git a/public/assets/images/properties/Cracked_Asphalt_Shingles.jpg b/public/assets/images/properties/Cracked_Asphalt_Shingles.jpg new file mode 100644 index 0000000..92409f0 Binary files /dev/null and b/public/assets/images/properties/Cracked_Asphalt_Shingles.jpg differ diff --git a/public/assets/images/properties/Cracked_Storm_Shingles.jpg b/public/assets/images/properties/Cracked_Storm_Shingles.jpg new file mode 100644 index 0000000..1af64c7 Binary files /dev/null and b/public/assets/images/properties/Cracked_Storm_Shingles.jpg differ diff --git a/public/assets/images/properties/Curled_Aging_Shingles.jpg b/public/assets/images/properties/Curled_Aging_Shingles.jpg new file mode 100644 index 0000000..2b11af3 Binary files /dev/null and b/public/assets/images/properties/Curled_Aging_Shingles.jpg differ diff --git a/public/assets/images/properties/Hail_Damaged_Shingles.jpg b/public/assets/images/properties/Hail_Damaged_Shingles.jpg new file mode 100644 index 0000000..bc0891e Binary files /dev/null and b/public/assets/images/properties/Hail_Damaged_Shingles.jpg differ diff --git a/public/assets/images/properties/Luxury_Driveway_Residence.jpg b/public/assets/images/properties/Luxury_Driveway_Residence.jpg new file mode 100644 index 0000000..4b97498 Binary files /dev/null and b/public/assets/images/properties/Luxury_Driveway_Residence.jpg differ diff --git a/public/assets/images/properties/Mall_Rooftop_HVAC_Units.jpg b/public/assets/images/properties/Mall_Rooftop_HVAC_Units.jpg new file mode 100644 index 0000000..c0217e3 Binary files /dev/null and b/public/assets/images/properties/Mall_Rooftop_HVAC_Units.jpg differ diff --git a/public/assets/images/properties/Minimal_Flat_Roof_House.jpg b/public/assets/images/properties/Minimal_Flat_Roof_House.jpg new file mode 100644 index 0000000..ace94c5 Binary files /dev/null and b/public/assets/images/properties/Minimal_Flat_Roof_House.jpg differ diff --git a/public/assets/images/properties/Modern_White_Suburban_Home.jpg b/public/assets/images/properties/Modern_White_Suburban_Home.jpg new file mode 100644 index 0000000..c5ecb33 Binary files /dev/null and b/public/assets/images/properties/Modern_White_Suburban_Home.jpg differ diff --git a/public/assets/images/properties/Office_Roof_Top_View.jpg b/public/assets/images/properties/Office_Roof_Top_View.jpg new file mode 100644 index 0000000..63939b6 Binary files /dev/null and b/public/assets/images/properties/Office_Roof_Top_View.jpg differ diff --git a/public/assets/images/properties/Overlapping_Roof_Shingles.jpg b/public/assets/images/properties/Overlapping_Roof_Shingles.jpg new file mode 100644 index 0000000..1aea266 Binary files /dev/null and b/public/assets/images/properties/Overlapping_Roof_Shingles.jpg differ diff --git a/public/assets/images/properties/Red_Metal_Roof_Home.jpg b/public/assets/images/properties/Red_Metal_Roof_Home.jpg new file mode 100644 index 0000000..d77ec4f Binary files /dev/null and b/public/assets/images/properties/Red_Metal_Roof_Home.jpg differ diff --git a/public/assets/images/properties/Red_Shingle_Cottage.jpg b/public/assets/images/properties/Red_Shingle_Cottage.jpg new file mode 100644 index 0000000..18d0b0b Binary files /dev/null and b/public/assets/images/properties/Red_Shingle_Cottage.jpg differ diff --git a/public/assets/images/properties/Red_Tiled_Roof_House.jpg b/public/assets/images/properties/Red_Tiled_Roof_House.jpg new file mode 100644 index 0000000..7950cf7 Binary files /dev/null and b/public/assets/images/properties/Red_Tiled_Roof_House.jpg differ diff --git a/public/assets/images/properties/Residential_Roof_Texture.jpg b/public/assets/images/properties/Residential_Roof_Texture.jpg new file mode 100644 index 0000000..2348383 Binary files /dev/null and b/public/assets/images/properties/Residential_Roof_Texture.jpg differ diff --git a/public/assets/images/properties/Roof_Inspection_Angle.jpg b/public/assets/images/properties/Roof_Inspection_Angle.jpg new file mode 100644 index 0000000..15a0bcb Binary files /dev/null and b/public/assets/images/properties/Roof_Inspection_Angle.jpg differ diff --git a/public/assets/images/properties/Storm_Worn_Roof.jpg b/public/assets/images/properties/Storm_Worn_Roof.jpg new file mode 100644 index 0000000..6a96470 Binary files /dev/null and b/public/assets/images/properties/Storm_Worn_Roof.jpg differ diff --git a/public/assets/images/properties/Sunny_Suburban_House.jpg b/public/assets/images/properties/Sunny_Suburban_House.jpg new file mode 100644 index 0000000..2cc991c Binary files /dev/null and b/public/assets/images/properties/Sunny_Suburban_House.jpg differ diff --git a/public/assets/images/properties/Warehouse_Roof_Aerial.jpg b/public/assets/images/properties/Warehouse_Roof_Aerial.jpg new file mode 100644 index 0000000..d9322ce Binary files /dev/null and b/public/assets/images/properties/Warehouse_Roof_Aerial.jpg differ diff --git a/src/components/IntelligenceMap.jsx b/src/components/IntelligenceMap.jsx index 9744c87..1168ece 100644 --- a/src/components/IntelligenceMap.jsx +++ b/src/components/IntelligenceMap.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Icons } from './landing/constants'; import MapBg from '../assets/images/hyper_intelligence_bg_image.jpg'; +import IntelligenceSidePanel from './dashboard/IntelligenceSidePanel'; // Updated with Residential & Commercial mix const hotspots = [ @@ -16,7 +17,11 @@ const hotspots = [ weather: 'Hail Expected', status: 'Urgent', specs: { built: '1998', maintenance: '5 years since last coating' }, - management: { name: 'Sterling Properties', contact: 'Sign in for contact details' } + management: { name: 'Sterling Properties', contact: 'Sign in for contact details' }, + photos: [ + { id: 1, url: '/assets/images/properties/Warehouse_Roof_Aerial.jpg', caption: 'Warehouse Roof Aerial' }, + { id: 2, url: '/assets/images/properties/Office_Roof_Top_View.jpg', caption: 'Office Roof Top' } + ] }, { id: 2, @@ -29,7 +34,10 @@ const hotspots = [ weather: 'Clear', status: 'Monitoring', specs: { built: '1982', maintenance: '20 years since last roof replacement permit' }, - management: { name: 'Goldman Group', contact: 'Sign in for contact details' } + management: { name: 'Goldman Group', contact: 'Sign in for contact details' }, + photos: [ + { id: 3, url: '/assets/images/properties/Mall_Rooftop_HVAC_Units.jpg', caption: 'Rooftop HVAC Units' } + ] }, { id: 3, @@ -42,7 +50,11 @@ const hotspots = [ weather: 'Rain Soon', status: 'Action Required', specs: { roofSize: '62 sq Roof', eventHistory: '8 years since last known hail event' }, - owner: { fico: '715', profile: 'Early Adopter / Long-term value' } + owner: { fico: '715', profile: 'Early Adopter / Long-term value' }, + photos: [ + { id: 4, url: '/assets/images/properties/Hail_Damaged_Shingles.jpg', caption: 'Hail Damage Close-up' }, + { id: 5, url: '/assets/images/properties/Broken_Roof_Surface.jpg', caption: 'Broken Surface' } + ] }, { id: 4, @@ -55,7 +67,11 @@ const hotspots = [ weather: 'Windy', status: 'Low Priority', specs: { roofSize: '45 sq Roof', eventHistory: 'High Wind Zone' }, - owner: { fico: '680', profile: 'First-time Buyer' } + owner: { fico: '680', profile: 'First-time Buyer' }, + photos: [ + { id: 6, url: '/assets/images/properties/Cracked_Asphalt_Shingles.jpg', caption: 'Cracked Shingles' }, + { id: 7, url: '/assets/images/properties/Curled_Aging_Shingles.jpg', caption: 'Aging Shingles' } + ] }, ]; @@ -190,97 +206,10 @@ const IntelligenceMap = () => { {/* Right Sidebar Panel (Glass Detail View) */} {activeSpot && ( -
-
-
-
-

INTEL_FEED

-
- -
- -
-
-
- -
- -
{activeSpot.gain}
-
- -
- -
{activeSpot.address}
-
Dallas-Fort Worth Metroplex • {activeSpot.type} Zone
-
- - {/* Divider */} -
- -
- -
- {activeSpot.problem} -
-
- - {/* Dynamic Specs & Intel Based on Type */} - {activeSpot.type === 'Commercial' && activeSpot.specs ? ( -
-
-
- -
{activeSpot.specs.built}
-
-
- -
{activeSpot.specs.maintenance}
-
-
-
- -
{activeSpot.management.name}
-
navigate('/login')} className="text-xs text-blue-400 cursor-pointer hover:underline mt-1">{activeSpot.management.contact}
-
-
- ) : activeSpot.type === 'Residential' && activeSpot.specs ? ( -
-
-
- -
{activeSpot.specs.roofSize}
-
-
- -
{activeSpot.specs.eventHistory}
-
-
-
- -
-
-
FICO Score
-
{activeSpot.owner.fico}
-
-
-
Profile
-
{activeSpot.owner.profile}
-
-
-
-
- ) : ( -
- > ANALYSIS: {activeSpot.type === 'Commercial' ? 'High-value commercial asset at risk. Immediate inspection recommended.' : 'High probability of insurance approval due to recent storm activity.'} -
- )} - -
- - -
+ setActiveSpot(null)} + /> )} diff --git a/src/components/dashboard/IntelligenceSidePanel.jsx b/src/components/dashboard/IntelligenceSidePanel.jsx new file mode 100644 index 0000000..36792e4 --- /dev/null +++ b/src/components/dashboard/IntelligenceSidePanel.jsx @@ -0,0 +1,308 @@ + +import React, { useState, useEffect, useRef } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Icons } from '../landing/constants'; +import { ChevronLeft, ChevronRight, X } from 'lucide-react'; + +const IntelligenceSidePanel = ({ data, onClose }) => { + const navigate = useNavigate(); + const [activeTab, setActiveTab] = useState('details'); + // Initialize photos from data or use empty array if not present + const [photos, setPhotos] = useState(data.photos || []); + // Lightbox State + const [lightboxIndex, setLightboxIndex] = useState(null); // null = closed, number = open at index + + const panelRef = useRef(null); + const closeButtonRef = useRef(null); + const lightboxRef = useRef(null); + + // Update photos state if data changes (e.g. switching pins) + useEffect(() => { + setPhotos(data.photos || []); + setActiveTab('details'); // Reset tab when data changes + setLightboxIndex(null); // Close lightbox if data changes + }, [data]); + + // Accessibility: Focus management and Escape key listener + useEffect(() => { + // Focus the close button when the panel opens + if (closeButtonRef.current && !lightboxIndex) { + closeButtonRef.current.focus(); + } + + const handleKeyDown = (e) => { + if (e.key === 'Escape') { + if (lightboxIndex !== null) { + setLightboxIndex(null); + } else { + onClose(); + } + } + }; + + document.addEventListener('keydown', handleKeyDown); + return () => document.removeEventListener('keydown', handleKeyDown); + }, [onClose, lightboxIndex]); + + // Lightbox Keyboard Navigation + useEffect(() => { + if (lightboxIndex === null) return; + + const handleLightboxKeys = (e) => { + if (e.key === 'ArrowRight') { + setLightboxIndex((prev) => (prev + 1) % photos.length); + } else if (e.key === 'ArrowLeft') { + setLightboxIndex((prev) => (prev - 1 + photos.length) % photos.length); + } + }; + + document.addEventListener('keydown', handleLightboxKeys); + return () => document.removeEventListener('keydown', handleLightboxKeys); + }, [lightboxIndex, photos.length]); + + if (!data) return null; + + return ( +
+ {/* Header */} +
+
+
+

INTEL_FEED

+
+ +
+ + {/* Tabs */} +
+ + +
+ + {/* Content Area */} +
+ + {/* DETAILS TAB */} + {activeTab === 'details' && ( +
+
+
+ +
+ +
{data.gain}
+
+ +
+ +
{data.address}
+
Dallas-Fort Worth Metroplex • {data.type} Zone
+
+ + {/* Divider */} +
+ +
+ +
+ {data.problem} +
+
+ + {/* Dynamic Specs & Intel Based on Type */} + {data.type === 'Commercial' && data.specs ? ( +
+
+
+ +
{data.specs.built}
+
+
+ +
{data.specs.maintenance}
+
+
+
+ +
{data.management.name}
+
navigate('/login')} + className="text-xs text-blue-400 cursor-pointer hover:underline mt-1 focus:outline-none focus:ring-1 focus:ring-blue-400 rounded" + role="button" + tabIndex={0} + onKeyDown={(e) => { if (e.key === 'Enter') navigate('/login'); }} + > + {data.management.contact} +
+
+
+ ) : data.type === 'Residential' && data.specs ? ( +
+
+
+ +
{data.specs.roofSize}
+
+
+ +
{data.specs.eventHistory}
+
+
+
+ +
+
+
FICO Score
+
{data.owner.fico}
+
+
+
Profile
+
{data.owner.profile}
+
+
+
+
+ ) : ( +
+ > ANALYSIS: {data.type === 'Commercial' ? 'High-value commercial asset at risk. Immediate inspection recommended.' : 'High probability of insurance approval due to recent storm activity.'} +
+ )} + + +
+ )} + + {/* PHOTOS TAB */} + {activeTab === 'photos' && ( +
+ + {/* Photo Grid */} +
{/* pb-20 for bottom fixed button space if needed, though button is inline here */} + {photos.map((photo, index) => ( +
setLightboxIndex(index)} + > + {photo.caption +
+ View +
+ + +
+ ))} + + {/* Upload Placeholders if empty */} + {photos.length === 0 && ( +
+

No photos available

+
+ )} +
+
+ )} +
+ + {/* LIGHTBOX OVERLAY */} + {lightboxIndex !== null && photos[lightboxIndex] && ( +
+ {/* Close Button */} + + + {/* Navigation Left */} + + + {/* Main Image */} +
+ {photos[lightboxIndex].caption + +
+ IMG_SEQ: {lightboxIndex + 1} / {photos.length} +
+
+ + {/* Navigation Right */} + + + {/* Mobile Navigation Hints */} +
+ < PREV + NEXT > +
+
+ )} +
+ ); +}; + +export default IntelligenceSidePanel; diff --git a/src/components/maps/PropertyDetailDrawer.jsx b/src/components/maps/PropertyDetailDrawer.jsx new file mode 100644 index 0000000..8309da8 --- /dev/null +++ b/src/components/maps/PropertyDetailDrawer.jsx @@ -0,0 +1,684 @@ + +import React, { useState, useEffect, useRef } from 'react'; +import { X, Home, DollarSign, User, Edit2, Save, Info, AlertCircle, ShieldCheck, Loader2, ChevronLeft, ChevronRight, Trash2 } from 'lucide-react'; +import { SpotlightCard } from '../SpotlightCard'; + +const StatusBadge = ({ status }) => { + const colors = { + "Neutral": "bg-violet-400", + "Hot Lead": "bg-red-500", + "Renovated": "bg-blue-500", + "Customer": "bg-emerald-500", + "Not Interested": "bg-white border border-zinc-200 text-zinc-900 shadow-sm" + }; + return ( + + {status} + + ); +}; + +const InputGroup = ({ label, children }) => ( +
+ +
{children}
+
+); + +const PropertyDetailDrawer = ({ isOpen, onClose, data, newLocation, onSave, loadingAddr, allowUpload = true }) => { + const [isEditing, setIsEditing] = useState(false); + const [activeTab, setActiveTab] = useState('details'); + // Initialize photos from data or use empty array + const [photos, setPhotos] = useState([]); + + // Lightbox State + const [lightboxIndex, setLightboxIndex] = useState(null); // null = closed, number = open at index + + const panelRef = useRef(null); + const closeButtonRef = useRef(null); + const lightboxRef = useRef(null); + + // Initial State Matching Schema + const initialFormState = { + // Status + status: 'Neutral', + // 1.1 Basic Property Details + propertyType: 'House', + builtUpArea: '', + lotSize: '', + yearBuilt: '', + bedrooms: '', + bathrooms: '', + parkingSpaces: '', + // 1.2 Transaction & Market + purchaseDate: '', + purchasePrice: '', + marketValue: 0, + taxValue: '', + // 1.3 Renovation + roofCondition: 'Good', + lastRenovationDate: '', + // 1.4 Rental Status + isRented: 'No', // Yes/No + tenantName: '', + currentRent: '', + leaseEnd: '', + ownerWillingToRent: 'Yes', + expectedRent: '', + // 1.5 Location + schoolDistrict: '', + neighborhoodRating: 5, + // 2.1 Owner Details + ownerName: '', + ownerPhone: '', + ownerEmail: '', + ownerAddress: '', + occupation: '', + ownershipType: 'Individual', + // 2.4 Owner Intent + willingToSell: 'No', + desiredPrice: '', + minPrice: '', + // 3.0 Insurance Information + insurance_company: '', + insurance_company_not_listed: false, + damage_location: '', + date_of_loss: '', + claim_filed: 'No', + claim_number: '', + has_paperwork: 'No', + adjuster_name: '', + adjuster_phone: '', + adjuster_ext: '', + adjuster_type: '', + adjuster_fax: '', + adjuster_email: '', + met_with_adjuster: 'No', + claim_approved: 'No', + // Notes + notes: '' + }; + + const [formData, setFormData] = useState(initialFormState); + + // Reset or Initialize Form + useEffect(() => { + if (data) { + setFormData({ + ...initialFormState, + status: data.canvassingStatus || 'Neutral', + ownerName: data.ownerData?.fullName || '', + ownerPhone: data.ownerData?.primaryPhoneNumber || '', + ownerEmail: data.ownerData?.emailAddress || '', + marketValue: data.propertyData?.currentEstimatedMarketValue || 0, + notes: data.propertyData?.notes || '', + propertyType: data.propertyData?.propertyType || 'House', + builtUpArea: data.propertyData?.totalBuiltUpArea || '', + lotSize: data.propertyData?.lotPlotSize || '', + yearBuilt: data.propertyData?.yearBuilt || '', + bedrooms: data.propertyData?.numberOfBedrooms || '', + bathrooms: data.propertyData?.numberOfBathrooms || '', + parkingSpaces: data.propertyData?.numberOfParkingSpaces || '', + taxValue: data.propertyData?.propertyTaxAssessmentValue || '', + roofCondition: data.propertyData?.roofCondition || 'Good', + lastRenovationDate: data.propertyData?.lastMajorRenovationDate || '', + isRented: data.propertyData?.currentlyRented ? 'Yes' : 'No', + tenantName: data.propertyData?.currentTenantName || '', + currentRent: data.propertyData?.currentMonthlyRentAmount || '', + leaseEnd: data.propertyData?.leaseEndDate || '', + ownerWillingToRent: data.propertyData?.ownerWillingToRent ? 'Yes' : 'No', + expectedRent: data.propertyData?.expectedMonthlyRentAmount || '', + schoolDistrict: data.propertyData?.schoolDistrict || '', + neighborhoodRating: data.propertyData?.neighborhoodRating || 5, + occupation: data.ownerData?.occupation || '', + ownershipType: data.ownerData?.ownershipType || 'Individual', + willingToSell: data.ownerData?.willingToSellProperty ? 'Yes' : 'No', + desiredPrice: data.ownerData?.desiredSellingPrice || '', + minPrice: data.ownerData?.minimumAcceptableSellingPrice || '', + ownerAddress: data.ownerData?.mailingAddress || '', + insurance_company: data.insuranceData?.insurance_company || '', + insurance_company_not_listed: data.insuranceData?.insurance_company_not_listed || false, + damage_location: data.insuranceData?.damage_location || '', + date_of_loss: data.insuranceData?.date_of_loss || '', + claim_filed: data.insuranceData?.claim_filed ? 'Yes' : 'No', + claim_number: data.insuranceData?.claim_number || '', + has_paperwork: data.insuranceData?.has_paperwork ? 'Yes' : 'No', + adjuster_name: data.insuranceData?.adjuster_name || '', + adjuster_phone: data.insuranceData?.adjuster_phone || '', + adjuster_ext: data.insuranceData?.adjuster_ext || '', + adjuster_type: data.insuranceData?.adjuster_type || '', + adjuster_fax: data.insuranceData?.adjuster_fax || '', + adjuster_email: data.insuranceData?.adjuster_email || '', + met_with_adjuster: data.insuranceData?.met_with_adjuster ? 'Yes' : 'No', + claim_approved: data.insuranceData?.claim_approved ? 'Yes' : 'No', + }); + setIsEditing(false); + setPhotos(data.photos || []); + } else if (newLocation) { + setFormData(initialFormState); + setIsEditing(true); + setPhotos([]); + } + setActiveTab('details'); + }, [data, newLocation]); + + // Accessibility: Focus and key listeners for Drawer + useEffect(() => { + if (isOpen && closeButtonRef.current) { + closeButtonRef.current.focus(); + } + + const handleKeyDown = (e) => { + if (e.key === 'Escape') { + // If Lightbox is open, close it first + if (lightboxIndex !== null) { + setLightboxIndex(null); + return; + } + onClose(); + } + }; + + if (isOpen) { + document.addEventListener('keydown', handleKeyDown); + } + return () => document.removeEventListener('keydown', handleKeyDown); + }, [isOpen, onClose, lightboxIndex]); + + // Lightbox Keyboard Navigation + useEffect(() => { + if (lightboxIndex === null) return; + + const handleLightboxKeys = (e) => { + if (e.key === 'ArrowRight') { + setLightboxIndex((prev) => (prev + 1) % photos.length); + } else if (e.key === 'ArrowLeft') { + setLightboxIndex((prev) => (prev - 1 + photos.length) % photos.length); + } + }; + + document.addEventListener('keydown', handleLightboxKeys); + return () => document.removeEventListener('keydown', handleLightboxKeys); + }, [lightboxIndex, photos.length]); + + const handleSave = () => { + onSave(formData); + if (data) setIsEditing(false); + }; + + // Photo Logic + const handleUploadPhoto = (e) => { + const file = e.target.files[0]; + if (file) { + const newPhoto = { + id: Date.now(), + url: URL.createObjectURL(file), // Mock URL + caption: file.name + }; + setPhotos([...photos, newPhoto]); + // Ideally notify parent to save photos + } + }; + + const handleDeletePhoto = (id) => { + setPhotos(photos.filter(p => p.id !== id)); + }; + + if (!isOpen) return null; + + const isCreating = !data && !!newLocation; + const address = data?.propertyData?.propertyAddress || newLocation?.address || "Unknown Location"; + + // Helper for Inputs + const RenderInput = ({ label, field, type = "text", placeholder, options, locked = false }) => { + if (!isEditing) { + return ( + + + {formData[field] || "-"} + + + ); + } + + if (locked) { + return ( + +
+ {placeholder || "Not Applicable"} +
+
+ ); + } + + return ( + + {options ? ( + + ) : ( + setFormData({ ...formData, [field]: e.target.value })} + placeholder={placeholder} + className="w-full bg-zinc-50 dark:bg-black/20 border border-zinc-200 dark:border-white/10 rounded-lg py-2 px-3 text-sm text-zinc-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-blue-500 placeholder-zinc-400" + /> + )} + + ); + }; + + return ( +
+ + + {/* Header */} +
+
+ + + +
+
+ {isCreating ? New Entry : } +
+

{loadingAddr ? "Fetching Address..." : address.split(',')[0]}

+ {loadingAddr ? "Locating..." : address} +
+
+ + {/* Tabs */} + {!loadingAddr && ( +
+ + +
+ )} + + {/* Body Content */} +
+ + {loadingAddr ? ( +
+ + Resolving Location... +
+ ) : ( + <> + {/* DETAILS TAB */} + {activeTab === 'details' && ( +
+ {/* Status Selector */} + {isEditing && ( +
+ +
+ {["Neutral", "Hot Lead", "Renovated", "Customer", "Not Interested"].map(s => ( + + ))} +
+
+ )} + + {/* SECTION 1: BASIC PROPERTY INFO */} +
+
+

Property Basics

+
+
+ + + + +
+ + + +
+
+
+ + {/* SECTION 2: VALUES & CONDITION */} +
+
+

Value & Condition

+
+
+ + + + +
+
+ + {/* SECTION 3: RENTAL STATUS (Conditional) */} +
+
+
+

Rental Status

+
+ + + + {formData.isRented === 'Yes' ? ( +
+

Tenant Profile

+ +
+ + +
+
+ + +
+
+ + +
+ +

Lease Details

+ +
+ + + +
+ +
+ ) : ( +
+ + {formData.ownerWillingToRent !== 'No' && ( + + )} +
+ )} +
+ + {/* SECTION 4: INSURANCE INFORMATION */} +
+
+

Insurance Information

+
+ +
+ + +
+ isEditing && setFormData({ ...formData, insurance_company_not_listed: e.target.checked })} + disabled={!isEditing} + className="rounded border-zinc-300 dark:border-white/10" + /> + Company Not Listed +
+ +
+ + +
+ + {formData.claim_filed === 'Yes' && ( +
+ +
+ + +
+ +

Adjuster Details

+ +
+ + + +
+
+ + +
+
+ + +
+
+ )} +
+
+ + {/* SECTION 5: OWNER INTENT (Conditional) */} +
+
+

Recall & Sales Intent

+
+ +
+ + +
+ + {formData.willingToSell === 'Yes' ? ( +
+
+ + +
+
+ ) : ( + + )} +
+ + {/* SECTION 5: OWNER CONTACT */} +
+
+

Owner Contact

+
+ +
+ + +
+ +
+ + {/* SECTION 6: NOTES */} +
+
+

Field Notes

+
+ {isEditing ? ( +