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..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, @@ -67,7 +68,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,13 +83,6 @@ 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 - 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..230a75da0c7a --- /dev/null +++ b/modules/costs/app/helpers/my/time_tracking_helper.rb @@ -0,0 +1,47 @@ +# 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 + 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(" - ") + 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" 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..4800e2f91e19 --- /dev/null +++ b/modules/costs/spec/helpers/my/time_tracking_helper_spec.rb @@ -0,0 +1,91 @@ +# 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 + + 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