import { Injectable, NotFoundException } from "@nestjs/common"; import { Prisma, Domain } from "@prisma/client"; import { PrismaService } from "../prisma/prisma.service"; import { ActivityService } from "../activity/activity.service"; import type { CreateDomainDto, UpdateDomainDto, QueryDomainsDto } from "./dto"; type DomainWithCount = Domain & { _count: { tasks: number; events: number; projects: number; ideas: number }; }; /** * Service for managing domains */ @Injectable() export class DomainsService { constructor( private readonly prisma: PrismaService, private readonly activityService: ActivityService ) {} /** * Create a new domain */ async create( workspaceId: string, userId: string, createDomainDto: CreateDomainDto ): Promise { const domain = await this.prisma.domain.create({ data: { name: createDomainDto.name, slug: createDomainDto.slug, description: createDomainDto.description ?? null, color: createDomainDto.color ?? null, icon: createDomainDto.icon ?? null, workspace: { connect: { id: workspaceId }, }, metadata: (createDomainDto.metadata ?? {}) as unknown as Prisma.InputJsonValue, sortOrder: 0, // Default to 0, consistent with other services }, include: { _count: { select: { tasks: true, events: true, projects: true, ideas: true }, }, }, }); // Log activity await this.activityService.logDomainCreated(workspaceId, userId, domain.id, { name: domain.name, }); return domain; } /** * Get paginated domains with filters */ async findAll(query: QueryDomainsDto): Promise<{ data: DomainWithCount[]; meta: { total: number; page: number; limit: number; totalPages: number; }; }> { const page = query.page ?? 1; const limit = query.limit ?? 50; const skip = (page - 1) * limit; // Build where clause const where: Prisma.DomainWhereInput = query.workspaceId ? { workspaceId: query.workspaceId, } : {}; // Add search filter if provided if (query.search) { where.OR = [ { name: { contains: query.search, mode: "insensitive" } }, { description: { contains: query.search, mode: "insensitive" } }, ]; } // Execute queries in parallel const [data, total] = await Promise.all([ this.prisma.domain.findMany({ where, include: { _count: { select: { tasks: true, events: true, projects: true, ideas: true }, }, }, orderBy: { sortOrder: "asc", }, skip, take: limit, }), this.prisma.domain.count({ where }), ]); return { data, meta: { total, page, limit, totalPages: Math.ceil(total / limit), }, }; } /** * Get a single domain by ID */ async findOne(id: string, workspaceId: string): Promise { const domain = await this.prisma.domain.findUnique({ where: { id, workspaceId, }, include: { _count: { select: { tasks: true, events: true, projects: true, ideas: true }, }, }, }); if (!domain) { throw new NotFoundException(`Domain with ID ${id} not found`); } return domain; } /** * Update a domain */ async update( id: string, workspaceId: string, userId: string, updateDomainDto: UpdateDomainDto ): Promise { // Verify domain exists const existingDomain = await this.prisma.domain.findUnique({ where: { id, workspaceId }, }); if (!existingDomain) { throw new NotFoundException(`Domain with ID ${id} not found`); } // Build update data, only including defined fields const updateData: Prisma.DomainUpdateInput = {}; if (updateDomainDto.name !== undefined) updateData.name = updateDomainDto.name; if (updateDomainDto.slug !== undefined) updateData.slug = updateDomainDto.slug; if (updateDomainDto.description !== undefined) updateData.description = updateDomainDto.description; if (updateDomainDto.color !== undefined) updateData.color = updateDomainDto.color; if (updateDomainDto.icon !== undefined) updateData.icon = updateDomainDto.icon; if (updateDomainDto.metadata !== undefined) { updateData.metadata = updateDomainDto.metadata as unknown as Prisma.InputJsonValue; } const domain = await this.prisma.domain.update({ where: { id, workspaceId, }, data: updateData, include: { _count: { select: { tasks: true, events: true, projects: true, ideas: true }, }, }, }); // Log activity await this.activityService.logDomainUpdated(workspaceId, userId, id, { changes: updateDomainDto as Prisma.JsonValue, }); return domain; } /** * Delete a domain */ async remove(id: string, workspaceId: string, userId: string): Promise { // Verify domain exists const domain = await this.prisma.domain.findUnique({ where: { id, workspaceId }, }); if (!domain) { throw new NotFoundException(`Domain with ID ${id} not found`); } await this.prisma.domain.delete({ where: { id, workspaceId, }, }); // Log activity await this.activityService.logDomainDeleted(workspaceId, userId, id, { name: domain.name, }); } }