Mandantenfähigkeit: Domain + Kunden-E-Mail-Label dynamisch pro Provider
Alle hardcoded Referenzen auf 'stressfrei-wechseln.de' und 'Stressfrei-Wechseln'
durch dynamische Werte aus der EmailProviderConfig ersetzt. Notwendig für
Multi-Mandanten-Betrieb, wenn das CRM an Dritte vermietet wird.
Schema:
- Neues Feld EmailProviderConfig.customerEmailLabel (String?)
- Wenn leer, wird Label aus Domain abgeleitet ('stressfrei-wechseln.de' → 'Stressfrei-Wechseln')
Backend:
- Neuer Endpoint GET /api/email-providers/public-settings liefert { domain, customerEmailLabel }
- Neue Service-Funktionen: getProviderPublicSettings(), deriveLabelFromDomain()
- create/updateProviderConfig erweitert um customerEmailLabel
Frontend:
- Neuer Hook useProviderSettings() mit Auto-Caching
- Neues Eingabefeld 'Bezeichnung für Kunden-E-Mails' im Provider-Modal
- Dynamische Domain-Suffix im Adress-Hinzufügen-Dialog (@<domain>)
- Tab-Label 'Stressfrei-Wechseln' im Kunden-Detail → dynamisch
- 'Stressfrei-Wechseln Adresse' in ContractForm → dynamisch
- '(Stressfrei-Wechseln)' Badge in ContractDetail → dynamisch
- 'Stressfrei-Wechseln E-Mail' im Generate-Modal → dynamisch
- Leere-Zustand-Meldungen in Tab und E-Mail-Client → dynamisch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { Edit, Trash2, Copy, Eye, EyeOff, ArrowLeft, ArrowRight, Download, Exter
|
||||
import { calculateConsumption, calculateCosts, calculateMultiMeterConsumption } from '../../utils/energyCalculations';
|
||||
import CopyButton, { CopyableBlock } from '../../components/ui/CopyButton';
|
||||
import { formatDate } from '../../utils/dateFormat';
|
||||
import { useProviderSettings } from '../../hooks/useProviderSettings';
|
||||
import type { ContractType, ContractStatus, SimCard, MeterReading, ContractTask, ContractTaskSubtask, ContractMeter, ContractDocument } from '../../types';
|
||||
|
||||
const typeLabels: Record<ContractType, string> = {
|
||||
@@ -1444,6 +1445,7 @@ export default function ContractDetail() {
|
||||
const currentPath = `/contracts/${id}`;
|
||||
const { hasPermission, isCustomer, isCustomerPortal } = useAuth();
|
||||
const contractId = parseInt(id!);
|
||||
const { customerEmailLabel } = useProviderSettings();
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [decryptedPassword, setDecryptedPassword] = useState<string | null>(null);
|
||||
@@ -2310,7 +2312,7 @@ export default function ContractDetail() {
|
||||
<dt className="text-sm text-gray-500">
|
||||
Benutzername
|
||||
{c.stressfreiEmail && (
|
||||
<span className="ml-2 text-xs text-blue-600">(Stressfrei-Wechseln)</span>
|
||||
<span className="ml-2 text-xs text-blue-600">({customerEmailLabel})</span>
|
||||
)}
|
||||
</dt>
|
||||
<dd className="font-mono flex items-center gap-1">
|
||||
@@ -3363,6 +3365,7 @@ function GenerateInputModal({ templateId, templateName, contractId, onClose }: {
|
||||
const [stressfreiEmailId, setStressfreiEmailId] = useState('');
|
||||
const [manualValues, setManualValues] = useState<Record<string, string>>({});
|
||||
const [generating] = useState(false);
|
||||
const { customerEmailLabel } = useProviderSettings();
|
||||
|
||||
const { data: inputsData, isLoading } = useQuery({
|
||||
queryKey: ['pdf-inputs', templateId, contractId],
|
||||
@@ -3390,7 +3393,7 @@ function GenerateInputModal({ templateId, templateName, contractId, onClose }: {
|
||||
<div className="space-y-4">
|
||||
{inputs?.needsStressfreiEmail && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Stressfrei-Wechseln E-Mail</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">{customerEmailLabel} E-Mail</label>
|
||||
<select
|
||||
value={stressfreiEmailId}
|
||||
onChange={(e) => setStressfreiEmailId(e.target.value)}
|
||||
|
||||
Reference in New Issue
Block a user