import { googleApi } from '@/admin/api/google'; import { googleCredentialsQuery, googleStatusQuery, } from '@/admin/queries/google'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; import { FileDropZone } from '@/components/ui/file-drop-zone'; import { Skeleton } from '@/components/ui/skeleton'; import { Spinner } from '@/components/ui/spinner'; import copy from '@/lib/copy-to-clipboard'; import { emitGoogleIntegration } from '@/lib/event'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { __ } from '@wordpress/i18n'; import { CalendarCheck, Copy, Info, Lock, X } from 'lucide-react'; import { useCallback, useEffect, useState } from 'react'; import { toast } from 'sonner'; const GoogleMeetSettings = () => { const queryClient = useQueryClient(); const [confirmOpen, setConfirmOpen] = useState(false); const [confirmRemoveOpen, setConfirmRemoveOpen] = useState(false); const isAdmin = __ALLCOACH_ADMIN__.isAdmin; const { data: credentials, isLoading: credentialsLoading } = useQuery({ ...googleCredentialsQuery(), retry: false, enabled: () => isAdmin, }); const { data: status, isLoading: statusLoading } = useQuery({ ...googleStatusQuery(), retry: false, }); // Handle redirect back from Google OAuth useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get('allcoach_google_connected') === '1') { queryClient.invalidateQueries({ queryKey: ['google-status'] }); toast.success(__('Google account connected successfully.', 'allcoach')); const url = new URL(window.location.href); url.searchParams.delete('allcoach_google_connected'); window.history.replaceState({}, '', url.toString()); } const error = params.get('allcoach_google_error'); if (error) { toast.error(decodeURIComponent(error)); const url = new URL(window.location.href); url.searchParams.delete('allcoach_google_error'); window.history.replaceState({}, '', url.toString()); } }, []); const uploadCredentials = useMutation({ mutationFn: (data: FormData) => googleApi.uploadCredentials(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['google-status'] }); toast.success(__('Google credentials saved.', 'allcoach')); emitGoogleIntegration({ type: 'configured', value: true }); }, onError: () => { toast.error(__('Failed to save credentials.', 'allcoach')); emitGoogleIntegration({ type: 'configured', value: false }); }, }); const removeCredentials = useMutation({ mutationFn: () => googleApi.deleteCredentials(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['settings'] }); queryClient.invalidateQueries({ queryKey: ['google-status'] }); emitGoogleIntegration({ type: 'configured', value: false }); }, }); const connect = useMutation({ mutationFn: googleApi.getAuthUrl, onSuccess: ({ url }) => { window.location.href = url; emitGoogleIntegration({ type: 'connected', value: true }); }, onError: () => { toast.error(__('Failed to get Google authorization URL.', 'allcoach')); emitGoogleIntegration({ type: 'connected', value: false }); }, }); const disconnect = useMutation({ mutationFn: googleApi.disconnect, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['google-status'] }); toast.success(__('Google account disconnected.', 'allcoach')); emitGoogleIntegration({ type: 'connected', value: false }); }, onError: () => { toast.error(__('Failed to disconnect Google account.', 'allcoach')); }, }); const handleFile = useCallback( (file: File) => { if (!file.name.endsWith('.json')) { toast.error(__('Please drop a valid JSON file.', 'allcoach')); return; } const formData = new FormData(); formData.append('credentials_file', file); uploadCredentials.mutate(formData); }, [uploadCredentials], ); const hasCredentials = status?.configured ?? false; const connected = status?.connected ?? false; const handleCopy = useCallback(async () => { try { await copy(__ALLCOACH_ADMIN__.googleCallbackUrl); toast.success(__('Redirect URL copied to clipboard.', 'allcoach')); } catch { toast.error(__('Failed to copy URL.', 'allcoach')); } }, []); return ( <>
{/* Header */}

{__('Google Meet / Calendar', 'allcoach')}

{/* Step 1 — Credentials */} {isAdmin ? ( <>

{__('Step 1 — OAuth Credentials', 'allcoach')}

{__( 'Download the OAuth 2.0 Client ID JSON from', 'allcoach', )}{' '} {__('Google Cloud Console', 'allcoach')} {' '} {__('and drop it below.', 'allcoach')}

{hasCredentials && ( )}
{credentialsLoading ? ( ) : hasCredentials ? (
{__('Credentials configured', 'allcoach')} {credentials?.client_id}
) : ( )}
{/* Step 2 — Authorized redirect URI */}

{__('Step 2 — Authorized Redirect URI', 'allcoach')}

{__( 'Add this URI to your Google Cloud Console under', 'allcoach', )}{' '} {__( 'OAuth 2.0 Client → Authorized redirect URIs', 'allcoach', )} {__(', then save the client.', 'allcoach')}

{__( 'Copy the URI below and paste it into your Google app credentials before connecting your account.', 'allcoach', )}

{__ALLCOACH_ADMIN__.googleCallbackUrl}
) : (

{__('Step 1 — OAuth Credentials', 'allcoach')}

{__('Configured by your administrator.', 'allcoach')}

)} {/* Step 3 — Connect Account */} {hasCredentials && (

{__('Step 3 — Connect Google Account', 'allcoach')}

{__( 'Authorize access to Google Calendar to enable Meet links for appointments.', 'allcoach', )}

{statusLoading ? ( ) : connected ? ( <> {__('Connected', 'allcoach')} {status?.email ? ` · ${status.email}` : ''} ) : ( <> {__('Not connected', 'allcoach')} )}
{!statusLoading && (connected ? ( ) : ( ))}
)}
{__('Remove OAuth Credentials', 'allcoach')} {__( 'Are you sure you want to remove the OAuth credentials? Google Meet and Calendar integration will stop working.', 'allcoach', )} {__('Cancel', 'allcoach')} removeCredentials.mutate()} > {__('Remove', 'allcoach')} {__('Disconnect Google Account', 'allcoach')} {__( 'Are you sure you want to disconnect your Google account? Calendar sync and Meet links will stop working for new appointments.', 'allcoach', )} {__('Cancel', 'allcoach')} disconnect.mutate()} > {__('Disconnect', 'allcoach')} ); }; export default GoogleMeetSettings;