diff --git a/apps/calendar/apps/web/src/lib/components/todo/TodoCheckbox.svelte b/apps/calendar/apps/web/src/lib/components/todo/TodoCheckbox.svelte
index 0c29e4f1e..f82cdba07 100644
--- a/apps/calendar/apps/web/src/lib/components/todo/TodoCheckbox.svelte
+++ b/apps/calendar/apps/web/src/lib/components/todo/TodoCheckbox.svelte
@@ -53,7 +53,7 @@
{#if loading}
{:else if checked}
-
+
{/if}
diff --git a/apps/questions/apps/backend/src/db/schema/collections.schema.ts b/apps/questions/apps/backend/src/db/schema/collections.schema.ts
index 600265ce6..d71ef913f 100644
--- a/apps/questions/apps/backend/src/db/schema/collections.schema.ts
+++ b/apps/questions/apps/backend/src/db/schema/collections.schema.ts
@@ -1,4 +1,4 @@
-import { pgTable, uuid, text, boolean, timestamp } from 'drizzle-orm/pg-core';
+import { pgTable, uuid, text, boolean, timestamp, integer } from 'drizzle-orm/pg-core';
export const collections = pgTable('collections', {
id: uuid('id').primaryKey().defaultRandom(),
@@ -9,11 +9,15 @@ export const collections = pgTable('collections', {
color: text('color').default('#6366f1'),
icon: text('icon').default('folder'),
+ isDefault: boolean('is_default').default(false),
+ sortOrder: integer('sort_order').default(0),
+
isShared: boolean('is_shared').default(false),
shareToken: text('share_token').unique(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
});
export type Collection = typeof collections.$inferSelect;
diff --git a/apps/questions/apps/backend/src/db/schema/questions.schema.ts b/apps/questions/apps/backend/src/db/schema/questions.schema.ts
index d59b846af..1b83892bd 100644
--- a/apps/questions/apps/backend/src/db/schema/questions.schema.ts
+++ b/apps/questions/apps/backend/src/db/schema/questions.schema.ts
@@ -32,6 +32,7 @@ export const questions = pgTable('questions', {
// Soft delete
isArchived: boolean('is_archived').default(false),
archivedAt: timestamp('archived_at', { withTimezone: true }),
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
});
export type Question = typeof questions.$inferSelect;
diff --git a/apps/questions/apps/backend/src/question/question.service.ts b/apps/questions/apps/backend/src/question/question.service.ts
index e425cecf5..e598181fc 100644
--- a/apps/questions/apps/backend/src/question/question.service.ts
+++ b/apps/questions/apps/backend/src/question/question.service.ts
@@ -8,7 +8,7 @@ import { CreateQuestionDto, UpdateQuestionDto } from './dto';
export class QuestionService {
constructor(
@Inject('DATABASE_CONNECTION')
- private readonly db: NodePgDatabase,
+ private readonly db: NodePgDatabase
) {}
async create(userId: string, dto: CreateQuestionDto): Promise {
@@ -35,7 +35,7 @@ export class QuestionService {
tags?: string[];
limit?: number;
offset?: number;
- },
+ }
): Promise<{ data: Question[]; total: number }> {
const conditions = [eq(questions.userId, userId), isNull(questions.deletedAt)];
@@ -48,12 +48,13 @@ export class QuestionService {
}
if (options?.search) {
- conditions.push(
- or(
- ilike(questions.title, `%${options.search}%`),
- ilike(questions.description, `%${options.search}%`),
- ),
+ const searchCondition = or(
+ ilike(questions.title, `%${options.search}%`),
+ ilike(questions.description, `%${options.search}%`)
);
+ if (searchCondition) {
+ conditions.push(searchCondition);
+ }
}
const limit = options?.limit || 20;
@@ -137,8 +138,8 @@ export class QuestionService {
and(
eq(questions.userId, userId),
eq(questions.collectionId, collectionId),
- isNull(questions.deletedAt),
- ),
+ isNull(questions.deletedAt)
+ )
)
.orderBy(desc(questions.createdAt));
}
diff --git a/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte b/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte
index d4ed11125..d80012c37 100644
--- a/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte
+++ b/apps/questions/apps/web/src/routes/(app)/question/[id]/+page.svelte
@@ -43,6 +43,9 @@
try {
const id = page.params.id;
+ if (!id) {
+ throw new Error('Question ID is required');
+ }
question = await questionsApi.getById(id);
researchResults = await researchApi.getByQuestion(id);
sources = await sourcesApi.getByQuestion(id);
diff --git a/apps/skilltree/apps/web/src/lib/services/storage.ts b/apps/skilltree/apps/web/src/lib/services/storage.ts
index 115a0e337..f9051dd89 100644
--- a/apps/skilltree/apps/web/src/lib/services/storage.ts
+++ b/apps/skilltree/apps/web/src/lib/services/storage.ts
@@ -1,7 +1,7 @@
-import { openDB, type DBSchema, type IDBPDatabase } from 'idb';
+import { openDB, type IDBPDatabase } from 'idb';
import type { Skill, Activity, UserStats } from '$lib/types';
-interface SkillTreeDB extends DBSchema {
+interface SkillTreeDB {
skills: {
key: string;
value: Skill;
diff --git a/packages/bot-services/src/ai/ai.module.ts b/packages/bot-services/src/ai/ai.module.ts
index b67d24d4f..bd393d140 100644
--- a/packages/bot-services/src/ai/ai.module.ts
+++ b/packages/bot-services/src/ai/ai.module.ts
@@ -1,8 +1,13 @@
-import { Module, DynamicModule } from '@nestjs/common';
+import { Module, DynamicModule, Provider, Type, ModuleMetadata } from '@nestjs/common';
import { AiService } from './ai.service';
import { AiServiceConfig } from './types';
-export interface AiModuleOptions extends Partial {}
+export type AiModuleOptions = Partial;
+
+export interface AiModuleAsyncOptions extends Pick {
+ useFactory: (...args: unknown[]) => Promise | AiModuleOptions;
+ inject?: (Type | string | symbol)[];
+}
@Module({})
export class AiModule {
@@ -42,4 +47,29 @@ export class AiModule {
exports: [AiService],
};
}
+
+ /**
+ * Register asynchronously with factory function
+ */
+ static registerAsync(options: AiModuleAsyncOptions): DynamicModule {
+ const configProvider: Provider = {
+ provide: 'AI_SERVICE_CONFIG',
+ useFactory: options.useFactory,
+ inject: options.inject || [],
+ };
+
+ return {
+ module: AiModule,
+ imports: options.imports || [],
+ providers: [
+ configProvider,
+ {
+ provide: AiService,
+ useFactory: (config: Partial) => new AiService(config),
+ inject: ['AI_SERVICE_CONFIG'],
+ },
+ ],
+ exports: [AiService],
+ };
+ }
}
diff --git a/packages/bot-services/src/calendar/calendar.module.ts b/packages/bot-services/src/calendar/calendar.module.ts
index a1cf28cdd..bac494f9f 100644
--- a/packages/bot-services/src/calendar/calendar.module.ts
+++ b/packages/bot-services/src/calendar/calendar.module.ts
@@ -1,4 +1,4 @@
-import { Module, DynamicModule } from '@nestjs/common';
+import { Module, DynamicModule, Provider, Type, ModuleMetadata } from '@nestjs/common';
import { CalendarService, CALENDAR_STORAGE_PROVIDER } from './calendar.service';
import { StorageProvider } from '../shared/types';
import { FileStorageProvider } from '../shared/storage';
@@ -9,6 +9,11 @@ export interface CalendarModuleOptions {
storageProvider?: StorageProvider;
}
+export interface CalendarModuleAsyncOptions extends Pick {
+ useFactory: (...args: unknown[]) => Promise | CalendarModuleOptions;
+ inject?: (Type | string | symbol)[];
+}
+
@Module({})
export class CalendarModule {
/**
@@ -24,7 +29,8 @@ export class CalendarModule {
{
provide: CALENDAR_STORAGE_PROVIDER,
useValue:
- options?.storageProvider ?? new FileStorageProvider(storagePath, defaultData),
+ options?.storageProvider ??
+ new FileStorageProvider(storagePath, defaultData),
},
CalendarService,
],
@@ -48,4 +54,30 @@ export class CalendarModule {
exports: [CalendarService],
};
}
+
+ /**
+ * Register asynchronously with factory function
+ */
+ static registerAsync(options: CalendarModuleAsyncOptions): DynamicModule {
+ const storageProvider: Provider = {
+ provide: CALENDAR_STORAGE_PROVIDER,
+ useFactory: async (...args: unknown[]) => {
+ const moduleOptions = await options.useFactory(...args);
+ const storagePath = moduleOptions?.storagePath ?? './data/calendar-data.json';
+ const defaultData: CalendarData = { events: [], calendars: [] };
+ return (
+ moduleOptions?.storageProvider ??
+ new FileStorageProvider(storagePath, defaultData)
+ );
+ },
+ inject: options.inject || [],
+ };
+
+ return {
+ module: CalendarModule,
+ imports: options.imports || [],
+ providers: [storageProvider, CalendarService],
+ exports: [CalendarService],
+ };
+ }
}
diff --git a/packages/bot-services/src/calendar/calendar.service.ts b/packages/bot-services/src/calendar/calendar.service.ts
index 318cd7555..7b9299def 100644
--- a/packages/bot-services/src/calendar/calendar.service.ts
+++ b/packages/bot-services/src/calendar/calendar.service.ts
@@ -36,7 +36,10 @@ export class CalendarService implements OnModuleInit {
) {
this.storage =
storage ||
- new FileStorageProvider('./data/calendar-data.json', { events: [], calendars: [] });
+ new FileStorageProvider('./data/calendar-data.json', {
+ events: [],
+ calendars: [],
+ });
}
async onModuleInit() {
@@ -46,7 +49,9 @@ export class CalendarService implements OnModuleInit {
private async loadData(): Promise {
try {
this.data = await this.storage.load();
- this.logger.log(`Loaded ${this.data.events.length} events, ${this.data.calendars.length} calendars`);
+ this.logger.log(
+ `Loaded ${this.data.events.length} events, ${this.data.calendars.length} calendars`
+ );
} catch (error) {
this.logger.error('Failed to load calendar data:', error);
this.data = { events: [], calendars: [] };
@@ -81,6 +86,19 @@ export class CalendarService implements OnModuleInit {
async createEvent(userId: string, input: CreateEventInput): Promise {
const calendar = this.ensureDefaultCalendar(userId);
+ // Calculate endTime if not provided
+ let endTime: Date;
+ if (input.endTime) {
+ endTime = input.endTime;
+ } else if (input.isAllDay) {
+ // For all-day events, end at end of the same day
+ endTime = new Date(input.startTime);
+ endTime.setHours(23, 59, 59, 999);
+ } else {
+ // Default to 1 hour after start
+ endTime = new Date(input.startTime.getTime() + 60 * 60 * 1000);
+ }
+
const event: CalendarEvent = {
id: generateId(),
userId,
@@ -88,7 +106,7 @@ export class CalendarService implements OnModuleInit {
description: input.description ?? null,
location: input.location ?? null,
startTime: input.startTime.toISOString(),
- endTime: input.endTime.toISOString(),
+ endTime: endTime.toISOString(),
isAllDay: input.isAllDay ?? false,
calendarId: input.calendarId ?? calendar.id,
calendarName: calendar.name,
@@ -101,7 +119,11 @@ export class CalendarService implements OnModuleInit {
return event;
}
- async updateEvent(userId: string, eventId: string, input: UpdateEventInput): Promise {
+ async updateEvent(
+ userId: string,
+ eventId: string,
+ input: UpdateEventInput
+ ): Promise {
const event = this.data.events.find((e) => e.id === eventId && e.userId === userId);
if (!event) return null;
@@ -197,7 +219,7 @@ export class CalendarService implements OnModuleInit {
return this.getEventsInRange(userId, today, weekEnd);
}
- async getUpcomingEvents(userId: string, days: number = 7): Promise {
+ async getUpcomingEvents(userId: string, days = 7): Promise {
const now = new Date();
const endDate = addDays(now, days);
return this.getEventsInRange(userId, now, endDate);
diff --git a/packages/bot-services/src/calendar/types.ts b/packages/bot-services/src/calendar/types.ts
index 48877c41c..a469b56a4 100644
--- a/packages/bot-services/src/calendar/types.ts
+++ b/packages/bot-services/src/calendar/types.ts
@@ -1,4 +1,4 @@
-import { UserEntity } from '../shared/types';
+import { type UserEntity } from '../shared/types';
/**
* Calendar event entity
@@ -38,7 +38,7 @@ export interface CalendarData {
export interface CreateEventInput {
title: string;
startTime: Date;
- endTime: Date;
+ endTime?: Date; // Optional - defaults to startTime + 1 hour, or end of day for all-day events
description?: string | null;
location?: string | null;
isAllDay?: boolean;
diff --git a/packages/bot-services/src/clock/clock.module.ts b/packages/bot-services/src/clock/clock.module.ts
index cd10c275d..a0c2591e8 100644
--- a/packages/bot-services/src/clock/clock.module.ts
+++ b/packages/bot-services/src/clock/clock.module.ts
@@ -1,8 +1,13 @@
-import { Module, DynamicModule } from '@nestjs/common';
+import { Module, DynamicModule, Provider, Type, ModuleMetadata } from '@nestjs/common';
import { ClockService } from './clock.service';
import { ClockServiceConfig } from './types';
-export interface ClockModuleOptions extends Partial {}
+export type ClockModuleOptions = Partial;
+
+export interface ClockModuleAsyncOptions extends Pick {
+ useFactory: (...args: unknown[]) => Promise | ClockModuleOptions;
+ inject?: (Type | string | symbol)[];
+}
@Module({})
export class ClockModule {
@@ -42,4 +47,29 @@ export class ClockModule {
exports: [ClockService],
};
}
+
+ /**
+ * Register asynchronously with factory function
+ */
+ static registerAsync(options: ClockModuleAsyncOptions): DynamicModule {
+ const configProvider: Provider = {
+ provide: 'CLOCK_SERVICE_CONFIG',
+ useFactory: options.useFactory,
+ inject: options.inject || [],
+ };
+
+ return {
+ module: ClockModule,
+ imports: options.imports || [],
+ providers: [
+ configProvider,
+ {
+ provide: ClockService,
+ useFactory: (config: Partial) => new ClockService(config),
+ inject: ['CLOCK_SERVICE_CONFIG'],
+ },
+ ],
+ exports: [ClockService],
+ };
+ }
}
diff --git a/packages/bot-services/src/clock/clock.service.ts b/packages/bot-services/src/clock/clock.service.ts
index f92d163ab..1237208fb 100644
--- a/packages/bot-services/src/clock/clock.service.ts
+++ b/packages/bot-services/src/clock/clock.service.ts
@@ -267,4 +267,116 @@ export class ClockService {
return parts.join(' ');
}
+
+ // ===== Convenience Methods for Bot Handlers =====
+
+ /**
+ * Start a timer from natural language input
+ * Parses duration and optional label from input like "25m Pomodoro"
+ */
+ async startTimerForUser(userId: string, input: string): Promise {
+ const token = this.getUserToken(userId);
+ if (!token) {
+ throw new Error('Nicht authentifiziert. Bitte zuerst anmelden.');
+ }
+
+ // Parse duration from input
+ const durationSeconds = this.parseDuration(input);
+ if (!durationSeconds) {
+ throw new Error('Ungültiges Dauer-Format. Beispiele: 25m, 1h30m, 90s');
+ }
+
+ // Extract label (everything after duration pattern)
+ const label = input.replace(/\d+\s*[hms]?(?:in)?/gi, '').trim() || null;
+
+ const timer = await this.createTimer({ durationSeconds, label }, token);
+ // Start the timer immediately
+ const started = await this.startTimer(timer.id, token);
+ return { ...started, name: started.label ?? undefined };
+ }
+
+ /**
+ * Stop the running timer for a user
+ */
+ async stopTimerForUser(userId: string, timerName?: string): Promise {
+ const token = this.getUserToken(userId);
+ if (!token) {
+ throw new Error('Nicht authentifiziert. Bitte zuerst anmelden.');
+ }
+
+ const timers = await this.getTimers(token);
+ let timer: Timer | undefined;
+
+ if (timerName) {
+ timer = timers.find(
+ (t) =>
+ (t.status === 'running' || t.status === 'paused') &&
+ t.label?.toLowerCase().includes(timerName.toLowerCase())
+ );
+ } else {
+ timer = timers.find((t) => t.status === 'running' || t.status === 'paused');
+ }
+
+ if (!timer) {
+ throw new Error('Kein aktiver Timer gefunden.');
+ }
+
+ await this.deleteTimer(timer.id, token);
+ return { ...timer, name: timer.label ?? undefined };
+ }
+
+ /**
+ * Set an alarm from natural language input
+ * Parses time and optional label from input like "14:30 Meeting"
+ */
+ async setAlarmForUser(userId: string, input: string): Promise {
+ const token = this.getUserToken(userId);
+ if (!token) {
+ throw new Error('Nicht authentifiziert. Bitte zuerst anmelden.');
+ }
+
+ const time = this.parseAlarmTime(input);
+ if (!time) {
+ throw new Error('Ungültiges Zeit-Format. Beispiele: 14:30, 9:00, 14 Uhr 30');
+ }
+
+ // Extract label (everything after time pattern)
+ const label =
+ input
+ .replace(/\d{1,2}:\d{2}(:\d{2})?/g, '')
+ .replace(/\d{1,2}\s*uhr(\s*\d{1,2})?/gi, '')
+ .trim() || null;
+
+ const alarm = await this.createAlarm({ time, label }, token);
+ return { ...alarm, name: alarm.label ?? undefined };
+ }
+
+ /**
+ * Get time for a specific city/timezone
+ */
+ async getWorldClockTime(city: string): Promise<{ city: string; time: string; date: string }> {
+ // Search for timezone
+ const results = await this.searchTimezones(city);
+ if (results.length === 0) {
+ throw new Error(`Stadt "${city}" nicht gefunden.`);
+ }
+
+ const tz = results[0];
+ const now = new Date();
+
+ const time = now.toLocaleTimeString('de-DE', {
+ timeZone: tz.timezone,
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+
+ const date = now.toLocaleDateString('de-DE', {
+ timeZone: tz.timezone,
+ weekday: 'long',
+ day: 'numeric',
+ month: 'long',
+ });
+
+ return { city: tz.city, time, date };
+ }
}
diff --git a/packages/bot-services/src/todo/todo.module.ts b/packages/bot-services/src/todo/todo.module.ts
index b65837bd3..774671fa7 100644
--- a/packages/bot-services/src/todo/todo.module.ts
+++ b/packages/bot-services/src/todo/todo.module.ts
@@ -1,4 +1,4 @@
-import { Module, DynamicModule } from '@nestjs/common';
+import { Module, DynamicModule, Provider, Type, ModuleMetadata } from '@nestjs/common';
import { TodoService, TODO_STORAGE_PROVIDER } from './todo.service';
import { StorageProvider } from '../shared/types';
import { FileStorageProvider } from '../shared/storage';
@@ -9,6 +9,11 @@ export interface TodoModuleOptions {
storageProvider?: StorageProvider;
}
+export interface TodoModuleAsyncOptions extends Pick {
+ useFactory: (...args: unknown[]) => Promise | TodoModuleOptions;
+ inject?: (Type | string | symbol)[];
+}
+
@Module({})
export class TodoModule {
/**
@@ -23,7 +28,8 @@ export class TodoModule {
providers: [
{
provide: TODO_STORAGE_PROVIDER,
- useValue: options?.storageProvider ?? new FileStorageProvider(storagePath, defaultData),
+ useValue:
+ options?.storageProvider ?? new FileStorageProvider(storagePath, defaultData),
},
TodoService,
],
@@ -47,4 +53,30 @@ export class TodoModule {
exports: [TodoService],
};
}
+
+ /**
+ * Register asynchronously with factory function
+ */
+ static registerAsync(options: TodoModuleAsyncOptions): DynamicModule {
+ const storageProvider: Provider = {
+ provide: TODO_STORAGE_PROVIDER,
+ useFactory: async (...args: unknown[]) => {
+ const moduleOptions = await options.useFactory(...args);
+ const storagePath = moduleOptions?.storagePath ?? './data/todo-data.json';
+ const defaultData: TodoData = { tasks: [], projects: [] };
+ return (
+ moduleOptions?.storageProvider ??
+ new FileStorageProvider(storagePath, defaultData)
+ );
+ },
+ inject: options.inject || [],
+ };
+
+ return {
+ module: TodoModule,
+ imports: options.imports || [],
+ providers: [storageProvider, TodoService],
+ exports: [TodoService],
+ };
+ }
}
diff --git a/services/matrix-mana-bot/src/handlers/clock.handler.ts b/services/matrix-mana-bot/src/handlers/clock.handler.ts
index a687400e0..6a55cc982 100644
--- a/services/matrix-mana-bot/src/handlers/clock.handler.ts
+++ b/services/matrix-mana-bot/src/handlers/clock.handler.ts
@@ -21,7 +21,7 @@ export class ClockHandler {
}
try {
- const result = await this.clockService.startTimer(ctx.userId, input);
+ const result = await this.clockService.startTimerForUser(ctx.userId, input);
this.logger.log(`Started timer for ${ctx.userId}: ${result.name}`);
const durationStr = this.formatDuration(result.durationSeconds);
@@ -33,7 +33,12 @@ export class ClockHandler {
async listTimers(ctx: CommandContext): Promise {
try {
- const timers = await this.clockService.getTimers(ctx.userId);
+ const token = this.clockService.getUserToken(ctx.userId);
+ if (!token) {
+ return '❌ Nicht authentifiziert. Bitte zuerst anmelden.';
+ }
+
+ const timers = await this.clockService.getTimers(token);
if (timers.length === 0) {
return '⏱️ Keine aktiven Timer.\n\nStarte einen mit `!timer [Dauer]`';
@@ -42,8 +47,8 @@ export class ClockHandler {
let response = '⏱️ **Aktive Timer:**\n\n';
for (const timer of timers) {
const remaining = this.formatDuration(timer.remainingSeconds);
- const status = timer.isPaused ? '⏸️' : '▶️';
- response += `${status} **${timer.name || 'Timer'}** - ${remaining} verbleibend\n`;
+ const status = timer.status === 'paused' ? '⏸️' : '▶️';
+ response += `${status} **${timer.label || 'Timer'}** - ${remaining} verbleibend\n`;
}
response += '\n`!stop` zum Beenden';
@@ -55,7 +60,7 @@ export class ClockHandler {
async stopTimer(ctx: CommandContext, args: string): Promise {
try {
- const result = await this.clockService.stopTimer(ctx.userId, args.trim() || undefined);
+ const result = await this.clockService.stopTimerForUser(ctx.userId, args.trim() || undefined);
return `⏹️ Timer gestoppt: **${result.name || 'Timer'}**`;
} catch (error) {
return `❌ ${error instanceof Error ? error.message : 'Kein aktiver Timer gefunden'}`;
@@ -73,7 +78,7 @@ export class ClockHandler {
}
try {
- const result = await this.clockService.setAlarm(ctx.userId, input);
+ const result = await this.clockService.setAlarmForUser(ctx.userId, input);
this.logger.log(`Set alarm for ${ctx.userId}: ${result.name} at ${result.time}`);
return `⏰ Alarm gesetzt: **${result.name || 'Alarm'}**\nZeit: ${result.time}`;
@@ -84,7 +89,12 @@ export class ClockHandler {
async listAlarms(ctx: CommandContext): Promise {
try {
- const alarms = await this.clockService.getAlarms(ctx.userId);
+ const token = this.clockService.getUserToken(ctx.userId);
+ if (!token) {
+ return '❌ Nicht authentifiziert. Bitte zuerst anmelden.';
+ }
+
+ const alarms = await this.clockService.getAlarms(token);
if (alarms.length === 0) {
return '⏰ Keine aktiven Alarme.\n\nSetze einen mit `!alarm [Zeit]`';
@@ -93,7 +103,7 @@ export class ClockHandler {
let response = '⏰ **Aktive Alarme:**\n\n';
for (const alarm of alarms) {
const status = alarm.enabled ? '🔔' : '🔕';
- response += `${status} **${alarm.name || 'Alarm'}** - ${alarm.time}\n`;
+ response += `${status} **${alarm.label || 'Alarm'}** - ${alarm.time}\n`;
}
return response;
@@ -130,7 +140,7 @@ export class ClockHandler {
}
try {
- const result = await this.clockService.getWorldClock(city);
+ const result = await this.clockService.getWorldClockTime(city);
return `🕐 **${result.city}:** ${result.time}\n📅 ${result.date}`;
} catch (error) {
return `❌ Stadt "${city}" nicht gefunden.\n\nVersuche: Berlin, London, New York, Tokyo, Sydney`;