diff --git a/apps/web/src/components/reui-kit/settings-shell.tsx b/apps/web/src/components/reui-kit/settings-shell.tsx index 7ec36c7..2be7145 100644 --- a/apps/web/src/components/reui-kit/settings-shell.tsx +++ b/apps/web/src/components/reui-kit/settings-shell.tsx @@ -5,6 +5,7 @@ import { SettingsIcon } from 'lucide-react' import { useIsMobile } from '@cfdm/ui/hooks/use-mobile' import { cn } from '@cfdm/ui/lib/utils' import { PageShell } from '@/components/page-shell' +import { Separator } from '@cfdm/ui/components/separator' export interface SettingsTabConfig { id: string @@ -38,19 +39,20 @@ export function SettingsShell({ return ( -
-
+
+
-

{title}

+

{title}

{description}

+
diff --git a/apps/web/src/routes/_auth/settings/integrations.tsx b/apps/web/src/routes/_auth/settings/integrations.tsx index c14148c..9dd2ac6 100644 --- a/apps/web/src/routes/_auth/settings/integrations.tsx +++ b/apps/web/src/routes/_auth/settings/integrations.tsx @@ -1,6 +1,7 @@ +import { useState, type ReactNode } from 'react' import { createFileRoute } from '@tanstack/react-router' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { LayoutGridIcon } from 'lucide-react' +import { ChevronDownIcon, LayoutGridIcon, ServerIcon } from 'lucide-react' import { toast } from 'sonner' import type { AppSettingsPatch } from '@cfdm/shared' @@ -13,6 +14,7 @@ import { } from '@/components/integrations/vps-tracker-integration-card' import { DEFAULT_APP_SWITCHER_CONFIG } from '@/lib/app-switcher-config' import { appSwitcherQueryKey } from '@/queries/app-switcher' +import { Badge } from '@/components/reui/badge' import { Frame, FrameDescription, @@ -20,20 +22,123 @@ import { FramePanel, FrameTitle, } from '@/components/reui/frame' -import { Item, ItemMedia } from '@cfdm/ui/components/item' -import { ServerIcon } from 'lucide-react' +import { Button } from '@cfdm/ui/components/button' +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from '@cfdm/ui/components/collapsible' +import { + Item, + ItemActions, + ItemContent, + ItemDescription, + ItemGroup, + ItemMedia, + ItemTitle, +} from '@cfdm/ui/components/item' +import { cn } from '@cfdm/ui/lib/utils' type SettingsResponse = AppSettingsView & { id: string appSwitcher: typeof DEFAULT_APP_SWITCHER_CONFIG } +type IntegrationStatus = 'connected' | 'available' | 'warning' + +const STATUS_META: Record< + IntegrationStatus, + { label: string; variant: 'success-light' | 'secondary' | 'warning-light' } +> = { + connected: { label: 'Подключено', variant: 'success-light' }, + available: { label: 'Доступно', variant: 'secondary' }, + warning: { label: 'Требует настройки', variant: 'warning-light' }, +} + export const Route = createFileRoute('/_auth/settings/integrations')({ component: SettingsIntegrationsPage, }) +function IntegrationLogo({ children }: { children: ReactNode }) { + return ( + + + {children} + + + ) +} + +function IntegrationRow({ + id, + name, + description, + logo, + status, + open, + onOpenChange, + children, +}: { + id: string + name: string + description: string + logo: ReactNode + status: IntegrationStatus + open: boolean + onOpenChange: (open: boolean) => void + children: ReactNode +}) { + const meta = STATUS_META[status] + + return ( + + + + {logo} + + + + + {name} + {meta.label} + + {description} + + + + + } + > + Настроить + + + + + +
{children}
+
+
+ ) +} + function SettingsIntegrationsPage() { const queryClient = useQueryClient() + const [openAppSwitcher, setOpenAppSwitcher] = useState(true) + const [openVpsTracker, setOpenVpsTracker] = useState(true) + const { data, isLoading, isError, error, refetch } = useQuery({ queryKey: ['app-settings'], queryFn: () => api.get('/api/v1/settings'), @@ -50,6 +155,18 @@ function SettingsIntegrationsPage() { onError: () => toast.error('Не удалось сохранить'), }) + const appSwitcher = data?.appSwitcher ?? DEFAULT_APP_SWITCHER_CONFIG + const appSwitcherStatus: IntegrationStatus = + appSwitcher.apps.length > 0 ? 'connected' : 'available' + + const vpsStatus: IntegrationStatus = !data + ? 'available' + : data.vpsTrackerSyncEnabled && data.vpsTrackerIntegrationTokenSet + ? 'connected' + : data.vpsTrackerUrl || data.vpsTrackerIntegrationTokenSet + ? 'warning' + : 'available' + return ( - - - - - -
- App Switcher - - Быстрый переход между связанными приложениями - -
+ + App Switcher + + Быстрый переход между связанными приложениями + - - saveMut.mutate({ appSwitcher })} - /> + + + + @@ -100,31 +222,40 @@ function SettingsIntegrationsPage() {
- - - - - -
- VPS Tracker - URL, токен и расписание синхронизации -
+ + VPS Tracker + URL, токен и расписание синхронизации - - { - const patch: AppSettingsPatch = { - vpsTrackerUrl: values.vpsTrackerUrl, - vpsTrackerSyncEnabled: values.vpsTrackerSyncEnabled, + + + + logo={ +