mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
refactor: extract shared ProviderIcon, fix canUnlink hiding all buttons
- Extract TelegramIcon + EmailIcon to shared ProviderIcon component - Remove duplicated icons from ConnectedAccounts and MergeAccounts - Remove isPending from canUnlink (buttons already have disabled prop) - Add onSettled to reset confirmingUnlink state after mutation
This commit is contained in:
49
src/components/ProviderIcon.tsx
Normal file
49
src/components/ProviderIcon.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import OAuthProviderIcon from './OAuthProviderIcon';
|
||||||
|
|
||||||
|
export function TelegramIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg className={className} viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path
|
||||||
|
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69.01-.03.01-.14-.07-.2-.08-.06-.19-.04-.28-.02-.12.03-2.02 1.28-5.69 3.77-.54.37-1.03.55-1.47.54-.48-.01-1.41-.27-2.1-.5-.85-.28-1.52-.43-1.46-.91.03-.25.38-.51 1.05-.78 4.12-1.79 6.87-2.97 8.26-3.54 3.93-1.62 4.75-1.9 5.28-1.91.12 0 .37.03.54.17.14.12.18.28.2.46-.01.06.01.24 0 .37z"
|
||||||
|
fill="#29B6F6"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EmailIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
className={className}
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ProviderIcon({
|
||||||
|
provider,
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
provider: string;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
switch (provider) {
|
||||||
|
case 'telegram':
|
||||||
|
return <TelegramIcon className={className ?? 'h-6 w-6'} />;
|
||||||
|
case 'email':
|
||||||
|
return <EmailIcon className={cn('text-dark-300', className ?? 'h-6 w-6')} />;
|
||||||
|
default:
|
||||||
|
return <OAuthProviderIcon provider={provider} className={className ?? 'h-6 w-6'} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import { useToast } from '../components/Toast';
|
|||||||
import { Card } from '@/components/data-display/Card';
|
import { Card } from '@/components/data-display/Card';
|
||||||
import { Button } from '@/components/primitives/Button';
|
import { Button } from '@/components/primitives/Button';
|
||||||
import { staggerContainer, staggerItem } from '@/components/motion/transitions';
|
import { staggerContainer, staggerItem } from '@/components/motion/transitions';
|
||||||
import OAuthProviderIcon from '../components/OAuthProviderIcon';
|
import ProviderIcon from '../components/ProviderIcon';
|
||||||
import { LINK_OAUTH_STATE_KEY, LINK_OAUTH_PROVIDER_KEY } from './LinkOAuthCallback';
|
import { LINK_OAUTH_STATE_KEY, LINK_OAUTH_PROVIDER_KEY } from './LinkOAuthCallback';
|
||||||
import type { LinkedProvider } from '../types';
|
import type { LinkedProvider } from '../types';
|
||||||
|
|
||||||
@@ -15,48 +15,6 @@ const OAUTH_PROVIDERS = ['google', 'yandex', 'discord', 'vk'];
|
|||||||
|
|
||||||
const isOAuthProvider = (provider: string): boolean => OAUTH_PROVIDERS.includes(provider);
|
const isOAuthProvider = (provider: string): boolean => OAUTH_PROVIDERS.includes(provider);
|
||||||
|
|
||||||
// Icons for providers not covered by OAuthProviderIcon
|
|
||||||
function TelegramIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
|
||||||
return (
|
|
||||||
<svg className={className} viewBox="0 0 24 24" aria-hidden="true">
|
|
||||||
<path
|
|
||||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69.01-.03.01-.14-.07-.2-.08-.06-.19-.04-.28-.02-.12.03-2.02 1.28-5.69 3.77-.54.37-1.03.55-1.47.54-.48-.01-1.41-.27-2.1-.5-.85-.28-1.52-.43-1.46-.91.03-.25.38-.51 1.05-.78 4.12-1.79 6.87-2.97 8.26-3.54 3.93-1.62 4.75-1.9 5.28-1.91.12 0 .37.03.54.17.14.12.18.28.2.46-.01.06.01.24 0 .37z"
|
|
||||||
fill="#29B6F6"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function EmailIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
className={className}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProviderIcon({ provider }: { provider: string }) {
|
|
||||||
switch (provider) {
|
|
||||||
case 'telegram':
|
|
||||||
return <TelegramIcon className="h-6 w-6" />;
|
|
||||||
case 'email':
|
|
||||||
return <EmailIcon className="h-6 w-6 text-dark-300" />;
|
|
||||||
default:
|
|
||||||
return <OAuthProviderIcon provider={provider} className="h-6 w-6" />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function LoadingSkeleton() {
|
function LoadingSkeleton() {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
@@ -103,12 +61,14 @@ export default function ConnectedAccounts() {
|
|||||||
message: t('profile.accounts.unlinkError'),
|
message: t('profile.accounts.unlinkError'),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setConfirmingUnlink(null);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const canUnlink = (provider: LinkedProvider): boolean => {
|
const canUnlink = (provider: LinkedProvider): boolean => {
|
||||||
if (!provider.linked) return false;
|
if (!provider.linked) return false;
|
||||||
if (!isOAuthProvider(provider.provider)) return false;
|
if (!isOAuthProvider(provider.provider)) return false;
|
||||||
if (unlinkMutation.isPending) return false;
|
|
||||||
const linkedCount = data?.providers.filter((p) => p.linked).length ?? 0;
|
const linkedCount = data?.providers.filter((p) => p.linked).length ?? 0;
|
||||||
return linkedCount > 1;
|
return linkedCount > 1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/data-disp
|
|||||||
import { Button } from '@/components/primitives/Button';
|
import { Button } from '@/components/primitives/Button';
|
||||||
import { staggerContainer, staggerItem } from '@/components/motion/transitions';
|
import { staggerContainer, staggerItem } from '@/components/motion/transitions';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import OAuthProviderIcon from '../components/OAuthProviderIcon';
|
import ProviderIcon from '../components/ProviderIcon';
|
||||||
import type { MergeAccountPreview } from '../types';
|
import type { MergeAccountPreview } from '../types';
|
||||||
|
|
||||||
// -- Icons --
|
// -- Icons --
|
||||||
@@ -72,47 +72,10 @@ function CheckCircleIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TelegramIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
|
||||||
return (
|
|
||||||
<svg className={className} viewBox="0 0 24 24" aria-hidden="true">
|
|
||||||
<path
|
|
||||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69.01-.03.01-.14-.07-.2-.08-.06-.19-.04-.28-.02-.12.03-2.02 1.28-5.69 3.77-.54.37-1.03.55-1.47.54-.48-.01-1.41-.27-2.1-.5-.85-.28-1.52-.43-1.46-.91.03-.25.38-.51 1.05-.78 4.12-1.79 6.87-2.97 8.26-3.54 3.93-1.62 4.75-1.9 5.28-1.91.12 0 .37.03.54.17.14.12.18.28.2.46-.01.06.01.24 0 .37z"
|
|
||||||
fill="#29B6F6"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function EmailIcon({ className = 'h-5 w-5' }: { className?: string }) {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
className={className}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Helpers --
|
// -- Helpers --
|
||||||
|
|
||||||
function ProviderBadgeIcon({ provider }: { provider: string }) {
|
function ProviderBadgeIcon({ provider }: { provider: string }) {
|
||||||
switch (provider) {
|
return <ProviderIcon provider={provider} className="h-4 w-4" />;
|
||||||
case 'telegram':
|
|
||||||
return <TelegramIcon className="h-4 w-4" />;
|
|
||||||
case 'email':
|
|
||||||
return <EmailIcon className="h-4 w-4 text-dark-300" />;
|
|
||||||
default:
|
|
||||||
return <OAuthProviderIcon provider={provider} className="h-4 w-4" />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCountdown(seconds: number): string {
|
function formatCountdown(seconds: number): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user