optimize password view in stressfrei addresses
This commit is contained in:
-1
File diff suppressed because one or more lines are too long
+78
-78
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -5,8 +5,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>OpenCRM</title>
|
<title>OpenCRM</title>
|
||||||
<script type="module" crossorigin src="/assets/index-CitfypIw.js"></script>
|
<script type="module" crossorigin src="/assets/index-BdT2l8pM.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-B7w5p8ZY.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DCjAycJ5.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import Modal from '../../components/ui/Modal';
|
|||||||
import Input from '../../components/ui/Input';
|
import Input from '../../components/ui/Input';
|
||||||
import Select from '../../components/ui/Select';
|
import Select from '../../components/ui/Select';
|
||||||
import FileUpload from '../../components/ui/FileUpload';
|
import FileUpload from '../../components/ui/FileUpload';
|
||||||
import { Edit, Plus, Trash2, MapPin, CreditCard, FileText, Gauge, Eye, EyeOff, Download, Globe, UserPlus, X, Search, Mail } from 'lucide-react';
|
import { Edit, Plus, Trash2, MapPin, CreditCard, FileText, Gauge, Eye, EyeOff, Download, Globe, UserPlus, X, Search, Mail, Copy, Check } from 'lucide-react';
|
||||||
import CopyButton, { CopyableBlock } from '../../components/ui/CopyButton';
|
import CopyButton, { CopyableBlock } from '../../components/ui/CopyButton';
|
||||||
import type { Address, BankCard, IdentityDocument, Meter, Customer, CustomerRepresentative, CustomerSummary } from '../../types';
|
import type { Address, BankCard, IdentityDocument, Meter, Customer, CustomerRepresentative, CustomerSummary } from '../../types';
|
||||||
|
|
||||||
@@ -2783,6 +2783,151 @@ function StressfreiEmailsTab({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== CREDENTIALS DISPLAY ====================
|
||||||
|
|
||||||
|
function CredentialsDisplay({
|
||||||
|
credentials,
|
||||||
|
onHide,
|
||||||
|
onResetPassword,
|
||||||
|
isResettingPassword,
|
||||||
|
}: {
|
||||||
|
credentials: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
imap: { server: string; port: number; encryption: string } | null;
|
||||||
|
smtp: { server: string; port: number; encryption: string } | null;
|
||||||
|
};
|
||||||
|
onHide: () => void;
|
||||||
|
onResetPassword: () => void;
|
||||||
|
isResettingPassword: boolean;
|
||||||
|
}) {
|
||||||
|
const [copiedField, setCopiedField] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const copyToClipboard = async (text: string, fieldName: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
setCopiedField(fieldName);
|
||||||
|
setTimeout(() => setCopiedField(null), 2000);
|
||||||
|
} catch {
|
||||||
|
// Fallback für ältere Browser
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = text;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
setCopiedField(fieldName);
|
||||||
|
setTimeout(() => setCopiedField(null), 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const CopyButton = ({ text, fieldName }: { text: string; fieldName: string }) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => copyToClipboard(text, fieldName)}
|
||||||
|
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
|
||||||
|
title="In Zwischenablage kopieren"
|
||||||
|
>
|
||||||
|
{copiedField === fieldName ? (
|
||||||
|
<Check className="w-4 h-4 text-green-600" />
|
||||||
|
) : (
|
||||||
|
<Copy className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const imapString = credentials.imap
|
||||||
|
? `${credentials.imap.server}:${credentials.imap.port}`
|
||||||
|
: '';
|
||||||
|
const smtpString = credentials.smtp
|
||||||
|
? `${credentials.smtp.server}:${credentials.smtp.port}`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-50 border border-gray-200 rounded-lg p-4 space-y-3">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
|
||||||
|
Zugangsdaten
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onHide}
|
||||||
|
className="text-gray-400 hover:text-gray-600 p-1 hover:bg-gray-200 rounded"
|
||||||
|
title="Zugangsdaten ausblenden"
|
||||||
|
>
|
||||||
|
<EyeOff className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Benutzername & Passwort */}
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
<div className="bg-white rounded-lg p-3 border border-gray-100">
|
||||||
|
<label className="text-xs text-gray-500 block mb-1">Benutzername</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<code className="text-sm text-gray-900 font-mono flex-1 break-all">
|
||||||
|
{credentials.email}
|
||||||
|
</code>
|
||||||
|
<CopyButton text={credentials.email} fieldName="email" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white rounded-lg p-3 border border-gray-100">
|
||||||
|
<label className="text-xs text-gray-500 block mb-1">Passwort</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<code className="text-sm text-gray-900 font-mono flex-1 break-all">
|
||||||
|
{credentials.password}
|
||||||
|
</code>
|
||||||
|
<CopyButton text={credentials.password} fieldName="password" />
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onResetPassword}
|
||||||
|
disabled={isResettingPassword}
|
||||||
|
className="mt-2 text-xs text-blue-600 hover:text-blue-800 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{isResettingPassword ? 'Generiere...' : 'Neu generieren'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Server-Einstellungen */}
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
{credentials.imap && (
|
||||||
|
<div className="bg-white rounded-lg p-3 border border-gray-100">
|
||||||
|
<label className="text-xs text-gray-500 block mb-1">
|
||||||
|
IMAP (Empfang)
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<code className="text-sm text-gray-900 font-mono flex-1">
|
||||||
|
{imapString}
|
||||||
|
</code>
|
||||||
|
<CopyButton text={imapString} fieldName="imap" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-gray-400 mt-1 block">
|
||||||
|
{credentials.imap.encryption}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{credentials.smtp && (
|
||||||
|
<div className="bg-white rounded-lg p-3 border border-gray-100">
|
||||||
|
<label className="text-xs text-gray-500 block mb-1">
|
||||||
|
SMTP (Versand)
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<code className="text-sm text-gray-900 font-mono flex-1">
|
||||||
|
{smtpString}
|
||||||
|
</code>
|
||||||
|
<CopyButton text={smtpString} fieldName="smtp" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-gray-400 mt-1 block">
|
||||||
|
{credentials.smtp.encryption}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== STRESSFREI-EMAIL MODAL ====================
|
// ==================== STRESSFREI-EMAIL MODAL ====================
|
||||||
|
|
||||||
function StressfreiEmailModal({
|
function StressfreiEmailModal({
|
||||||
@@ -3224,55 +3369,12 @@ function StressfreiEmailModal({
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
) : credentials && (
|
) : credentials && (
|
||||||
<div className="bg-white border border-gray-200 rounded-lg p-3 space-y-2">
|
<CredentialsDisplay
|
||||||
<div className="flex justify-between items-center mb-2">
|
credentials={credentials}
|
||||||
<span className="text-xs font-medium text-gray-500 uppercase">Zugangsdaten</span>
|
onHide={() => setShowCredentials(false)}
|
||||||
<button
|
onResetPassword={handleResetPassword}
|
||||||
type="button"
|
isResettingPassword={isResettingPassword}
|
||||||
onClick={() => setShowCredentials(false)}
|
/>
|
||||||
className="text-gray-400 hover:text-gray-600"
|
|
||||||
>
|
|
||||||
<EyeOff className="w-4 h-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-2 gap-2 text-xs">
|
|
||||||
<div>
|
|
||||||
<span className="text-gray-500">E-Mail:</span>
|
|
||||||
<p className="font-mono text-gray-900 break-all">{credentials.email}</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="text-gray-500">Passwort:</span>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p className="font-mono text-gray-900 break-all select-all flex-1">{credentials.password}</p>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleResetPassword}
|
|
||||||
disabled={isResettingPassword}
|
|
||||||
className="text-blue-600 hover:text-blue-800 text-xs whitespace-nowrap disabled:opacity-50"
|
|
||||||
title="Neues Kennwort generieren"
|
|
||||||
>
|
|
||||||
{isResettingPassword ? 'Generiere...' : 'Neu generieren'}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{credentials.imap && (
|
|
||||||
<div className="pt-2 border-t border-gray-100">
|
|
||||||
<span className="text-xs font-medium text-gray-500">IMAP (Empfang)</span>
|
|
||||||
<p className="font-mono text-xs text-gray-900">
|
|
||||||
{credentials.imap.server}:{credentials.imap.port} ({credentials.imap.encryption})
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{credentials.smtp && (
|
|
||||||
<div className="pt-2 border-t border-gray-100">
|
|
||||||
<span className="text-xs font-medium text-gray-500">SMTP (Versand)</span>
|
|
||||||
<p className="font-mono text-xs text-gray-900">
|
|
||||||
{credentials.smtp.server}:{credentials.smtp.port} ({credentials.smtp.encryption})
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user