From 2b0c3cb7569003693940d284272adab6f0981f6d Mon Sep 17 00:00:00 2001 From: Mir Bhatia Date: Thu, 7 May 2026 17:07:39 +0200 Subject: [PATCH 1/4] Update title to show date range instead of calendar weeks in month mode --- .../app/components/my/time_tracking/list_component.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/costs/app/components/my/time_tracking/list_component.rb b/modules/costs/app/components/my/time_tracking/list_component.rb index 4ea3c954fb9f..85018e286b93 100644 --- a/modules/costs/app/components/my/time_tracking/list_component.rb +++ b/modules/costs/app/components/my/time_tracking/list_component.rb @@ -67,7 +67,7 @@ def grouped_time_entries def date_title(date) if mode == :month - I18n.t(:label_specific_week, week: week_number(date)) + week_date_range(date) else I18n.l(date, format: "%A %d") end @@ -82,12 +82,8 @@ def month_days date.all_month.map(&:beginning_of_week).uniq end - def week_number(date) - if Setting.start_of_week == 1 # monday - I18n.l(date, format: "%W") - else # 6 saturday, 7 sunday - I18n.l(date, format: "%U") - end + def week_date_range(date) + SubHeaderComponent.new(mode: :week, date:, view_mode: :list).title end def week_start_day From 8d85470e12270814dec8f1fbc763da4e4d0e6002 Mon Sep 17 00:00:00 2001 From: Mir Bhatia Date: Fri, 8 May 2026 10:55:39 +0200 Subject: [PATCH 2/4] Move to helper and remove unused string --- .../my/time_tracking/list_component.rb | 4 +- .../my/time_tracking/sub_header_component.rb | 15 ++---- .../app/helpers/my/time_tracking_helper.rb | 46 +++++++++++++++++++ modules/costs/config/locales/en.yml | 1 - 4 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 modules/costs/app/helpers/my/time_tracking_helper.rb diff --git a/modules/costs/app/components/my/time_tracking/list_component.rb b/modules/costs/app/components/my/time_tracking/list_component.rb index 85018e286b93..d8c44886fd1a 100644 --- a/modules/costs/app/components/my/time_tracking/list_component.rb +++ b/modules/costs/app/components/my/time_tracking/list_component.rb @@ -33,6 +33,7 @@ module TimeTracking class ListComponent < ApplicationComponent include OpTurbo::Streamable include OpPrimer::ComponentHelpers + include My::TimeTrackingHelper options time_entries: [], mode: :week, @@ -82,9 +83,6 @@ def month_days date.all_month.map(&:beginning_of_week).uniq end - def week_date_range(date) - SubHeaderComponent.new(mode: :week, date:, view_mode: :list).title - end def week_start_day case Setting.start_of_week diff --git a/modules/costs/app/components/my/time_tracking/sub_header_component.rb b/modules/costs/app/components/my/time_tracking/sub_header_component.rb index 006792336f68..29f0eba560f2 100644 --- a/modules/costs/app/components/my/time_tracking/sub_header_component.rb +++ b/modules/costs/app/components/my/time_tracking/sub_header_component.rb @@ -31,23 +31,16 @@ module My module TimeTracking class SubHeaderComponent < ApplicationComponent + include My::TimeTrackingHelper + options :date, :mode, :view_mode - def title # rubocop:disable Metrics/AbcSize + def title case mode when :day I18n.l(date, format: :long) when :week, :workweek - bow = date.beginning_of_week - eow = date.end_of_week - - if bow.year == eow.year && bow.month == eow.month - [I18n.l(bow, format: "%d."), I18n.l(eow, format: "%d. %B %Y")].join(" - ") - elsif bow.year == eow.year - [I18n.l(bow, format: "%d. %B"), I18n.l(eow, format: "%d. %B %Y")].join(" - ") - else - [I18n.l(bow, format: "%d. %B %Y"), I18n.l(eow, format: "%d. %B %Y")].join(" - ") - end + week_date_range(date) when :month I18n.l(date, format: "%B %Y") end diff --git a/modules/costs/app/helpers/my/time_tracking_helper.rb b/modules/costs/app/helpers/my/time_tracking_helper.rb new file mode 100644 index 000000000000..025b9b93a418 --- /dev/null +++ b/modules/costs/app/helpers/my/time_tracking_helper.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# -- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +# ++ + +module My + module TimeTrackingHelper + def week_date_range(date) # rubocop:disable Metrics/AbcSize + bow = date.beginning_of_week + eow = date.end_of_week + + if bow.year == eow.year && bow.month == eow.month + [I18n.l(bow, format: "%d."), I18n.l(eow, format: "%d. %B %Y")].join(" - ") + elsif bow.year == eow.year + [I18n.l(bow, format: "%d. %B"), I18n.l(eow, format: "%d. %B %Y")].join(" - ") + else + [I18n.l(bow, format: "%d. %B %Y"), I18n.l(eow, format: "%d. %B %Y")].join(" - ") + end + end + end +end diff --git a/modules/costs/config/locales/en.yml b/modules/costs/config/locales/en.yml index 1ebae1bde1a0..cd8642843f37 100644 --- a/modules/costs/config/locales/en.yml +++ b/modules/costs/config/locales/en.yml @@ -186,7 +186,6 @@ en: label_previous_week: "Previous week" label_previous_month: "Previous month" label_specific_day: "Day %{day}" - label_specific_week: "Calendar week %{week}" label_specific_month: "Month %{month}" label_list: "List" label_month: "Month" From 8c73eb76be99082036c709b33ca1e6dc2acddc90 Mon Sep 17 00:00:00 2001 From: Mir Bhatia Date: Fri, 8 May 2026 11:44:08 +0200 Subject: [PATCH 3/4] Use i18n beginning_of_week --- .../app/helpers/my/time_tracking_helper.rb | 5 +- .../helpers/my/time_tracking_helper_spec.rb | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 modules/costs/spec/helpers/my/time_tracking_helper_spec.rb diff --git a/modules/costs/app/helpers/my/time_tracking_helper.rb b/modules/costs/app/helpers/my/time_tracking_helper.rb index 025b9b93a418..230a75da0c7a 100644 --- a/modules/costs/app/helpers/my/time_tracking_helper.rb +++ b/modules/costs/app/helpers/my/time_tracking_helper.rb @@ -31,8 +31,9 @@ module My module TimeTrackingHelper def week_date_range(date) # rubocop:disable Metrics/AbcSize - bow = date.beginning_of_week - eow = date.end_of_week + start_day = OpenProject::Internationalization::Date.beginning_of_week + bow = date.beginning_of_week(start_day) + eow = date.end_of_week(start_day) if bow.year == eow.year && bow.month == eow.month [I18n.l(bow, format: "%d."), I18n.l(eow, format: "%d. %B %Y")].join(" - ") diff --git a/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb b/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb new file mode 100644 index 000000000000..15f6e872fd3a --- /dev/null +++ b/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require_relative "../../spec_helper" + +RSpec.describe My::TimeTrackingHelper do + describe "#week_date_range" do + subject { helper.week_date_range(date) } + + context "when week starts on Monday", with_settings: { start_of_week: 1 } do + let(:date) { Date.new(2026, 5, 7) } + + it { is_expected.to eq("04. - 10. May 2026") } + end + + context "when week starts on Saturday", with_settings: { start_of_week: 6 } do + let(:date) { Date.new(2026, 5, 7) } + + it { is_expected.to eq("02. - 08. May 2026") } + end + + context "when week starts on Sunday", with_settings: { start_of_week: 7 } do + let(:date) { Date.new(2026, 5, 7) } + + it { is_expected.to eq("03. - 09. May 2026") } + end + + context "when week start is based on language", with_settings: { start_of_week: nil } do + let(:date) { Date.new(2026, 5, 7) } + + context "when the language defines Monday as the first day of the week" do + before { allow(I18n).to receive(:t).with(:general_first_day_of_week).and_return("1") } + + it { is_expected.to eq("04. - 10. May 2026") } + end + + context "when the language defines Sunday as the first day of the week" do + before { allow(I18n).to receive(:t).with(:general_first_day_of_week).and_return("7") } + + it { is_expected.to eq("03. - 09. May 2026") } + end + end + end +end From 1181c549b09304e12d9d749511f868349af94e04 Mon Sep 17 00:00:00 2001 From: Mir Bhatia Date: Fri, 8 May 2026 11:55:21 +0200 Subject: [PATCH 4/4] Add transition case specs --- .../helpers/my/time_tracking_helper_spec.rb | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb b/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb index 15f6e872fd3a..4800e2f91e19 100644 --- a/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb +++ b/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb @@ -67,5 +67,25 @@ it { is_expected.to eq("03. - 09. May 2026") } end end + + context "when rendering the date range string", with_settings: { start_of_week: 1 } do + context "when the week falls within the same month" do + let(:date) { Date.new(2026, 5, 7) } + + it { is_expected.to eq("04. - 10. May 2026") } + end + + context "when the week spans two months" do + let(:date) { Date.new(2026, 4, 30) } + + it { is_expected.to eq("27. April - 03. May 2026") } + end + + context "when the week spans two years" do + let(:date) { Date.new(2025, 12, 31) } + + it { is_expected.to eq("29. December 2025 - 04. January 2026") } + end + end end end