Skip to content
This repository was archived by the owner on Sep 7, 2020. It is now read-only.

Commit 754fcf4

Browse files
committed
feat: users can delete their messages
1 parent cce64b6 commit 754fcf4

File tree

7 files changed

+66
-45
lines changed

7 files changed

+66
-45
lines changed

src/Chat/SlashCommands.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react'
22
import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
3-
import { Message as MessageItemMessage } from './components/MessageItem'
3+
import { Message } from 'twilio-chat/lib/message'
44
import { Status } from './components/StatusItem'
55
import { v4 } from 'uuid'
66
import {
@@ -20,11 +20,9 @@ type UpdateMessages = React.Dispatch<
2020
React.SetStateAction<{
2121
messages: (
2222
| {
23-
sid: string
24-
message: MessageItemMessage
23+
message: Message
2524
}
2625
| {
27-
sid: string
2826
status: Status
2927
}
3028
)[]

src/Chat/Twilio/ChannelView.tsx

+37-28
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import * as React from 'react'
22
import { useState, useEffect, useLayoutEffect } from 'react'
3-
import {
4-
MessageItem,
5-
Message as MessageItemMessage,
6-
stringToColor,
7-
} from '../components/MessageItem'
3+
import { MessageItem, stringToColor } from '../components/MessageItem'
84
import { StatusItem, Status } from '../components/StatusItem'
95
import { Channel } from 'twilio-chat/lib/channel'
106
import { Client, User } from 'twilio-chat'
@@ -67,15 +63,11 @@ export const ChannelView = ({
6763
}
6864
const [message, setMessage] = useState<string>('')
6965
const [messages, updateMessages] = useState<{
70-
messages: (
71-
| { sid: string; message: MessageItemMessage }
72-
| { sid: string; status: Status }
73-
)[]
66+
messages: ({ message: Message } | { status: Status })[]
7467
lastIndex?: number
7568
}>({
7669
messages: [
7770
{
78-
sid: v4(),
7971
status: {
8072
message: `Hint: type /help to list available commands.`,
8173
timestamp: new Date(),
@@ -133,16 +125,6 @@ export const ChannelView = ({
133125
setMessage('')
134126
}
135127

136-
const toMessage = (message: Message) => ({
137-
sid: message.sid,
138-
message: {
139-
timestamp: message.timestamp,
140-
from: message.author,
141-
message: message.body,
142-
fromUser: message.author === identity,
143-
},
144-
})
145-
146128
const userChangedNickHandler = ({
147129
updateReasons,
148130
user,
@@ -176,7 +158,7 @@ export const ChannelView = ({
176158
const newMessageHandler = (message: Message) => {
177159
updateMessages(prevMessages => ({
178160
...prevMessages,
179-
messages: [...prevMessages.messages, toMessage(message)],
161+
messages: [...prevMessages.messages, { message }],
180162
lastIndex: prevMessages.lastIndex
181163
? prevMessages.lastIndex
182164
: message.index,
@@ -202,6 +184,15 @@ export const ChannelView = ({
202184
}
203185
}
204186

187+
const messageRemovedHandler = (message: Message) => {
188+
updateMessages(prevMessages => ({
189+
...prevMessages,
190+
messages: prevMessages.messages.filter(
191+
m => 'status' in m || m.message.sid !== message.sid,
192+
),
193+
}))
194+
}
195+
205196
const memberJoinedHandler = (member: Member) => {
206197
updateMessages(prevMessages => ({
207198
...prevMessages,
@@ -237,13 +228,18 @@ export const ChannelView = ({
237228
useEffect(() => {
238229
if (channelConnection) {
239230
channelConnection.channel.on('messageAdded', newMessageHandler)
231+
channelConnection.channel.on('messageRemoved', messageRemovedHandler)
240232
channelConnection.channel.on('memberJoined', memberJoinedHandler)
241233
channelConnection.channel.on('memberLeft', memberLeftHandler)
242234
return () => {
243235
channelConnection.channel.removeListener(
244236
'messageAdded',
245237
newMessageHandler,
246238
)
239+
channelConnection.channel.removeListener(
240+
'messageRemoved',
241+
messageRemovedHandler,
242+
)
247243
channelConnection.channel.removeListener(
248244
'memberJoined',
249245
memberJoinedHandler,
@@ -295,7 +291,7 @@ export const ChannelView = ({
295291
updateMessages(prevMessages => ({
296292
...prevMessages,
297293
messages: [
298-
...messages.items.map(toMessage),
294+
...messages.items.map(message => ({ message })),
299295
...prevMessages.messages,
300296
],
301297
lastIndex: messages.items[0]?.index ?? undefined,
@@ -432,17 +428,19 @@ export const ChannelView = ({
432428
}}
433429
/>
434430
)}
435-
{messages.messages.map(m =>
431+
{messages.messages.map((m, i) =>
436432
'status' in m ? (
437-
<StatusItem key={m.sid} status={m.status} />
433+
<StatusItem key={i} status={m.status} />
438434
) : (
439435
<MessageItem
440-
key={m.sid}
436+
key={m.message.sid}
441437
message={{
442-
...m.message,
443-
from: m.message.from,
438+
timestamp: m.message.timestamp,
439+
from: m.message.author,
440+
message: m.message.body,
441+
fromUser: m.message.author === identity,
444442
}}
445-
nick={authorNicks[m.message.from]}
443+
nick={authorNicks[m.message.author]}
446444
onRendered={() => {
447445
// Scroll to the last item in the list
448446
// if not at beginning
@@ -457,6 +455,17 @@ export const ChannelView = ({
457455
}
458456
}, 250)
459457
}}
458+
onDelete={() => {
459+
if (confirm('Really delete this message?')) {
460+
console.log(`Deleting message ${m.message.sid}`)
461+
m.message
462+
.remove()
463+
.then(() => {
464+
console.log('Removed')
465+
})
466+
.catch(console.error)
467+
}
468+
}}
460469
/>
461470
),
462471
)}

src/Chat/Twilio/TwilioChat.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const TwilioChat = ({
2525
const [error, setError] = useState<{ type: string; message: string }>()
2626
const [selectedChannel, setSelectedChannel] = useState<string>(context)
2727
const [channelConnection, setConnectedChannel] = useState<
28-
{ channel: Channel; client: Client } | undefined
28+
{ channel: Channel; client: Client; token: string } | undefined
2929
>()
3030
const [joinedChannels, setJoinedChannels] = useState<string[]>([
3131
...new Set(['general', 'random', context]),

src/Chat/Twilio/api.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ export const authenticateClient = ({
102102
apollo: ApolloClient<NormalizedCacheObject>
103103
}) =>
104104
pipe(
105-
TE.right({ apollo, deviceId, token }),
106-
chain(createChatToken),
107-
chain(createClient),
105+
createChatToken({ apollo, deviceId, token }),
106+
chain(token =>
107+
pipe(
108+
createClient(token),
109+
TE.map(client => ({ client, token })),
110+
),
111+
),
108112
)
109113

110114
export const connectToChannel = async ({
@@ -117,16 +121,18 @@ export const connectToChannel = async ({
117121
deviceId: string
118122
token: string
119123
apollo: ApolloClient<NormalizedCacheObject>
120-
}): Promise<Either<ErrorInfo, { client: Client; channel: Channel }>> =>
124+
}): Promise<Either<
125+
ErrorInfo,
126+
{ client: Client; channel: Channel; token: string }
127+
>> =>
121128
pipe(
122-
TE.right({ apollo, deviceId, token }),
123-
chain(authenticateClient),
124-
chain(client =>
129+
authenticateClient({ apollo, deviceId, token }),
130+
chain(({ client, token }) =>
125131
pipe(
126132
fetchSubscribedChannels(client),
127133
TE.map(maybeAlreadyJoinedChannel(context)),
128134
getOrElse(joinChannel({ client, channel: context })),
129-
TE.map(channel => ({ client, channel })),
135+
TE.map(channel => ({ client, channel, token })),
130136
),
131137
),
132138
)()

src/Chat/components/ChannelView.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ export const UIButton = styled.button`
5353
background-color: transparent;
5454
height: 30px;
5555
width: 30px;
56-
${Header} & {
57-
color: inherit;
58-
}
56+
color: inherit;
5957
cursor: pointer;
6058
`
6159

src/Chat/components/MessageItem.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { useLayoutEffect } from 'react'
33
import styled from 'styled-components'
44
import { Timestamp } from './Timestamp'
55
import { emojify } from './Emojify'
6+
import { UIButton } from './ChannelView'
7+
8+
import DeleteIcon from 'feather-icons/dist/icons/trash-2.svg'
69

710
const MessageView = styled.div`
811
border-radius: 10px;
@@ -128,10 +131,12 @@ export const MessageItem = ({
128131
message: { from, message, timestamp, fromUser },
129132
nick,
130133
onRendered,
134+
onDelete,
131135
}: {
132136
message: Message
133137
nick?: string
134138
onRendered: () => void
139+
onDelete: () => void
135140
}) => {
136141
const V = fromUser ? UserMessageView : MessageView
137142

@@ -145,6 +150,11 @@ export const MessageItem = ({
145150
<Text>{emojify(message)}</Text>
146151
<Meta>
147152
<Timestamp from={timestamp} />
153+
{fromUser && (
154+
<UIButton onClick={onDelete}>
155+
<DeleteIcon />
156+
</UIButton>
157+
)}
148158
</Meta>
149159
</V>
150160
)

src/types.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
declare module '*.svg' {
2-
const content: string
2+
const content: React.StatelessComponent<React.SVGAttributes<SVGElement>>
33
export default content
44
}

0 commit comments

Comments
 (0)