Skip to content

Application Tracking: split status from tasks, and let students date their own work - #47

Merged
DanialBeg merged 5 commits into
mainfrom
feat/ui-changes
Sep 24, 2026
Merged

DanialBeg merged 5 commits into
mainfrom
feat/ui-changes

Conversation

@DanialBeg

Copy link
Copy Markdown
Member

Five UI changes, each a separate commit, read in order.

Custom tasks in the sidebar

The add-a-date form offered Application Tracking or Financial Aid, so a driving test, a shift, or a form due at school had to be filed under one of them or not recorded at all. There is a Custom option now.

Custom is a DeadlineModule but not a module — there is nothing to open. Making it a module value rather than a special case is what lets it filter in settings, count in the week strip and export like everything else with no branching anywhere. Only self-set dates carry it, so nextDueForModule still returns nothing for it, which is right.

Three places assumed there were exactly two modules. The worst was the deadline row's short label — a two-value ternary where anything that was not Application Tracking rendered as "Financial Aid", so a Custom date would have claimed to be financial aid on every row. Settings kept its own hardcoded copy of the names, and the add form had hand-written options. All three read one list now.

The module opens on Application Status

A student coming back wants to see where each application stands, not re-read the strategy checklist.

The nav keeps its order — overview, discover, list, status — which is a teaching order and also the order the guided tour walks. The landing tab and the reading order answer different questions.

Status's empty state had to change with it: it said "Add colleges to your list first" and offered no way to get there, which was tolerable as the fourth tab and is not as the first thing a new student sees. It has a button through to the College List now.

Status split into two pages

Application Status carried five things and answered two questions badly at once.

  • Application Status keeps the overview: the ring, the next deadline, the balance chips, the tiles, the funnel, a row per college. Where do I stand.
  • Tasks is new: every college as a section, checklist grouped by phase, ordered by deadline. What do I do next.

The modal was the real problem. The most actionable content in the module showed one college at a time and closed the moment you looked away, so a student could not see everything they owed without opening and shutting a dialog per school. SchoolTasksModal is deleted; its body is now SchoolTaskList, used by the page. The confetti on finishing a school moved with it.

Colleges with no deadline on file sort last rather than being dropped — most colleges outside the curated set have no date, and hiding them would hide most of the list.

Finished colleges fold away

Ten colleges at ten tasks each is a hundred checkboxes in one scroll, and the ticked ones are least worth the space. A college with every task done collapses to its header and reopens on a click.

Nothing else collapses. A student opens this page to work; putting unfinished work behind a click would be the wrong trade. A college reached by clicking through from the status page is never collapsed either — they asked for it by name, and arriving at a closed box is a dead end.

Also guards the scrollIntoView call. Scrolling to the focused college is a courtesy, and an environment without it — jsdom, as it turns out — must not throw out of an effect and take the page down.

Tasks can carry their own dates

A college's application deadline is derived and fixed. The dates that actually need remembering are the ones leading up to it — essay drafted by the 12th, recommendations asked by the 15th — and there was nowhere to put them.

AppTask carries an optional due, set from a control on each row that stays empty until used, so an untouched checklist does not become a wall of date pickers.

Dated tasks derive into DeadlineEvents and appear on the calendar, the week strip and the deadline panel. The title carries the college — "Draft the supplemental essay — Harvard" — because on a calendar the task name alone does not say which school. Ticking one from the calendar writes the task's own done flag, not the stored id list, so the two views cannot disagree about whether the same thing is finished.

A bug the tests caught

Event ids were task-<collegeId>-<taskId>, parsed greedily, so task-harvard-c-1 split into harvard-c and 1. Both halves can contain hyphens — cal-poly, and every task a student adds themselves is c-1, c-2. Ticking a self-added task would have written to the wrong college or nowhere. The delimiter is :: and the round trip is tested across all four shapes.

Testing

408 tests, 29 files (+23). New coverage: the Custom module end to end including storage round-trip, the Tasks page's ordering, collapse, focus exemption and empty state, and task-deadline derivation plus the tick write-through.

tsc -b, eslint ., vitest run, npm run build clean locally.

What is not verified

