fix: recurring event display and AI query improvements
- Use occurrenceStart instead of startTime in getEventsInRange so recurring events show their actual occurrence date to the AI - Add lazy CalDAV sync in ChatService (syncOnce before first DB access) - Add CaldavService.sync() with internal config check (silent no-op) - Show German recurrence description (e.g. "Jede Woche") instead of generic "Wiederkehrend" in EventCardBase via formatRecurrenceRule() - Move RepeatType and REPEAT_TYPE_LABELS from editEvent to shared - Separate calendar overlay useFocusEffect from event loading
This commit is contained in:
@@ -234,7 +234,7 @@ export async function executeToolCall(
|
||||
|
||||
const eventsText = events
|
||||
.map((e) => {
|
||||
const start = new Date(e.startTime);
|
||||
const start = new Date(e.occurrenceStart);
|
||||
const recurrenceInfo = e.recurrenceRule ? " (wiederkehrend)" : "";
|
||||
return `- ${e.title} (ID: ${e.id}) am ${formatDate(start)} um ${formatTime(start)} Uhr${recurrenceInfo}`;
|
||||
})
|
||||
|
||||
@@ -62,12 +62,13 @@ const aiProvider = new GPTAdapter();
|
||||
// Initialize services
|
||||
const authService = new AuthService(userRepo);
|
||||
const eventService = new EventService(eventRepo);
|
||||
const caldavService = new CaldavService(caldavRepo, eventService);
|
||||
const chatService = new ChatService(
|
||||
chatRepo,
|
||||
eventService,
|
||||
aiProvider,
|
||||
caldavService,
|
||||
);
|
||||
const caldavService = new CaldavService(caldavRepo, eventService);
|
||||
|
||||
// Initialize controllers
|
||||
const authController = new AuthController(authService);
|
||||
|
||||
@@ -257,4 +257,14 @@ export class CaldavService {
|
||||
async deleteConfig(userId: string) {
|
||||
return await this.caldavRepo.deleteByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync with CalDAV server if config exists. Silent no-op if no config.
|
||||
*/
|
||||
async sync(userId: string): Promise<void> {
|
||||
const config = await this.getConfig(userId);
|
||||
if (!config) return;
|
||||
await this.pushAll(userId);
|
||||
await this.pullEvents(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from "@calchat/shared";
|
||||
import { ChatRepository, AIProvider } from "./interfaces";
|
||||
import { EventService } from "./EventService";
|
||||
import { CaldavService } from "./CaldavService";
|
||||
import { getWeeksOverview, getMonthOverview } from "../utils/eventFormatters";
|
||||
|
||||
type TestResponse = {
|
||||
@@ -543,6 +544,7 @@ export class ChatService {
|
||||
private chatRepo: ChatRepository,
|
||||
private eventService: EventService,
|
||||
private aiProvider: AIProvider,
|
||||
private caldavService: CaldavService,
|
||||
) {}
|
||||
|
||||
async processMessage(
|
||||
@@ -573,17 +575,32 @@ export class ChatService {
|
||||
limit: 20,
|
||||
});
|
||||
|
||||
// Lazy CalDAV sync: only sync once when the AI first accesses event data
|
||||
let hasSynced = false;
|
||||
const syncOnce = async () => {
|
||||
if (hasSynced) return;
|
||||
hasSynced = true;
|
||||
try {
|
||||
await this.caldavService.sync(userId);
|
||||
} catch {
|
||||
// CalDAV sync is not critical for AI responses
|
||||
}
|
||||
};
|
||||
|
||||
response = await this.aiProvider.processMessage(data.content, {
|
||||
userId,
|
||||
conversationHistory: history,
|
||||
currentDate: new Date(),
|
||||
fetchEventsInRange: async (start, end) => {
|
||||
await syncOnce();
|
||||
return this.eventService.getByDateRange(userId, start, end);
|
||||
},
|
||||
searchEvents: async (query) => {
|
||||
await syncOnce();
|
||||
return this.eventService.searchByTitle(userId, query);
|
||||
},
|
||||
fetchEventById: async (eventId) => {
|
||||
await syncOnce();
|
||||
return this.eventService.getById(eventId, userId);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user