import { google } from 'googleapis'; import { OAuth2Client } from 'google-auth-library'; export interface GoogleTaskList { id: string; title: string; updated: string; } export interface GoogleTask { id: string; title: string; notes?: string; status: string; due?: string; updated: string; } /** * Create an authenticated Google OAuth2 client */ export const createGoogleClient = (accessToken: string, refreshToken?: string): OAuth2Client => { const clientId = process.env.GOOGLE_CLIENT_ID; const clientSecret = process.env.GOOGLE_CLIENT_SECRET; const redirectUri = process.env.GOOGLE_REDIRECT_URI || `${process.env.NEXTAUTH_URL}/api/calendar/google/oauth`; const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri); oauth2Client.setCredentials({ access_token: accessToken, refresh_token: refreshToken }); return oauth2Client; }; /** * Fetch all task lists for the user */ export const fetchGoogleTaskLists = async (client: OAuth2Client): Promise => { const service = google.tasks({ version: 'v1', auth: client }); try { const response = await service.tasklists.list(); return (response.data.items || []).map(item => ({ id: item.id!, title: item.title!, updated: item.updated! })); } catch (error) { console.error('Error fetching Google Task lists:', error); throw error; } }; /** * Fetch tasks from a specific task list */ export const fetchGoogleTasks = async (client: OAuth2Client, taskListId: string): Promise => { const service = google.tasks({ version: 'v1', auth: client }); try { const response = await service.tasks.list({ tasklist: taskListId, showCompleted: false, // We usually only want active tasks for import showHidden: false }); return (response.data.items || []).map(item => ({ id: item.id!, title: item.title!, notes: item.notes || undefined, status: item.status!, due: item.due || undefined, updated: item.updated! })); } catch (error) { console.error(`Error fetching Google Tasks from list ${taskListId}:`, error); throw error; } }; /** * Update a Google Task status */ export const updateGoogleTask = async (client: OAuth2Client, taskListId: string, taskId: string, updates: { title?: string; notes?: string; status?: 'needsAction' | 'completed'; due?: string | null }): Promise => { const service = google.tasks({ version: 'v1', auth: client }); try { const requestBody: any = {}; if (updates.title !== undefined) requestBody.title = updates.title; if (updates.notes !== undefined) requestBody.notes = updates.notes; if (updates.due !== undefined) requestBody.due = updates.due; if (updates.status !== undefined) { requestBody.status = updates.status; requestBody.completed = updates.status === 'completed' ? new Date().toISOString() : null; } const response = await service.tasks.patch({ tasklist: taskListId, task: taskId, requestBody, }); const item = response.data; return { id: item.id!, title: item.title!, notes: item.notes || undefined, status: item.status!, due: item.due || undefined, updated: item.updated! }; } catch (error) { console.error(`Error updating Google Task ${taskId}:`, error); throw error; } }; export const deleteGoogleTask = async (client: OAuth2Client, taskListId: string, taskId: string): Promise => { const service = google.tasks({ version: 'v1', auth: client }); try { await service.tasks.delete({ tasklist: taskListId, task: taskId, }); } catch (error) { console.error(`Error deleting Google Task ${taskId}:`, error); throw error; } }; export const updateGoogleTaskStatus = async (client: OAuth2Client, taskListId: string, taskId: string, status: 'needsAction' | 'completed'): Promise => { const service = google.tasks({ version: 'v1', auth: client }); try { const response = await service.tasks.patch({ tasklist: taskListId, task: taskId, requestBody: { status: status, completed: status === 'completed' ? new Date().toISOString() : null } }); const item = response.data; return { id: item.id!, title: item.title!, notes: item.notes || undefined, status: item.status!, due: item.due || undefined, updated: item.updated! }; } catch (error) { console.error(`Error updating Google Task ${taskId} in list ${taskListId}:`, error); throw error; } };