import { useState, useEffect } from 'react' import { Clock } from 'lucide-react' import { maintenanceSchedulesApi } from '@/api/maintenanceSchedules' import { targetListsApi } from '@/api/targetLists' import type { MaintenanceSchedule, TargetList } from '@/types' import { cn } from '@/lib/utils' import { toast } from '@/lib/toast' interface MaintenanceScheduleSectionProps { treeId: string | null onScheduleLoaded?: (schedule: MaintenanceSchedule | null, targetList: TargetList | null) => void } const FREQUENCY_OPTIONS = [ { value: 'daily', label: 'Daily', cron: (hour: number, min: number) => `${min} ${hour} * * *` }, { value: 'weekly-mon', label: 'Weekly (Monday)', cron: (hour: number, min: number) => `${min} ${hour} * * 1` }, { value: 'weekly-fri', label: 'Weekly (Friday)', cron: (hour: number, min: number) => `${min} ${hour} * * 5` }, { value: 'monthly', label: 'Monthly (1st)', cron: (hour: number, min: number) => `${min} ${hour} 1 * *` }, ] as const const TIMEZONE_OPTIONS = [ 'UTC', 'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'Europe/London', 'Europe/Berlin', 'Asia/Tokyo', 'Australia/Sydney', ] export function MaintenanceScheduleSection({ treeId, onScheduleLoaded }: MaintenanceScheduleSectionProps) { const [schedule, setSchedule] = useState(null) const [targetLists, setTargetLists] = useState([]) const [isLoading, setIsLoading] = useState(false) const [isSaving, setIsSaving] = useState(false) // Draft form state (local UI only — not in store) const [frequency, setFrequency] = useState('weekly-mon') const [hour, setHour] = useState(9) const [minute, setMinute] = useState(0) const [timezone, setTimezone] = useState('UTC') const [selectedTargetListId, setSelectedTargetListId] = useState('') // Load existing schedule and target lists useEffect(() => { const load = async () => { setIsLoading(true) try { const lists = await targetListsApi.list() setTargetLists(lists) if (treeId) { try { const existing = await maintenanceSchedulesApi.getForTree(treeId) setSchedule(existing) // Hydrate form from existing schedule hydrateFromSchedule(existing) if (existing.target_list_id) { setSelectedTargetListId(existing.target_list_id) const tl = lists.find(l => l.id === existing.target_list_id) || null onScheduleLoaded?.(existing, tl) } else { onScheduleLoaded?.(existing, null) } } catch { // 404 = no schedule yet (valid state) onScheduleLoaded?.(null, null) } } } catch { // Target lists may not load — non-critical } finally { setIsLoading(false) } } load() }, [treeId, onScheduleLoaded]) const hydrateFromSchedule = (s: MaintenanceSchedule) => { const parts = s.cron_expression.split(' ') const min = parseInt(parts[0] || '0', 10) const hr = parseInt(parts[1] || '9', 10) setMinute(min) setHour(hr) setTimezone(s.timezone) // Detect frequency from cron const dayOfMonth = parts[2] const dayOfWeek = parts[4] if (dayOfMonth === '1') { setFrequency('monthly') } else if (dayOfWeek === '*') { setFrequency('daily') } else if (dayOfWeek === '5') { setFrequency('weekly-fri') } else { setFrequency('weekly-mon') } } const handleSaveSchedule = async () => { if (!treeId) { toast.error('Save the flow first before configuring a schedule') return } setIsSaving(true) try { const freqOption = FREQUENCY_OPTIONS.find(f => f.value === frequency) const cronExpression = freqOption?.cron(hour, minute) ?? `${minute} ${hour} * * 1` if (schedule) { const updated = await maintenanceSchedulesApi.update(schedule.id, { cron_expression: cronExpression, timezone, target_list_id: selectedTargetListId || undefined, }) setSchedule(updated) const tl = targetLists.find(l => l.id === selectedTargetListId) || null onScheduleLoaded?.(updated, tl) toast.success('Schedule updated') } else { const created = await maintenanceSchedulesApi.create({ tree_id: treeId, cron_expression: cronExpression, timezone, target_list_id: selectedTargetListId || undefined, }) setSchedule(created) const tl = targetLists.find(l => l.id === selectedTargetListId) || null onScheduleLoaded?.(created, tl) toast.success('Schedule created') } } catch { toast.error('Failed to save schedule. The flow was saved successfully — you can retry the schedule.') } finally { setIsSaving(false) } } if (isLoading) { return (
Loading schedule...
) } return (
{/* Frequency */}
{/* Time */}
setHour(Number(e.target.value))} className="w-full rounded-lg border border-border bg-card px-3 py-2 text-foreground focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20" />
setMinute(Number(e.target.value))} className="w-full rounded-lg border border-border bg-card px-3 py-2 text-foreground focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20" />
{/* Timezone */}
{/* Target List */} {targetLists.length > 0 && (
)} {/* Save button */} {!treeId && (

Save the flow first to configure a schedule.

)}
) }