118 lines
4.5 KiB
Svelte
118 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { GoogleAuthManager, createGoogleAuthState } from '$lib/google/auth/manager.js';
|
|
|
|
// Props
|
|
let {
|
|
onSuccess,
|
|
onError,
|
|
disabled = false,
|
|
size = 'default',
|
|
variant = 'primary'
|
|
} = $props<{
|
|
onSuccess?: (token: string) => void;
|
|
onError?: (error: string) => void;
|
|
disabled?: boolean;
|
|
size?: 'small' | 'default' | 'large';
|
|
variant?: 'primary' | 'secondary';
|
|
}>();
|
|
|
|
// State
|
|
let authState = $state(createGoogleAuthState());
|
|
let authManager = new GoogleAuthManager(authState);
|
|
|
|
onMount(() => {
|
|
authManager.checkConnection();
|
|
});
|
|
|
|
async function handleConnect() {
|
|
if (authState.connecting || disabled) return;
|
|
|
|
try {
|
|
await authManager.connectToGoogle();
|
|
if (authState.isConnected && authState.token) {
|
|
onSuccess?.(authState.token);
|
|
}
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Failed to connect to Google';
|
|
onError?.(errorMessage);
|
|
}
|
|
}
|
|
|
|
async function handleDisconnect() {
|
|
await authManager.disconnectGoogle();
|
|
}
|
|
|
|
// Size classes
|
|
const sizeClasses = {
|
|
small: 'px-3 py-1.5 text-sm',
|
|
default: 'px-4 py-2 text-base',
|
|
large: 'px-6 py-3 text-lg'
|
|
};
|
|
|
|
// Variant classes
|
|
const variantClasses = {
|
|
primary: 'bg-blue-600 hover:bg-blue-700 text-white border-transparent',
|
|
secondary: 'bg-white hover:bg-gray-50 text-gray-900 border-gray-300'
|
|
};
|
|
</script>
|
|
|
|
{#if authState.isConnected}
|
|
<div class="flex flex-wrap items-center gap-3">
|
|
<div class="flex items-center gap-2 rounded-full bg-green-100 px-3 py-1 border border-green-300 whitespace-nowrap">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-green-600" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
<span class="text-sm font-medium text-green-800">Connected</span>
|
|
</div>
|
|
|
|
{#if authState.userEmail}
|
|
<div class="flex items-center gap-2 rounded-full bg-blue-100 px-3 py-1 border border-blue-300 max-w-full overflow-hidden">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
|
|
</svg>
|
|
<span class="text-sm font-medium text-blue-800 truncate">{authState.userEmail}</span>
|
|
</div>
|
|
{/if}
|
|
|
|
<button
|
|
onclick={handleDisconnect}
|
|
class="text-sm text-red-600 hover:text-red-800 flex items-center gap-1 whitespace-nowrap mt-1 sm:mt-0"
|
|
aria-label="Disconnect from Google"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
|
</svg>
|
|
Disconnect
|
|
</button>
|
|
</div>
|
|
{:else}
|
|
<div class="flex flex-col gap-2">
|
|
<button
|
|
onclick={handleConnect}
|
|
disabled={authState.connecting || disabled}
|
|
class="inline-flex items-center border font-medium rounded-md transition disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {sizeClasses[size as keyof typeof sizeClasses]} {variantClasses[variant as keyof typeof variantClasses]}"
|
|
aria-label="Connect to Google"
|
|
>
|
|
{#if authState.connecting}
|
|
<div class="w-4 h-4 mr-2 animate-spin rounded-full border-2 border-current border-t-transparent"></div>
|
|
Connecting...
|
|
{:else}
|
|
<svg class="w-4 h-4 mr-2" viewBox="0 0 24 24">
|
|
<path fill="currentColor" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
|
<path fill="currentColor" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
|
<path fill="currentColor" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
|
<path fill="currentColor" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
|
</svg>
|
|
Connect to Google
|
|
{/if}
|
|
</button>
|
|
|
|
{#if authState.error}
|
|
<div class="text-sm text-red-600 mt-1">
|
|
{authState.error}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{/if}
|