feat(pages): add /application/[guildId]/[channelId] (#4)

This commit is contained in:
Divlo
2022-01-01 20:42:25 +01:00
committed by GitHub
parent 91e246b759
commit fdc2a2d1de
118 changed files with 6040 additions and 2094 deletions

View File

@ -0,0 +1,16 @@
import { Meta, Story } from '@storybook/react'
import { Message as Component, MessageProps } from './Message'
import { messageExampleComplete } from '../../../../cypress/fixtures/messages/message'
const Stories: Meta = {
title: 'Message',
component: Component
}
export default Stories
export const Message: Story<MessageProps> = (arguments_) => {
return <Component {...arguments_} />
}
Message.args = { message: messageExampleComplete }

View File

@ -0,0 +1,61 @@
import Image from 'next/image'
import Link from 'next/link'
import date from 'date-and-time'
import { MessageWithMember } from '../../../../models/Message'
import { API_URL } from '../../../../tools/api'
import { MessageContent } from './MessageContent'
export interface MessageProps {
message: MessageWithMember
}
export const Message: React.FC<MessageProps> = (props) => {
const { message } = props
return (
<div className='p-4 flex transition hover:bg-gray-200 dark:hover:bg-gray-900'>
<Link href={`/application/users/${message.member.user.id}`}>
<a>
<div className='w-12 h-12 mr-4 flex flex-shrink-0 items-center justify-center'>
<div className='w-10 h-10 drop-shadow-md'>
<Image
className='rounded-full'
src={
message.member.user.logo == null
? '/images/data/user-default.png'
: API_URL + message.member.user.logo
}
alt={"Users's profil picture"}
width={50}
height={50}
draggable={false}
/>
</div>
</div>
</a>
</Link>
<div className='w-full'>
<div className='w-max flex items-center'>
<Link href={`/application/users/${message.member.user.id}`}>
<a>
<span
data-cy='message-member-user-name'
className='font-bold text-gray-900 dark:text-gray-200'
>
{message.member.user.name}
</span>
</a>
</Link>
<span
data-cy='message-date'
className='text-gray-500 dark:text-gray-200 text-xs ml-4 select-none'
>
{date.format(new Date(message.createdAt), 'DD/MM/YYYY - HH:mm:ss')}
</span>
</div>
<MessageContent message={message} />
</div>
</div>
)
}

View File

@ -0,0 +1,46 @@
import { useMemo } from 'react'
import ReactMarkdown from 'react-markdown'
import gfm from 'remark-gfm'
import remarkBreaks from 'remark-breaks'
import { Emoji, emojiPlugin, isStringWithOnlyOneEmoji } from '../../../../Emoji'
import { MessageWithMember } from '../../../../../models/Message'
export interface MessageContentProps {
message: MessageWithMember
}
export const MessageContent: React.FC<MessageContentProps> = (props) => {
const { message } = props
const isMessageWithOnlyOneEmoji = useMemo(() => {
return isStringWithOnlyOneEmoji(message.value)
}, [message.value])
if (isMessageWithOnlyOneEmoji) {
return (
<div>
<p>
<Emoji value={message.value} size={40} />
</p>
</div>
)
}
return (
<ReactMarkdown
disallowedElements={['table']}
unwrapDisallowed
remarkPlugins={[[gfm], [remarkBreaks]]}
rehypePlugins={[emojiPlugin]}
linkTarget='_blank'
components={{
emoji: (props) => {
return <Emoji value={props.value} size={20} />
}
}}
>
{message.value}
</ReactMarkdown>
)
}

View File

@ -0,0 +1 @@
export * from './MessageContent'

View File

@ -0,0 +1 @@
export * from './Message'

View File

@ -1,12 +0,0 @@
import { Meta, Story } from '@storybook/react'
import { Messages as Component } from './'
const Stories: Meta = {
title: 'Messages',
component: Component
}
export default Stories
export const Messages: Story = (arguments_) => <Component {...arguments_} />

View File

@ -1,10 +0,0 @@
import { render } from '@testing-library/react'
import { Messages } from './'
describe('<Messages />', () => {
it('should render successfully', () => {
const { baseElement } = render(<Messages />)
expect(baseElement).toBeTruthy()
})
})

View File

@ -1,82 +1,45 @@
import Image from 'next/image'
import TextareaAutosize from 'react-textarea-autosize'
import InfiniteScroll from 'react-infinite-scroll-component'
import { Loader } from 'components/design/Loader'
import { Message } from './Message'
import { useMessages } from 'contexts/Messages'
import { Emoji } from 'components/Emoji'
export const Messages: React.FC = () => {
const { messages, hasMore, nextPage } = useMessages()
if (messages.length === 0) {
return (
<div
id='messages'
className='w-full scrollbar-firefox-support overflow-y-auto transition-all flex-1 flex flex-col text-center mt-8 text-lg'
>
<p>
Nothing to show here! <Emoji value=':ghost:' size={20} />
</p>
<p>Start chatting to kill this Ghost!</p>
</div>
)
}
return (
<>
<div className='w-full scrollbar-firefox-support overflow-y-auto transition-all'>
{new Array(20).fill(null).map((_, index) => {
return (
<div
key={index}
className='p-4 flex transition hover:bg-gray-200 dark:hover:bg-gray-900'
>
<div className='w-12 h-12 mr-4 flex flex-shrink-0 items-center justify-center'>
<div className='w-10 h-10 drop-shadow-md'>
<Image
className='rounded-full'
src='/images/data/user-default.png'
alt='logo'
width={50}
height={50}
/>
</div>
</div>
<div className='w-full'>
<div className='w-max flex items-center'>
<span className='font-bold text-gray-900 dark:text-gray-200'>
Divlo
</span>
<span className='text-gray-500 dark:text-gray-200 text-xs ml-4 select-none'>
06/04/2021 - 22:28:40
</span>
</div>
<div className='text-gray-800 dark:text-gray-300 font-paragraph mt-1 break-words'>
<p>Message {index}</p>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Eum debitis voluptatum itaque quaerat. Nemo optio voluptas
quas mollitia rerum commodi laboriosam voluptates et sit
quo. Repudiandae eius at inventore magnam. Voluptas nisi
maxime laborum architecto fuga a consequuntur reiciendis
rerum beatae hic possimus, omnis dolorum libero, illo
dolorem assumenda. Repellat, ad!
</p>
</div>
</div>
</div>
)
<div
id='messages'
className='w-full scrollbar-firefox-support overflow-y-auto transition-all flex-1 flex flex-col-reverse'
>
<InfiniteScroll
scrollableTarget='messages'
className='messages-list'
dataLength={messages.length}
next={nextPage}
inverse
hasMore={hasMore}
loader={<Loader />}
>
{messages.map((message) => {
return <Message key={message.id} message={message} />
})}
</div>
<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='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'
/>
<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>
</>
</InfiniteScroll>
</div>
)
}