#706 Show Position Deadlines On Draft Applications - #707
cielbellerose wants to merge 7 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
cielbellerose
left a comment
There was a problem hiding this comment.
Code Review — Cycle 1 · needs revision
4 open — 1 🟠 Medium, 3 🟡 Low (see inline)
Revision — Cycle 1fixed R1-M1, R1-L1, R1-L2, R1-L3 · faf8184 |
cielbellerose
left a comment
There was a problem hiding this comment.
Code Review — Cycle 2 · approved
0 open
Revision requested — UX feedback from review of the previewThree changes, all in 1.
|
Revision — UX feedback follow-upfixed all 3 items (past-deadline distinctness, deadline-before-badge ordering, Badge → AA-safe text tokens) · 2591a05 New tokens |
cielbellerose
left a comment
There was a problem hiding this comment.
Code Review — Cycle 5 · approved
1 open — 1 🟡 Low (see inline)
Pipeline EscalationRebasing
|
cielbellerose
left a comment
There was a problem hiding this comment.
Human Direction — Cycle 1
Operator-authored, not a review-agent pass. Three items: one rebase decision and two scope changes now recorded in the #706 body ("Scope addendum"). Re-read that issue body before starting.
1. Rebase conflict — resolution authorized: keep both sides
The escalation in the previous comment is resolved. In components/features/my-applications-table.tsx, origin/dev's f110d13 (#709) wrapped the action column cell in a TERMINAL_DECISION_STATUSES guard rendering an aria-hidden em-dash for terminal rows; this PR independently rewrote that cell inside the new buildColumns(now) factory without the guard.
The two changes do not conflict in intent — combine them. Keep this PR's buildColumns(now) structure, the new deadline column, and the atRiskDeadlineDate helper, and wrap the action cell's body in dev's guard so it reads:
cell: (a) =>
TERMINAL_DECISION_STATUSES.includes(a.status) ? (
<span className="text-muted-foreground text-sm" aria-hidden="true">
—
</span>
) : (
<div className="flex items-center gap-2">
<MyApplicationPrimaryAction application={a} />
<MyApplicationRowActions
applicationId={a.id}
status={a.status}
positionTitle={a.position.title}
/>
</div>
),Keep dev's TERMINAL_DECISION_STATUSES import. Also carry over the rest of f110d13 that landed in this file — it deleted the draft mobile card's bare dash, and that deletion must survive the rebase. Verify against git show f110d13 -- components/features/my-applications-table.tsx rather than assuming this hunk is the whole of it. If any other hunk in the rebase is genuinely ambiguous, escalate that one as normal — this authorization covers the action-cell collision only.
2. Restore the widget row order (regression introduced by this PR)
components/features/my-applications-widget.tsx moved <ApplicationStatusBadge> to after the trailing <span>, changing the row from title · badge · date to title · date · badge. Not requested, and it contradicts the widget mock in the issue. Put the badge back immediately after the title link; the DeadlineIndicator / LocalTime trailing slot stays where it is on the right.
3. Add the close date to the application detail page
app/(main)/(auth)/applications/[id]/page.tsx:82-95 — append the deadline as a fourth segment of the meta line, after the View position link, for drafts only. Reuse DeadlineIndicator with variant="full" and emphasizeUrgency; resolve now in the page (server component) and pass it in. No change to getMyApplication — its select already carries position.status, opensAt and closesAt. Submitted and terminal statuses keep today's line unchanged.
Update docs/WORKFLOWS.md for the detail-page deadline in the same PR, and add coverage for the draft/non-draft split on that page.
The full acceptance criteria are in the #706 body, including the four added ones.
Adds a Deadline column/mobile line and dashboard-widget trailing slot with amber/red urgency badges for at-risk drafts, and floats at-risk drafts ahead of recency order in both the table and getRecentMyApplications so a stale-but-closing-soon draft can't be hidden by a take-bounded query. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Distinguish past deadlines (icon + dimmer muted line), move the deadline before the status badge in the widget, and replace the soon/urgent/past Badge with AA-safe text tokens (--warning-text / --destructive-text) instead of the fill-only --warning/--destructive. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deadline column header already names the field, so drop the redundant Closes/Closed prefix (upcoming keeps Opens, which is load-bearing); render soon/urgent as the compact Nd/Nh-left countdown everywhere instead of a longer table-only form. Removes the now-unused DeadlineInfo.countdown field and its tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Restore the widget's title-badge-trailing order and add the draft deadline segment to the application detail page per the addendum. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
db45223 to
298d505
Compare
Closes out three still-open review threads from earlier cycles (R4-L1, R4-L2, R5-L1) that were never trimmed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Revision — Cycle 1 (Human Direction)fixed rebase-authorized action-cell merge, widget row order regression, detail-page deadline segment (scope addendum) · fixed R4-L1, R4-L2, R5-L1 (leftover long comments) · rebase: components/features/my-applications-table.tsx (combined per authorized resolution — kept buildColumns structure, wrapped action cell in TERMINAL_DECISION_STATUSES guard) · 298d505, db005d0 follow-up: no automated render-test coverage added for the detail page's draft/non-draft split — this repo has no component-render test infra (no testing-library dependency), so the split relies on the already-unit-tested |


