ca-grow-ops-manager/frontend/src/features/layout-designer/components/FloorSelector.tsx
fullsizemalt e34df722bb
Some checks failed
Deploy to Production / deploy (push) Failing after 1s
Test / backend-test (push) Failing after 1s
Test / frontend-test (push) Failing after 0s
feat: Add Building creation functionality to Layout Designer
2025-12-11 11:36:31 -08:00

202 lines
9.8 KiB
TypeScript

import { useState } from 'react';
import { X, Plus, Building2, Layers, ChevronRight, Check, MapPin } from 'lucide-react';
import { useLayoutStore } from '../../../stores/layoutStore';
interface FloorSelectorProps {
isOpen: boolean;
onClose: () => void;
onSelectFloor: (floorId: string, buildingId: string) => void;
onAddProperty?: () => void;
onAddBuilding?: () => void;
onAddFloor?: (buildingId: string) => void;
}
export function FloorSelector({
isOpen,
onClose,
onSelectFloor,
onAddProperty,
onAddBuilding,
onAddFloor
}: FloorSelectorProps) {
const { property, buildingId, floorId } = useLayoutStore();
const [expandedBuildings, setExpandedBuildings] = useState<Set<string>>(new Set());
if (!isOpen) return null;
const toggleBuilding = (id: string) => {
setExpandedBuildings(prev => {
const next = new Set(prev);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return next;
});
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="bg-slate-900 border border-white/10 rounded-2xl w-full max-w-md mx-4 overflow-hidden shadow-2xl">
{/* Header */}
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-emerald-600/20 flex items-center justify-center">
<Layers className="text-emerald-400" size={20} />
</div>
<div>
<h2 className="text-lg font-bold text-white">Select Floor</h2>
<p className="text-xs text-slate-400">Choose a floor to edit</p>
</div>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-white/5 rounded-lg transition-colors"
>
<X size={20} className="text-slate-400" />
</button>
</div>
{/* Property Info */}
<div className="px-6 py-3 bg-slate-800/50 border-b border-white/10 flex items-center justify-between gap-3">
<div className="flex items-center gap-3">
<MapPin size={16} className="text-emerald-500" />
<div>
<p className="text-sm font-medium text-white">{property?.name || 'No Property'}</p>
{property?.address && (
<p className="text-xs text-slate-400">{property.address}</p>
)}
</div>
</div>
{onAddProperty && (
<button
onClick={() => {
onAddProperty();
onClose();
}}
className="text-xs px-2 py-1 bg-slate-700 hover:bg-slate-600 rounded text-slate-300 transition-colors"
>
Change/New
</button>
)}
</div>
{/* Buildings & Floors List */}
<div className="max-h-96 overflow-auto p-4">
{onAddBuilding && property && (
<button
onClick={() => {
onAddBuilding();
onClose();
}}
className="w-full flex items-center justify-center gap-2 px-3 py-2 mb-3 bg-slate-800 hover:bg-slate-700 border border-slate-700 border-dashed rounded-lg text-slate-400 hover:text-emerald-400 transition-colors"
>
<Plus size={16} />
<span className="text-sm font-medium">Add New Building</span>
</button>
)}
{property?.buildings.map(building => (
<div key={building.id} className="mb-2">
{/* Building Header */}
<button
onClick={() => toggleBuilding(building.id)}
className="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 transition-colors"
>
<Building2 size={18} className="text-slate-400" />
<span className="flex-1 text-left font-medium text-white">
{building.name}
</span>
<span className="text-xs text-slate-500 mr-2">
{building.floors.length} floors
</span>
<ChevronRight
size={16}
className={`text-slate-500 transition-transform ${expandedBuildings.has(building.id) ? 'rotate-90' : ''
}`}
/>
</button>
{/* Floors */}
{expandedBuildings.has(building.id) && (
<div className="ml-6 mt-1 space-y-0.5">
{building.floors.map(floor => {
const isSelected = floorId === floor.id && buildingId === building.id;
return (
<button
key={floor.id}
onClick={() => {
onSelectFloor(floor.id, building.id);
onClose();
}}
className={`
w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors
${isSelected
? 'bg-emerald-600/30 text-emerald-400'
: 'hover:bg-white/5 text-slate-300'
}
`}
>
<Layers size={16} className={isSelected ? 'text-emerald-400' : 'text-slate-500'} />
<span className="flex-1 text-left">{floor.name}</span>
<span className="text-xs text-slate-500">
{floor.rooms?.length || 0} rooms
</span>
{isSelected && <Check size={16} className="text-emerald-400" />}
</button>
);
})}
{/* Add Floor Button */}
{onAddFloor && (
<button
onClick={() => {
onAddFloor(building.id);
onClose();
}}
className="w-full flex items-center gap-3 px-3 py-2 text-slate-500 hover:text-emerald-400 hover:bg-white/5 rounded-lg transition-colors"
>
<Plus size={16} />
<span className="text-sm">Add Floor</span>
</button>
)}
</div>
)}
</div>
))}
{/* Empty State */}
{(!property || property.buildings.length === 0) && (
<div className="text-center py-8">
<Building2 size={32} className="text-slate-600 mx-auto mb-3" />
<p className="text-slate-400 mb-2">No buildings found</p>
<button
onClick={() => {
if (onAddProperty) {
onAddProperty();
onClose();
}
}}
className="text-sm text-emerald-400 hover:text-emerald-300"
>
Setup Property
</button>
</div>
)}
</div>
{/* Footer */}
<div className="px-6 py-4 border-t border-white/10 flex justify-end gap-3">
<button
onClick={onClose}
className="px-4 py-2 text-sm text-slate-400 hover:text-white transition-colors"
>
Cancel
</button>
</div>
</div>
</div>
);
}