diff --git a/.changeset/brown-llamas-worry.md b/.changeset/brown-llamas-worry.md new file mode 100644 index 00000000000..9cbf74ba731 --- /dev/null +++ b/.changeset/brown-llamas-worry.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/rest-typings": patch +--- + +Adds a deprecation warning for `livechat:saveBusinessHour` and new endpoint replacing it; `livechat/business-hours.save` diff --git a/apps/meteor/app/livechat/imports/server/rest/businessHours.ts b/apps/meteor/app/livechat/imports/server/rest/businessHours.ts index fc0f6209b42..699ed63922f 100644 --- a/apps/meteor/app/livechat/imports/server/rest/businessHours.ts +++ b/apps/meteor/app/livechat/imports/server/rest/businessHours.ts @@ -1,7 +1,16 @@ -import { isGETBusinessHourParams } from '@rocket.chat/rest-typings'; +import type { ILivechatBusinessHour } from '@rocket.chat/core-typings'; +import { + isGETBusinessHourParams, + isPOSTLivechatBusinessHoursSaveParams, + POSTLivechatBusinessHoursSaveSuccessResponse, + validateBadRequestErrorResponse, + validateUnauthorizedErrorResponse, +} from '@rocket.chat/rest-typings'; import { API } from '../../../../api/server'; +import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; import { findLivechatBusinessHour } from '../../../server/api/lib/businessHours'; +import { businessHourManager } from '../../../server/business-hour'; API.v1.addRoute( 'livechat/business-hour', @@ -16,3 +25,31 @@ API.v1.addRoute( }, }, ); + +const livechatBusinessHoursEndpoints = API.v1.post( + 'livechat/business-hours.save', + { + response: { + 200: POSTLivechatBusinessHoursSaveSuccessResponse, + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + }, + authRequired: true, + body: isPOSTLivechatBusinessHoursSaveParams, + }, + async function action() { + const params = this.bodyParams; + + // TODO: Remove typecasting after refactoring saveBusinessHour logic with proper type logic. See: CORE-1552 + const result = await businessHourManager.saveBusinessHour(params as unknown as ILivechatBusinessHour); + + return API.v1.success(result); + } +); + +type LivechatBusinessHoursEndpoints = ExtractRoutesFromAPI; + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface + interface Endpoints extends LivechatBusinessHoursEndpoints {} +} diff --git a/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts b/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts index 9bf32697fae..43534f86a7b 100644 --- a/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts +++ b/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts @@ -2,6 +2,7 @@ import type { ILivechatBusinessHour } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Meteor } from 'meteor/meteor'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; import { businessHourManager } from '../business-hour'; declare module '@rocket.chat/ddp-client' { @@ -13,6 +14,7 @@ declare module '@rocket.chat/ddp-client' { Meteor.methods({ async 'livechat:saveBusinessHour'(businessHourData) { + methodDeprecationLogger.method('livechat:saveBusinessHour', '8.0.0', '/v1/livechat/business-hours.save'); try { await businessHourManager.saveBusinessHour(businessHourData); } catch (e) { diff --git a/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHours.tsx b/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHours.tsx index 7e3ec642c1a..006b420e3b6 100644 --- a/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHours.tsx +++ b/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHours.tsx @@ -1,7 +1,7 @@ import type { ILivechatBusinessHour, LivechatBusinessHourTypes, Serialized } from '@rocket.chat/core-typings'; import { Box, Button, ButtonGroup } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { useToastMessageDispatch, useMethod, useTranslation, useRouter } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useTranslation, useRouter, useEndpoint } from '@rocket.chat/ui-contexts'; import { useId } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; @@ -39,7 +39,7 @@ const EditBusinessHours = ({ businessHourData, type }: EditBusinessHoursProps) = const dispatchToastMessage = useToastMessageDispatch(); const isSingleBH = useIsSingleBusinessHours(); - const saveBusinessHour = useMethod('livechat:saveBusinessHour'); + const saveBusinessHour = useEndpoint('POST', '/v1/livechat/business-hours.save'); const handleRemove = useRemoveBusinessHour(); const router = useRouter(); @@ -69,7 +69,7 @@ const EditBusinessHours = ({ businessHourData, type }: EditBusinessHoursProps) = })), }; - await saveBusinessHour(payload as any); + await saveBusinessHour(payload); dispatchToastMessage({ type: 'success', message: t('Business_hours_updated') }); router.navigate('/omnichannel/businessHours'); } catch (error) { diff --git a/apps/meteor/tests/data/livechat/businessHours.ts b/apps/meteor/tests/data/livechat/businessHours.ts index ad835b0cff2..b21882def86 100644 --- a/apps/meteor/tests/data/livechat/businessHours.ts +++ b/apps/meteor/tests/data/livechat/businessHours.ts @@ -1,5 +1,6 @@ import type { ILivechatBusinessHour } from '@rocket.chat/core-typings'; import { LivechatBusinessHourTypes } from '@rocket.chat/core-typings'; +import type { POSTLivechatBusinessHoursSaveParams } from '@rocket.chat/rest-typings'; import moment from 'moment'; import { api, credentials, methodCall, request } from '../api-data'; @@ -9,26 +10,30 @@ type ISaveBhApiWorkHour = Omit workHours: { day: string; start: string; finish: string; open: boolean }[]; } & { departmentsToApplyBusinessHour?: string } & { timezoneName: string }; -// TODO: Migrate to an API call and return the business hour updated/created -export const saveBusinessHour = async (businessHour: ISaveBhApiWorkHour) => { - const { body } = await request - .post(methodCall('livechat:saveBusinessHour')) - .set(credentials) - .send({ message: JSON.stringify({ params: [businessHour], msg: 'method', method: 'livechat:saveBusinessHour', id: '101' }) }) - .expect(200); +export const saveBusinessHour = async (businessHour: POSTLivechatBusinessHoursSaveParams) => { + const { body } = await request.post(api('livechat/business-hours.save')).set(credentials).send(businessHour); - return JSON.parse(body.message); + return body; }; export const createCustomBusinessHour = async (departments: string[], open = true): Promise => { const name = `business-hour-${Date.now()}`; - const businessHour: ISaveBhApiWorkHour = { + const businessHour: POSTLivechatBusinessHoursSaveParams = { name, active: true, type: LivechatBusinessHourTypes.CUSTOM, workHours: getWorkHours(open), timezoneName: 'Asia/Calcutta', + timezone: 'Asia/Calcutta', departmentsToApplyBusinessHour: '', + daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + daysTime: [ + { day: 'Monday', start: { time: '08:00' }, finish: { time: '18:00' }, open }, + { day: 'Tuesday', start: { time: '08:00' }, finish: { time: '18:00' }, open }, + { day: 'Wednesday', start: { time: '08:00' }, finish: { time: '18:00' }, open }, + { day: 'Thursday', start: { time: '08:00' }, finish: { time: '18:00' }, open }, + { day: 'Friday', start: { time: '08:00' }, finish: { time: '18:00' }, open }, + ], }; if (departments.length) { @@ -56,31 +61,35 @@ export const makeDefaultBusinessHourActiveAndClosed = async () => { body: { businessHour }, } = await request.get(api('livechat/business-hour')).query({ type: 'default' }).set(credentials).send(); - // TODO: Refactor this to use openOrCloseBusinessHour() instead - const workHours = businessHour.workHours as { start: string; finish: string; day: string; open: boolean }[]; - const allEnabledWorkHours = workHours.map((workHour) => { - workHour.open = true; - workHour.start = '00:00'; - workHour.finish = '00:01'; // if a job runs between 00:00 and 00:01, then this test will fail :P - return workHour; - }); + const { workHours } = businessHour; + + // Remove properties not accepted by the endpoint schema + const { _updatedAt, ts, ...cleanedBusinessHour } = businessHour; const enabledBusinessHour = { - ...businessHour, - workHours: allEnabledWorkHours, + ...cleanedBusinessHour, + timezoneName: 'America/Sao_Paulo', + timezone: 'America/Sao_Paulo', + departmentsToApplyBusinessHour: '', + daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + daysTime: workHours.map((workHour: { open: boolean; start: { time: string }; finish: { time: string }; day: string }) => { + return { + open: true, + start: { time: '00:00' }, + finish: { time: '00:01' }, + day: workHour.day, + }; + }), + workHours: workHours.map((workHour: { open: boolean; start: string; finish: string; day: string; code?: number }) => { + workHour.open = true; + workHour.start = '00:00'; + workHour.finish = '00:01'; // if a job runs between 00:00 and 00:01, then this test will fail :P + delete workHour.code; + return workHour; + }), }; - await request - .post(methodCall('livechat:saveBusinessHour')) - .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:saveBusinessHour', - params: [enabledBusinessHour], - id: 'id', - msg: 'method', - }), - }); + return request.post(api('livechat/business-hours.save')).set(credentials).send(enabledBusinessHour).expect(200); }; export const disableDefaultBusinessHour = async () => { @@ -93,31 +102,33 @@ export const disableDefaultBusinessHour = async () => { body: { businessHour }, } = await request.get(api('livechat/business-hour')).query({ type: 'default' }).set(credentials).send(); - // TODO: Refactor this to use openOrCloseBusinessHour() instead - const workHours = businessHour.workHours as { start: string; finish: string; day: string; open: boolean }[]; - const allDisabledWorkHours = workHours.map((workHour) => { - workHour.open = false; - workHour.start = '00:00'; - workHour.finish = '23:59'; - return workHour; - }); + const { workHours } = businessHour; + // Remove properties not accepted by the endpoint schema + const { _updatedAt, ts, ...cleanedBusinessHour } = businessHour; const disabledBusinessHour = { - ...businessHour, - workHours: allDisabledWorkHours, + ...cleanedBusinessHour, + timezoneName: 'America/Sao_Paulo', + timezone: 'America/Sao_Paulo', + departmentsToApplyBusinessHour: '', + daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + daysTime: workHours.map((workHour: { open: boolean; start: { time: string }; finish: { time: string }; day: string }) => { + return { + open: false, + start: { time: '00:00' }, + finish: { time: '23:59' }, + day: workHour.day, + }; + }), + workHours: workHours.map((workHour: { open: boolean; start: string; finish: string; day: string }) => { + workHour.open = false; + workHour.start = '00:00'; + workHour.finish = '23:59'; + return workHour; + }), }; - await request - .post(methodCall('livechat:saveBusinessHour')) - .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:saveBusinessHour', - params: [disabledBusinessHour], - id: 'id', - msg: 'method', - }), - }); + return request.post(api('livechat/business-hours.save')).set(credentials).send(disabledBusinessHour).expect(200); }; const removeCustomBusinessHour = async (businessHourId: string) => { @@ -167,10 +178,15 @@ export const getCustomBusinessHourById = async (businessHourId: string): Promise return response.body.businessHour; }; +// TODO: Refactor logic so object passed is of the correct type for POST /livechat/business-hours.save. See: CORE-1552 export const openOrCloseBusinessHour = async (businessHour: ILivechatBusinessHour, open: boolean) => { + const { _updatedAt, ts, ...cleanedBusinessHour } = businessHour; + const timezoneName = businessHour.timezone.name; + const enabledBusinessHour = { - ...businessHour, - timezoneName: businessHour.timezone.name, + ...cleanedBusinessHour, + timezoneName, + timezone: timezoneName, workHours: getWorkHours().map((workHour) => { return { ...workHour, diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts index 90eff68549f..f1904e053cd 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts @@ -1,4 +1,3 @@ -import { faker } from '@faker-js/faker'; import type { Page } from '@playwright/test'; import { IS_EE } from '../config/constants'; @@ -19,7 +18,6 @@ test.describe('OC - Business Hours', () => { let department2: Awaited>; let agent: Awaited>; - const BHid = faker.string.uuid(); const BHName = 'TEST Business Hours'; test.beforeAll(async ({ api }) => { @@ -89,7 +87,6 @@ test.describe('OC - Business Hours', () => { test('OC - Business hours - Edit BH departments', async ({ api, page }) => { await test.step('expect to create new businessHours', async () => { const createBH = await createBusinessHour(api, { - id: BHid, name: BHName, departments: [department.data._id], }); @@ -139,7 +136,6 @@ test.describe('OC - Business Hours', () => { test('OC - Business hours - Toggle BH active status', async ({ api, page }) => { await test.step('expect to create new businessHours', async () => { const createBH = await createBusinessHour(api, { - id: BHid, name: BHName, departments: [department.data._id], }); diff --git a/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts b/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts index 7d4aced1e36..c876fd7cf97 100644 --- a/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts +++ b/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts @@ -7,41 +7,30 @@ type CreateBusinessHoursParams = { departments?: { departmentId: string }[]; }; -export const createBusinessHour = async (api: BaseTest['api'], { id = null, name, departments = [] }: CreateBusinessHoursParams = {}) => { +export const createBusinessHour = async (api: BaseTest['api'], { name, departments = [] }: CreateBusinessHoursParams = {}) => { const departmentIds = departments.join(','); - const response = await api.post('/method.call/livechat:saveBusinessHour', { - message: JSON.stringify({ - msg: 'method', - id: id || '33', - method: 'livechat:saveBusinessHour', - params: [ - { - name, - timezoneName: 'America/Sao_Paulo', - daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - daysTime: [ - { day: 'Monday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, - { day: 'Tuesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, - { day: 'Wednesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, - { day: 'Thursday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, - { day: 'Friday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, - ], - departmentsToApplyBusinessHour: departmentIds, - active: true, - type: 'custom', - timezone: 'America/Sao_Paulo', - workHours: [ - { day: 'Monday', start: '08:00', finish: '18:00', open: true }, - { day: 'Tuesday', start: '08:00', finish: '18:00', open: true }, - { day: 'Wednesday', start: '08:00', finish: '18:00', open: true }, - { day: 'Thursday', start: '08:00', finish: '18:00', open: true }, - { day: 'Friday', start: '08:00', finish: '18:00', open: true }, - ], - }, - ], - }), + return api.post('/livechat/business-hours.save', { + name, + timezoneName: 'America/Sao_Paulo', + daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + daysTime: [ + { day: 'Monday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Tuesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Wednesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Thursday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Friday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + ], + departmentsToApplyBusinessHour: departmentIds, + active: true, + type: 'custom', + timezone: 'America/Sao_Paulo', + workHours: [ + { day: 'Monday', start: '08:00', finish: '18:00', open: true }, + { day: 'Tuesday', start: '08:00', finish: '18:00', open: true }, + { day: 'Wednesday', start: '08:00', finish: '18:00', open: true }, + { day: 'Thursday', start: '08:00', finish: '18:00', open: true }, + { day: 'Friday', start: '08:00', finish: '18:00', open: true }, + ], }); - - return response; }; diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index 07dce78e14c..fde41281910 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -49,12 +49,11 @@ describe('LIVECHAT - business hours', () => { let defaultBhId: any; describe('[CE] livechat/business-hour', () => { after(async () => { + const { _updatedAt, ts, ...cleanedBusinessHour } = defaultBhId; await saveBusinessHour({ - ...defaultBhId, - timezone: { - name: 'America/Sao_Paulo', - utc: '-03:00', - }, + ...cleanedBusinessHour, + timezone: 'America/Sao_Paulo', + timezoneName: 'America/Sao_Paulo', workHours: getWorkHours(true), }); }); @@ -89,8 +88,11 @@ describe('LIVECHAT - business hours', () => { defaultBhId = response.body.businessHour; }); it('should not allow a user to be available if BH are closed', async () => { + const { _updatedAt, ts, ...cleanedBusinessHour } = defaultBhId; await saveBusinessHour({ - ...defaultBhId, + ...cleanedBusinessHour, + timezone: 'America/Sao_Paulo', + timezoneName: 'America/Sao_Paulo', workHours: [ { day: 'Monday', @@ -107,8 +109,11 @@ describe('LIVECHAT - business hours', () => { expect(body.error).to.be.equal('error-business-hours-are-closed'); }); it('should allow a user to be available if BH are open', async () => { + const { _updatedAt, ts, ...cleanedBusinessHour } = defaultBhId; await saveBusinessHour({ - ...defaultBhId, + ...cleanedBusinessHour, + timezone: 'America/Sao_Paulo', + timezoneName: 'America/Sao_Paulo', workHours: getWorkHours(true), }); @@ -117,12 +122,10 @@ describe('LIVECHAT - business hours', () => { expect(body).to.have.property('success', true); }); it('should save a default business hour with proper timezone settings', async () => { + const { _updatedAt, ts, ...cleanedBusinessHour } = defaultBhId; await saveBusinessHour({ - ...defaultBhId, - timezone: { - name: 'Asia/Kolkata', - utc: '+05:30', - }, + ...cleanedBusinessHour, + timezone: 'Asia/Kolkata', workHours: getWorkHours(true), timezoneName: 'Asia/Kolkata', }); @@ -183,21 +186,11 @@ describe('LIVECHAT - business hours', () => { name, active: true, type: LivechatBusinessHourTypes.CUSTOM, - workHours: [ - { - day: 'Monday', - open: true, - // @ts-expect-error - this is valid for endpoint, actual type converts this into an object - start: '08:00', - // @ts-expect-error - same as previous one - finish: '18:00', - }, - ], - timezone: { - name: 'America/Sao_Paulo', - utc: '-03:00', - }, + workHours: [{ day: 'Monday', start: '08:00', finish: '18:00', open: true }], + daysOpen: ['Monday'], + daysTime: [{ day: 'Monday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }], departmentsToApplyBusinessHour: '', + timezone: 'America/Sao_Paulo', timezoneName: 'America/Sao_Paulo', }); @@ -222,20 +215,10 @@ describe('LIVECHAT - business hours', () => { name, active: true, type: LivechatBusinessHourTypes.CUSTOM, - workHours: [ - { - day: 'Monday', - open: true, - // @ts-expect-error - this is valid for endpoint, actual type converts this into an object - start: '08:00', - // @ts-expect-error - same as previous one - finish: '08:00', - }, - ], - timezone: { - name: 'America/Sao_Paulo', - utc: '-03:00', - }, + workHours: [{ day: 'Monday', open: true, start: '08:00', finish: '08:00' }], + daysOpen: ['Monday'], + daysTime: [{ day: 'Monday', start: { time: '08:00' }, finish: { time: '08:00' }, open: true }], + timezone: 'America/Sao_Paulo', departmentsToApplyBusinessHour: '', timezoneName: 'America/Sao_Paulo', }); @@ -249,20 +232,10 @@ describe('LIVECHAT - business hours', () => { name, active: true, type: LivechatBusinessHourTypes.CUSTOM, - workHours: [ - { - day: 'Monday', - open: true, - // @ts-expect-error - this is valid for endpoint, actual type converts this into an object - start: '10:00', - // @ts-expect-error - same as previous one - finish: '08:00', - }, - ], - timezone: { - name: 'America/Sao_Paulo', - utc: '-03:00', - }, + workHours: [{ day: 'Monday', open: true, start: '10:00', finish: '08:00' }], + daysOpen: ['Monday'], + daysTime: [{ day: 'Monday', start: { time: '10:00' }, finish: { time: '08:00' }, open: true }], + timezone: 'America/Sao_Paulo', departmentsToApplyBusinessHour: '', timezoneName: 'America/Sao_Paulo', }); @@ -276,20 +249,10 @@ describe('LIVECHAT - business hours', () => { name, active: true, type: LivechatBusinessHourTypes.CUSTOM, - workHours: [ - { - day: 'Monday', - open: true, - // @ts-expect-error - this is valid for endpoint, actual type converts this into an object - start: '20000', - // @ts-expect-error - same as previous one - finish: 'xxxxx', - }, - ], - timezone: { - name: 'America/Sao_Paulo', - utc: '-03:00', - }, + workHours: [{ day: 'Monday', open: true, start: '20000', finish: 'xxxxx' }], + daysOpen: ['Monday'], + daysTime: [{ day: 'Monday', start: { time: '20000' }, finish: { time: 'xxxxx' }, open: true }], + timezone: 'America/Sao_Paulo', departmentsToApplyBusinessHour: '', timezoneName: 'America/Sao_Paulo', }); diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index 81107a2c2dc..e71457aa6cc 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -3285,6 +3285,132 @@ const GETLivechatTriggersParamsSchema = { additionalProperties: false, }; +// TODO: Remove these types after business hour endpoint refactor, see CORE-1552 +type BusinessHourDaysTime = { + day: string; + start: { time: string }; + finish: { time: string }; + open: boolean; +}; + +type BusinessHourWorkHours = { + day: string; + start: string; + finish: string; + open: boolean; +}; + +export type POSTLivechatBusinessHoursSaveParams = { + name: string; + timezoneName: string; + daysOpen: string[]; + daysTime?: BusinessHourDaysTime[]; + departmentsToApplyBusinessHour: string; + active: boolean; + _id?: string; + type: string; + timezone?: string; + workHours: BusinessHourWorkHours[]; +}; + +const POSTLivechatBusinessHoursSaveParamsSchema = { + type: 'object', + properties: { + name: { + type: 'string', + }, + timezoneName: { + type: 'string', + }, + daysOpen: { + type: 'array', + items: { + type: 'string', + }, + }, + daysTime: { + type: 'array', + items: { + type: 'object', + properties: { + day: { type: 'string' }, + start: { + type: 'object', + properties: { + time: { type: 'string' }, + }, + required: ['time'], + additionalProperties: false, + }, + finish: { + type: 'object', + properties: { + time: { type: 'string' }, + }, + required: ['time'], + additionalProperties: false, + }, + open: { type: 'boolean' }, + }, + required: ['day', 'start', 'finish', 'open'], + additionalProperties: false, + }, + minItems: 1, + }, + departmentsToApplyBusinessHour: { + type: 'string', + }, + active: { + type: 'boolean', + }, + _id: { + type: 'string', + nullable: true, + }, + type: { + type: 'string', + }, + timezone: { + type: 'string', + }, + workHours: { + type: 'array', + items: { + type: 'object', + properties: { + day: { type: 'string' }, + start: { type: 'string' }, + finish: { type: 'string' }, + open: { type: 'boolean' }, + }, + required: ['day', 'start', 'finish', 'open'], + additionalProperties: false, + }, + minItems: 1, + }, + }, + required: ['name', 'timezoneName', 'daysOpen', 'departmentsToApplyBusinessHour', 'active', 'type', 'workHours'], + additionalProperties: false, +}; + +export const isPOSTLivechatBusinessHoursSaveParams = ajv.compile( + POSTLivechatBusinessHoursSaveParamsSchema, +); + +export const POSTLivechatBusinessHoursSaveSuccessSchema = { + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + required: ['success'], + additionalProperties: false, +}; + +export const POSTLivechatBusinessHoursSaveSuccessResponse = ajv.compile(POSTLivechatBusinessHoursSaveSuccessSchema); + export const isGETLivechatTriggersParams = ajv.compile(GETLivechatTriggersParamsSchema); export type GETLivechatRoomsParams = PaginatedRequest<{