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:
@@ -18,6 +18,7 @@ import CopyButton, { CopyableBlock } from '../../components/ui/CopyButton';
|
||||
import BirthdayManagementModal from '../../components/BirthdayManagementModal';
|
||||
import { formatDate } from '../../utils/dateFormat';
|
||||
import { getContractTypeInfo } from '../../utils/contractInfo';
|
||||
import { useProviderSettings } from '../../hooks/useProviderSettings';
|
||||
import type { Address, BankCard, IdentityDocument, Meter, Customer, CustomerRepresentative, CustomerSummary, CustomerConsent, ConsentType, ConsentStatus, RepresentativeAuthorization } from '../../types';
|
||||
|
||||
export default function CustomerDetail({ portalCustomerId }: { portalCustomerId?: number } = {}) {
|
||||
@@ -31,6 +32,7 @@ export default function CustomerDetail({ portalCustomerId }: { portalCustomerId?
|
||||
const customerId = portalCustomerId || parseInt(id!);
|
||||
const defaultTab = searchParams.get('tab') || 'addresses';
|
||||
const [activeTab, setActiveTab] = useState(defaultTab);
|
||||
const { customerEmailLabel } = useProviderSettings();
|
||||
|
||||
// Tab-Wechsel in URL synchronisieren (für Browser-History)
|
||||
const handleTabChange = (tabId: string) => {
|
||||
@@ -148,7 +150,7 @@ export default function CustomerDetail({ portalCustomerId }: { portalCustomerId?
|
||||
},
|
||||
...(!isCustomerPortal ? [{
|
||||
id: 'stressfrei',
|
||||
label: 'Stressfrei-Wechseln',
|
||||
label: customerEmailLabel,
|
||||
content: (
|
||||
<StressfreiEmailsTab
|
||||
customerId={customerId}
|
||||
@@ -2928,9 +2930,7 @@ function MeterReadingModal({
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== STRESSFREI-WECHSELN E-MAIL TAB ====================
|
||||
|
||||
const STRESSFREI_DOMAIN = '@stressfrei-wechseln.de';
|
||||
// ==================== KUNDEN-E-MAIL TAB ====================
|
||||
|
||||
function StressfreiEmailsTab({
|
||||
customerId,
|
||||
@@ -2950,6 +2950,7 @@ function StressfreiEmailsTab({
|
||||
onEdit: (email: StressfreiEmail) => void;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const { customerEmailLabel } = useProviderSettings();
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: number; data: Partial<StressfreiEmail> }) =>
|
||||
@@ -3067,7 +3068,7 @@ function StressfreiEmailsTab({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-gray-500">Keine Stressfrei-Wechseln Adressen vorhanden.</p>
|
||||
<p className="text-gray-500">Keine {customerEmailLabel} Adressen vorhanden.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -3240,6 +3241,10 @@ function StressfreiEmailModal({
|
||||
const [provisionError, setProvisionError] = useState<string | null>(null);
|
||||
const [providerStatus, setProviderStatus] = useState<'idle' | 'checking' | 'exists' | 'not_exists' | 'error'>('idle');
|
||||
const [isProvisioning, setIsProvisioning] = useState(false);
|
||||
|
||||
// Domain dynamisch vom Provider (mit Fallback)
|
||||
const { domain: providerDomain } = useProviderSettings();
|
||||
const domainSuffix = `@${providerDomain || 'stressfrei-wechseln.de'}`;
|
||||
const [isEnablingMailbox, setIsEnablingMailbox] = useState(false);
|
||||
const [mailboxEnabled, setMailboxEnabled] = useState(false);
|
||||
const [showCredentials, setShowCredentials] = useState(false);
|
||||
@@ -3446,7 +3451,7 @@ function StressfreiEmailModal({
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setProvisionError(null);
|
||||
const fullEmail = localPart + STRESSFREI_DOMAIN;
|
||||
const fullEmail = localPart + domainSuffix;
|
||||
|
||||
if (isEditing) {
|
||||
updateMutation.mutate({
|
||||
@@ -3482,11 +3487,11 @@ function StressfreiEmailModal({
|
||||
className="block w-full px-3 py-2 border border-gray-300 rounded-l-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
/>
|
||||
<span className="inline-flex items-center px-3 py-2 border border-l-0 border-gray-300 bg-gray-100 text-gray-600 rounded-r-lg text-sm">
|
||||
{STRESSFREI_DOMAIN}
|
||||
{domainSuffix}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Vollständige Adresse: <span className="font-mono">{localPart || '...'}{STRESSFREI_DOMAIN}</span>
|
||||
Vollständige Adresse: <span className="font-mono">{localPart || '...'}{domainSuffix}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user