Extract types, constants, helpers, and UI pieces (shared LoadingSkeleton/ EmptyState/StatusBadge/CopyButton, SSOConfigFormModal, DeleteConfirmModal, ConnectionTestPanel, SSOConfigCard, SSOUsersTable, SSOInfoSection) into _components/ and _types.ts to bring page.tsx from 1482 LOC to 339 LOC (under the 500 hard cap). Behavior preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState } from 'react'
|
|
import { CheckCircle2, Copy, XCircle } from 'lucide-react'
|
|
|
|
export function LoadingSkeleton({ rows = 3 }: { rows?: number }) {
|
|
return (
|
|
<div className="space-y-4 animate-pulse">
|
|
{Array.from({ length: rows }).map((_, i) => (
|
|
<div key={i} className="h-16 bg-slate-100 rounded-lg" />
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function EmptyState({
|
|
icon,
|
|
title,
|
|
description,
|
|
action,
|
|
}: {
|
|
icon: React.ReactNode
|
|
title: string
|
|
description: string
|
|
action?: React.ReactNode
|
|
}) {
|
|
return (
|
|
<div className="text-center py-12">
|
|
<div className="w-16 h-16 mx-auto bg-slate-100 rounded-full flex items-center justify-center mb-4">
|
|
{icon}
|
|
</div>
|
|
<h3 className="text-lg font-semibold text-slate-900">{title}</h3>
|
|
<p className="mt-2 text-sm text-slate-500 max-w-md mx-auto">{description}</p>
|
|
{action && <div className="mt-4">{action}</div>}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function StatusBadge({ enabled }: { enabled: boolean }) {
|
|
return enabled ? (
|
|
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-green-100 text-green-700 rounded-full">
|
|
<CheckCircle2 className="w-3 h-3" />
|
|
Aktiv
|
|
</span>
|
|
) : (
|
|
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-slate-100 text-slate-600 rounded-full">
|
|
<XCircle className="w-3 h-3" />
|
|
Deaktiviert
|
|
</span>
|
|
)
|
|
}
|
|
|
|
export function CopyButton({ value }: { value: string }) {
|
|
const [copied, setCopied] = useState(false)
|
|
|
|
const handleCopy = () => {
|
|
navigator.clipboard.writeText(value)
|
|
setCopied(true)
|
|
setTimeout(() => setCopied(false), 2000)
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={handleCopy}
|
|
className="p-1 text-slate-400 hover:text-slate-600 transition-colors"
|
|
title="In Zwischenablage kopieren"
|
|
>
|
|
{copied ? <CheckCircle2 className="w-4 h-4 text-green-500" /> : <Copy className="w-4 h-4" />}
|
|
</button>
|
|
)
|
|
}
|