Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion web/src/data/applicationTasks.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest'
import { defaultTasksFor, deriveTaskEvents, initialTasksFor, setSharedTask, sharedTaskSummary, tasksForEntry, tasksForRound, updateSharedTask, suggestedWaiverDue, applicationFeeFact, WAIVER_LEAD_DAYS } from './applicationTasks'
import { defaultTasksFor, deriveTaskEvents, initialTasksFor, setSharedTask, sharedTaskSummary, tasksForEntry, tasksForRound, updateSharedTask, suggestedWaiverDue, applicationFeeFact, taskProgress, WAIVER_LEAD_DAYS } from './applicationTasks'
import { withKnownCategory, type ApplicationEntry } from './applicationsChecklist'

const app = (collegeId: string, fields: Partial<ApplicationEntry> = {}): ApplicationEntry => ({
Expand Down Expand Up @@ -195,6 +195,24 @@ describe('fee waivers need lead time', () => {
expect(topped.find((t) => t.id === 'waiver')?.phase).toBe('before')
})

it('does not hand a submitted school something new to do', () => {
// Found by @ZubairQazi on #56. A school with everything ticked dropped to
// "10 of 11" and was told to ask about waiving a fee for an application it
// had already sent.
const base = app('a', { status: 'submitted', applicationFeeCents: 8500 })
const finished = defaultTasksFor(base).filter((t) => t.id !== 'waiver').map((t) => ({ ...t, done: true }))
const entry = app('a', { status: 'submitted', applicationFeeCents: 8500, tasks: finished })
expect(tasksForEntry(entry)).toBe(entry.tasks)
expect(taskProgress(entry).done).toBe(taskProgress(entry).total)
})

it('still tops up a school that is still being worked on', () => {
const base = app('a', { status: 'in-progress', applicationFeeCents: 8500 })
const old = defaultTasksFor(base).filter((t) => t.id !== 'waiver')
expect(tasksForEntry(app('a', { status: 'in-progress', applicationFeeCents: 8500, tasks: old }))
.some((t) => t.id === 'waiver')).toBe(true)
})

it('leaves a complete list exactly as it was', () => {
const entry = app('a', { tasks: defaultTasksFor(app('a')) })
expect(tasksForEntry(entry)).toBe(entry.tasks)
Expand Down
9 changes: 9 additions & 0 deletions web/src/data/applicationTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const isPrivate = (app: ApplicationEntry) =>
(app.ownership ?? '').toLowerCase().includes('private')
const isEarlyBinding = (app: ApplicationEntry) =>
app.deadlineType === 'ED' || app.deadlineType === 'REA'
/** Still being worked on, so still worth adding to. */
const isActive = (app: ApplicationEntry) =>
app.status === 'not-started' || app.status === 'in-progress'

/**
* Whether there is a fee here to waive.
Expand Down Expand Up @@ -110,9 +113,15 @@ export function tasksForRound(app: ApplicationEntry, deadlineType: ApplicationEn
* tasks cannot be deleted (only custom ones can), so a list without one was
* saved before that task existed, and a student who added a school last month
* should not be the only one without the fee-waiver step.
*
* Only while the application is still being worked on, though. A submitted or
* decided school has nothing left to do, and handing it a new task drops it
* from "all done" to one short — with, in the fee-waiver case, an instruction
* to go and ask about waiving a fee for an application already sent.
*/
export function tasksForEntry(app: ApplicationEntry): AppTask[] {
if (!app.tasks) return defaultTasksFor(app)
if (!isActive(app)) return app.tasks
const saved = new Set(app.tasks.filter((t) => !t.custom).map((t) => t.id))
const missing = defaultTasksFor(app).filter((t) => !saved.has(t.id))
if (missing.length === 0) return app.tasks
Expand Down
Loading