import { Injectable, NotFoundException } from "@nestjs/common"; import { Prisma } from "@prisma/client"; import { PrismaService } from "../prisma/prisma.service"; import { ActivityService } from "../activity/activity.service"; import { IdeaStatus } from "@prisma/client"; import type { CreateIdeaDto, CaptureIdeaDto, UpdateIdeaDto, QueryIdeasDto, } from "./dto"; /** * Service for managing ideas */ @Injectable() export class IdeasService { constructor( private readonly prisma: PrismaService, private readonly activityService: ActivityService ) {} /** * Create a new idea */ async create( workspaceId: string, userId: string, createIdeaDto: CreateIdeaDto ) { const data: any = { ...createIdeaDto, workspaceId, creatorId: userId, status: createIdeaDto.status || IdeaStatus.CAPTURED, priority: createIdeaDto.priority || "MEDIUM", tags: createIdeaDto.tags || [], metadata: createIdeaDto.metadata || {}, }; const idea = await this.prisma.idea.create({ data, include: { creator: { select: { id: true, name: true, email: true }, }, domain: { select: { id: true, name: true, color: true }, }, project: { select: { id: true, name: true, color: true }, }, }, }); // Log activity await this.activityService.logIdeaCreated( workspaceId, userId, idea.id, { title: idea.title || "Untitled", } ); return idea; } /** * Quick capture - create an idea with minimal fields * Optimized for rapid idea capture from the front-end */ async capture( workspaceId: string, userId: string, captureIdeaDto: CaptureIdeaDto ) { const data: any = { workspaceId, creatorId: userId, content: captureIdeaDto.content, title: captureIdeaDto.title, status: IdeaStatus.CAPTURED, priority: "MEDIUM", tags: [], metadata: {}, }; const idea = await this.prisma.idea.create({ data, include: { creator: { select: { id: true, name: true, email: true }, }, }, }); // Log activity await this.activityService.logIdeaCreated( workspaceId, userId, idea.id, { quickCapture: true, title: idea.title || "Untitled", } ); return idea; } /** * Get paginated ideas with filters */ async findAll(query: QueryIdeasDto) { const page = query.page || 1; const limit = query.limit || 50; const skip = (page - 1) * limit; // Build where clause const where: any = { workspaceId: query.workspaceId, }; if (query.status) { where.status = query.status; } if (query.domainId) { where.domainId = query.domainId; } if (query.projectId) { where.projectId = query.projectId; } if (query.category) { where.category = query.category; } // Add search filter if provided if (query.search) { where.OR = [ { title: { contains: query.search, mode: "insensitive" } }, { content: { contains: query.search, mode: "insensitive" } }, ]; } // Execute queries in parallel const [data, total] = await Promise.all([ this.prisma.idea.findMany({ where, include: { creator: { select: { id: true, name: true, email: true }, }, domain: { select: { id: true, name: true, color: true }, }, project: { select: { id: true, name: true, color: true }, }, }, orderBy: { createdAt: "desc", }, skip, take: limit, }), this.prisma.idea.count({ where }), ]); return { data, meta: { total, page, limit, totalPages: Math.ceil(total / limit), }, }; } /** * Get a single idea by ID */ async findOne(id: string, workspaceId: string) { const idea = await this.prisma.idea.findUnique({ where: { id, workspaceId, }, include: { creator: { select: { id: true, name: true, email: true }, }, domain: { select: { id: true, name: true, color: true }, }, project: { select: { id: true, name: true, color: true }, }, }, }); if (!idea) { throw new NotFoundException(`Idea with ID ${id} not found`); } return idea; } /** * Update an idea */ async update( id: string, workspaceId: string, userId: string, updateIdeaDto: UpdateIdeaDto ) { // Verify idea exists const existingIdea = await this.prisma.idea.findUnique({ where: { id, workspaceId }, }); if (!existingIdea) { throw new NotFoundException(`Idea with ID ${id} not found`); } const idea = await this.prisma.idea.update({ where: { id, workspaceId, }, data: updateIdeaDto as any, include: { creator: { select: { id: true, name: true, email: true }, }, domain: { select: { id: true, name: true, color: true }, }, project: { select: { id: true, name: true, color: true }, }, }, }); // Log activity await this.activityService.logIdeaUpdated( workspaceId, userId, id, { changes: updateIdeaDto as Prisma.JsonValue, } ); return idea; } /** * Delete an idea */ async remove(id: string, workspaceId: string, userId: string) { // Verify idea exists const idea = await this.prisma.idea.findUnique({ where: { id, workspaceId }, }); if (!idea) { throw new NotFoundException(`Idea with ID ${id} not found`); } await this.prisma.idea.delete({ where: { id, workspaceId, }, }); // Log activity await this.activityService.logIdeaDeleted( workspaceId, userId, id, { title: idea.title || "Untitled", } ); } }