import { useState } from 'react'; import { Link } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import Card from '../../components/ui/Card'; import Button from '../../components/ui/Button'; import { ArrowLeft, Download, Package, Info, Loader2, Check, AlertCircle, Building2, Tag, Clock, Calendar, FileType, FileText, } from 'lucide-react'; import api from '../../services/api'; interface PreviewCounts { providers: number; tariffs: number; cancellationPeriods: number; contractDurations: number; contractCategories: number; pdfTemplates: number; } export default function FactoryDefaults() { const [downloading, setDownloading] = useState(false); const [downloadError, setDownloadError] = useState(null); const [downloadDone, setDownloadDone] = useState(false); const { data: previewData, isLoading } = useQuery({ queryKey: ['factory-defaults-preview'], queryFn: async () => { const res = await api.get<{ success: boolean; data: { counts: PreviewCounts } }>( '/factory-defaults/preview', ); return res.data; }, }); const counts = previewData?.data?.counts; const handleExport = async () => { setDownloading(true); setDownloadError(null); setDownloadDone(false); try { const res = await api.get('/factory-defaults/export', { responseType: 'blob', }); const blob = new Blob([res.data as BlobPart], { type: 'application/zip' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); const dateStr = new Date().toISOString().split('T')[0]; a.href = url; a.download = `factory-defaults-${dateStr}.zip`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); setDownloadDone(true); setTimeout(() => setDownloadDone(false), 3000); } catch (err) { setDownloadError( err instanceof Error ? err.message : 'Fehler beim Export', ); } finally { setDownloading(false); } }; const sections = counts ? [ { icon: Building2, label: 'Anbieter', count: counts.providers, color: 'text-blue-600' }, { icon: Tag, label: 'Tarife', count: counts.tariffs, color: 'text-indigo-600' }, { icon: Clock, label: 'Kündigungsfristen', count: counts.cancellationPeriods, color: 'text-purple-600' }, { icon: Calendar, label: 'Laufzeiten', count: counts.contractDurations, color: 'text-pink-600' }, { icon: FileType, label: 'Vertragskategorien', count: counts.contractCategories, color: 'text-orange-600' }, { icon: FileText, label: 'PDF-Auftragsvorlagen', count: counts.pdfTemplates, color: 'text-green-600' }, ] : []; return (

Factory-Defaults

{/* Info-Box */}

Was sind Factory-Defaults?

Das sind reine Stammdaten-Kataloge wie Anbieter, Tarife, Kündigungsfristen, Vertragskategorien und PDF-Auftragsvorlagen. Du kannst sie exportieren, um sie in anderen OpenCRM-Installationen als Startpunkt zu verwenden.

Nicht enthalten sind Kundendaten, Verträge, Dokumente, Emails oder Einstellungen – dafür gibt es den separaten{' '} Datenbank-Backup .

Erstellt ein ZIP mit allen Kataloge-Daten + PDF-Vorlagen. Lade es herunter und entpacke den Inhalt in einer anderen Installation unter{' '} backend/factory-defaults/ , dann dort{' '} npm run seed:defaults {' '} ausführen.

{isLoading ? (
Lade Übersicht…
) : counts ? (
{sections.map((s) => (
{s.label}
{s.count}
))}
) : null}
{downloadError && (
{downloadError}
)}

Der Import läuft über ein Kommandozeilen-Script – dadurch bleibt klar, was wann passiert und es gibt keine ungeplanten Überschreibungen im Produktivbetrieb.

  1. ZIP in einer beliebigen Installation herunterladen und den Inhalt nach{' '} backend/factory-defaults/ {' '} entpacken
  2. Optional mehrere ZIPs zusammenwerfen (JSON-Dateien werden automatisch gemerged)
  3. Im Backend-Ordner:{' '} npm run seed:defaults

Das Script läuft idempotent – gleiche Einträge werden per unique-Key aktualisiert, neue hinzugefügt. Kann beliebig oft ausgeführt werden.

); }