import React, { useState, useEffect } from "react"; import { PrimaryButton, DefaultButton, TextField, Dropdown, IDropdownOption, Stack, Text, Toggle, Spinner, SpinnerSize, MessageBar, MessageBarType, } from "@fluentui/react"; import { SyncProfile, StarfaceConnection, StarfaceAddressBook, OutlookContactFolder, } from "../../models/types"; import { ProfileManager } from "../../services/profile-manager"; import { SyncEngine } from "../../services/sync-engine"; interface Props { profile: SyncProfile | null; onSave: () => void; onCancel: () => void; } const defaultConnection: StarfaceConnection = { host: "", port: 443, useSsl: true, loginId: "", password: "", }; export const ProfileEditor: React.FC = ({ profile, onSave, onCancel, }) => { const pm = new ProfileManager(); const engine = new SyncEngine(); const isNew = !profile; const [name, setName] = useState(profile?.name || ""); const [connection, setConnection] = useState( profile?.starfaceConnection || { ...defaultConnection } ); const [addressBooks, setAddressBooks] = useState([]); const [selectedBook, setSelectedBook] = useState( profile?.starfaceAddressBook || null ); const [outlookFolders, setOutlookFolders] = useState( [] ); const [selectedFolderId, setSelectedFolderId] = useState( profile?.outlookFolderId || "" ); const [syncDirection, setSyncDirection] = useState( profile?.syncDirection || "both" ); const [enabled, setEnabled] = useState(profile?.enabled ?? true); const [loading, setLoading] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string; } | null>(null); const [error, setError] = useState(""); // Load Outlook folders on mount useEffect(() => { loadOutlookFolders(); }, []); const loadOutlookFolders = async () => { try { const folders = await engine.loadOutlookFolders(); setOutlookFolders(folders); if (!selectedFolderId && folders.length > 0) { setSelectedFolderId(folders[0].id); } } catch (err) { console.error("Failed to load Outlook folders:", err); // Provide a default folder option setOutlookFolders([{ id: "default", displayName: "Kontakte (Standard)" }]); if (!selectedFolderId) setSelectedFolderId("default"); } }; const handleTestConnection = async () => { setLoading(true); setTestResult(null); const result = await engine.testStarfaceConnection(connection); setTestResult(result); if (!result.success && result.message.toLowerCase().includes("fetch")) { result.message += "\n\nMögliche Ursache: Das SSL-Zertifikat der Starface ist nicht vertrauenswürdig. " + "Bitte als Administrator ausführen:\n" + `import-cert.ps1 -StarfaceHost ${connection.host} -Port ${connection.port}`; } setLoading(false); }; const handleLoadAddressBooks = async () => { setLoading(true); setError(""); try { const books = await engine.loadStarfaceAddressBooks(connection); setAddressBooks(books); if (books.length > 0 && !selectedBook) { setSelectedBook(books[0]); } if (books.length === 0) { setError("Keine Adressbücher gefunden"); } } catch (err) { setError(`Fehler: ${err}`); } setLoading(false); }; const handleSave = () => { if (!name.trim()) { setError("Bitte einen Profilnamen eingeben"); return; } if (!connection.host.trim()) { setError("Bitte Starface-Host eingeben"); return; } if (!selectedBook) { setError("Bitte ein Starface-Adressbuch auswählen"); return; } if (!selectedFolderId) { setError("Bitte einen Outlook-Ordner auswählen"); return; } const selectedFolder = outlookFolders.find( (f) => f.id === selectedFolderId ); const newProfile: SyncProfile = { id: profile?.id || pm.generateId(), name: name.trim(), starfaceConnection: connection, starfaceAddressBook: selectedBook, outlookFolderId: selectedFolderId, outlookFolderName: selectedFolder?.displayName || "Kontakte", syncDirection, lastSync: profile?.lastSync, enabled, }; if (isNew) { pm.addProfile(newProfile); } else { pm.updateProfile(newProfile); } onSave(); }; const directionOptions: IDropdownOption[] = [ { key: "both", text: "Bidirektional (↔)" }, { key: "outlook-to-starface", text: "Outlook → Starface" }, { key: "starface-to-outlook", text: "Starface → Outlook" }, ]; const bookOptions: IDropdownOption[] = addressBooks.map((b, i) => ({ key: i.toString(), text: b.name, data: b, })); const folderOptions: IDropdownOption[] = outlookFolders.map((f) => ({ key: f.id, text: f.displayName, })); return (
{isNew ? "Neues Profil" : "Profil bearbeiten"} {error && ( setError("")} > {error} )} setName(v || "")} placeholder="z.B. Firmenkontakte Hauptanlage" required /> Starface-Verbindung setConnection({ ...connection, host: v || "" }) } placeholder="z.B. pbx.firma.de oder 192.168.1.100" required /> setConnection({ ...connection, port: parseInt(v || "443") || 443 }) } styles={{ root: { width: 80 } }} /> setConnection({ ...connection, useSsl: checked ?? true, port: checked ? 443 : 80, }) } /> setConnection({ ...connection, loginId: v || "" }) } required /> setConnection({ ...connection, password: v || "" }) } canRevealPassword required /> {loading && } {testResult && ( {testResult.message.split("\n").map((line, i) => ( {i > 0 &&
} {line}
))}
)} {addressBooks.length > 0 && ( { if (option?.data) setSelectedBook(option.data); }} required /> )} Outlook-Einstellungen { if (option) setSelectedFolderId(option.key as string); }} required /> { if (option) setSyncDirection(option.key as SyncProfile["syncDirection"]); }} /> setEnabled(checked ?? true)} />
); };