import { useEffect, useMemo, useState } from "react"; import { Calendar, CheckCircle2, Cloud, Loader2, Save, Upload, Wifi } from "lucide-react"; import { trpc } from "@/lib/trpc"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { toast } from "sonner"; /** Les identifiants Azure restent centralisés dans Paramètres, hors des règles métier. */ export default function AzureAdExportSettingsCard() { const utils = trpc.useUtils(); const { data: settings } = trpc.importSettings.get.useQuery(); const [sharepointUrl, setSharepointUrl] = useState(""); const [tenantId, setTenantId] = useState(""); const [clientId, setClientId] = useState(""); const [clientSecret, setClientSecret] = useState(""); const [secretExpiresAt, setSecretExpiresAt] = useState(""); useEffect(() => { if (!settings) return; setSharepointUrl(settings.exportFolder || ""); setTenantId(settings.azureTenantId || ""); setClientId(settings.azureClientId || ""); setSecretExpiresAt(settings.azureSecretExpiresAt ? new Date(settings.azureSecretExpiresAt).toISOString().slice(0, 10) : ""); }, [settings]); const updateMutation = trpc.importSettings.update.useMutation({ onSuccess: () => { toast.success("Configuration Microsoft Azure AD enregistrée"); setClientSecret(""); utils.importSettings.get.invalidate(); }, onError: (error) => toast.error(error.message || "Impossible d’enregistrer la configuration Azure AD"), }); const testConnectionMutation = trpc.importSettings.testAzureConnection.useMutation(); const testUploadMutation = trpc.importSettings.testSharePointUpload.useMutation(); const expiration = useMemo(() => { if (!secretExpiresAt) return null; const date = new Date(`${secretExpiresAt}T12:00:00Z`); if (Number.isNaN(date.getTime())) return null; return Math.ceil((date.getTime() - Date.now()) / 86_400_000); }, [secretExpiresAt]); const save = () => { if (!settings) return; if (!sharepointUrl.trim() || !tenantId.trim() || !clientId.trim()) { toast.error("URL SharePoint, Tenant ID et Client ID sont obligatoires"); return; } updateMutation.mutate({ manualImportEnabled: settings.manualImportEnabled, autoImportEnabled: settings.autoImportEnabled, emailImportEnabled: settings.emailImportEnabled, exportFolder: sharepointUrl.trim(), exportFolderType: "sharepoint", bapExportMode: settings.bapExportMode, azureTenantId: tenantId.trim(), azureClientId: clientId.trim(), azureSecretExpiresAt: secretExpiresAt || null, ...(clientSecret ? { azureClientSecret: clientSecret } : {}), }); }; const testConnection = async () => { try { const result = await testConnectionMutation.mutateAsync(); result.success ? toast.success(result.message || "Connexion Azure AD réussie") : toast.error(result.error || "Connexion Azure AD impossible"); } catch (error: any) { toast.error(error.message || "Connexion Azure AD impossible"); } }; const testUpload = async () => { try { const result = await testUploadMutation.mutateAsync(); if (!result.success) { toast.error(result.error || "Upload SharePoint impossible"); return; } toast.success("Fichier test déposé dans SharePoint"); if (result.webUrl) window.open(result.webUrl, "_blank", "noopener,noreferrer"); } catch (error: any) { toast.error(error.message || "Upload SharePoint impossible"); } }; const canTest = Boolean(sharepointUrl && tenantId && clientId); return
Configuration Microsoft Azure ADAccès partagé utilisé par les destinations SharePoint et Teams des automatismes d’export.
setSharepointUrl(event.target.value)} placeholder="https://…sharepoint.com/:f:/r/sites/…/Documents/Factures" />

Pour un canal Teams, utilisez l’URL SharePoint du dossier Fichiers concerné.

setTenantId(event.target.value)} />
setClientId(event.target.value)} />
setClientSecret(event.target.value)} placeholder="Conserver le secret configuré" />

Laissez vide pour conserver le secret enregistré. Permissions requises : Files.ReadWrite.All et Sites.ReadWrite.All.

setSecretExpiresAt(event.target.value)} />{expiration !== null &&

{expiration < 0 ? "Secret expiré" : `Secret valide encore ${expiration} jours`}

}
{settings?.azureClientSecret &&

Un secret client est déjà enregistré de manière masquée.

}
; }