feat(final-docs): applicant.getFinalDocumentStatus procedure
This commit is contained in:
@@ -9,6 +9,7 @@ import { sendStyledNotificationEmail, sendTeamMemberInviteEmail } from '@/lib/em
|
|||||||
import { logAudit } from '@/server/utils/audit'
|
import { logAudit } from '@/server/utils/audit'
|
||||||
import { createNotification } from '../services/in-app-notification'
|
import { createNotification } from '../services/in-app-notification'
|
||||||
import { checkRequirementsAndTransition, triggerInProgressOnActivity, transitionProject, isTerminalState } from '../services/round-engine'
|
import { checkRequirementsAndTransition, triggerInProgressOnActivity, transitionProject, isTerminalState } from '../services/round-engine'
|
||||||
|
import { getFinalDocumentStatusForProject } from '../services/final-documents'
|
||||||
import { EvaluationConfigSchema, MentoringConfigSchema } from '@/types/competition-configs'
|
import { EvaluationConfigSchema, MentoringConfigSchema } from '@/types/competition-configs'
|
||||||
import type { PrismaClient, Prisma, RoundType } from '@prisma/client'
|
import type { PrismaClient, Prisma, RoundType } from '@prisma/client'
|
||||||
|
|
||||||
@@ -1521,6 +1522,22 @@ export const applicantRouter = router({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/** Grand-final document status for the caller's project (banner + mentor panel). */
|
||||||
|
getFinalDocumentStatus: protectedProcedure.query(async ({ ctx }) => {
|
||||||
|
const project = await ctx.prisma.project.findFirst({
|
||||||
|
where: {
|
||||||
|
OR: [
|
||||||
|
{ submittedByUserId: ctx.user.id },
|
||||||
|
{ teamMembers: { some: { userId: ctx.user.id } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
if (!project) return null
|
||||||
|
return getFinalDocumentStatusForProject(ctx.prisma, project.id)
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lightweight flags for conditional nav rendering.
|
* Lightweight flags for conditional nav rendering.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import {
|
|||||||
createTestRound,
|
createTestRound,
|
||||||
createTestProject,
|
createTestProject,
|
||||||
createTestProjectRoundState,
|
createTestProjectRoundState,
|
||||||
|
createTestUser,
|
||||||
cleanupTestData,
|
cleanupTestData,
|
||||||
uid,
|
uid,
|
||||||
} from '../helpers'
|
} from '../helpers'
|
||||||
import { getFinalDocumentStatusForProject } from '@/server/services/final-documents'
|
import { getFinalDocumentStatusForProject } from '@/server/services/final-documents'
|
||||||
|
import * as applicantRouter from '@/server/routers/applicant'
|
||||||
|
import { createCaller } from '../setup'
|
||||||
|
|
||||||
const programIds: string[] = []
|
const programIds: string[] = []
|
||||||
|
|
||||||
@@ -100,3 +103,36 @@ describe('getFinalDocumentStatusForProject', () => {
|
|||||||
expect(status!.allRequiredUploaded).toBe(false)
|
expect(status!.allRequiredUploaded).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('applicant.getFinalDocumentStatus', () => {
|
||||||
|
const localPrograms: string[] = []
|
||||||
|
const localUsers: string[] = []
|
||||||
|
afterAll(async () => {
|
||||||
|
for (const id of localPrograms) await cleanupTestData(id, localUsers)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the status for the caller\'s enrolled finalist project', async () => {
|
||||||
|
const program = await createTestProgram()
|
||||||
|
localPrograms.push(program.id)
|
||||||
|
const comp = await createTestCompetition(program.id, { status: 'ACTIVE' })
|
||||||
|
const round = await createTestRound(comp.id, { roundType: 'LIVE_FINAL', status: 'ROUND_ACTIVE', sortOrder: 6, windowCloseAt: new Date(Date.now() + 86_400_000) })
|
||||||
|
await prisma.fileRequirement.create({ data: { id: uid('req'), roundId: round.id, name: 'Executive Summary', acceptedMimeTypes: ['application/pdf'], isRequired: true, sortOrder: 1 } })
|
||||||
|
const project = await createTestProject(program.id)
|
||||||
|
await createTestProjectRoundState(project.id, round.id)
|
||||||
|
const user = await createTestUser('APPLICANT')
|
||||||
|
localUsers.push(user.id)
|
||||||
|
await prisma.teamMember.create({ data: { projectId: project.id, userId: user.id, role: 'LEAD' } })
|
||||||
|
|
||||||
|
const caller = createCaller(applicantRouter.applicantRouter, user)
|
||||||
|
const status = await caller.getFinalDocumentStatus()
|
||||||
|
expect(status?.roundId).toBe(round.id)
|
||||||
|
expect(status?.requirements).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns null when the caller has no project', async () => {
|
||||||
|
const user = await createTestUser('APPLICANT')
|
||||||
|
localUsers.push(user.id)
|
||||||
|
const caller = createCaller(applicantRouter.applicantRouter, user)
|
||||||
|
expect(await caller.getFinalDocumentStatus()).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user