diff --git a/.changeset/cool-yaks-perform.md b/.changeset/cool-yaks-perform.md new file mode 100644 index 00000000000..c259a1470bf --- /dev/null +++ b/.changeset/cool-yaks-perform.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Adds deprecation warning for `livechat:saveUnit` diff --git a/apps/meteor/client/omnichannel/units/UnitEdit.tsx b/apps/meteor/client/omnichannel/units/UnitEdit.tsx index 75b8d796fec..8ce7abdb205 100644 --- a/apps/meteor/client/omnichannel/units/UnitEdit.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEdit.tsx @@ -1,8 +1,14 @@ -import type { ILivechatDepartment, ILivechatUnitMonitor, Serialized, IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; +import type { + ILivechatDepartment, + ILivechatUnitMonitor, + Serialized, + IOmnichannelBusinessUnit, + OmnichannelBusinessUnitPayload, +} from '@rocket.chat/core-typings'; import type { SelectOption } from '@rocket.chat/fuselage'; import { FieldError, Field, TextInput, Button, Select, ButtonGroup, FieldGroup, Box, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useId, useMemo } from 'react'; import { useForm, Controller } from 'react-hook-form'; @@ -34,13 +40,14 @@ type UnitEditProps = { unitData?: Serialized; unitMonitors?: Serialized[]; unitDepartments?: Serialized[]; - onClose: () => void; + onUpdate?: (params: OmnichannelBusinessUnitPayload) => void; onDelete?: () => void; + onClose: () => void; }; -const UnitEdit = ({ unitData, unitMonitors, unitDepartments, onClose, onDelete }: UnitEditProps) => { +const UnitEdit = ({ unitData, unitMonitors, unitDepartments, onUpdate, onDelete, onClose }: UnitEditProps) => { const t = useTranslation(); - const saveUnit = useMethod('livechat:saveUnit'); + const saveUnit = useEndpoint('POST', '/v1/livechat/units'); const dispatchToastMessage = useToastMessageDispatch(); const queryClient = useQueryClient(); @@ -94,8 +101,19 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments, onClose, onDelete } username: monitor.label, })); + const payload = { + unitData: { name, visibility }, + unitMonitors: monitorsData, + unitDepartments: departmentsData, + }; + try { - await saveUnit(_id as unknown as string, { name, visibility }, monitorsData, departmentsData); + if (_id && onUpdate) { + await onUpdate(payload); + } else { + await saveUnit(payload); + } + dispatchToastMessage({ type: 'success', message: t('Saved') }); queryClient.invalidateQueries({ queryKey: ['livechat-units'], diff --git a/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx b/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx index f8c3f55adb0..3bd6677e3f5 100644 --- a/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx @@ -14,6 +14,7 @@ const UnitEditWithData = ({ unitId, onClose }: { unitId: IOmnichannelBusinessUni const getUnitById = useEndpoint('GET', '/v1/livechat/units/:id', { id: unitId }); const getMonitorsByUnitId = useEndpoint('GET', '/v1/livechat/units/:unitId/monitors', { unitId }); const getDepartmentsByUnitId = useEndpoint('GET', '/v1/livechat/units/:unitId/departments', { unitId }); + const editUnit = useEndpoint('POST', '/v1/livechat/units/:id', { id: unitId }); const removeUnit = useRemoveUnit(unitId); const { @@ -61,8 +62,9 @@ const UnitEditWithData = ({ unitId, onClose }: { unitId: IOmnichannelBusinessUni unitData={unitData} unitMonitors={unitMonitors?.monitors} unitDepartments={unitDepartments?.departments} - onClose={onClose} + onUpdate={editUnit} onDelete={removeUnit} + onClose={onClose} /> ); }; diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts index f09857571bb..bede0d24577 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts @@ -1,4 +1,4 @@ -import type { ILivechatUnitMonitor, IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; +import type { ILivechatUnitMonitor, IOmnichannelBusinessUnit, OmnichannelBusinessUnitPayload } from '@rocket.chat/core-typings'; import type { PaginatedResult, PaginatedRequest } from '@rocket.chat/rest-typings'; import { API } from '../../../../../app/api/server'; @@ -16,11 +16,11 @@ declare module '@rocket.chat/rest-typings' { }; '/v1/livechat/units': { GET: (params: PaginatedRequest<{ text?: string }>) => PaginatedResult & { units: IOmnichannelBusinessUnit[] }; - POST: (params: { unitData: string; unitMonitors: string; unitDepartments: string }) => Omit; + POST: (params: OmnichannelBusinessUnitPayload) => Omit; }; '/v1/livechat/units/:id': { GET: () => IOmnichannelBusinessUnit; - POST: (params: { unitData: string; unitMonitors: string; unitDepartments: string }) => Omit; + POST: (params: OmnichannelBusinessUnitPayload) => Omit; DELETE: () => number; }; } diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.ts index 042a2808389..25fd6bdec96 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.ts @@ -3,6 +3,7 @@ import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../../../app/authorization/server/functions/hasPermission'; +import { methodDeprecationLogger } from '../../../../../app/lib/server/lib/deprecationWarningLogger'; import { LivechatEnterprise } from '../lib/LivechatEnterprise'; declare module '@rocket.chat/ddp-client' { @@ -14,6 +15,7 @@ declare module '@rocket.chat/ddp-client' { Meteor.methods({ async 'livechat:saveUnit'(_id, unitData, unitMonitors, unitDepartments) { + methodDeprecationLogger.method('livechat:saveUnit', '8.0.0', '/v1/livechat/units'); const uid = Meteor.userId(); if (!uid || !(await hasPermissionAsync(uid, 'manage-livechat-units'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:saveUnit' }); diff --git a/apps/meteor/tests/data/livechat/units.ts b/apps/meteor/tests/data/livechat/units.ts index 98560713cd4..691d8a23fd6 100644 --- a/apps/meteor/tests/data/livechat/units.ts +++ b/apps/meteor/tests/data/livechat/units.ts @@ -35,29 +35,21 @@ export const createUnit = async ( ): Promise => { return new Promise((resolve, reject) => { void request - .post(methodCall(`livechat:saveUnit`)) + .post(api('livechat/units')) .set(credentials) .send({ - message: JSON.stringify({ - method: 'livechat:saveUnit', - params: [ - null, - { - name: name || `${faker.person.firstName()} ${faker.string.uuid()}`, - visibility: faker.helpers.arrayElement(['public', 'private']), - }, - [{ monitorId, username }, ...extraMonitor], - departmentIds.map((departmentId) => ({ departmentId })), - ], - id: '101', - msg: 'method', - }), + unitData: { + name: name || `${faker.person.firstName()} ${faker.string.uuid()}`, + visibility: faker.helpers.arrayElement(['public', 'private']), + }, + unitMonitors: [{ monitorId, username }, ...extraMonitor], + unitDepartments: departmentIds.map((departmentId) => ({ departmentId })), }) - .end((err: Error, res: DummyResponse) => { + .end((err: Error, res: DummyResponse) => { if (err) { return reject(err); } - resolve(JSON.parse(res.body.message).result); + resolve(res.body); }); }); }; diff --git a/apps/meteor/tests/e2e/utils/omnichannel/units.ts b/apps/meteor/tests/e2e/utils/omnichannel/units.ts index 4b590194c8a..9427d8beafe 100644 --- a/apps/meteor/tests/e2e/utils/omnichannel/units.ts +++ b/apps/meteor/tests/e2e/utils/omnichannel/units.ts @@ -1,7 +1,5 @@ import { faker } from '@faker-js/faker'; -import type { IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; -import { parseMeteorResponse } from '../parseMeteorResponse'; import type { BaseTest } from '../test'; type CreateUnitParams = { @@ -21,21 +19,27 @@ export const createOrUpdateUnit = async ( api: BaseTest['api'], { id = null, name, visibility, monitors, departments }: CreateUnitParams = {}, ) => { - const response = await api.post('/method.call/livechat:saveUnit', { - message: JSON.stringify({ - msg: 'method', - id: '34', - method: 'livechat:saveUnit', - params: [id, { name: name || faker.string.uuid(), visibility: visibility || 'public' }, monitors, departments], - }), - }); + const unitPayload = { + unitData: { + name: name ?? faker.string.uuid(), + visibility: visibility ?? 'public', + }, + unitMonitors: monitors, + unitDepartments: departments, + }; - const unit = await parseMeteorResponse(response); + const response = id ? await api.post(`/livechat/units/${id}`, unitPayload) : await api.post('/livechat/units', unitPayload); + + if (response.status() !== 200) { + throw new Error(`Failed to create or update unit [http status: ${response.status()}]`); + } + + const data = await response.json(); return { response, - data: unit, - delete: async () => removeUnit(api, unit?._id), + data, + delete: async () => removeUnit(api, data?._id), }; }; diff --git a/packages/core-typings/src/IOmnichannelBusinessUnit.ts b/packages/core-typings/src/IOmnichannelBusinessUnit.ts index baf5bc3ee53..fff6495534e 100644 --- a/packages/core-typings/src/IOmnichannelBusinessUnit.ts +++ b/packages/core-typings/src/IOmnichannelBusinessUnit.ts @@ -10,3 +10,16 @@ export interface IOmnichannelBusinessUnit extends IRocketChatRecord { // Units don't have ancestors per se, but we need TS to know it can access the property from the collection ancestors?: string[]; } + +export type OmnichannelBusinessUnitPayload = { + unitData: { + name: string; + visibility: string; + enabled?: boolean; + description?: string; + email?: string; + showOnOfflineForm?: boolean; + }; + unitMonitors: { monitorId: string; username: string }[]; + unitDepartments: { departmentId: string }[]; +};