import { __ } from '@wordpress/i18n' import { useCallback, useEffect, useState } from 'react' import apiFetch from '@wordpress/api-fetch' import { addQueryArgs } from '@wordpress/url' import { useDispatch, useSelect } from '@wordpress/data' import classNames from 'classnames' import { store, store_name } from '../../../store/backend' import { Button } from '../Button/Button' import './IcloudAuthForm.scss' type FormMessage = { text: string type: 'success' | 'error' } type CalendarDetail = { id: string name: string writable?: boolean readonly?: boolean } type AuthData = { isAuthenticated?: boolean email?: string lastError?: string needsReconnect?: boolean calendarDetails?: CalendarDetail[] selectedCalendarId?: string helpUrl?: string helpText?: string } type IcloudAuthFormProps = { calendarId: number | string selectedCalendarId?: string onConnected?: () => void onCalendarSaved?: (providerCalendarId: string) => void } export const IcloudAuthForm = ({ calendarId, selectedCalendarId = '', onConnected, onCalendarSaved, }: IcloudAuthFormProps) => { const { setGgAuthData, setItems } = useDispatch(store) const [email, setEmail] = useState('') const [appPassword, setAppPassword] = useState('') const [busy, setBusy] = useState(false) const [message, setMessage] = useState(null) const [calendarHref, setCalendarHref] = useState(selectedCalendarId) const connectedCalendars = useSelect( (select: any) => select(store).getItems('connected_calendars') || [], [] ) as Array> const refreshAuth = useCallback(() => { if (calendarId == null) return apiFetch({ path: addQueryArgs('/wbk/v2/get-calendar-auth-data/', { calendar_id: calendarId, }), }) .then((result: any) => setGgAuthData(calendarId, result)) .catch(() => setGgAuthData(calendarId, {})) }, [calendarId, setGgAuthData]) useEffect(() => { refreshAuth() }, [refreshAuth]) const authData = useSelect( (select: any) => select(store_name).getGgAuthData(calendarId), [calendarId] ) as AuthData | null useEffect(() => { if (authData?.email) { setEmail(authData.email) } const savedId = authData?.selectedCalendarId || selectedCalendarId || '' if (savedId) { setCalendarHref(savedId) } }, [authData, selectedCalendarId]) const syncSavedCalendar = useCallback( (providerCalendarId: string) => { const next = (connectedCalendars || []).map((item) => String(item?.id) === String(calendarId) ? { ...item, in_provider_id: providerCalendarId } : item ) setItems('connected_calendars', next) onCalendarSaved?.(providerCalendarId) }, [ calendarId, connectedCalendars, onCalendarSaved, setItems, ] ) const postAction = async ( path: string, body: Record = {} ) => { setBusy(true) setMessage(null) try { const result: any = await apiFetch({ path, method: 'POST', data: { calendar_id: calendarId, ...body }, }) if (result?.ok === false) { setMessage({ type: 'error', text: result.message || __('Action failed.', 'webba-booking-lite'), }) } else { setMessage({ type: 'success', text: result?.data?.message || __('Done.', 'webba-booking-lite'), }) setAppPassword('') if (path.includes('/calendars/')) { const savedId = (result?.data?.in_provider_id as string) || (body.provider_calendar_id as string) || calendarHref if (savedId) { setCalendarHref(savedId) syncSavedCalendar(savedId) } } refreshAuth() if (path.includes('/connect/') && onConnected) { onConnected() } } } catch (e: any) { setMessage({ type: 'error', text: e?.message || __('Action failed. Please try again.', 'webba-booking-lite'), }) } finally { setBusy(false) } } const testConnection = async () => { // Snapshot so a busy/disabled cycle cannot lose the typed password on success. const passwordSnapshot = appPassword setBusy(true) setMessage(null) try { const result: any = await apiFetch({ path: '/wbk/v2/icloud-calendar/test/', method: 'POST', data: { calendar_id: calendarId, email: email || undefined, app_password: passwordSnapshot || undefined, }, }) if (result?.ok === false) { setAppPassword('') setMessage({ type: 'error', text: result.message || __('Action failed.', 'webba-booking-lite'), }) return } // Success: restore snapshot (do not clear). setAppPassword(passwordSnapshot) setMessage({ type: 'success', text: result?.data?.message || __('Connection successful.', 'webba-booking-lite'), }) } catch (e: any) { setAppPassword('') setMessage({ type: 'error', text: e?.message || __('Action failed. Please try again.', 'webba-booking-lite'), }) } finally { setBusy(false) } } if (!authData || Object.keys(authData).length === 0) { return (
{__('Loading...', 'webba-booking-lite')}
) } const isAuthenticated = !!authData.isAuthenticated const writableCalendars = (authData.calendarDetails || []).filter( (c) => !c.readonly ) return (
{authData.needsReconnect && (

{__( 'Credentials invalid. Please reconnect.', 'webba-booking-lite' )}

)} {authData.lastError && (

{authData.lastError}

)}

https://account.apple.com/ {' — '} {authData.helpText || __( 'Sign-In and Security → App-Specific Passwords. Never use your regular Apple Account password.', 'webba-booking-lite' )}

{isAuthenticated && ( )}
{isAuthenticated && writableCalendars.length > 0 && (
)} {message && (

{message.text}

)}
) }