From 6cc69f444b83d4a0db11f14b8ff1ee75510daab8 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:51:25 +0530 Subject: [PATCH] chore: Include 11:59 PM slot in business hours display (#12610) --- .../settings/inbox/components/BusinessDay.vue | 13 +++-- .../settings/inbox/helpers/businessHour.js | 8 +++ .../inbox/helpers/specs/businessHour.spec.js | 58 ++++++++++++++++++- 3 files changed, 70 insertions(+), 9 deletions(-) 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 14ba5b371..b90ea92ad 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue @@ -96,11 +96,12 @@ export default { return parse(this.toTime, 'hh:mm a', new Date()); }, totalHours() { - if (this.timeSlot.openAllDay) { - return 24; - } - const totalHours = differenceInMinutes(this.toDate, this.fromDate) / 60; - return totalHours; + if (this.timeSlot.openAllDay) return '24h'; + + const totalMinutes = differenceInMinutes(this.toDate, this.fromDate); + const [h, m] = [Math.floor(totalMinutes / 60), totalMinutes % 60]; + + return [h && `${h}h`, m && `${m}m`].filter(Boolean).join(' ') || '0m'; }, hasError() { return !this.timeSlot.valid; @@ -211,7 +212,7 @@ export default { v-if="isDayEnabled && !hasError" class="label bg-n-brand/10 dark:bg-n-brand/30 text-n-blue-text text-xs inline-block px-2 py-1 rounded-lg cursor-default whitespace-nowrap" > - {{ totalHours }} {{ $t('INBOX_MGMT.BUSINESS_HOURS.DAY.HOURS') }} + {{ totalHours }} 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 69089bf3c..b73368035 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/helpers/businessHour.js @@ -53,6 +53,7 @@ export const generateTimeSlots = (step = 15) => { Generates a list of time strings from 12:00 AM to next 24 hours. Each new string will be generated by adding `step` minutes to the previous one. The list is generated by starting with a random day and adding step minutes till end of the same day. + Always includes 11:59 PM as the final slot to complete the day. */ const date = new Date(1970, 1, 1); const slots = []; @@ -66,6 +67,13 @@ export const generateTimeSlots = (step = 15) => { ); date.setMinutes(date.getMinutes() + step); } + + // Always add 11:59 PM as the final slot if it's not already included + const lastSlot = '11:59 PM'; + if (!slots.includes(lastSlot)) { + slots.push(lastSlot); + } + return slots; }; 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 077337ae6..c9cfa2d24 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 @@ -7,10 +7,19 @@ import { } from '../businessHour'; describe('#generateTimeSlots', () => { - it('returns correct number of time slots', () => { - expect(generateTimeSlots(15).length).toStrictEqual((60 / 15) * 24); + it('returns correct number of time slots for 15-minute intervals', () => { + const slots = generateTimeSlots(15); + // 24 hours * 4 slots per hour + 1 for 11:59 PM = 97 slots + expect(slots.length).toStrictEqual(97); }); - it('returns correct time slots', () => { + + it('returns correct number of time slots for 30-minute intervals', () => { + const slots = generateTimeSlots(30); + // 24 hours * 2 slots per hour + 1 for 11:59 PM = 49 slots + expect(slots.length).toStrictEqual(49); + }); + + it('returns correct time slots for 4-hour intervals', () => { expect(generateTimeSlots(240)).toStrictEqual([ '12:00 AM', '04:00 AM', @@ -18,8 +27,51 @@ describe('#generateTimeSlots', () => { '12:00 PM', '04:00 PM', '08:00 PM', + '11:59 PM', ]); }); + + it('always starts with 12:00 AM', () => { + expect(generateTimeSlots(15)[0]).toStrictEqual('12:00 AM'); + expect(generateTimeSlots(30)[0]).toStrictEqual('12:00 AM'); + expect(generateTimeSlots(60)[0]).toStrictEqual('12:00 AM'); + }); + + it('always ends with 11:59 PM', () => { + const slots15 = generateTimeSlots(15); + const slots30 = generateTimeSlots(30); + const slots60 = generateTimeSlots(60); + + expect(slots15[slots15.length - 1]).toStrictEqual('11:59 PM'); + expect(slots30[slots30.length - 1]).toStrictEqual('11:59 PM'); + expect(slots60[slots60.length - 1]).toStrictEqual('11:59 PM'); + }); + + it('includes 11:59 PM even when it would not be in regular intervals', () => { + const slots = generateTimeSlots(30); + expect(slots).toContain('11:59 PM'); + expect(slots).toContain('11:30 PM'); // Regular interval + }); + + it('does not duplicate 11:59 PM if it already exists in regular intervals', () => { + // Test with a step that would naturally include 11:59 PM + const slots = generateTimeSlots(1); // 1-minute intervals + const count11_59 = slots.filter(slot => slot === '11:59 PM').length; + expect(count11_59).toStrictEqual(1); + }); + + it('generates correct time format', () => { + const slots = generateTimeSlots(60); + expect(slots).toContain('01:00 AM'); + expect(slots).toContain('12:00 PM'); + expect(slots).toContain('01:00 PM'); + expect(slots).toContain('11:00 PM'); + }); + + it('handles edge case with very large step', () => { + const slots = generateTimeSlots(1440); // 24 hours + expect(slots).toStrictEqual(['12:00 AM', '11:59 PM']); + }); }); describe('#getTime', () => {