My-Weekly-ToDo-List/src/lib/apple-reminders.ts
mARTin f9d578ddf1 fix: time grid layout alignment and task drag/drop collision detection
- Removed boxed background from grid tasks and added hover-only resize handle

- Fixed vertical drop calculation using correct cell sizes

- Aligned time column header perfectly using a structural ghost replica

- Added collision detection to prevent dragging tasks over occupied slots
2026-02-23 21:29:56 +01:00

101 lines
3.1 KiB
TypeScript

import { DAVClient } from 'tsdav';
// iCloud CalDAV Server URL
const ICLOUD_CALDAV_URL = 'https://caldav.icloud.com';
export interface AppleReminderList {
id: string; // URL
title: string;
color?: string;
}
/**
* Create a configured DAV client for Apple iCloud
*/
const createClient = (email: string, appSpecificPassword: string) => {
return new DAVClient({
serverUrl: ICLOUD_CALDAV_URL,
credentials: {
username: email,
password: appSpecificPassword,
},
authMethod: 'Basic',
defaultAccountType: 'caldav',
});
};
/**
* Fetch all reminder lists (VTODO collections)
*/
export const fetchAppleReminderLists = async (email: string, appSpecificPassword: string): Promise<AppleReminderList[]> => {
try {
const client = createClient(email, appSpecificPassword);
await client.login();
const calendars = await client.fetchCalendars();
// Filter to VTODO collections (Reminders)
const reminderLists = calendars.filter(cal => {
const components: string[] = (cal as any).components || [];
return components.includes('VTODO');
});
return reminderLists.map(cal => ({
id: cal.url,
title: (cal.displayName as string) || 'Untitled List',
color: (cal as any).calendarColor,
}));
} catch (error) {
console.error('Error fetching Apple reminder lists:', error);
throw error;
}
};
/**
* Create a new reminder list (collection)
*/
export const createAppleReminderList = async (email: string, appSpecificPassword: string, title: string): Promise<AppleReminderList> => {
try {
const client = createClient(email, appSpecificPassword);
await client.login();
// tsdav's createDAVClient returns an object where we can use makeCalendar
// First we need a base URL. We can derive it from existing calendars.
const calendars = await client.fetchCalendars();
if (calendars.length === 0) {
throw new Error('No existing Apple calendars found to derive base URL');
}
// Deriving the base URL for new collections (usually parent of existing calendars)
const firstCalUrl = calendars[0].url;
const urlParts = firstCalUrl.split('/');
// Remove the last part (and trailing slash if exists)
if (firstCalUrl.endsWith('/')) urlParts.pop();
urlParts.pop();
const baseWebDavUrl = urlParts.join('/') + '/';
const newId = crypto.randomUUID();
const newCalendarUrl = `${baseWebDavUrl}${newId}/`;
// Create the calendar (reminder list)
await (client as any).makeCalendar({
url: newCalendarUrl,
props: {
'displayname': title,
'supported-calendar-component-set': {
'comp': { _attributes: { name: 'VTODO' } }
}
}
});
return {
id: newCalendarUrl,
title: title,
};
} catch (error) {
console.error('Error creating Apple reminder list:', error);
throw error;
}
};