Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

1 change: 0 additions & 1 deletion apps/meteor/app/canned-responses/client/index.ts

This file was deleted.

51 changes: 0 additions & 51 deletions apps/meteor/app/canned-responses/client/startup/responses.ts

This file was deleted.

1 change: 0 additions & 1 deletion apps/meteor/client/importPackages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import '../app/apple/client';
import '../app/authorization/client';
import '../app/autotranslate/client';
import '../app/canned-responses/client';
import '../app/custom-sounds/client';
import '../app/emoji/client';
import '../app/emoji-emojione/client';
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/client/lib/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ export const subscriptionsQueryKeys = {
all: ['subscriptions'] as const,
subscription: (rid: IRoom['_id']) => [...subscriptionsQueryKeys.all, { rid }] as const,
};

export const cannedResponsesQueryKeys = {
all: ['canned-responses'] as const,
};
36 changes: 19 additions & 17 deletions apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { useLocalStorage } from '@rocket.chat/fuselage-hooks';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { useMethod, useSetting, useUserPreference } from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
import { useMemo, useState } from 'react';
import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import { hasAtLeastOnePermission } from '../../../../app/authorization/client';
import { CannedResponse } from '../../../../app/canned-responses/client/collections/CannedResponse';
import { emoji } from '../../../../app/emoji/client';
import { Subscriptions } from '../../../../app/models/client';
import { usersFromRoomMessages } from '../../../../app/ui-message/client/popup/messagePopupConfig';
import { slashCommands } from '../../../../app/utils/client';
import { cannedResponsesQueryKeys } from '../../../lib/queryKeys';
import ComposerBoxPopupCannedResponse from '../composer/ComposerBoxPopupCannedResponse';
import type { ComposerBoxPopupEmojiProps } from '../composer/ComposerBoxPopupEmoji';
import ComposerBoxPopupEmoji from '../composer/ComposerBoxPopupEmoji';
Expand All @@ -24,6 +25,9 @@ import ComposerBoxPopupUser from '../composer/ComposerBoxPopupUser';
import type { ComposerBoxPopupUserProps } from '../composer/ComposerBoxPopupUser';
import type { ComposerPopupContextValue } from '../contexts/ComposerPopupContext';
import { ComposerPopupContext, createMessageBoxPopupConfig } from '../contexts/ComposerPopupContext';
import useCannedResponsesQuery from './hooks/useCannedResponsesQuery';

export type CannedResponse = { _id: string; shortcut: string; text: string };

type ComposerPopupProviderProps = {
children: ReactNode;
Expand All @@ -32,6 +36,11 @@ type ComposerPopupProviderProps = {

const ComposerPopupProvider = ({ children, room }: ComposerPopupProviderProps) => {
const { _id: rid, encrypted: isRoomEncrypted } = room;

// TODO: this is awful because we are just triggering the query to get the data
// and we are not using the data itself, we should find a better way to do this
useCannedResponsesQuery(room);

const userSpotlight = useMethod('spotlight');
const suggestionsCount = useSetting('Number_of_users_autocomplete_suggestions', 5);
const cannedResponseEnabled = useSetting('Canned_Responses_Enable', true);
Expand All @@ -43,6 +52,7 @@ const ComposerPopupProvider = ({ children, room }: ComposerPopupProviderProps) =
const e2eEnabled = useSetting('E2E_Enable', false);
const unencryptedMessagesAllowed = useSetting('E2E_Allow_Unencrypted_Messages', false);
const encrypted = isRoomEncrypted && e2eEnabled && !unencryptedMessagesAllowed;
const queryClient = useQueryClient();

const call = useMethod('getSlashCommandPreviews');
const value: ComposerPopupContextValue = useMemo(() => {
Expand Down Expand Up @@ -334,28 +344,20 @@ const ComposerPopupProvider = ({ children, room }: ComposerPopupProviderProps) =
renderItem: ({ item }) => <ComposerBoxPopupCannedResponse {...item} />,
getItemsFromLocal: async (filter: string) => {
const exp = new RegExp(filter, 'i');
return CannedResponse.find(
{
shortcut: exp,
},
{
limit: 12,
sort: {
shortcut: -1,
},
},
)
.fetch()
// TODO: this is bad, but can only be fixed by refactoring the whole thing
const cannedResponses = queryClient.getQueryData<CannedResponse[]>(cannedResponsesQueryKeys.all) ?? [];
return cannedResponses
.filter((record) => record.shortcut.match(exp))
.sort((a, b) => a.shortcut.localeCompare(b.shortcut))
.slice(0, 11)
.map((record) => ({
_id: record._id,
text: record.text,
shortcut: record.shortcut,
}));
},
getItemsFromServer: async () => [],
getValue: (item) => {
return item.text;
},
getValue: (item) => item.text,
}),
createMessageBoxPopupConfig({
title: previewTitle,
Expand Down Expand Up @@ -388,8 +390,8 @@ const ComposerPopupProvider = ({ children, room }: ComposerPopupProviderProps) =
rid,
recentEmojis,
i18n,
queryClient,
call,
setPreviewTitle,
]);

return <ComposerPopupContext.Provider value={value} children={children} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { useEndpoint, usePermission, useSetting, useStream, useUserId } from '@rocket.chat/ui-contexts';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';

import { cannedResponsesQueryKeys } from '../../../../lib/queryKeys';

type CannedResponse = { _id: string; shortcut: string; text: string };

const useCannedResponsesQuery = (room: IRoom) => {
const isOmnichannel = isOmnichannelRoom(room);
const uid = useUserId();
const isCannedResponsesEnabled = useSetting('Canned_Responses_Enable', true);
const canViewCannedResponses = usePermission('view-canned-responses');
const subscribeToCannedResponses = useStream('canned-responses');

const enabled = isOmnichannel && !!uid && isCannedResponsesEnabled && canViewCannedResponses;

const getCannedResponses = useEndpoint('GET', '/v1/canned-responses.get');

const queryClient = useQueryClient();

useEffect(() => {
if (!enabled) return;

return subscribeToCannedResponses('canned-responses', (...[response, options]) => {
const { agentsId } = options || {};
if (Array.isArray(agentsId) && !agentsId.includes(uid)) {
return;
}

switch (response.type) {
case 'changed': {
const { _id, shortcut, text } = response;
queryClient.setQueryData<CannedResponse[]>(cannedResponsesQueryKeys.all, (responses) =>
responses?.filter((response) => response._id !== _id).concat([{ _id, shortcut, text }]),
);
break;
}

case 'removed': {
const { _id } = response;
queryClient.setQueryData<CannedResponse[]>(cannedResponsesQueryKeys.all, (responses) =>
responses?.filter((response) => response._id !== _id),
);
break;
}
}
});
}, [enabled, getCannedResponses, queryClient, subscribeToCannedResponses, uid]);

return useQuery<CannedResponse[]>({
queryKey: cannedResponsesQueryKeys.all,
queryFn: async () => {
const { responses } = await getCannedResponses();
return responses.map(({ _id, shortcut, text }) => ({ _id, shortcut, text }));
},
enabled,
staleTime: Infinity,
});
};

export default useCannedResponsesQuery;
Loading