Consolidate dashboard into two-column layout
Replace separate List, Focus, Calendar, and Agenda pages with a single
dashboard: overdue tasks on the left (most urgent promoted to a "Next up"
focus section), 7-day upcoming agenda on the right with a mini week strip
showing task counts per day.

Focus/calendar/agenda routes now redirect to root. Series detail, new
series, and user pages remain standalone. New series "Create" button
moved into the section header to match Edit/Save pattern. Series editing
gains a Cancel option.

Assisted-by: Claude Opus 4.6 via pi
change rrvzmxsmmluwotrzwknotomkxpvkzxsy
commit d5f8b625243a275cee8db2c8b13309b5f331e64d
author Alpha Chen <alpha@kejadlen.dev>
date
parent kszsuyvw
diff --git a/lib/ketchup/views/dashboard.rb b/lib/ketchup/views/dashboard.rb
index e307772..6290e6b 100644
--- a/lib/ketchup/views/dashboard.rb
+++ b/lib/ketchup/views/dashboard.rb
@@ -3,11 +3,13 @@
 require "phlex"
 
 require_relative "layout"
-require_relative "task_list"
+require_relative "task_card"
 
 module Views
   INTERVAL_OPTIONS = Series::INTERVAL_UNITS.map { |u| [u, "#{u}(s)"] }.freeze
 
+  AGENDA_DAYS = 7
+
   class Dashboard < Phlex::HTML
     def initialize(current_user:, csrf:)
       @current_user = current_user
@@ -15,25 +17,121 @@ module Views
     end
 
     def view_template
+      overdue = @current_user.overdue_tasks.all.sort_by { |t| -t.urgency }
+      upcoming = @current_user.upcoming_tasks
+        .where { due_date <= Date.today + AGENDA_DAYS }
+        .all
+
       render Layout.new(current_user: @current_user) do
         div(class: "dashboard") do
-          render_main_column
+          div(class: "column-overdue") do
+            render_focus(overdue)
+            render_overdue(overdue.drop(1))
+          end
+          div(class: "column-agenda") do
+            render_agenda(upcoming, overdue_count: overdue.size)
+          end
         end
       end
     end
 
     private
 
-    def render_main_column
-      overdue = @current_user.overdue_tasks.all.sort_by { |t| -t.urgency }
-      upcoming = @current_user.upcoming_tasks.all
-
-      div(class: "main-column") do
-        render TaskList.new(
-          overdue: overdue,
-          upcoming: upcoming,
-          csrf: @csrf
-        )
+    def render_focus(overdue)
+      if overdue.empty?
+        section(class: "section section--focus") do
+          p(class: "empty") { "All caught up!" }
+        end
+        return
+      end
+
+      task = overdue.first
+      name = task[:note].lines.first&.strip || task[:note]
+      complete_path = "/series/#{task[:series_id]}/tasks/#{task[:id]}/complete"
+
+      section(class: "section section--focus") do
+        div(class: "section-header") do
+          h2(class: "section-title") do
+            span(class: "section-title-text") { "Next up" }
+          end
+        end
+        render TaskCard.new(task: task, csrf: @csrf, overdue: true)
+      end
+    end
+
+    def render_overdue(tasks)
+      return if tasks.empty?
+
+      section(class: "section section--overdue") do
+        div(class: "section-header") do
+          h2(class: "section-title") do
+            span(class: "section-title-text") { "Overdue (#{tasks.size})" }
+          end
+        end
+
+        ul(class: "task-list") do
+          tasks.each do |task|
+            li(class: "task-item") do
+              render TaskCard.new(task: task, csrf: @csrf, overdue: true)
+            end
+          end
+        end
+      end
+    end
+
+    def render_agenda(upcoming, overdue_count: 0)
+      tasks_by_date = {}
+      upcoming.each { |t| (tasks_by_date[t[:due_date]] ||= []) << t }
+
+      today = Date.today
+
+      section(class: "section section--agenda") do
+        div(class: "agenda-week") do
+          if overdue_count > 0
+            div(class: "agenda-week-day agenda-week-day--overdue") do
+              span(class: "agenda-week-label") { "!" }
+              span(class: "agenda-week-count") { overdue_count.to_s }
+            end
+          end
+
+          AGENDA_DAYS.times do |i|
+            date = today + i
+            count = (tasks_by_date[date] || []).size
+            classes = ["agenda-week-day"]
+            classes << "agenda-week-day--today" if i == 0
+            classes << "agenda-week-day--has-tasks" if count > 0
+
+            div(class: classes) do
+              span(class: "agenda-week-label") { date.strftime("%a") }
+              span(class: "agenda-week-count") { count.to_s } if count > 0
+            end
+          end
+        end
+
+        AGENDA_DAYS.times do |i|
+          date = today + i
+          day_tasks = tasks_by_date[date] || []
+          next if day_tasks.empty?
+
+          div(class: ["agenda-day", ("agenda-day--today" if i == 0)]) do
+            div(class: "agenda-day-header") { friendly_day(date, i) }
+            day_tasks.each do |task|
+              task_name = task[:note].lines.first&.strip || task[:note]
+              a(
+                href: "/series/#{task[:series_id]}",
+                class: "agenda-day-pill"
+              ) { task_name }
+            end
+          end
+        end
+      end
+    end
+
+    def friendly_day(date, offset)
+      case offset
+      when 0 then "Today"
+      when 1 then "Tomorrow"
+      else date.strftime("%a, %b %-d")
       end
     end
   end
