import { Injectable, NotFoundException } from '@nestjs/common'; import type { CreateFaqArticleRequest, FaqArticleDto, UpdateFaqArticleRequest, } from '@mento/shared'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../prisma/prisma.service'; import { buildSearchWhere, ci } from '../common/search'; @Injectable() export class FaqService { constructor(private readonly prisma: PrismaService) {} async list( organizationId: string, opts: { q?: string; category?: string; publishedOnly?: boolean }, ): Promise { const where: Prisma.FaqArticleWhereInput = { organizationId, ...(opts.publishedOnly ? { isPublished: true } : {}), ...(opts.category?.trim() ? { category: opts.category.trim() } : {}), }; const search = buildSearchWhere(opts.q, (t) => [ { question: ci(t) }, { answer: ci(t) }, ]); if (search) where.AND = [search]; const rows = await this.prisma.faqArticle.findMany({ where, orderBy: [{ position: 'asc' }, { createdAt: 'asc' }], }); return rows.map(toDto); } async get(organizationId: string, id: string): Promise { const row = await this.prisma.faqArticle.findFirst({ where: { id, organizationId }, }); if (!row) throw new NotFoundException('مقاله FAQ پیدا نشد'); return toDto(row); } async create( organizationId: string, dto: CreateFaqArticleRequest, ): Promise { const row = await this.prisma.faqArticle.create({ data: { organizationId, question: dto.question.trim(), answer: dto.answer.trim(), category: emptyToNull(dto.category ?? null), isPublished: dto.isPublished ?? true, position: dto.position ?? 0, }, }); return toDto(row); } async update( organizationId: string, id: string, dto: UpdateFaqArticleRequest, ): Promise { await this.ensureExists(organizationId, id); const data: Prisma.FaqArticleUpdateInput = {}; if (dto.question !== undefined) data.question = dto.question.trim(); if (dto.answer !== undefined) data.answer = dto.answer.trim(); if ('category' in dto) data.category = emptyToNull(dto.category ?? null); if (dto.isPublished !== undefined) data.isPublished = dto.isPublished; if (dto.position !== undefined) data.position = dto.position; const row = await this.prisma.faqArticle.update({ where: { id }, data }); return toDto(row); } async remove(organizationId: string, id: string): Promise { await this.ensureExists(organizationId, id); await this.prisma.faqArticle.delete({ where: { id } }); } private async ensureExists(organizationId: string, id: string) { const found = await this.prisma.faqArticle.findFirst({ where: { id, organizationId }, select: { id: true }, }); if (!found) throw new NotFoundException('مقاله FAQ پیدا نشد'); } } function toDto(row: { id: string; question: string; answer: string; category: string | null; isPublished: boolean; position: number; createdAt: Date; updatedAt: Date; }): FaqArticleDto { return { id: row.id, question: row.question, answer: row.answer, category: row.category, isPublished: row.isPublished, position: row.position, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString(), }; } function emptyToNull(value?: string | null): string | null { if (value == null) return null; const trimmed = value.trim(); return trimmed.length ? trimmed : null; }