oxios 1.5.2

Oxios Agent OS — Agent Operating System powered by oxi-sdk
import { createFileRoute } from '@tanstack/react-router'
import { Plus } from 'lucide-react'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { CalendarView } from '@/components/calendar/calendar-view'
import { ConflictWarning } from '@/components/calendar/conflict-warning'
import { EventDetail } from '@/components/calendar/event-detail'
import { EventEditor } from '@/components/calendar/event-editor'
import { Button } from '@/components/ui/button'
import {
  useCalendarCreate,
  useCalendarDelete,
  useCalendarEvents,
  useCalendarUpdate,
} from '@/hooks/use-calendar'
import type { CalendarEvent, CreateEventRequest } from '@/types/calendar'

export const Route = createFileRoute('/calendar')({ component: CalendarPage })

function CalendarPage() {
  const { t } = useTranslation()
  const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(null)
  const [editorOpen, setEditorOpen] = useState(false)
  const [editingEvent, setEditingEvent] = useState<CalendarEvent | undefined>()
  const [defaultStart, setDefaultStart] = useState<Date | undefined>()

  // Date range: past 1 month + next 2 months for the calendar view
  const { from, to } = useMemo(() => {
    const now = new Date()
    const from = new Date(now.getFullYear(), now.getMonth() - 1, 1)
    const to = new Date(now.getFullYear(), now.getMonth() + 2, 0)
    return {
      from: from.toISOString(),
      to: new Date(to.getTime() + 86400000).toISOString(),
    }
  }, [])

  const { data, isLoading } = useCalendarEvents(from, to)
  const events = Array.isArray(data?.events) ? data.events : []

  const createMutation = useCalendarCreate()
  const updateMutation = useCalendarUpdate()
  const deleteMutation = useCalendarDelete()

  const handleCreate = (req: CreateEventRequest) => {
    createMutation.mutate(req, {
      onSuccess: () => setEditorOpen(false),
    })
  }

  const handleDelete = () => {
    if (selectedEvent) {
      deleteMutation.mutate(selectedEvent.uid, {
        onSuccess: () => setSelectedEvent(null),
      })
    }
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold">{t('calendar.title')}</h1>
          <p className="text-sm text-muted-foreground">{t('calendar.subtitle')}</p>
        </div>
        <Button
          onClick={() => {
            setEditingEvent(undefined)
            setDefaultStart(new Date())
            setEditorOpen(true)
          }}
        >
          <Plus className="h-4 w-4 mr-1" /> {t('calendar.newEvent')}
        </Button>
      </div>

      {createMutation.data?.conflicts && createMutation.data.conflicts.length > 0 && (
        <ConflictWarning conflicts={createMutation.data.conflicts} />
      )}

      {isLoading ? (
        <div className="flex items-center justify-center h-64 text-muted-foreground">
          {t('calendar.loading')}
        </div>
      ) : (
        <CalendarView
          events={events}
          onEventClick={(uid) => {
            const event = events.find((e) => e.uid === uid)
            if (event) setSelectedEvent(event)
          }}
          onDateClick={(date) => {
            setDefaultStart(date)
            setEditingEvent(undefined)
            setEditorOpen(true)
          }}
        />
      )}

      <EventEditor
        open={editorOpen}
        onClose={() => setEditorOpen(false)}
        event={editingEvent}
        defaultStart={defaultStart}
        onSubmit={(data) => {
          if (editingEvent) {
            updateMutation.mutate(
              { uid: editingEvent.uid, ...data },
              {
                onSuccess: () => setEditorOpen(false),
              },
            )
          } else {
            handleCreate(data as CreateEventRequest)
          }
        }}
        isLoading={createMutation.isPending || updateMutation.isPending}
      />

      {selectedEvent && (
        <EventDetail
          event={selectedEvent}
          onEdit={() => {
            setEditingEvent(selectedEvent)
            setEditorOpen(true)
          }}
          onDelete={handleDelete}
          onClose={() => setSelectedEvent(null)}
        />
      )}
    </div>
  )
}