Closes #706
Summary
getDeadlineInfo(lib/utils.ts) — a pure helper that classifies a position's window intoupcoming/distant/soon/urgent/pastand derives the countdown text from a singlediffMs, so the tier and the displayed text can never disagree.rows, sort-key staysnullso a header click still takes over), and query-side ingetRecentMyApplications(merges a bounded at-risk query with the existing recency query) — the dashboard widget'stake 3was silently hiding an old draft with an approaching deadline.getClosingSoonDraftCountand aN closing soonsegment to the widget's subtitle.Changes
lib/constants.ts—DEADLINE_SOON_DAYS(7),DEADLINE_URGENT_HOURS(48): sole owners of the urgency boundaries, shared by the helper and the query.lib/types.ts—DeadlineTier,DeadlineInfo.lib/utils.ts—getDeadlineInfo(position, now), placed directly belowgetPositionDateInfo(deliberately not merged into it — see the "Notes" section).components/features/deadline-indicator.tsx— new; the only place a deadline is styled,full(table/card) andcompact(widget) variants.components/features/my-applications-table.tsx—Deadlinecolumn,nowprop, at-risk pre-sort, mobile card line.app/(main)/(auth)/applications/page.tsx— resolvesnowserver-side and passes it down (avoids a hydration mismatch near a tier boundary).prisma/data/applications.ts—buildAtRiskDraftWhere(shared), the at-risk float ingetRecentMyApplications, newgetClosingSoonDraftCount.components/features/my-applications-widget.tsx— deadline in the trailing slot for drafts,N closing soonsubtitle segment, one sharednow.tests/unit/utils.test.ts— tier/countdown/boundary coverage forgetDeadlineInfo.tests/db/my-applications-deadline-ordering.test.ts— new; float order, dedupe,takecap, exclusions (past-due, not-yet-open, unpublished, soft-deleted), and count parity.docs/WORKFLOWS.md— AP-10 (Deadline column, tiers, at-risk float) and AP-1 (widget trailing slot +N closing soon).Deliberately not changed:
getPositionDateInfo/PositionDateLine. Widening itsemphasisunion with a "closing soon" tier would repaint every position card and detail page amber/red, which this ticket doesn't ask for.getDeadlineInfoowns applicant urgency instead; both still classify through the sharedgetPositionAvailability, so they can never disagree about the underlying window state, only about how to present it.Testing plan
/applicationsshows aDeadlinecell for every row: a draft closing in ~12 hours gets a red badge ("Closes in N hours"), one closing in ~3 days gets an amber badge ("Closes in N days"), one closing in ~30 days shows a plain muted "Closes ", one with noclosesAtshows "—", one past its close date shows a red "Closed " badge (with Continue still available), and one not yet open shows a muted "Opens " with no badge.?sort=/?dir=round-trips on reload.md, the stacked mobile card shows the same deadline/tiering on its own line.N closing soonwhen at least one at-risk draft exists./drops the count and removes theclosing soonsegment.warning) and red (destructive) badges stay legible in light and dark mode.getDeadlineInfo's tier boundaries (48h inclusive/exclusive, 7d inclusive/exclusive, past, upcoming, null-date) and singular/plural countdown text.getRecentMyApplications's float order, dedupe of a row qualifying for both queries, thetakecap, and exclusion of past-due/not-yet-open/unpublished/soft-deleted positions from the float, plusgetClosingSoonDraftCountparity.Automated checks
npm run prettier:check— passnpm run eslint:check— passnpm run tsc:check— passnpm run test:unit— pass (409 tests)tests/db/my-applications-deadline-ordering.test.ts— added but not executed in this environment: this worktree's Postgres port (5432) was already occupied by an unrelated container and I could not safely provision a second local database to run thedbtest project. The test logic was traced manually against the implementation (see PR description); please runnpm run test(or thedbproject alone) in CI/review to confirm.Notes
useEffectthis codebase avoids.formatCountdowninlib/utils.ts(the login OTPmm:sstimer) is unrelated and untouched.🤖 Generated with Claude Code