From 66d3c0358c74f02b514d654de3005de6d1541423 Mon Sep 17 00:00:00 2001 From: Siddesh Date: Wed, 15 May 2024 16:20:25 +0530 Subject: [PATCH] feat(uiweb): adds commands feature --- .../chat/MessageInput/MessageInput.tsx | 107 +++++++++++++++++- .../src/lib/components/chat/types/index.ts | 15 ++- packages/uiweb/src/lib/config/constants.ts | 13 +-- .../lib/utilities/getFrameUrlDynamicParams.ts | 11 ++ 4 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 packages/uiweb/src/lib/utilities/getFrameUrlDynamicParams.ts diff --git a/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx b/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx index adec52c20..66ced2963 100644 --- a/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx +++ b/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx @@ -24,13 +24,14 @@ import { ConnectButtonComp } from '../ConnectButton'; import { Modal, ModalHeader } from '../reusables/Modal'; import { ThemeContext } from '../theme/ThemeProvider'; -import { PUBLIC_GOOGLE_TOKEN, device } from '../../../config'; +import { FRAMES_REGISTRY_URL, PUBLIC_GOOGLE_TOKEN, device } from '../../../config'; import usePushUser from '../../../hooks/usePushUser'; import { MODAL_BACKGROUND_TYPE, MODAL_POSITION_TYPE, type FileMessageContent } from '../../../types'; import { GIFType, Group, IChatTheme, MessageInputProps } from '../exportedTypes'; import { checkIfAccessVerifiedGroup } from '../helpers'; import { InfoContainer } from '../reusables'; -import { ChatInfoResponse } from '../types'; +import { ChatInfoResponse, FrameCommand } from '../types'; +import { extractDynamicArgs } from '../../../utilities/getFrameUrlDynamicParams'; /** * @interface IThemeProps @@ -85,7 +86,8 @@ export const MessageInput: React.FC = ({ const [isRules, setIsRules] = useState(false); const [isMember, setIsMember] = useState(false); const [formattedChatId, setFormattedChatId] = useState(''); - + const [allFrameCommands, setAllFrameCommands] = useState([]); // all available frame commands + const [filteredFrameCommands, setFilteredFrameCommands] = useState([]); // filtered frame commands based on typed command const { getGroupByIDnew } = useGetGroupByIDnew(); const [groupInfo, setGroupInfo] = useState(null); @@ -119,6 +121,22 @@ export const MessageInput: React.FC = ({ const onChangeTypedMessage = (val: string) => { setTypedMessage(val); + if (val === '') setFilteredFrameCommands([]); + // Check if the message contains a slash and process accordingly + if (val.includes('/')) { + const parts = val.split(' '); + + const commandIndex = parts.findIndex((part) => part.startsWith('/')); + + if (commandIndex !== -1) { + // Filter commands that start with the typed command part + const matchingCommands = allFrameCommands.filter((command) => command.command.startsWith(parts[commandIndex])); + + if (matchingCommands.length > 0) { + setFilteredFrameCommands(matchingCommands); + } + } + } }; useClickAway(modalRef, () => { setShowEmojis(false); @@ -243,6 +261,20 @@ export const MessageInput: React.FC = ({ } }, [chatAcceptStream]); + // fetch all available frame commands on mount + useEffect(() => { + const fetchAllFrameCommands = async () => { + console.log('fetching all frame commands'); + const response = await fetch(FRAMES_REGISTRY_URL); + const data = await response.json(); + if (data) { + console.log('data', data); + setAllFrameCommands(data); + } + }; + fetchAllFrameCommands(); + }, []); + const transformGroupDetails = (item: any): void => { if (groupInfo?.chatId === item?.chatId) { const updatedGroupInfo = groupInfo; @@ -381,11 +413,32 @@ export const MessageInput: React.FC = ({ const sendPushMessage = async (content: string, type: string) => { try { + if (content.includes('/')) { + const parts = content.split(' '); + const commandIndex = parts.findIndex((part) => part.startsWith('/')); + const frameCommand = parts[commandIndex]; + const matchingCommand = allFrameCommands.find((command) => command.command === frameCommand); + if (matchingCommand) { + let url = matchingCommand.url; + const dynamicArgs = extractDynamicArgs(url); + const dynamicArgsValues = parts.slice(commandIndex + 1, parts.length); + + dynamicArgs.forEach((arg, index) => { + url = url.replace(`\${${arg}}`, dynamicArgsValues[index]); + }); + const textBeforeCommand = parts.slice(0, commandIndex).join(' '); + content = `${textBeforeCommand} ${url} ${dynamicArgsValues.slice(dynamicArgs.length).join(' ')}`; + } + + setFilteredFrameCommands([]); + } + const sendMessageResponse = await sendMessage({ message: content, chatId: formattedChatId, messageType: type as any, }); + if (sendMessageResponse && typeof sendMessageResponse === 'string' && sendMessageResponse.includes('403')) { setAccessControl(chatId, true); setVerified(false); @@ -395,7 +448,6 @@ export const MessageInput: React.FC = ({ console.log(error); } }; - const sendTextMsg = async () => { if (typedMessage.trim() !== '') { await sendPushMessage(typedMessage as string, 'Text'); @@ -427,7 +479,53 @@ export const MessageInput: React.FC = ({ justifyContent="space-between" alignItems="center" className={chatInfo?.list === 'REQUESTS' ? 'hide' : ''} + position="relative" > + {filteredFrameCommands && filteredFrameCommands.length > 0 && ( +
+ {filteredFrameCommands.map((command, index) => ( +
+ + {command.command} + {`${ + extractDynamicArgs(command.url).length > 0 ? ` [${extractDynamicArgs(command.url).join('] [')}]` : `` + }`} + + + {command.description ?? 'This Frame does something '} + +
+ ))} +
+ )} = ({ /> )} + // Livekit Server URLs export const LIVEKIT_SERVER_URL = 'https://spacev2-demo-17wvllxz.livekit.cloud'; -export const LIVEKIT_SERVER_WEBSOCKET_URL = - 'wss://spacev2-demo-17wvllxz.livekit.cloud'; -export const LIVEKIT_TOKEN_GENERATOR_SERVER_URL = - 'https://ms-lk-server.onrender.com'; +export const LIVEKIT_SERVER_WEBSOCKET_URL = 'wss://spacev2-demo-17wvllxz.livekit.cloud'; +export const LIVEKIT_TOKEN_GENERATOR_SERVER_URL = 'https://ms-lk-server.onrender.com'; export const GUEST_MODE_ACCOUNT = '0x0000000000000000000000000000000000000001'; +export const FRAMES_REGISTRY_URL = 'https://frames.push.org/api/register-frame'; diff --git a/packages/uiweb/src/lib/utilities/getFrameUrlDynamicParams.ts b/packages/uiweb/src/lib/utilities/getFrameUrlDynamicParams.ts new file mode 100644 index 000000000..8e7e5e796 --- /dev/null +++ b/packages/uiweb/src/lib/utilities/getFrameUrlDynamicParams.ts @@ -0,0 +1,11 @@ +export function extractDynamicArgs(str: string) { + const regex = /\$\{([^}]+)\}/g; + const matches = []; + let match; + + while ((match = regex.exec(str)) !== null) { + matches.push(match[1]); + } + + return matches; +}