'use client' import { useState } from 'react' import { trpc } from '@/lib/trpc/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Badge } from '@/components/ui/badge' import { Checkbox } from '@/components/ui/checkbox' import { toast } from 'sonner' import { CheckCircle, AlertCircle, Loader2, ArrowRight, ArrowLeft, Database, } from 'lucide-react' interface NotionImportFormProps { roundId: string roundName: string onSuccess?: () => void } type Step = 'connect' | 'map' | 'preview' | 'import' | 'complete' export function NotionImportForm({ roundId, roundName, onSuccess, }: NotionImportFormProps) { const [step, setStep] = useState('connect') const [apiKey, setApiKey] = useState('') const [databaseId, setDatabaseId] = useState('') const [isConnecting, setIsConnecting] = useState(false) const [connectionError, setConnectionError] = useState(null) // Mapping state const [mappings, setMappings] = useState({ title: '', teamName: '', description: '', tags: '', }) const [includeUnmapped, setIncludeUnmapped] = useState(true) // Results const [importResults, setImportResults] = useState<{ imported: number skipped: number errors: Array<{ recordId: string; error: string }> } | null>(null) const testConnection = trpc.notionImport.testConnection.useMutation() const { data: schema, refetch: refetchSchema } = trpc.notionImport.getDatabaseSchema.useQuery( { apiKey, databaseId }, { enabled: false } ) const { data: preview, refetch: refetchPreview } = trpc.notionImport.previewData.useQuery( { apiKey, databaseId, limit: 5 }, { enabled: false } ) const importMutation = trpc.notionImport.importProjects.useMutation() const handleConnect = async () => { if (!apiKey || !databaseId) { toast.error('Please enter both API key and database ID') return } setIsConnecting(true) setConnectionError(null) try { const result = await testConnection.mutateAsync({ apiKey }) if (!result.success) { setConnectionError(result.error || 'Connection failed') return } // Fetch schema await refetchSchema() setStep('map') } catch (error) { setConnectionError( error instanceof Error ? error.message : 'Connection failed' ) } finally { setIsConnecting(false) } } const handlePreview = async () => { if (!mappings.title) { toast.error('Please map the Title field') return } await refetchPreview() setStep('preview') } const handleImport = async () => { setStep('import') try { const result = await importMutation.mutateAsync({ apiKey, databaseId, roundId, mappings: { title: mappings.title, teamName: mappings.teamName || undefined, description: mappings.description || undefined, tags: mappings.tags || undefined, }, includeUnmappedInMetadata: includeUnmapped, }) setImportResults(result) setStep('complete') if (result.imported > 0) { toast.success(`Imported ${result.imported} projects`) onSuccess?.() } } catch (error) { toast.error( error instanceof Error ? error.message : 'Import failed' ) setStep('preview') } } const properties = schema?.properties || [] return (
{/* Progress indicator */}
{['connect', 'map', 'preview', 'import', 'complete'].map((s, i) => (
{i > 0 &&
}
i ? 'bg-primary/20 text-primary' : 'bg-muted text-muted-foreground' }`} > {i + 1}
))}
{/* Step 1: Connect */} {step === 'connect' && ( Connect to Notion Enter your Notion API key and database ID to connect
setApiKey(e.target.value)} />

Create an integration at{' '} notion.so/my-integrations

setDatabaseId(e.target.value)} />

The ID from your Notion database URL

{connectionError && ( Connection Failed {connectionError} )}
)} {/* Step 2: Map columns */} {step === 'map' && ( Map Columns Map Notion properties to project fields. Database: {schema?.title}
setIncludeUnmapped(!!c)} />
)} {/* Step 3: Preview */} {step === 'preview' && ( Preview Import Review the first {preview?.count || 0} records before importing
{preview?.records.map((record, i) => ( ))}
Title Team Tags
{String(record.properties[mappings.title] || '-')} {mappings.teamName ? String(record.properties[mappings.teamName] || '-') : '-'} {mappings.tags && record.properties[mappings.tags] ? ( record.properties[mappings.tags] as string[] ).map((tag, j) => ( {tag} )) : '-'}
Ready to import This will import all records from the Notion database into{' '} {roundName}.
)} {/* Step 4: Importing */} {step === 'import' && (

Importing projects...

Please wait while we import your data from Notion

)} {/* Step 5: Complete */} {step === 'complete' && importResults && (

Import Complete

{importResults.imported}

projects imported

{importResults.skipped > 0 && (

{importResults.skipped} records skipped

)} {importResults.errors.length > 0 && (

Errors ({importResults.errors.length}):

{importResults.errors.slice(0, 5).map((e, i) => (

{e.recordId}: {e.error}

))}
)}
)}
) }