diff --git a/.changeset/tender-geckos-accept.md b/.changeset/tender-geckos-accept.md new file mode 100644 index 0000000..6313f3e --- /dev/null +++ b/.changeset/tender-geckos-accept.md @@ -0,0 +1,6 @@ +--- +"@twilio-labs/dev-phone-ui": patch +--- + +Preserve newlines in inbound and outbound sms. +Add react text area auto resize component. diff --git a/package.json b/package.json index e6502bb..8c9a751 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,12 @@ "packages/dev-phone-ui" ], "devDependencies": { - "@changesets/cli": "^2.23.0", + "@changesets/cli": "^2.26.1", "turbo": "^1.2.16" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "redux": "^4.2.1" } } diff --git a/packages/dev-phone-ui/package.json b/packages/dev-phone-ui/package.json index 853afaa..297bef0 100644 --- a/packages/dev-phone-ui/package.json +++ b/packages/dev-phone-ui/package.json @@ -25,11 +25,13 @@ "webpack": "^5.69.1", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4", - "webpack-license-plugin": "^4.2.2" + "webpack-license-plugin": "^4.2.2", + "@changesets/cli": "^2.26.1", + "turbo": "^1.2.16" }, "dependencies": { - "@twilio-paste/core": "^19.0.0", - "@twilio-paste/icons": "^11.1.0", + "@twilio-paste/core": "^20.2.0", + "@twilio-paste/icons": "^12.1.0", "@twilio/conversations": "^2.0.0", "@twilio/voice-sdk": "^2.1.0", "date-fns": "^2.28.0", @@ -43,6 +45,10 @@ "twilio-sync": "^3.0.6", "util": "^0.12.4" }, + "overrides": { + "@twilio-paste/core": "^20.2.0", + "@twilio-paste/icons": "^12.1.0" + }, "peerDependencies": { "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/packages/dev-phone-ui/src/components/PhoneNumberPicker/PhoneNumberPicker.jsx b/packages/dev-phone-ui/src/components/PhoneNumberPicker/PhoneNumberPicker.jsx index 0670c16..85eaae2 100644 --- a/packages/dev-phone-ui/src/components/PhoneNumberPicker/PhoneNumberPicker.jsx +++ b/packages/dev-phone-ui/src/components/PhoneNumberPicker/PhoneNumberPicker.jsx @@ -32,30 +32,6 @@ const sortUnconfiguredNumbersFirstThenAlphabetically = (pn1, pn2) => { return pn1.phoneNumber.localeCompare(pn2.phoneNumber); }; -const numPicker = async (currentNum, selectNum, getAvailableNums) => { - if (!currentNum) { - try { - const response = await fetch('/phone-numbers') - const data = await response.json() - data["phone-numbers"].sort( - sortUnconfiguredNumbersFirstThenAlphabetically - ) - getAvailableNums(data["phone-numbers"]); - if (data["phone-numbers"].length !== 0) { - selectNum( - getPnDetailsByNumber( - data["phone-numbers"][0].phoneNumber, - data["phone-numbers"] - ) - ); - } - } catch (error) { - console.error(error) - } - } -} - - function PhoneNumberPickerContainer({ children }) { return } - function PhoneNumberPicker({ configureNumberInUse, phoneNumbers }) { const [twilioPns, setTwilioPns] = useState(null); const [selectedPn, setSelectedPn] = useState(null); - useEffect(() => { - numPicker(selectedPn, setSelectedPn, setTwilioPns); + useEffect( () => { + const asyncFn = async() => { + if (!selectedPn) { + try { + const response = await fetch('/phone-numbers') + const data = await response.json() + data["phone-numbers"].sort( + sortUnconfiguredNumbersFirstThenAlphabetically + ) + setTwilioPns(data["phone-numbers"]); + if (data["phone-numbers"].length !== 0) { + setSelectedPn( + getPnDetailsByNumber( + data["phone-numbers"][0].phoneNumber, + data["phone-numbers"] + ) + ); + } + } catch (error) { + console.error(error) + } + } + } +asyncFn() }, [selectedPn]); if (twilioPns === null) { diff --git a/packages/dev-phone-ui/src/components/SendSmsForm/MessageList.jsx b/packages/dev-phone-ui/src/components/SendSmsForm/MessageList.jsx index d4a6f1a..27f26a1 100644 --- a/packages/dev-phone-ui/src/components/SendSmsForm/MessageList.jsx +++ b/packages/dev-phone-ui/src/components/SendSmsForm/MessageList.jsx @@ -1,14 +1,11 @@ -import { - Box, Flex, SkeletonLoader, - Text, ChatLog, ChatMessage, - ChatBubble, ChatMessageMeta, ChatMessageMetaItem, - Avatar -} from "@twilio-paste/core" -import { UserIcon } from '@twilio-paste/icons/esm/UserIcon'; +import { Box, SkeletonLoader } from "@twilio-paste/core" +import { ChatLog, ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem } from "@twilio-paste/chat-log"; +import { Avatar } from "@twilio-paste/avatar"; import { useSelector } from "react-redux" import EmptyMessageList from "./EmptyMessageList"; + function MessageList({ devPhoneName }) { const messageList = useSelector(state => state.messageList) const numberInUse = useSelector(state => state.numberInUse ? state.numberInUse.phoneNumber : ""); @@ -27,7 +24,7 @@ function MessageList({ devPhoneName }) { - + {message.author} diff --git a/packages/dev-phone-ui/src/components/SendSmsForm/SendSmsForm.jsx b/packages/dev-phone-ui/src/components/SendSmsForm/SendSmsForm.jsx index beeacfd..d4629ce 100644 --- a/packages/dev-phone-ui/src/components/SendSmsForm/SendSmsForm.jsx +++ b/packages/dev-phone-ui/src/components/SendSmsForm/SendSmsForm.jsx @@ -1,24 +1,46 @@ -import { useContext, useState, useMemo } from "react"; -import { Button, Input, Label, Box, Grid, Column } from "@twilio-paste/core"; -import { SendIcon } from '@twilio-paste/icons/esm/SendIcon'; +import React, { useContext, useState, useMemo } from "react"; import { useSelector } from "react-redux"; +import { Button, Label, Box, Grid, HelpText, Column, AutoScrollPlugin } from "@twilio-paste/core"; +import { ChatComposer } from "@twilio-paste/core/chat-composer"; +import { SendIcon } from '@twilio-paste/icons/esm/SendIcon'; import { TwilioConversationsContext } from '../WebsocketManagers/ConversationsManager'; import MessageList from "./MessageList" +import {$getRoot, ClearEditorPlugin, useLexicalComposerContext, CLEAR_EDITOR_COMMAND } from "@twilio-paste/core/lexical-library"; + + + +function SendButtonPlugin({onClick, canSendMessages}) { + const [editor] = useLexicalComposerContext(); + + const sendIt = (e) => { + onClick(e); + editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); + } + + + return ( + + ) +} function SendSmsForm({ numberInUse }) { + const myRef = React.createRef() + const [messageBody, setMessageBody] = useState(''); const channelData = useSelector(state => state.channelData) const destinationNumber = useSelector(state => state.destinationNumber) const conversationsClient = useContext(TwilioConversationsContext) - const {sendMessage, sendSms} = conversationsClient + const { sendMessage, sendSms } = conversationsClient const canSendMessages = useMemo(() => { return destinationNumber && destinationNumber.length > 6; }, [destinationNumber]); - // Handles the UI state for sending messages const sendIt = async (e) => { e.preventDefault() if (canSendMessages) { @@ -30,25 +52,41 @@ function SendSmsForm({ numberInUse }) { } }; + const myOnChange = (editorState) => { + editorState.read(() => { + const root = $getRoot(); + setMessageBody(root.getTextContent()); + }); + }; + + return ( - + + -
sendIt(e)} method={"GET"}> - - - - setMessageBody(e.target.value)} /> - - - - - -
+ + + + + { + throw e; + } + }} + placeholder="Chat text" + ariaLabel="A basic chat composer" + onChange={myOnChange} + > + + + + Enter at most 1600 characters + +
);