252 lines
8.2 KiB
TypeScript
252 lines
8.2 KiB
TypeScript
import {
|
|
BadRequestException,
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
Put,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
import { SchedulingService } from './scheduling.service';
|
|
import { DailyPlanService } from './daily-plan.service';
|
|
import { DailyLogService } from './daily-log.service';
|
|
import { CreateTimeBlockDto } from './dto/create-time-block.dto';
|
|
import { UpdateTimeBlockDto } from './dto/update-time-block.dto';
|
|
import { AddTimeBlockNoteDto } from './dto/add-time-block-note.dto';
|
|
import { UpdateDailyPlanDto, UpdateReflectionDto } from './dto/create-daily-plan.dto';
|
|
import { CreateDailyLogEntryDto } from './dto/create-daily-log-entry.dto';
|
|
import { QueryTimeBlocksDto } from './dto/query-scheduling.dto';
|
|
import { AvailabilityConfigDto, GenerateAvailabilityBlocksDto } from './dto/availability-config.dto';
|
|
import type { AvailabilityConfig, TimeBlockNote } from '@life-platform/shared';
|
|
import { TimeBlock } from './entities/time-block.entity';
|
|
import { DailyPlan } from './entities/daily-plan.entity';
|
|
import { DailyLogEntry } from './entities/daily-log-entry.entity';
|
|
|
|
@ApiTags('Scheduling')
|
|
@Controller('scheduling')
|
|
export class SchedulingController {
|
|
constructor(
|
|
private readonly schedulingService: SchedulingService,
|
|
private readonly dailyPlanService: DailyPlanService,
|
|
private readonly dailyLogService: DailyLogService,
|
|
) {}
|
|
|
|
@Get('time-blocks')
|
|
@ApiOperation({ summary: 'Query time blocks by date or date range' })
|
|
getTimeBlocks(@Query() query: QueryTimeBlocksDto): Promise<TimeBlock[]> {
|
|
return this.schedulingService.queryTimeBlocks(query);
|
|
}
|
|
|
|
@Post('time-blocks')
|
|
@ApiOperation({ summary: 'Create a time block' })
|
|
createTimeBlock(@Body() dto: CreateTimeBlockDto): Promise<TimeBlock> {
|
|
return this.schedulingService.createTimeBlock(dto);
|
|
}
|
|
|
|
@Patch('time-blocks/:id')
|
|
@ApiOperation({ summary: 'Update a time block' })
|
|
updateTimeBlock(
|
|
@Param('id') id: string,
|
|
@Body() dto: UpdateTimeBlockDto,
|
|
): Promise<TimeBlock> {
|
|
return this.schedulingService.updateTimeBlock(id, dto);
|
|
}
|
|
|
|
@Delete('time-blocks')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Bulk delete time blocks by date or date range' })
|
|
bulkDeleteTimeBlocks(@Query() query: QueryTimeBlocksDto): Promise<void> {
|
|
if (!query.date && !query.startDate) {
|
|
throw new BadRequestException('Must provide date or startDate for bulk delete');
|
|
}
|
|
if (query.endDate && !query.startDate && !query.date) {
|
|
throw new BadRequestException('Must provide startDate or date when endDate is specified');
|
|
}
|
|
return this.schedulingService.bulkDeleteTimeBlocks(query);
|
|
}
|
|
|
|
@Delete('time-blocks/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete a time block' })
|
|
deleteTimeBlock(@Param('id') id: string): Promise<void> {
|
|
return this.schedulingService.deleteTimeBlock(id);
|
|
}
|
|
|
|
// --- Time Block Notes ---
|
|
|
|
@Get('time-blocks/current')
|
|
@ApiOperation({ summary: 'Get current or most recently ended time block' })
|
|
getCurrentBlock(): Promise<TimeBlock | null> {
|
|
return this.schedulingService.findCurrentOrRecentBlock();
|
|
}
|
|
|
|
@Get('time-blocks/:id/notes')
|
|
@ApiOperation({ summary: 'Get notes for a time block' })
|
|
getNotes(@Param('id') id: string): Promise<TimeBlockNote[]> {
|
|
return this.schedulingService.getNotes(id);
|
|
}
|
|
|
|
@Post('time-blocks/:id/notes')
|
|
@ApiOperation({ summary: 'Add a note to a time block' })
|
|
addNote(
|
|
@Param('id') id: string,
|
|
@Body() dto: AddTimeBlockNoteDto,
|
|
): Promise<TimeBlockNote> {
|
|
return this.schedulingService.addNote(id, dto);
|
|
}
|
|
|
|
@Delete('time-blocks/:id/notes/:noteId')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Remove a note from a time block' })
|
|
removeNote(
|
|
@Param('id') id: string,
|
|
@Param('noteId') noteId: string,
|
|
): Promise<void> {
|
|
return this.schedulingService.removeNote(id, noteId);
|
|
}
|
|
|
|
@Get('daily-plan/:date')
|
|
@ApiOperation({ summary: 'Get or create daily plan for a date' })
|
|
getDailyPlan(@Param('date') date: string): Promise<DailyPlan> {
|
|
return this.dailyPlanService.findByDate(date);
|
|
}
|
|
|
|
@Delete('daily-plan/:date')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete daily plan for a date' })
|
|
deleteDailyPlan(@Param('date') date: string): Promise<void> {
|
|
this.validateDateParam(date);
|
|
return this.dailyPlanService.deleteByDate(date);
|
|
}
|
|
|
|
@Put('daily-plan/:date')
|
|
@ApiOperation({ summary: 'Upsert daily plan for a date' })
|
|
upsertDailyPlan(
|
|
@Param('date') date: string,
|
|
@Body() dto: UpdateDailyPlanDto,
|
|
): Promise<DailyPlan> {
|
|
return this.dailyPlanService.upsert(date, dto);
|
|
}
|
|
|
|
@Patch('daily-plan/:date/reflection')
|
|
@ApiOperation({ summary: 'Update evening reflection for a daily plan' })
|
|
updateReflection(
|
|
@Param('date') date: string,
|
|
@Body() dto: UpdateReflectionDto,
|
|
): Promise<DailyPlan> {
|
|
return this.dailyPlanService.updateReflection(date, dto);
|
|
}
|
|
|
|
// --- Daily Log Entries ---
|
|
|
|
@Get('daily-log')
|
|
@ApiOperation({ summary: 'Query log entries by type (cross-date)' })
|
|
queryDailyLogs(
|
|
@Query('type') type?: string,
|
|
@Query('types') types?: string,
|
|
@Query('limit') limit?: string,
|
|
@Query('offset') offset?: string,
|
|
@Query('dateFrom') dateFrom?: string,
|
|
@Query('dateTo') dateTo?: string,
|
|
): Promise<DailyLogEntry[]> {
|
|
const parsedLimit = limit ? parseInt(limit, 10) : 10;
|
|
const parsedOffset = offset ? parseInt(offset, 10) : undefined;
|
|
|
|
if (types) {
|
|
return this.dailyLogService.findRecent({
|
|
types: types.split(','),
|
|
limit: parsedLimit,
|
|
offset: parsedOffset,
|
|
dateFrom,
|
|
dateTo,
|
|
});
|
|
}
|
|
|
|
if (type) {
|
|
return this.dailyLogService.findByType(type, {
|
|
limit: parsedLimit,
|
|
offset: parsedOffset,
|
|
});
|
|
}
|
|
|
|
return this.dailyLogService.findRecent({
|
|
limit: parsedLimit,
|
|
offset: parsedOffset,
|
|
dateFrom,
|
|
dateTo,
|
|
});
|
|
}
|
|
|
|
@Post('daily-log')
|
|
@ApiOperation({ summary: 'Create a log entry (no date param required)' })
|
|
createDailyLog(@Body() dto: CreateDailyLogEntryDto): Promise<DailyLogEntry> {
|
|
return this.dailyLogService.create(dto);
|
|
}
|
|
|
|
@Get('daily-plan/:date/log')
|
|
@ApiOperation({ summary: 'Get log entries for a date' })
|
|
getDailyLog(@Param('date') date: string): Promise<DailyLogEntry[]> {
|
|
this.validateDateParam(date);
|
|
return this.dailyLogService.findByDate(date);
|
|
}
|
|
|
|
@Post('daily-plan/:date/log')
|
|
@ApiOperation({ summary: 'Add a log entry for a date' })
|
|
addDailyLogEntry(
|
|
@Param('date') date: string,
|
|
@Body() dto: CreateDailyLogEntryDto,
|
|
): Promise<DailyLogEntry> {
|
|
this.validateDateParam(date);
|
|
return this.dailyLogService.create({ ...dto, date });
|
|
}
|
|
|
|
@Delete('daily-plan/:date/log/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete a log entry' })
|
|
deleteDailyLogEntry(@Param('id') id: string): Promise<void> {
|
|
return this.dailyLogService.delete(id);
|
|
}
|
|
|
|
@Delete('daily-log/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete a log entry by ID (cross-date)' })
|
|
deleteDailyLogById(@Param('id') id: string): Promise<void> {
|
|
return this.dailyLogService.delete(id);
|
|
}
|
|
|
|
// --- Availability Windows ---
|
|
|
|
@Get('availability-windows/config')
|
|
@ApiOperation({ summary: 'Get availability window configuration' })
|
|
getAvailabilityConfig(): Promise<AvailabilityConfig> {
|
|
return this.schedulingService.getAvailabilityConfig();
|
|
}
|
|
|
|
@Put('availability-windows/config')
|
|
@ApiOperation({ summary: 'Update availability window configuration' })
|
|
updateAvailabilityConfig(
|
|
@Body() dto: AvailabilityConfigDto,
|
|
): Promise<AvailabilityConfig> {
|
|
return this.schedulingService.setAvailabilityConfig(dto);
|
|
}
|
|
|
|
@Post('availability-windows/generate')
|
|
@ApiOperation({ summary: 'Generate availability time blocks for a date' })
|
|
generateAvailabilityBlocks(
|
|
@Body() dto: GenerateAvailabilityBlocksDto,
|
|
): Promise<TimeBlock[]> {
|
|
return this.schedulingService.generateAvailabilityBlocks(dto.date);
|
|
}
|
|
|
|
private validateDateParam(date: string): void {
|
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
throw new BadRequestException('date param must be in YYYY-MM-DD format');
|
|
}
|
|
}
|
|
}
|