Create Organisation Fix
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Eye, EyeOff, Copy, Check } from 'lucide-react';
|
||||
import { useToast } from './Toast';
|
||||
|
||||
export interface ObfuscatedIdNumberProps {
|
||||
idNumber?: string | null;
|
||||
className?: string;
|
||||
allowToggle?: boolean;
|
||||
}
|
||||
|
||||
export function maskIdNumber(id: string): string {
|
||||
const clean = id ? id.trim() : '';
|
||||
if (clean.length <= 4) {
|
||||
return '••••';
|
||||
}
|
||||
if (clean.length <= 8) {
|
||||
return `${clean.slice(0, 2)}••••${clean.slice(-2)}`;
|
||||
}
|
||||
// SA ID (13 digits) or standard national IDs: keep first 6 (DOB), mask middle 5, show last 2
|
||||
return `${clean.slice(0, 6)}•••••${clean.slice(-2)}`;
|
||||
}
|
||||
|
||||
export function ObfuscatedIdNumber({
|
||||
idNumber,
|
||||
className = '',
|
||||
allowToggle = true,
|
||||
}: ObfuscatedIdNumberProps): React.ReactElement {
|
||||
const [isRevealed, setIsRevealed] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
const { success } = useToast();
|
||||
|
||||
if (!idNumber) {
|
||||
return <span className="text-slate-600 font-mono text-xs">-</span>;
|
||||
}
|
||||
|
||||
const rawId: string = idNumber;
|
||||
|
||||
const handleCopy = async (e: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
await navigator.clipboard.writeText(rawId);
|
||||
setCopied(true);
|
||||
success('Copied to Clipboard', 'ID Number copied.');
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch {
|
||||
// Clipboard fallback
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggle = (e: React.MouseEvent<HTMLButtonElement>): void => {
|
||||
e.stopPropagation();
|
||||
setIsRevealed((prev) => !prev);
|
||||
};
|
||||
|
||||
const displayedText = isRevealed ? rawId : maskIdNumber(rawId);
|
||||
|
||||
return (
|
||||
<div className={`inline-flex items-center gap-1.5 font-mono text-xs text-slate-300 ${className}`}>
|
||||
<span className="tracking-wider select-all">{displayedText}</span>
|
||||
|
||||
{allowToggle && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleToggle}
|
||||
title={isRevealed ? 'Hide ID Number' : 'Reveal ID Number'}
|
||||
className="p-1 rounded hover:bg-slate-800 text-slate-400 hover:text-slate-200 transition-colors cursor-pointer"
|
||||
>
|
||||
{isRevealed ? <EyeOff className="w-3.5 h-3.5 text-blue-400" /> : <Eye className="w-3.5 h-3.5" />}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopy}
|
||||
title="Copy ID Number"
|
||||
className="p-1 rounded hover:bg-slate-800 text-slate-400 hover:text-slate-200 transition-colors cursor-pointer"
|
||||
>
|
||||
{copied ? <Check className="w-3.5 h-3.5 text-emerald-400" /> : <Copy className="w-3.5 h-3.5" />}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user