jan/web-app/src/containers/auth/AuthLoginButton.tsx
Dinh Long Nguyen 0f85fce6ef
feat: add auth + google auth provider for web (#6505)
* handle google auth

* fix lint

* fix auto login button type

* update i18 language + userprofilemenu position

* minor api rename for consistency
2025-09-18 11:11:14 +07:00

85 lines
2.5 KiB
TypeScript

/**
* Auth Login Button with Dropdown Menu
* Shows available authentication providers in a dropdown menu
*/
import { useState } from 'react'
import { IconLogin, IconBrandGoogleFilled } from '@tabler/icons-react'
import { useTranslation } from '@/i18n/react-i18next-compat'
import { useAuth } from '@/hooks/useAuth'
import { toast } from 'sonner'
import type { ProviderType } from '@jan/extensions-web'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export const AuthLoginButton = () => {
const { t } = useTranslation()
const { getAllProviders, loginWithProvider } = useAuth()
const [isLoading, setIsLoading] = useState(false)
const enabledProviders = getAllProviders()
const handleProviderLogin = async (providerId: ProviderType) => {
try {
setIsLoading(true)
await loginWithProvider(providerId)
} catch (error) {
console.error('Failed to login with provider:', error)
toast.error(t('common:loginFailed'))
} finally {
setIsLoading(false)
}
}
const getProviderIcon = (iconName: string) => {
switch (iconName) {
case 'IconBrandGoogleFilled':
return IconBrandGoogleFilled
default:
return IconLogin
}
}
if (enabledProviders.length === 0) {
return null
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
disabled={isLoading}
className="flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded w-full"
>
<IconLogin size={18} className="text-left-panel-fg/70" />
<span className="font-medium text-left-panel-fg/90">{t('common:login')}</span>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start" className="w-48">
{enabledProviders.map((provider) => {
const IconComponent = getProviderIcon(provider.icon)
return (
<DropdownMenuItem
key={provider.id}
onClick={() => handleProviderLogin(provider.id as ProviderType)}
disabled={isLoading}
className="gap-2"
>
<IconComponent size={16} />
<span className="text-sm text-left-panel-fg/90">
{t('common:loginWith', {
provider: provider.name,
})}
</span>
</DropdownMenuItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
)
}