import { useCallback, useMemo, useState, type ReactElement } from "react"; import { ScrollView, Text, View } from "react-native"; import { useIsFocused } from "@react-navigation/native"; import { Plus } from "lucide-react-native"; import { StyleSheet } from "react-native-unistyles"; import { MenuHeader } from "@/components/headers/menu-header"; import { ScheduleFormSheet } from "@/components/schedules/schedule-form-sheet"; import { SchedulesTable } from "@/components/schedules/schedules-table"; import { Button } from "@/components/ui/button"; import { LoadingSpinner } from "@/components/ui/loading-spinner"; import { useSchedules, type ScheduleHostSection } from "@/hooks/use-schedules"; import type { ScheduleSummary } from "@getpaseo/protocol/schedule/types"; type FormState = | { mode: "closed" } | { mode: "create" } | { mode: "edit"; serverId: string; schedule: ScheduleSummary }; export function SchedulesScreen(): ReactElement { const isFocused = useIsFocused(); if (!isFocused) { return ; } return ; } function SchedulesScreenContent(): ReactElement { const { sections, isLoading, isError, error, refetch } = useSchedules(); const [form, setForm] = useState({ mode: "closed" }); const openCreate = useCallback(() => { setForm({ mode: "create" }); }, []); const openEdit = useCallback((serverId: string, schedule: ScheduleSummary) => { setForm({ mode: "edit", serverId, schedule }); }, []); const closeForm = useCallback(() => { setForm({ mode: "closed" }); }, []); const headerAction = useMemo( () => ( ), [openCreate], ); return ( ); } function SchedulesBody({ sections, isLoading, isError, error, onRetry, onCreate, onEdit, }: { sections: ScheduleHostSection[]; isLoading: boolean; isError: boolean; error: Error | null; onRetry: () => void; onCreate: () => void; onEdit: (serverId: string, schedule: ScheduleSummary) => void; }): ReactElement { if (isLoading) { return ( ); } if (isError) { return ( {error?.message ?? "Could not load schedules"} ); } if (sections.length === 0) { return ( No schedules yet ); } return ( {sections.map((section) => ( ))} ); } function ScheduleHostSectionView({ section, onEdit, }: { section: ScheduleHostSection; onEdit: (serverId: string, schedule: ScheduleSummary) => void; }): ReactElement { const handleEdit = useCallback( (schedule: ScheduleSummary) => { onEdit(section.serverId, schedule); }, [onEdit, section.serverId], ); const emptyMessage = section.isOnline ? "No schedules" : "Host offline"; return ( {section.serverName} {section.error ? {section.error} : null} {section.schedules.length > 0 ? ( ) : null} {section.schedules.length === 0 && !section.error ? ( {emptyMessage} ) : null} ); } const styles = StyleSheet.create((theme) => ({ container: { flex: 1, backgroundColor: theme.colors.surface0, }, centered: { flex: 1, justifyContent: "center", alignItems: "center", gap: theme.spacing[6], padding: theme.spacing[6], }, scroll: { flex: 1, minHeight: 0, }, scrollContent: { gap: theme.spacing[4], paddingTop: theme.spacing[4], paddingBottom: theme.spacing[6], }, section: { gap: theme.spacing[2], }, sectionTitle: { width: "100%", maxWidth: 720, alignSelf: "center", paddingHorizontal: theme.spacing[4], color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.medium, }, sectionError: { width: "100%", maxWidth: 720, alignSelf: "center", paddingHorizontal: theme.spacing[4], color: theme.colors.destructive, fontSize: theme.fontSize.sm, }, sectionEmpty: { width: "100%", maxWidth: 720, alignSelf: "center", paddingHorizontal: theme.spacing[4], paddingVertical: theme.spacing[3], }, sectionEmptyText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, }, message: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.lg, textAlign: "center", }, // Static color holder read by the spinner; keeps the muted token without // useUnistyles (banned in new code). spinner: { color: theme.colors.foregroundMuted, }, }));