diff --git a/lib/ketchup/views/layout.rb b/lib/ketchup/views/layout.rb
index 3c85f78..5ee369f 100644
--- a/lib/ketchup/views/layout.rb
+++ b/lib/ketchup/views/layout.rb
@@ -4,7 +4,7 @@ require "phlex"
 
 module Views
   class Layout < Phlex::HTML
-    def initialize(current_user:, title: "Ketchup", active_view: :list)
+    def initialize(current_user:, title: "Ketchup", active_view: nil)
       @current_user = current_user
       @title = title
       @active_view = active_view
@@ -40,12 +40,6 @@ module Views
           header(class: "site-header") do
             a(href: "/", class: "site-name") { "Ketchup" }
             nav(class: "site-nav") do
-              view_links.each do |path, label, view_key|
-                a(
-                  href: path,
-                  class: ["view-link", ("view-link--active" if @active_view == view_key)]
-                ) { label }
-              end
               a(
                 href: "/series/new",
                 class: ["header-action", ("header-action--active" if @active_view == :new)]
@@ -61,15 +55,6 @@ module Views
 
     private
 
-    def view_links
-      [
-        ["/", "List", :list],
-        ["/focus", "Focus", :focus],
-        ["/calendar", "Calendar", :calendar],
-        ["/agenda", "Agenda", :agenda],
-      ]
-    end
-
     def render_footer
       config = CONFIG
       parts = []
diff --git a/lib/ketchup/views/series/new.rb b/lib/ketchup/views/series/new.rb
index 6abc3a4..80d67f3 100644
--- a/lib/ketchup/views/series/new.rb
+++ b/lib/ketchup/views/series/new.rb
@@ -21,9 +21,15 @@ module Views
                   h2(class: "section-title") do
                     span(class: "section-title-text") { "New series" }
                   end
+                  button(
+                    class: "section-edit-btn",
+                    id: "create-series-btn",
+                    disabled: true,
+                    "x-on:click": "document.getElementById('new-series-form').requestSubmit()"
+                  ) { "Create" }
                 end
 
-                form(method: "post", action: "/series", class: "new-series-form") do
+                form(method: "post", action: "/series", id: "new-series-form", class: "new-series-form") do
                   input(type: "hidden", name: "_csrf", value: @csrf.call("/series"))
                   div(class: "field") do
                     label(for: "series-note-editor") { "Note" }
@@ -50,8 +56,6 @@ module Views
                       value: Date.today.to_s, required: true
                     )
                   end
-
-                  button(type: "submit", id: "create-series-btn", disabled: true) { "Create" }
                 end
               end
             end
diff --git a/lib/ketchup/views/series/show.rb b/lib/ketchup/views/series/show.rb
index 19cee2c..19f6cd8 100644
--- a/lib/ketchup/views/series/show.rb
+++ b/lib/ketchup/views/series/show.rb
@@ -31,9 +31,18 @@ module Views
                   ) do
                     plain "Edit"
                   end
