Adds a PROJECT_TEAM recipient type to the message router (resolver returns team members + project lead) and an "Email Team" button on the admin project detail page that opens a self-contained dialog matching the look of /admin/messages: subject, body (pre-filled with "Hello [Project Title] team,\n\n"), live HTML preview iframe, "Send test to me" + "Send to N" actions. The composer reuses the existing message.previewEmail and message.send tRPC procedures end-to-end — no parallel email infrastructure introduced. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
import { prisma, createCaller } from '../setup'
|
|
import {
|
|
createTestUser, createTestProgram, createTestProject, cleanupTestData, uid,
|
|
} from '../helpers'
|
|
import { messageRouter } from '../../src/server/routers/message'
|
|
|
|
describe('message.previewRecipients — PROJECT_TEAM', () => {
|
|
let programId: string
|
|
let admin: { id: string; email: string; role: 'SUPER_ADMIN' }
|
|
let projectId: string
|
|
const userIds: string[] = []
|
|
|
|
beforeAll(async () => {
|
|
const program = await createTestProgram({ name: `proj-team-${uid()}` })
|
|
programId = program.id
|
|
|
|
const lead = await createTestUser('APPLICANT')
|
|
userIds.push(lead.id)
|
|
const project = await createTestProject(programId, { title: 'TestProj' })
|
|
projectId = project.id
|
|
await prisma.project.update({ where: { id: projectId }, data: { submittedByUserId: lead.id } })
|
|
|
|
const member1 = await createTestUser('APPLICANT')
|
|
const member2 = await createTestUser('APPLICANT')
|
|
userIds.push(member1.id, member2.id)
|
|
await prisma.teamMember.createMany({
|
|
data: [
|
|
{ id: uid('tm'), projectId, userId: member1.id, role: 'MEMBER' },
|
|
{ id: uid('tm'), projectId, userId: member2.id, role: 'MEMBER' },
|
|
],
|
|
})
|
|
|
|
const a = await createTestUser('SUPER_ADMIN')
|
|
userIds.push(a.id)
|
|
admin = { id: a.id, email: a.email, role: 'SUPER_ADMIN' }
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await cleanupTestData(programId, userIds)
|
|
})
|
|
|
|
it('counts the lead + 2 team members', async () => {
|
|
const caller = createCaller(messageRouter, admin)
|
|
const result = await caller.previewRecipients({
|
|
recipientType: 'PROJECT_TEAM',
|
|
recipientFilter: { projectId },
|
|
})
|
|
expect(result.totalApplicants).toBe(3)
|
|
})
|
|
|
|
it('returns 0 when projectId is missing', async () => {
|
|
const caller = createCaller(messageRouter, admin)
|
|
const result = await caller.previewRecipients({
|
|
recipientType: 'PROJECT_TEAM',
|
|
recipientFilter: {},
|
|
})
|
|
expect(result.totalApplicants).toBe(0)
|
|
})
|
|
})
|