Everything here was checked by rendering components and by tests. Nobody has clicked through this module in a live session — this work has had no authenticated environment available. The Tasks page, the collapse, the date control and the status→tasks jump all render correctly and are tested, but none has been used. The preview deploy is worth two minutes before merging.

One judgement call worth a second opinion: the undated date control is deliberately faint — a small dashed picker. It keeps the list clean at the cost of discoverability, and a student may not notice dates are available at all.

The add-a-date form offered Application Tracking or Financial Aid, so a
driving test, a shift, or a form due at school had to be filed under one of
them or not recorded at all. There is a third option now.

'Custom' is a DeadlineModule but not a module: there is nothing to open. It
is a bucket for dates that belong to the student rather than to the app, and
making it a module value is what lets it be filtered in settings, counted in
the week strip and exported like everything else, with no special case
anywhere.

Only self-set dates can carry it — derivation produces the other two — so
nextDueForModule keeps returning nothing for it, which is right: there is no
Custom card to hang a "next due" chip on.

Three places assumed there were exactly two modules and are now driven by one
list. The worst was the deadline row's short label, a two-value ternary where
anything that was not Application Tracking rendered as "Financial Aid" — a
Custom date would have claimed to be financial aid. Settings had its own
hardcoded copy of the module names, and the add form had hand-written
options.

Stored rows with an unrecognised module still fall back rather than being
dropped. The row is the student's own work, and a module name we no longer
recognise is no reason to lose it.

The option reads "Custom — anything else", because "Custom" alone in a list
of two app areas reads as a setting rather than as a place to put a driving
test.
A student coming back to this module wants to see where each application
stands, not re-read the strategy checklist. It opened on Overview.

The nav keeps its existing order — overview, discover, list, status — which
is a teaching order, and also the order the guided tour walks through. The
landing tab and the reading order are answering different questions, so they
do not have to match.

Status's empty state had to change with it. It said "Add colleges to your
list first" and offered no way to get there, which was tolerable as the
fourth tab and is not as the first thing a new student sees. It now has a
button through to the College List, where the search box is.
Application Status carried five things: a progress hero, three stat tiles, a
stage funnel, per-college status rows, and — behind a click — each college's
task checklist in a popup. It answered two different questions badly at once.

It is two pages now.

**Application Status** keeps the overview: the ring, the next deadline, the
balance chips, the tiles, the funnel, and a row per college showing status at
a glance. Where do I stand.

**Tasks** is new and holds what was trapped in the modal: every college as a
section, its checklist grouped by phase, ordered by deadline. What do I do
next. Clicking a college on the status page lands on its section rather than
opening a dialog.

The modal was the real problem. The most actionable thing in the module
showed one college at a time and closed the moment you looked away, so a
student could not see everything they owed without opening and shutting a
dialog per school. SchoolTasksModal is deleted; its body is now
SchoolTaskList, used by the page.

Colleges we hold no deadline for sort last rather than being dropped — most
colleges outside the curated set have no date on file, and hiding them would
hide most of the list.

The confetti on finishing a school's checklist moved with the checklist. It
was the one moment in this module worth marking and losing it with the modal
would have been a loss.
Ten colleges at ten tasks each is a hundred checkboxes in one scroll, and the
ticked ones are the ones least worth the space. A college with every task
done now collapses to its header — name, "All N done", category, status — and
reopens on a click.

Nothing else collapses. A student opens this page to work, and putting their
unfinished work behind a click would be the wrong trade; only the work that
is over gets folded away. A college the student clicked through to from the
status page is never collapsed either, since they asked for it by name and
arriving at a closed box would be a dead end.

Also guards the scroll-into-view call. Scrolling to the focused college is a
courtesy, and an environment without scrollIntoView — jsdom, as it turns out
— must not throw out of an effect and take the page with it.

Seven tests: the deadline ordering, that unfinished colleges stay open and
offer no toggle, that finished ones collapse and reopen, that a focused one
is exempt, the cross-college progress count, and the empty state's way out.
A college's application deadline is derived and fixed. The dates that
actually need remembering are the ones leading up to it — have the essay
drafted by the 12th, ask Ms. Reyes by the 15th — and there was nowhere to put
them. A student could add a task but not say when it was due.

