feat: add realtime with socket.io
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
import { Meta, Story } from '@storybook/react'
|
||||
|
||||
import { SendMessage as Component } from './SendMessage'
|
||||
import { channelExample } from '../../../cypress/fixtures/channels/channel'
|
||||
import { guildExample } from '../../../cypress/fixtures/guilds/guild'
|
||||
import { SendMessage as Component, SendMessageProps } from './SendMessage'
|
||||
|
||||
const Stories: Meta = {
|
||||
title: 'SendMessage',
|
||||
@ -9,7 +11,9 @@ const Stories: Meta = {
|
||||
|
||||
export default Stories
|
||||
|
||||
export const SendMessage: Story = (arguments_) => {
|
||||
export const SendMessage: Story<SendMessageProps> = (arguments_) => {
|
||||
return <Component {...arguments_} />
|
||||
}
|
||||
SendMessage.args = {}
|
||||
SendMessage.args = {
|
||||
path: { channelId: channelExample.id, guildId: guildExample.id }
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { SendMessage } from './SendMessage'
|
||||
|
||||
describe('<SendMessage />', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<SendMessage />)
|
||||
expect(baseElement).toBeTruthy()
|
||||
})
|
||||
})
|
@ -1,38 +1,126 @@
|
||||
import { useState, useRef } from 'react'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
|
||||
export const SendMessage: React.FC = () => {
|
||||
import { GuildsChannelsPath } from '..'
|
||||
import { useAuthentication } from '../../../tools/authentication'
|
||||
import { EmojiPicker, EmojiPickerOnClick } from '../../Emoji'
|
||||
|
||||
export interface SendMessageProps {
|
||||
path: GuildsChannelsPath
|
||||
}
|
||||
|
||||
export const SendMessage: React.FC<SendMessageProps> = (props) => {
|
||||
const { path } = props
|
||||
const { t } = useTranslation()
|
||||
const { authentication } = useAuthentication()
|
||||
|
||||
const [isVisibleEmojiPicker, setIsVisibleEmojiPicker] = useState(false)
|
||||
const [message, setMessage] = useState('')
|
||||
const textareaReference = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
const handleTextareaKeyDown: React.KeyboardEventHandler<HTMLFormElement> = (
|
||||
event
|
||||
) => {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
event.preventDefault()
|
||||
event.currentTarget.dispatchEvent(
|
||||
new Event('submit', { cancelable: true, bubbles: true })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit: React.FormEventHandler<HTMLFormElement> = async (
|
||||
event
|
||||
) => {
|
||||
event.preventDefault()
|
||||
if (typeof message === 'string' && message.length > 0) {
|
||||
await authentication.api.post(`/channels/${path.channelId}/messages`, {
|
||||
value: message
|
||||
})
|
||||
setMessage('')
|
||||
}
|
||||
}
|
||||
|
||||
const handleTextareaChange: React.ChangeEventHandler<HTMLTextAreaElement> = (
|
||||
event
|
||||
) => {
|
||||
setMessage(event.target.value)
|
||||
}
|
||||
|
||||
const handleFileChange: React.ChangeEventHandler<HTMLInputElement> = async (
|
||||
event
|
||||
) => {
|
||||
const files = event?.target?.files
|
||||
if (files != null && files.length === 1) {
|
||||
const file = files[0]
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
await authentication.api.post(
|
||||
`/channels/${path.channelId}/messages/uploads`,
|
||||
formData
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const handleVisibleEmojiPicker = (): void => {
|
||||
setIsVisibleEmojiPicker((isVisible) => !isVisible)
|
||||
}
|
||||
|
||||
const handleEmojiPicker: EmojiPickerOnClick = (emoji) => {
|
||||
const emojiColons = emoji.colons ?? ''
|
||||
setMessage((oldMessage) => {
|
||||
return oldMessage + emojiColons
|
||||
})
|
||||
handleVisibleEmojiPicker()
|
||||
textareaReference.current?.focus()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='p-6 pb-4'>
|
||||
<div className='w-full h-full py-1 flex rounded-lg bg-gray-200 dark:bg-gray-800 text-gray-600 dark:text-gray-200'>
|
||||
<form className='w-full h-full flex items-center'>
|
||||
<TextareaAutosize
|
||||
className='w-full scrollbar-firefox-support p-2 px-6 my-2 bg-transparent outline-none font-paragraph tracking-wide resize-none'
|
||||
placeholder={t('application:write-a-message')}
|
||||
wrap='soft'
|
||||
maxRows={6}
|
||||
/>
|
||||
</form>
|
||||
<div className='h-full flex items-center justify-around pr-6'>
|
||||
<button className='w-full h-full flex items-center justify-center p-1 text-2xl transition hover:-translate-y-1'>
|
||||
🙂
|
||||
</button>
|
||||
<button className='relative w-full h-full flex items-center justify-center p-1 text-green-800 dark:text-green-400 transition hover:-translate-y-1'>
|
||||
<input
|
||||
type='file'
|
||||
className='absolute w-full h-full opacity-0 cursor-pointer'
|
||||
<>
|
||||
{isVisibleEmojiPicker && <EmojiPicker onClick={handleEmojiPicker} />}
|
||||
<div className='p-6 pb-4'>
|
||||
<div className='w-full h-full py-1 flex rounded-lg bg-gray-200 dark:bg-gray-800 text-gray-600 dark:text-gray-200'>
|
||||
<form
|
||||
className='w-full h-full flex items-center'
|
||||
onSubmit={handleSubmit}
|
||||
onKeyDown={handleTextareaKeyDown}
|
||||
>
|
||||
<TextareaAutosize
|
||||
className='w-full scrollbar-firefox-support p-2 px-6 my-2 bg-transparent outline-none font-paragraph tracking-wide resize-none'
|
||||
placeholder={t('application:write-a-message')}
|
||||
wrap='soft'
|
||||
maxRows={6}
|
||||
name='message'
|
||||
onChange={handleTextareaChange}
|
||||
value={message}
|
||||
ref={textareaReference}
|
||||
autoFocus
|
||||
/>
|
||||
<svg width='25' height='25' viewBox='0 0 22 22'>
|
||||
<path
|
||||
d='M11 0C4.925 0 0 4.925 0 11C0 17.075 4.925 22 11 22C17.075 22 22 17.075 22 11C22 4.925 17.075 0 11 0ZM12 15C12 15.2652 11.8946 15.5196 11.7071 15.7071C11.5196 15.8946 11.2652 16 11 16C10.7348 16 10.4804 15.8946 10.2929 15.7071C10.1054 15.5196 10 15.2652 10 15V12H7C6.73478 12 6.48043 11.8946 6.29289 11.7071C6.10536 11.5196 6 11.2652 6 11C6 10.7348 6.10536 10.4804 6.29289 10.2929C6.48043 10.1054 6.73478 10 7 10H10V7C10 6.73478 10.1054 6.48043 10.2929 6.29289C10.4804 6.10536 10.7348 6 11 6C11.2652 6 11.5196 6.10536 11.7071 6.29289C11.8946 6.48043 12 6.73478 12 7V10H15C15.2652 10 15.5196 10.1054 15.7071 10.2929C15.8946 10.4804 16 10.7348 16 11C16 11.2652 15.8946 11.5196 15.7071 11.7071C15.5196 11.8946 15.2652 12 15 12H12V15Z'
|
||||
fill='currentColor'
|
||||
</form>
|
||||
<div className='h-full flex items-center justify-around pr-6'>
|
||||
<button
|
||||
className='w-full h-full flex items-center justify-center p-1 text-2xl transition hover:-translate-y-1'
|
||||
onClick={handleVisibleEmojiPicker}
|
||||
>
|
||||
🙂
|
||||
</button>
|
||||
<button className='cursor-pointer relative w-full h-full flex items-center justify-center p-1 text-green-800 dark:text-green-400 transition hover:-translate-y-1'>
|
||||
<input
|
||||
type='file'
|
||||
className='absolute w-full h-full opacity-0 cursor-pointer'
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<svg width='25' height='25' viewBox='0 0 22 22'>
|
||||
<path
|
||||
d='M11 0C4.925 0 0 4.925 0 11C0 17.075 4.925 22 11 22C17.075 22 22 17.075 22 11C22 4.925 17.075 0 11 0ZM12 15C12 15.2652 11.8946 15.5196 11.7071 15.7071C11.5196 15.8946 11.2652 16 11 16C10.7348 16 10.4804 15.8946 10.2929 15.7071C10.1054 15.5196 10 15.2652 10 15V12H7C6.73478 12 6.48043 11.8946 6.29289 11.7071C6.10536 11.5196 6 11.2652 6 11C6 10.7348 6.10536 10.4804 6.29289 10.2929C6.48043 10.1054 6.73478 10 7 10H10V7C10 6.73478 10.1054 6.48043 10.2929 6.29289C10.4804 6.10536 10.7348 6 11 6C11.2652 6 11.5196 6.10536 11.7071 6.29289C11.8946 6.48043 12 6.73478 12 7V10H15C15.2652 10 15.5196 10.1054 15.7071 10.2929C15.8946 10.4804 16 10.7348 16 11C16 11.2652 15.8946 11.5196 15.7071 11.7071C15.5196 11.8946 15.2652 12 15 12H12V15Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user