+                  button(
+                    class: "section-edit-btn section-edit-btn--cancel",
+                    "x-show": "editing",
+                    "x-cloak": true,
+                    "x-on:click": "editing = false; location.reload()"
+                  ) do
+                    plain "Cancel"
+                  end
                   button(
                     class: "section-edit-btn",
                     "x-show": "editing",
+                    "x-cloak": true,
                     "x-on:click": "editing = false; $dispatch('stop-editing')"
                   ) do
                     plain "Save"
@@ -41,6 +50,7 @@ module Views
                 end
 
                 div(class: "series-note", id: "series-note-detail",
+                    "x-bind:class": "{ 'series-note--editable': editing }",
                     "data-value": @series.note || "",
                     "data-series-id": @series.id.to_s)
 
diff --git a/lib/ketchup/web.rb b/lib/ketchup/web.rb
index 27e6ddc..e9c21de 100644
--- a/lib/ketchup/web.rb
+++ b/lib/ketchup/web.rb
@@ -5,9 +5,6 @@ require "roda"
 
 require_relative "models"
 require_relative "views/dashboard"
-require_relative "views/focus"
-require_relative "views/calendar"
-require_relative "views/agenda"
 require_relative "views/series/new"
 require_relative "views/series/show"
 require_relative "views/user/show"
@@ -47,31 +44,15 @@ class Web < Roda
     end
 
     r.get "focus" do
-      overdue = @user.overdue_tasks.all.sort_by { |t| -t.urgency }
-      if overdue.empty?
-        r.redirect "/"
-      else
-        Views::Focus.new(
-          current_user: @user,
-          task: overdue.first,
-          csrf: method(:csrf_token),
-          position: 1,
-          total: overdue.size
-        ).call
-      end
+      r.redirect "/"
     end
 
     r.get "calendar" do
-      date = begin
-               Date.parse(r.params["date"].to_s)
-             rescue Date::Error
-               Date.today
-             end
-      Views::Calendar.new(current_user: @user, csrf: method(:csrf_token), date: date).call
+      r.redirect "/"
     end
 
     r.get "agenda" do
-      Views::Agenda.new(current_user: @user, csrf: method(:csrf_token)).call
+      r.redirect "/"
     end
 
     r.on "users", Integer do |user_id|
diff --git a/public/css/app.css b/public/css/app.css
index f506ab5..6769908 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -128,6 +128,11 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   flex: 1;
 }
 
+.dashboard:has(.column-overdue) {
+  max-width: 56rem;
+  margin-inline: auto;
+}
+
 .main-column {
   flex: 1;
   max-width: 32rem;
@@ -135,6 +140,123 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   padding: var(--space-m) var(--space-l);
 }
 
+.column-overdue {
+  flex: 1;
+  min-width: 0;
+  overflow-y: auto;
+  padding: var(--space-m) var(--space-l);
+}
+
+.column-agenda {
+  width: 24rem;
+  flex-shrink: 0;
+  overflow-y: auto;
+  padding: var(--space-m) var(--space-l);
+}
+
+/* -------------------- */
+/* Focus row (minimal) */
+/* -------------------- */
+
+.section--focus {
+}
+
+/* -------------------- */
+/* Agenda (day-by-day) */
+/* -------------------- */
+
+.agenda-week {
+  display: flex;
+  margin-block-end: var(--space-m);
+  border: 1px solid #eee;
+  border-radius: 6px;
+  overflow: hidden;
+}
+
+.agenda-week-day {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 1px;
+  padding: var(--space-3xs) 0 var(--space-2xs);
+  border-inline-end: 1px solid #eee;
+}
+
+.agenda-week-day:last-child {
+  border-inline-end: none;
+}
+
+.agenda-week-label {
+  font-size: 9px;
+  color: #aaa;
+  font-weight: 500;
+  text-transform: uppercase;
+  letter-spacing: 0.03em;
+  padding-block-end: var(--space-3xs);
+  margin-block-end: var(--space-3xs);
+  border-block-end: 1px solid #eee;
+  width: 100%;
+  text-align: center;
+}
+
+.agenda-week-count {
+  font-size: var(--step--1);
+  font-weight: 600;
+  color: #666;
+}
+
+.agenda-week-day--today .agenda-week-count {
+  color: #222;
+}
+
+.agenda-week-day--overdue .agenda-week-label {
+  color: #c00;
+}
+
+.agenda-week-day--overdue .agenda-week-count {
+  color: #c00;
+}
+
+.agenda-day {
+  margin-block-end: var(--space-s);
+}
+
+.agenda-day-header {
+  font-size: var(--step--2);
+  font-weight: 600;
+  color: #888;
+  margin-block-end: var(--space-3xs);
+}
+
+.agenda-day--today .agenda-day-header {
+  color: #222;
+}
+
+.agenda-day-empty {
+  font-size: var(--step--2);
+  color: #ccc;
+  padding-block: 2px;
+}
+
+.agenda-day-pill {
+  display: block;
+  font-size: var(--step--2);
+  padding: 3px 6px;
+  background: #f0f0f0;
+  color: #222;
+  border-radius: 4px;
+  margin-block-end: 3px;
+  text-decoration: none;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.agenda-day-pill:hover {
+  background: #e8e8e8;
+}
+
 /* -------------------- */
 /* Sections (overdue / upcoming) */
 /* -------------------- */
@@ -168,17 +290,34 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   all: unset;
   order: 1;
   font-size: var(--step--1);
-  color: #999;
+  color: #666;
   cursor: pointer;
 }
 
 .section-edit-btn:hover {
-  color: #444;
+  color: #222;
+}
+
+.section-edit-btn--cancel {
+  color: #aaa;
+}
+
+.section-edit-btn--cancel:hover {
+  color: #666;
+}
+
+.section-edit-btn:disabled {
+  color: #ccc;
+  cursor: default;
+  pointer-events: none;
 }
 
 .section-header::after {
   content: "";
   flex: 1;
+}
+
+.main-column .section-header::after {
   height: 1px;
   background: #ddd;
 }
@@ -220,22 +359,20 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   grid-template-columns: auto 1fr auto;
   align-items: baseline;
   gap: var(--space-xs);
-  padding: calc(7px + var(--space-3xs)) 0;
+  padding: var(--space-2xs) var(--space-xs);
+  margin-inline: calc(-1 * var(--space-xs));
   cursor: pointer;
   transition: background 0.1s;
   position: relative;
+  border-radius: 6px;
 }
 
 .task-card:hover {
   background: #f0f0f0;
-  margin-inline: -6px;
-  padding-inline: 6px;
 }
 
 .task-card--selected {
   background: #ebebeb;
-  margin-inline: -6px;
-  padding-inline: 6px;
 }
 
 .task-card--overdue {
@@ -464,9 +601,7 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   border-color: #999;
 }
 
-.series-note:hover {
-  border-color: transparent;
-}
+
 
 .series-note:focus-within {
   border-color: #999;
@@ -949,6 +1084,21 @@ button[type="submit"]:not(.complete-btn):not(.panel-action):hover {
     padding-inline: var(--space-s);
   }
 
+  .dashboard {
+    flex-direction: column;
+  }
+
+  .column-overdue {
+    padding-inline: var(--space-s);
+    padding-block-end: 0;
+  }
+
+  .column-agenda {
+    width: auto;
+    border-inline-start: none;
+    padding: 0 var(--space-s) var(--space-m);
+  }
+
   .panel {
     width: 100vw;
   }
diff --git a/test/test_web.rb b/test/test_web.rb
index 11b77e4..d1749b6 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -34,27 +34,36 @@ class TestWeb < Minitest::Test
   def test_root_shows_empty_state
     get "/", {}, auth_headers
     assert_includes last_response.body, "All caught up!"
-    assert_includes last_response.body, "Nothing upcoming."
   end
 
-  def test_root_shows_active_tasks
-    create_series(note: "Call Mom", first_due_date: "2026-03-01", interval_unit: "week", interval_count: "2")
+  def test_root_shows_overdue_task_in_focus
+    create_series(note: "Call Mom", first_due_date: (Date.today - 3).to_s,
+                  interval_unit: "week", interval_count: "2")
 
     get "/", {}, auth_headers
     assert_includes last_response.body, "Call Mom"
-    assert_includes last_response.body, "Mar 1"
+    assert_includes last_response.body, "Next up"
+  end
+
+  def test_root_shows_upcoming_task_in_agenda
+    create_series(note: "Call Mom", first_due_date: Date.today.to_s,
+                  interval_unit: "week", interval_count: "2")
+
+    get "/", {}, auth_headers
+    assert_includes last_response.body, "Call Mom"
+    assert_includes last_response.body, "agenda-day-pill"
   end
 
   def test_root_only_shows_own_tasks
     create_series(
       note: "Alice task", interval_unit: "week", interval_count: "1",
-      first_due_date: "2026-03-01",
+      first_due_date: (Date.today - 1).to_s,
       headers: auth_headers(login: "alice@example.com")
     )
 
     create_series(
       note: "Bob task", interval_unit: "day", interval_count: "1",
-      first_due_date: "2026-03-01",
+      first_due_date: (Date.today - 1).to_s,
       headers: auth_headers(login: "bob@example.com")
     )
 
@@ -164,7 +173,7 @@ class TestWeb < Minitest::Test
 
   def test_complete_task
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: "2026-03-01")
+                  first_due_date: (Date.today - 3).to_s)
 
     task = DB[:tasks].first
     series = DB[:series].first
@@ -207,7 +216,7 @@ class TestWeb < Minitest::Test
   def test_complete_task_requires_own_task
     create_series(
       note: "Alice task", interval_unit: "day", interval_count: "1",
-      first_due_date: "2026-03-01",
+      first_due_date: (Date.today - 1).to_s,
       headers: auth_headers(login: "alice@example.com")
     )
 
@@ -235,7 +244,7 @@ class TestWeb < Minitest::Test
 
   def test_task_card_links_to_series
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: "2026-03-01")
+                  first_due_date: (Date.today - 3).to_s)
 
     series = DB[:series].first
     get "/", {}, auth_headers
@@ -245,17 +254,17 @@ class TestWeb < Minitest::Test
 
   def test_task_card_has_complete_form
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: "2026-03-01")
+                  first_due_date: (Date.today - 3).to_s)
 
     task = DB[:tasks].first
-    get "/", {}, auth_headers
     series = DB[:series].first
+    get "/", {}, auth_headers
     assert_includes last_response.body, "action=\"/series/#{series[:id]}/tasks/#{task[:id]}/complete\""
   end
 
   def test_task_card_has_csrf_token
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: "2026-03-01")
+                  first_due_date: (Date.today - 3).to_s)
 
     get "/", {}, auth_headers
     assert_includes last_response.body, 'name="_csrf"'
@@ -291,7 +300,7 @@ class TestWeb < Minitest::Test
 
   def test_patch_note_saves_on_completed_task
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "1",
-                  first_due_date: "2026-03-01")
+                  first_due_date: (Date.today - 3).to_s)
 
     task = DB[:tasks].first
     series = DB[:series].first
@@ -319,7 +328,7 @@ class TestWeb < Minitest::Test
   def test_patch_note_requires_own_task
     create_series(
       note: "Alice task", interval_unit: "day", interval_count: "1",
-      first_due_date: "2026-03-01",
+      first_due_date: (Date.today - 1).to_s,
       headers: auth_headers(login: "alice@example.com")
     )
 
@@ -473,17 +482,10 @@ class TestWeb < Minitest::Test
     assert_includes last_response.body, "site-footer"
   end
 
-  def test_header_shows_view_nav
+  def test_header_links_home_and_new
     get "/", {}, auth_headers
     assert_includes last_response.body, 'href="/"'
-    assert_includes last_response.body, 'href="/focus"'
-    assert_includes last_response.body, 'href="/calendar"'
-    assert_includes last_response.body, 'href="/agenda"'
-  end
-
-  def test_header_highlights_active_view
-    get "/", {}, auth_headers
-    assert_includes last_response.body, "view-link--active"
+    assert_includes last_response.body, 'href="/series/new"'
   end
 
   def test_csrf_rejects_post_without_token
