forked from Shiloh/remnantchat
feat: show animation when message is successfully sent
This commit is contained in:
parent
3be1f2e88a
commit
0d28df82c2
@ -5,7 +5,7 @@ export const joinRoom: typeof trysteroJoinRoom = (
|
|||||||
_roomId: string
|
_roomId: string
|
||||||
) => {
|
) => {
|
||||||
const room: Room = {
|
const room: Room = {
|
||||||
makeAction: () => [() => {}, () => {}, () => {}],
|
makeAction: () => [() => Promise.resolve([]), () => {}, () => {}],
|
||||||
ping: () => Promise.resolve(0),
|
ping: () => Promise.resolve(0),
|
||||||
leave: () => {},
|
leave: () => {},
|
||||||
getPeers: () => [],
|
getPeers: () => [],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Typography from '@mui/material/Typography'
|
import Typography from '@mui/material/Typography'
|
||||||
|
|
||||||
import { UnsentMessage, ReceivedMessage } from 'models/chat'
|
import { isMessageReceived, UnsentMessage, ReceivedMessage } from 'models/chat'
|
||||||
|
|
||||||
export interface ChatTranscriptProps {
|
export interface ChatTranscriptProps {
|
||||||
messageLog: Array<UnsentMessage | ReceivedMessage>
|
messageLog: Array<UnsentMessage | ReceivedMessage>
|
||||||
@ -10,24 +10,35 @@ export interface ChatTranscriptProps {
|
|||||||
export const ChatTranscript = ({ messageLog, userId }: ChatTranscriptProps) => {
|
export const ChatTranscript = ({ messageLog, userId }: ChatTranscriptProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="ChatTranscript flex flex-col">
|
<div className="ChatTranscript flex flex-col">
|
||||||
{messageLog.map((message, idx) => (
|
{messageLog.map(message => {
|
||||||
<div className="block">
|
let backgroundColor: string
|
||||||
|
|
||||||
|
if (message.authorId === userId) {
|
||||||
|
backgroundColor = isMessageReceived(message)
|
||||||
|
? 'primary.dark'
|
||||||
|
: 'primary.main'
|
||||||
|
} else {
|
||||||
|
backgroundColor = 'grey.700'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="block" key={message.id}>
|
||||||
<Typography
|
<Typography
|
||||||
key={`${idx}_${message}`}
|
|
||||||
variant="body1"
|
variant="body1"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor:
|
backgroundColor,
|
||||||
message.authorId === userId ? 'primary.dark' : 'grey.700',
|
|
||||||
margin: 0.5,
|
margin: 0.5,
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderRadius: 4,
|
borderRadius: 6,
|
||||||
float: message.authorId === userId ? 'right' : 'left',
|
float: message.authorId === userId ? 'right' : 'left',
|
||||||
|
transition: 'background-color 1s',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{message.text}
|
{message.text}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
))}
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PropsWithChildren } from 'react'
|
import { PropsWithChildren } from 'react'
|
||||||
import { render, screen } from '@testing-library/react'
|
import { waitFor, render, screen } from '@testing-library/react'
|
||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
import { MemoryRouter as Router, Route, Routes } from 'react-router-dom'
|
import { MemoryRouter as Router, Route, Routes } from 'react-router-dom'
|
||||||
|
|
||||||
@ -8,7 +8,9 @@ import { Room } from './'
|
|||||||
const stubUserId = 'user-id'
|
const stubUserId = 'user-id'
|
||||||
|
|
||||||
const mockGetUuid = jest.fn()
|
const mockGetUuid = jest.fn()
|
||||||
const mockMessagedSender = jest.fn()
|
const mockMessagedSender = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve([]))
|
||||||
|
|
||||||
jest.mock('trystero', () => ({
|
jest.mock('trystero', () => ({
|
||||||
joinRoom: () => ({
|
joinRoom: () => ({
|
||||||
@ -73,7 +75,7 @@ describe('Room', () => {
|
|||||||
expect(sendButton).not.toBeDisabled()
|
expect(sendButton).not.toBeDisabled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('sending a message clears the text input', () => {
|
test('sending a message clears the text input', async () => {
|
||||||
render(
|
render(
|
||||||
<RouteStub>
|
<RouteStub>
|
||||||
<Room userId={stubUserId} />
|
<Room userId={stubUserId} />
|
||||||
@ -83,11 +85,15 @@ describe('Room', () => {
|
|||||||
const sendButton = screen.getByText('Send')
|
const sendButton = screen.getByText('Send')
|
||||||
const textInput = screen.getByPlaceholderText('Your message')
|
const textInput = screen.getByPlaceholderText('Your message')
|
||||||
userEvent.type(textInput, 'hello')
|
userEvent.type(textInput, 'hello')
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
userEvent.click(sendButton)
|
userEvent.click(sendButton)
|
||||||
|
})
|
||||||
|
|
||||||
expect(textInput).toHaveValue('')
|
expect(textInput).toHaveValue('')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('message is sent to peer', () => {
|
test('message is sent to peer', async () => {
|
||||||
render(
|
render(
|
||||||
<RouteStub>
|
<RouteStub>
|
||||||
<Room
|
<Room
|
||||||
@ -100,7 +106,11 @@ describe('Room', () => {
|
|||||||
const sendButton = screen.getByText('Send')
|
const sendButton = screen.getByText('Send')
|
||||||
const textInput = screen.getByPlaceholderText('Your message')
|
const textInput = screen.getByPlaceholderText('Your message')
|
||||||
userEvent.type(textInput, 'hello')
|
userEvent.type(textInput, 'hello')
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
userEvent.click(sendButton)
|
userEvent.click(sendButton)
|
||||||
|
})
|
||||||
|
|
||||||
expect(mockMessagedSender).toHaveBeenCalledWith({
|
expect(mockMessagedSender).toHaveBeenCalledWith({
|
||||||
authorId: stubUserId,
|
authorId: stubUserId,
|
||||||
text: 'hello',
|
text: 'hello',
|
||||||
|
@ -24,6 +24,7 @@ export function Room({
|
|||||||
}: RoomProps) {
|
}: RoomProps) {
|
||||||
const { roomId = '' } = useParams()
|
const { roomId = '' } = useParams()
|
||||||
|
|
||||||
|
const [isMessageSending, setIsMessageSending] = useState(false)
|
||||||
const [textMessage, setTextMessage] = useState('')
|
const [textMessage, setTextMessage] = useState('')
|
||||||
const [messageLog, setMessageLog] = useState<
|
const [messageLog, setMessageLog] = useState<
|
||||||
Array<ReceivedMessage | UnsentMessage>
|
Array<ReceivedMessage | UnsentMessage>
|
||||||
@ -46,7 +47,7 @@ export function Room({
|
|||||||
setTextMessage(value)
|
setTextMessage(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMessageSubmit = (
|
const handleMessageSubmit = async (
|
||||||
event: React.SyntheticEvent<HTMLFormElement>
|
event: React.SyntheticEvent<HTMLFormElement>
|
||||||
) => {
|
) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@ -58,10 +59,16 @@ export function Room({
|
|||||||
id: getUuid(),
|
id: getUuid(),
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(unsentMessage)
|
|
||||||
|
|
||||||
setTextMessage('')
|
setTextMessage('')
|
||||||
|
setIsMessageSending(true)
|
||||||
setMessageLog([...messageLog, unsentMessage])
|
setMessageLog([...messageLog, unsentMessage])
|
||||||
|
await sendMessage(unsentMessage)
|
||||||
|
|
||||||
|
setMessageLog([
|
||||||
|
...messageLog,
|
||||||
|
{ ...unsentMessage, timeReceived: Date.now() },
|
||||||
|
])
|
||||||
|
setIsMessageSending(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveMessage(message => {
|
receiveMessage(message => {
|
||||||
@ -85,7 +92,7 @@ export function Room({
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={textMessage.length === 0}
|
disabled={textMessage.length === 0 || isMessageSending}
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
}}
|
}}
|
||||||
|
@ -8,3 +8,7 @@ export interface UnsentMessage {
|
|||||||
export interface ReceivedMessage extends UnsentMessage {
|
export interface ReceivedMessage extends UnsentMessage {
|
||||||
timeReceived: number
|
timeReceived: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isMessageReceived = (
|
||||||
|
message: UnsentMessage
|
||||||
|
): message is ReceivedMessage => 'timeReceived' in message
|
||||||
|
4
src/react-app-env.d.ts
vendored
4
src/react-app-env.d.ts
vendored
@ -25,13 +25,13 @@ declare module 'trystero' {
|
|||||||
export type RoomConfig = BaseRoomConfig &
|
export type RoomConfig = BaseRoomConfig &
|
||||||
(BitTorrentRoomConfig | FirebaseRoomConfig | IpfsRoomConfig)
|
(BitTorrentRoomConfig | FirebaseRoomConfig | IpfsRoomConfig)
|
||||||
|
|
||||||
export interface ActionSender<T> {
|
export interface ActionSender<T> extends Promise {
|
||||||
(
|
(
|
||||||
data: T,
|
data: T,
|
||||||
targetPeers?: string[],
|
targetPeers?: string[],
|
||||||
metadata?: Record,
|
metadata?: Record,
|
||||||
progress?: (percent: number, peerId: string) => void
|
progress?: (percent: number, peerId: string) => void
|
||||||
): void
|
): Promise<Array<undefined>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionReceiver<T> {
|
export interface ActionReceiver<T> {
|
||||||
|
Loading…
Reference in New Issue
Block a user