diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index 27172cdba..538d6d5f0 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -463,7 +463,8 @@ "HOURS": "hours", "VALIDATION_ERROR": "Starting time should be before closing time.", "CHOOSE": "Choose" - } + }, + "ALL_DAY":"All-Day" }, "IMAP": { "TITLE": "IMAP", diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue index a0701e2cb..119dd149a 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue @@ -4,7 +4,7 @@ @@ -14,26 +14,38 @@
+
+ + {{ $t('INBOX_MGMT.BUSINESS_HOURS.ALL_DAY') }} +
@@ -79,9 +91,14 @@ export default { }, }, computed: { - timeSlots() { + fromTimeSlots() { return timeSlots; }, + toTimeSlots() { + return timeSlots.filter(slot => { + return slot !== '12:00 AM'; + }); + }, isDayEnabled: { get() { return this.timeSlot.from && this.timeSlot.to; @@ -93,12 +110,14 @@ export default { from: timeSlots[0], to: timeSlots[16], valid: true, + openAllDay: false, } : { ...this.timeSlot, from: '', to: '', valid: false, + openAllDay: false, }; this.$emit('update', newSlot); }, @@ -146,15 +165,39 @@ export default { return parse(this.toTime, 'hh:mm a', new Date()); }, totalHours() { - const totalHours = differenceInMinutes(this.toDate, this.fromDate) / 60; - if (this.toTime === '12:00 AM') { - return 24 + totalHours; + if (this.timeSlot.openAllDay) { + return 24; } + const totalHours = differenceInMinutes(this.toDate, this.fromDate) / 60; return totalHours; }, hasError() { return !this.timeSlot.valid; }, + isOpenAllDay: { + get() { + return this.timeSlot.openAllDay; + }, + set(value) { + if (value) { + this.$emit('update', { + ...this.timeSlot, + from: '12:00 AM', + to: '11:59 PM', + valid: true, + openAllDay: value, + }); + } else { + this.$emit('update', { + ...this.timeSlot, + from: '09:00 AM', + to: '05:00 PM', + valid: true, + openAllDay: value, + }); + } + }, + }, }, }; @@ -182,7 +225,7 @@ export default { box-sizing: content-box; border-bottom: 1px solid var(--color-border-light); } -.enable-day { +.enable-checkbox { margin: 0; } @@ -240,4 +283,17 @@ export default { font-size: var(--font-size-mini); color: var(--r-300); } + +.open-all-day { + margin-right: var(--space-medium); + span { + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + margin-left: var(--space-smaller); + } + input { + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + } +} diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js b/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js index 2bd9a281a..69089bf3c 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js @@ -86,6 +86,7 @@ export const timeSlotParse = timeSlots => { close_hour: closeHour, close_minutes: closeMinutes, closed_all_day: closedAllDay, + open_all_day: openAllDay, } = slot; const from = closedAllDay ? '' : getTime(openHour, openMinutes); const to = closedAllDay ? '' : getTime(closeHour, closeMinutes); @@ -95,13 +96,15 @@ export const timeSlotParse = timeSlots => { to, from, valid: !closedAllDay, + openAllDay, }; }); }; export const timeSlotTransform = timeSlots => { return timeSlots.map(slot => { - const closed = !(slot.to && slot.from); + const closed = slot.openAllDay ? false : !(slot.to && slot.from); + const openAllDay = slot.openAllDay; let fromDate = ''; let toDate = ''; let openHour = ''; @@ -125,6 +128,7 @@ export const timeSlotTransform = timeSlots => { open_minutes: openMinutes, close_hour: closeHour, close_minutes: closeMinutes, + open_all_day: openAllDay, }; }); }; diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/specs/businessHour.spec.js b/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/specs/businessHour.spec.js index d6534cb5e..077337ae6 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/specs/businessHour.spec.js +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/specs/businessHour.spec.js @@ -40,6 +40,7 @@ describe('#timeSlotParse', () => { close_hour: 4, close_minutes: 30, closed_all_day: false, + open_all_day: false, }; expect(timeSlotParse([slot])).toStrictEqual([ @@ -48,6 +49,7 @@ describe('#timeSlotParse', () => { from: '01:30 AM', to: '04:30 AM', valid: true, + openAllDay: false, }, ]); }); @@ -60,6 +62,7 @@ describe('#timeSlotTransform', () => { from: '01:30 AM', to: '04:30 AM', valid: true, + openAllDay: false, }; expect(timeSlotTransform([slot])).toStrictEqual([ @@ -70,6 +73,7 @@ describe('#timeSlotTransform', () => { close_hour: 4, close_minutes: 30, closed_all_day: false, + open_all_day: false, }, ]); }); diff --git a/app/javascript/widget/mixins/availability.js b/app/javascript/widget/mixins/availability.js index 730c09c95..c797f79e4 100644 --- a/app/javascript/widget/mixins/availability.js +++ b/app/javascript/widget/mixins/availability.js @@ -31,9 +31,12 @@ export default { closeHour, closeMinute, closedAllDay, + openAllDay, } = this.currentDayAvailability; const { utcOffset } = this.channelConfig; + if (openAllDay) return true; + if (closedAllDay) return false; const startTime = buildDateFromTime(openHour, openMinute, utcOffset); @@ -56,6 +59,7 @@ export default { openMinute: workingHourConfig.open_minutes, closeHour: workingHourConfig.close_hour, closeMinute: workingHourConfig.close_minutes, + openAllDay: workingHourConfig.open_all_day, }; }, isInBusinessHours() { diff --git a/app/models/concerns/out_of_offisable.rb b/app/models/concerns/out_of_offisable.rb index e22dd668c..f1753a5f8 100644 --- a/app/models/concerns/out_of_offisable.rb +++ b/app/models/concerns/out_of_offisable.rb @@ -3,7 +3,7 @@ module OutOfOffisable extend ActiveSupport::Concern - OFFISABLE_ATTRS = %w[day_of_week closed_all_day open_hour open_minutes close_hour close_minutes].freeze + OFFISABLE_ATTRS = %w[day_of_week closed_all_day open_hour open_minutes close_hour close_minutes open_all_day].freeze included do has_many :working_hours, dependent: :destroy_async @@ -29,7 +29,8 @@ module OutOfOffisable # "open_hour"=>9, # "open_minutes"=>0, # "close_hour"=>17, - # "close_minutes"=>0},...] + # "close_minutes"=>0, + # "open_all_day=>false" },...] def update_working_hours(params) ActiveRecord::Base.transaction do params.each do |working_hour| @@ -41,12 +42,12 @@ module OutOfOffisable private def create_default_working_hours - working_hours.create!(day_of_week: 0, closed_all_day: true) - working_hours.create!(day_of_week: 1, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0) - working_hours.create!(day_of_week: 2, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0) - working_hours.create!(day_of_week: 3, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0) - working_hours.create!(day_of_week: 4, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0) - working_hours.create!(day_of_week: 5, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0) - working_hours.create!(day_of_week: 6, closed_all_day: true) + working_hours.create!(day_of_week: 0, closed_all_day: true, open_all_day: false) + working_hours.create!(day_of_week: 1, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0, open_all_day: false) + working_hours.create!(day_of_week: 2, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0, open_all_day: false) + working_hours.create!(day_of_week: 3, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0, open_all_day: false) + working_hours.create!(day_of_week: 4, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0, open_all_day: false) + working_hours.create!(day_of_week: 5, open_hour: 9, open_minutes: 0, close_hour: 17, close_minutes: 0, open_all_day: false) + working_hours.create!(day_of_week: 6, closed_all_day: true, open_all_day: false) end end diff --git a/app/models/working_hour.rb b/app/models/working_hour.rb index 890a452ba..885165da2 100644 --- a/app/models/working_hour.rb +++ b/app/models/working_hour.rb @@ -7,6 +7,7 @@ # close_minutes :integer # closed_all_day :boolean default(FALSE) # day_of_week :integer not null +# open_all_day :boolean default(FALSE) # open_hour :integer # open_minutes :integer # created_at :datetime not null @@ -22,6 +23,7 @@ class WorkingHour < ApplicationRecord belongs_to :inbox + before_validation :ensure_open_all_day_hours before_save :assign_account validates :open_hour, presence: true, unless: :closed_all_day? @@ -35,6 +37,7 @@ class WorkingHour < ApplicationRecord validates :close_minutes, inclusion: 0..59, unless: :closed_all_day? validate :close_after_open, unless: :closed_all_day? + validate :open_all_day_and_closed_all_day def self.today find_by(day_of_week: Date.current.wday) @@ -69,4 +72,19 @@ class WorkingHour < ApplicationRecord errors.add(:close_hour, 'Closing time cannot be before opening time') end + + def ensure_open_all_day_hours + return unless open_all_day? + + self.open_hour = 0 + self.open_minutes = 0 + self.close_hour = 23 + self.close_minutes = 59 + end + + def open_all_day_and_closed_all_day + return unless open_all_day? && closed_all_day? + + errors.add(:base, 'open_all_day and closed_all_day cannot be true at the same time') + end end diff --git a/db/migrate/20220216151613_add_open_all_day_to_working_hour.rb b/db/migrate/20220216151613_add_open_all_day_to_working_hour.rb new file mode 100644 index 000000000..138f6edb6 --- /dev/null +++ b/db/migrate/20220216151613_add_open_all_day_to_working_hour.rb @@ -0,0 +1,5 @@ +class AddOpenAllDayToWorkingHour < ActiveRecord::Migration[6.1] + def change + add_column :working_hours, :open_all_day, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index c1cd951ab..8c37b7897 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -773,6 +773,7 @@ ActiveRecord::Schema.define(version: 2022_02_18_120357) do t.integer "close_minutes" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.boolean "open_all_day", default: false t.index ["account_id"], name: "index_working_hours_on_account_id" t.index ["inbox_id"], name: "index_working_hours_on_inbox_id" end diff --git a/spec/models/working_hour_spec.rb b/spec/models/working_hour_spec.rb index 73cb4efdf..c126f6f87 100644 --- a/spec/models/working_hour_spec.rb +++ b/spec/models/working_hour_spec.rb @@ -50,4 +50,42 @@ RSpec.describe WorkingHour do expect(described_class.today.closed_now?).to be true end end + + context 'when open_all_day is true' do + let(:inbox) { create(:inbox) } + + before do + Time.zone = 'UTC' + inbox.working_hours.find_by(day_of_week: 5).update(open_all_day: true) + travel_to '18.02.2022 11:00'.to_datetime + end + + it 'updates open hour and close hour' do + expect(described_class.today.open_all_day?).to be true + expect(described_class.today.open_hour).to be 0 + expect(described_class.today.open_minutes).to be 0 + expect(described_class.today.close_hour).to be 23 + expect(described_class.today.close_minutes).to be 59 + end + end + + context 'when open_all_day and closed_all_day true at the same time' do + let(:inbox) { create(:inbox) } + + before do + Time.zone = 'UTC' + inbox.working_hours.find_by(day_of_week: 5).update(open_all_day: true) + travel_to '18.02.2022 11:00'.to_datetime + end + + it 'throws validation error' do + working_hour = inbox.working_hours.find_by(day_of_week: 5) + working_hour.closed_all_day = true + expect(working_hour.invalid?).to be true + expect do + working_hour.save! + end.to raise_error(ActiveRecord::RecordInvalid, + 'Validation failed: open_all_day and closed_all_day cannot be true at the same time') + end + end end