AppTask carries an optional `due` now, set from a date control on each task
row. Empty until they use it, so an untouched checklist stays a checklist
rather than becoming a wall of date pickers.

Dated tasks derive into DeadlineEvents, so they appear on the calendar, the
week strip and the deadline panel beside everything else. The title carries
the college — "Draft the supplemental essay — Harvard" — because on a
calendar the task name alone says nothing about which school it belongs to.
They are marked source 'self': the student chose the date.

Ticking one from the calendar writes the task's own done flag, not the stored
id list, so the calendar and the college's checklist cannot disagree about
whether the same thing is finished. Withdrawn applications contribute
nothing; their tasks are not work any more.

The tests caught a real bug before it shipped. Event ids were
`task-<collegeId>-<taskId>` and parsed with a greedy pattern, so
`task-harvard-c-1` split into `harvard-c` and `1`. Both halves can contain
hyphens — `cal-poly`, and every task a student adds themselves is `c-1`,
`c-2` — which meant ticking a self-added task would have written to the wrong
place, or nowhere. The delimiter is `::` and the round trip is tested across
all four shapes.
@vercel

vercel Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
webapp Ready Ready Preview Sep 24, 2026 12:46am UTC

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying timeline-prototype with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4b8a0ff
Status: ✅  Deploy successful!
Preview URL: https://7dc74a2e.timeline-prototype.pages.dev
Branch Preview URL: https://feat-ui-changes.timeline-prototype.pages.dev

View logs

@DanialBeg
DanialBeg merged commit 22600bd into main Sep 24, 2026
5 checks passed
@DanialBeg
DanialBeg deleted the feat/ui-changes branch September 24, 2026 00:47
ZubairQazi added a commit that referenced this pull request Sep 24, 2026
…m dates

main (#47) split Application Status into an overview plus a Tasks tab, while
this branch replaced the tasks popup with a page per school and folded the
College List into Discover. Kept this branch's structure; brought in the rest.

- Task due dates: the date control from SchoolTaskList now sits on each task
  row of the school page, so dated tasks still reach the calendar, week strip
  and deadline panel.
- Shared tasks (recommendations, transcript, CSS Profile) keep one date for
  every school that needs them: set from any school, shown on the calendar
  once ("— all your schools"), and ticked from the calendar for every school.
- The module opens on Application Status; its empty state links to Discover
  (the College List tab it pointed at is gone).
- Custom dates, the deadline panel/row and settings changes come in as-is.
- The Tasks tab (ApplicationTasksTab, SchoolTaskList) is dropped: the school
  pages cover it. Its task-event tests move to applicationTaskEvents.test.ts.
ZubairQazi added a commit that referenced this pull request Sep 24, 2026
Fixes from reviewing the merge and the Category sort added on top of it.

Application Status
- "Sort by" gains Category: schools grouped under reach / match / safety /
  unranked headings, by deadline within each.
- A category this build doesn't know shows as Unranked instead of crashing
  every view (normalized once where the list loads; storage untouched).

Task due dates
- The date box keeps focus while typing, saves after a pause or on leaving,
  never saves a half-typed value, and only clears when really emptied.
- Shared tasks keep one date and tick across every school (withdrawn ones
  included, so a school brought back is in step); a new school inherits
  both, preferring an active school's date.
- Dates saved per school before this stay on the calendar, one per date,
  instead of all but one being dropped.

From main (#47), made to work here
- The tour resets to Application Status, the tab the module opens on.
- The calendar's remove button only shows on the student's own dates, not
  task dates (tagged with isTask); Dashboard "next due" skips ticked-off
  items and task dates.
- Custom dates stay visible for settings saved before Custom existed:
  saves now record which modules existed, and older lists are read by what
  they could only have been chosen from.
- Settings saves run in order on the last confirmed write, so a quick
  second change can't drop the first and a failed one can't slip through.
- Calendar writes compute once outside state updaters and wait for their
  list to load, so they can't save a stale copy.
- One ISO-day parser instead of two.

This branch was successfully deployed

1 active deployment
Preview — 4b8a0ff7 Deployed Sep 24, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant