Let Dashboard derive task lists from current_user
The route handler assembled overdue/upcoming arrays that the view
could query itself. Dashboard now takes only current_user and series.
Assisted-by: Claude Opus 4.6 via Claude Code
diff --git a/lib/ketchup/models.rb b/lib/ketchup/models.rb
index 31be73c..399ec55 100644
--- a/lib/ketchup/models.rb
+++ b/lib/ketchup/models.rb
@@ -7,6 +7,18 @@ Sequel::Model.plugin :sole
class User < Sequel::Model
one_to_many :series
+
+ def active_tasks
+ Task.active.for_user(self)
+ end
+
+ def overdue_tasks
+ active_tasks.where { due_date < Date.today }
+ end
+
+ def upcoming_tasks
+ active_tasks.where { due_date >= Date.today }.order(:due_date)
+ end
end
class Series < Sequel::Model
diff --git a/lib/ketchup/views/dashboard.rb b/lib/ketchup/views/dashboard.rb
index 04c3c6d..462827c 100644
--- a/lib/ketchup/views/dashboard.rb
+++ b/lib/ketchup/views/dashboard.rb
@@ -6,12 +6,9 @@ require_relative "layout"
module Views
class Dashboard < Phlex::HTML
- def initialize(current_user:, overdue:, upcoming:,
- selected_series: nil)
+ def initialize(current_user:, series: nil)
@current_user = current_user
- @overdue = overdue
- @upcoming = upcoming
- @selected_series = selected_series
+ @series = series
end
def view_template
@@ -33,7 +30,7 @@ module Views
) { "Urgency" }
end
end
- task_list(@overdue, empty: "Nothing overdue.", sortable: true)
+ task_list(@current_user.overdue_tasks.all.sort_by { |t| -t.urgency }, empty: "Nothing overdue.", sortable: true)
end
div(class: "column", "x-data": "upcoming") do
@@ -46,10 +43,10 @@ module Views
) { "Calendar" }
end
end
- upcoming_list(@upcoming)
+ upcoming_list(@current_user.upcoming_tasks.all)
end
- if @selected_series
+ if @series
series_detail_sidebar
else
new_series_sidebar
@@ -61,7 +58,7 @@ module Views
private
def series_detail_sidebar
- active_task = @selected_series.active_task
+ active_task = @series.active_task
div(class: "column column-aside", "x-data": "{ editing: false }") do
div(class: "column-header") do
h2(class: "aside-heading") do
@@ -83,19 +80,19 @@ module Views
div(
id: "series-note-detail",
class: "task-detail-note",
- "data-value": @selected_series.note || "",
- "data-series-id": @selected_series.id.to_s
+ "data-value": @series.note || "",
+ "data-series-id": @series.id.to_s
)
dl(class: "task-detail-fields") do
dt { "Repeat every" }
dd("x-show": "!editing") do
- plain interval_text(@selected_series.interval_count, @selected_series.interval_unit)
+ plain interval_text(@series.interval_count, @series.interval_unit)
end
dd(
class: "detail-edit-interval",
"x-show": "editing",
"x-cloak": true,
- "x-data": "intervalEditor(#{@selected_series.id}, #{@selected_series.interval_count}, '#{@selected_series.interval_unit}')",
+ "x-data": "intervalEditor(#{@series.id}, #{@series.interval_count}, '#{@series.interval_unit}')",
) do
input(
type: "number",
@@ -126,7 +123,7 @@ module Views
dd(
"x-show": "editing",
"x-cloak": true,
- "x-data": "dueDateEditor(#{@selected_series.id}, '#{active_task[:due_date]}')"
+ "x-data": "dueDateEditor(#{@series.id}, '#{active_task[:due_date]}')"
) do
input(
type: "date",
@@ -143,11 +140,11 @@ module Views
end
end
- unless @selected_series.completed_tasks.empty?
+ unless @series.completed_tasks.empty?
div(class: "task-history") do
h3 { "History" }
ul do
- @selected_series.completed_tasks.each do |ct|
+ @series.completed_tasks.each do |ct|
li(class: "task-history-item") do
div(class: "task-history-row") do
span(class: "task-history-check") { "✓" }
@@ -303,7 +300,7 @@ module Views
def task_card(task, sortable: false)
name = task[:note].lines.first&.strip || task[:note]
overdue = task[:due_date] < Date.today
- selected = @selected_series && @selected_series.id == task[:series_id]
+ selected = @series && @series.id == task[:series_id]
div(class: ["task-card", ("task-overdue" if overdue), ("task-selected" if selected)]) do
form(method: "post", action: "/tasks/#{task[:id]}/complete", class: "complete-form") do
diff --git a/lib/ketchup/web.rb b/lib/ketchup/web.rb
index 0b326fe..3ebe052 100644
--- a/lib/ketchup/web.rb
+++ b/lib/ketchup/web.rb
@@ -19,20 +19,11 @@ class Web < Roda
User.find_or_create(login: login) { |u| u.name = name }
end
- def active_tasks_for(user)
- all_tasks = Task.active.for_user(user).all
- overdue, upcoming = all_tasks.partition { |t| t.urgency > 0 }
- overdue.sort_by! { |t| -t.urgency }
- upcoming.sort_by! { |t| t[:due_date] }
- [overdue, upcoming]
- end
-
route do |r|
r.halt 403 unless current_user
r.root do
- overdue, upcoming = active_tasks_for(current_user)
- Views::Dashboard.new(current_user:, overdue:, upcoming:).call
+ Views::Dashboard.new(current_user:).call
end
r.on "tasks", Integer do |task_id|
@@ -66,12 +57,7 @@ class Web < Roda
r.halt 404 unless series
r.get do
- overdue, upcoming = active_tasks_for(current_user)
-
- Views::Dashboard.new(
- current_user:, overdue:, upcoming:,
- selected_series: series
- ).call
+ Views::Dashboard.new(current_user:, series:).call
end
r.patch do