Unified search algorithm across all lists; per-section record visibility (contacts, deals, activities, leads, finance, tickets, notes, projects)
This commit is contained in:
@@ -14,6 +14,7 @@ import type {
|
||||
import { TICKET_SLA_HOURS } from '@mento/shared';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { buildSearchWhere, ci } from '../common/search';
|
||||
import {
|
||||
type Actor,
|
||||
elevated,
|
||||
@@ -63,9 +64,19 @@ export class TicketsService {
|
||||
const limit = opts.limit ?? 50;
|
||||
const now = new Date();
|
||||
const access = ticketAccessWhere(actor);
|
||||
const where: Prisma.TicketWhereInput = {
|
||||
const search = buildSearchWhere<Prisma.TicketWhereInput>(opts.q, (t) => [
|
||||
{ subject: ci(t) },
|
||||
{ number: ci(t) },
|
||||
{ description: ci(t) },
|
||||
{
|
||||
person: {
|
||||
OR: [{ firstName: ci(t) }, { lastName: ci(t) }, { mobile: { contains: t } }],
|
||||
},
|
||||
},
|
||||
]);
|
||||
const finalWhere: Prisma.TicketWhereInput = {
|
||||
organizationId: actor.organizationId,
|
||||
...access,
|
||||
AND: [access, ...(search ? [search] : [])],
|
||||
...(opts.status ? { status: opts.status as never } : {}),
|
||||
...(opts.priority ? { priority: opts.priority as never } : {}),
|
||||
...(opts.personId ? { personId: opts.personId } : {}),
|
||||
@@ -79,62 +90,8 @@ export class TicketsService {
|
||||
status: { in: ['open', 'in_progress', 'waiting'] },
|
||||
}
|
||||
: {}),
|
||||
...(opts.q?.trim()
|
||||
? {
|
||||
AND: [
|
||||
access,
|
||||
{
|
||||
OR: [
|
||||
{ subject: { contains: opts.q.trim(), mode: 'insensitive' } },
|
||||
{ number: { contains: opts.q.trim(), mode: 'insensitive' } },
|
||||
{
|
||||
description: {
|
||||
contains: opts.q.trim(),
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
// When q is set, avoid double-spreading access at top level
|
||||
const finalWhere: Prisma.TicketWhereInput = opts.q?.trim()
|
||||
? {
|
||||
organizationId: actor.organizationId,
|
||||
...(opts.status ? { status: opts.status as never } : {}),
|
||||
...(opts.priority ? { priority: opts.priority as never } : {}),
|
||||
...(opts.personId ? { personId: opts.personId } : {}),
|
||||
...(opts.assigneeId && elevated(actor.role)
|
||||
? { assigneeId: opts.assigneeId }
|
||||
: {}),
|
||||
...(opts.sla === 'overdue'
|
||||
? {
|
||||
slaDueAt: { lt: now },
|
||||
firstRespondedAt: null,
|
||||
status: { in: ['open', 'in_progress', 'waiting'] },
|
||||
}
|
||||
: {}),
|
||||
AND: [
|
||||
access,
|
||||
{
|
||||
OR: [
|
||||
{ subject: { contains: opts.q.trim(), mode: 'insensitive' } },
|
||||
{ number: { contains: opts.q.trim(), mode: 'insensitive' } },
|
||||
{
|
||||
description: {
|
||||
contains: opts.q.trim(),
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
: where;
|
||||
|
||||
const [rows, total] = await this.prisma.$transaction([
|
||||
this.prisma.ticket.findMany({
|
||||
where: finalWhere,
|
||||
|
||||
Reference in New Issue
Block a user