@@ -495,84 +497,56 @@ class TestWeb < Minitest::Test
     assert_equal 403, last_response.status
   end
 
-  def test_focus_view_shows_overdue_task
-    create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: (Date.today - 3).to_s)
-
+  def test_focus_redirects_to_root
     get "/focus", {}, auth_headers
-    assert last_response.ok?
-    assert_includes last_response.body, "Call Mom"
-    assert_includes last_response.body, "focus-task"
+    assert last_response.redirect?
+    assert_includes last_response["Location"], "/"
   end
 
-  def test_focus_view_redirects_when_caught_up
-    get "/focus", {}, auth_headers
+  def test_calendar_redirects_to_root
+    get "/calendar", {}, auth_headers
     assert last_response.redirect?
     assert_includes last_response["Location"], "/"
   end
 
-  def test_focus_view_shows_most_urgent_first
+  def test_agenda_redirects_to_root
+    get "/agenda", {}, auth_headers
+    assert last_response.redirect?
+    assert_includes last_response["Location"], "/"
+  end
+
+  def test_dashboard_shows_most_urgent_in_focus
     create_series(note: "Low urgency", interval_unit: "month", interval_count: "1",
                   first_due_date: (Date.today - 1).to_s)
     create_series(note: "High urgency", interval_unit: "day", interval_count: "1",
                   first_due_date: (Date.today - 10).to_s)
 
-    get "/focus", {}, auth_headers
-    assert_includes last_response.body, "High urgency"
+    get "/", {}, auth_headers
+    body = last_response.body
+    # Focus section (first task card) should be the most urgent
+    focus_pos = body.index("Next up")
+    high_pos = body.index("High urgency")
+    low_pos = body.index("Low urgency")
+    assert focus_pos, "Expected Next up section"
+    assert high_pos, "Expected High urgency task"
+    assert low_pos, "Expected Low urgency task"
+    assert high_pos < low_pos, "High urgency should appear before Low urgency"
+  end
+
+  def test_dashboard_agenda_shows_week_strip
+    get "/", {}, auth_headers
+    assert_includes last_response.body, "agenda-week"
   end
 
-  def test_complete_from_focus_redirects_to_focus
+  def test_complete_from_dashboard_redirects_to_series
     create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
                   first_due_date: (Date.today - 3).to_s)
 
     task = DB[:tasks].first
     series = DB[:series].first
-    csrf_post "/series/#{series[:id]}/tasks/#{task[:id]}/complete",
-              { "return_to" => "/focus" }, auth_headers
+    csrf_post "/series/#{series[:id]}/tasks/#{task[:id]}/complete", {}, auth_headers
     assert last_response.redirect?
-    assert_equal "/focus", last_response["Location"]
-  end
-
-  def test_calendar_view_renders
-    get "/calendar", {}, auth_headers
-    assert last_response.ok?
-    assert_includes last_response.body, "calendar-grid"
-  end
-
-  def test_calendar_shows_tasks_on_due_date
-    create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: Date.today.to_s)
-
-    get "/calendar", {}, auth_headers
-    assert_includes last_response.body, "Call Mom"
-  end
-
-  def test_calendar_view_highlights_active
-    get "/calendar", {}, auth_headers
-    assert_includes last_response.body, "view-link--active"
-  end
-
-  def test_agenda_view_renders
-    get "/agenda", {}, auth_headers
-    assert last_response.ok?
-    assert_includes last_response.body, "agenda-view"
-  end
-
-  def test_agenda_shows_overdue_column
-    create_series(note: "Call Mom", interval_unit: "week", interval_count: "2",
-                  first_due_date: (Date.today - 3).to_s)
-
-    get "/agenda", {}, auth_headers
-    assert_includes last_response.body, "Call Mom"
-    assert_includes last_response.body, "agenda-overdue"
-  end
-
-  def test_agenda_shows_upcoming_on_day
-    create_series(note: "Haircut", interval_unit: "week", interval_count: "6",
-                  first_due_date: Date.today.to_s)
-
-    get "/agenda", {}, auth_headers
-    assert_includes last_response.body, "Haircut"
+    assert_includes last_response["Location"], "/series/#{series[:id]}"
   end
 
   private