feat: procedural editor redesign with collapsible sections and DnD #84
@@ -1,14 +1,15 @@
|
|||||||
import { useEffect, useState, useCallback } from 'react'
|
import { useEffect, useState, useCallback } from 'react'
|
||||||
import { useParams, useNavigate, useSearchParams } from 'react-router-dom'
|
import { useParams, useNavigate, useSearchParams } from 'react-router-dom'
|
||||||
import { Save, ArrowLeft, ListOrdered, Wrench, Settings, FileText } from 'lucide-react'
|
import { Save, ArrowLeft, ListOrdered, Wrench, Settings, FileText, Calendar } from 'lucide-react'
|
||||||
import { treesApi } from '@/api/trees'
|
import { treesApi } from '@/api/trees'
|
||||||
import { useProceduralEditorStore } from '@/store/proceduralEditorStore'
|
import { useProceduralEditorStore } from '@/store/proceduralEditorStore'
|
||||||
import { CollapsibleEditorSection } from '@/components/procedural-editor/CollapsibleEditorSection'
|
import { CollapsibleEditorSection } from '@/components/procedural-editor/CollapsibleEditorSection'
|
||||||
import { IntakeFormBuilder } from '@/components/procedural-editor/IntakeFormBuilder'
|
import { IntakeFormBuilder } from '@/components/procedural-editor/IntakeFormBuilder'
|
||||||
|
import { MaintenanceScheduleSection, getScheduleSummary } from '@/components/procedural-editor/MaintenanceScheduleSection'
|
||||||
import { StepList } from '@/components/procedural-editor/StepList'
|
import { StepList } from '@/components/procedural-editor/StepList'
|
||||||
import { TagInput } from '@/components/common/TagInput'
|
import { TagInput } from '@/components/common/TagInput'
|
||||||
import { toast } from '@/lib/toast'
|
import { toast } from '@/lib/toast'
|
||||||
import type { TreeType } from '@/types'
|
import type { TreeType, MaintenanceSchedule, TargetList } from '@/types'
|
||||||
|
|
||||||
type SectionKey = 'details' | 'intake' | 'schedule'
|
type SectionKey = 'details' | 'intake' | 'schedule'
|
||||||
|
|
||||||
@@ -49,10 +50,19 @@ export function ProceduralEditorPage() {
|
|||||||
isEditMode ? null : 'details'
|
isEditMode ? null : 'details'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Schedule state for collapsed summary
|
||||||
|
const [schedule, setSchedule] = useState<MaintenanceSchedule | null>(null)
|
||||||
|
const [scheduleTargetList, setScheduleTargetList] = useState<TargetList | null>(null)
|
||||||
|
|
||||||
const toggleSection = useCallback((key: SectionKey) => {
|
const toggleSection = useCallback((key: SectionKey) => {
|
||||||
setExpandedSection(prev => prev === key ? null : key)
|
setExpandedSection(prev => prev === key ? null : key)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleScheduleLoaded = useCallback((s: MaintenanceSchedule | null, tl: TargetList | null) => {
|
||||||
|
setSchedule(s)
|
||||||
|
setScheduleTargetList(tl)
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Load tree or init new
|
// Load tree or init new
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditMode && id) {
|
if (isEditMode && id) {
|
||||||
@@ -123,6 +133,8 @@ export function ProceduralEditorPage() {
|
|||||||
isPublic ? 'Public' : 'Private',
|
isPublic ? 'Public' : 'Private',
|
||||||
].join(' \u00b7 ')
|
].join(' \u00b7 ')
|
||||||
|
|
||||||
|
const scheduleSummary = getScheduleSummary(schedule, scheduleTargetList)
|
||||||
|
|
||||||
const intakeSummary = intakeForm.length === 0
|
const intakeSummary = intakeForm.length === 0
|
||||||
? 'No fields defined'
|
? 'No fields defined'
|
||||||
: `${intakeForm.length} field${intakeForm.length !== 1 ? 's' : ''}: ${intakeForm.map(f => f.label || f.variable_name).slice(0, 4).join(', ')}${intakeForm.length > 4 ? ', \u2026' : ''}`
|
: `${intakeForm.length} field${intakeForm.length !== 1 ? 's' : ''}: ${intakeForm.map(f => f.label || f.variable_name).slice(0, 4).join(', ')}${intakeForm.length > 4 ? ', \u2026' : ''}`
|
||||||
@@ -241,6 +253,21 @@ export function ProceduralEditorPage() {
|
|||||||
>
|
>
|
||||||
<IntakeFormBuilder />
|
<IntakeFormBuilder />
|
||||||
</CollapsibleEditorSection>
|
</CollapsibleEditorSection>
|
||||||
|
|
||||||
|
{isMaintenance && (
|
||||||
|
<CollapsibleEditorSection
|
||||||
|
title="Schedule"
|
||||||
|
icon={<Calendar className="h-4 w-4" />}
|
||||||
|
summary={scheduleSummary}
|
||||||
|
expanded={expandedSection === 'schedule'}
|
||||||
|
onToggle={() => toggleSection('schedule')}
|
||||||
|
>
|
||||||
|
<MaintenanceScheduleSection
|
||||||
|
treeId={treeId}
|
||||||
|
onScheduleLoaded={handleScheduleLoaded}
|
||||||
|
/>
|
||||||
|
</CollapsibleEditorSection>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Step List — flex-1, scrolls independently */}
|
{/* Step List — flex-1, scrolls independently */}
|
||||||
|
|||||||
Reference in New Issue
Block a user