diff --git a/e2eTests/newUser.e2e.ts b/e2eTests/newUser.e2e.ts index 1fb610d6e..2ba703847 100644 --- a/e2eTests/newUser.e2e.ts +++ b/e2eTests/newUser.e2e.ts @@ -54,10 +54,4 @@ test('User can create new community, register and send few messages to general c const messageGroupContent = messagesGroup.find('p').withAttribute('data-testid', /messagesGroupContent-/) await t.expect(messageGroupContent.exists).ok() await t.expect(messageGroupContent.textContent).eql('Hello\xa0everyone') - - // Send second message, should appear in the same messages group - await t.typeText(messageInput, 'Welcome') - await t.pressKey('enter') - await t.expect(messagesGroup.count).eql(1) - await t.expect(messageGroupContent.textContent).eql('Hello\xa0everyone\nWelcome') }) diff --git a/package-lock.json b/package-lock.json index 54ef5d048..e4804aece 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14947,9 +14947,9 @@ } }, "@zbayapp/nectar": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@zbayapp/nectar/-/nectar-1.19.2.tgz", - "integrity": "sha512-ripZLZmO8CxplO16rAEcPKwKkb9zsZQ02yROzk+yuhSRXtd62RueGqyh6E0x5lUI2CoWMMqcww1XhiaG9M1CIA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@zbayapp/nectar/-/nectar-1.20.0.tgz", + "integrity": "sha512-taPmnjyg/Shr9WQg/isBWCyCfjARL5zLy3rd7Jmr8Ji4AozgEAKRr1eMB/glVe4sseGMSRPT7BLgLWuDX1gP9Q==", "requires": { "@reduxjs/toolkit": "^1.6.1", "debug": "^4.3.2", diff --git a/package.json b/package.json index 052aebb1c..c741919ab 100644 --- a/package.json +++ b/package.json @@ -229,7 +229,7 @@ "@types/ps-node": "^0.1.0", "@types/redux-debounced": "^0.2.19", "@zbayapp/identity": "^3.3.3", - "@zbayapp/nectar": "^1.19.2", + "@zbayapp/nectar": "^1.20.0", "asn1js": "^2.1.1", "async": "^3.1.0", "atob": "^2.1.2", diff --git a/src/renderer/components/pages/Channel.stories.tsx b/src/renderer/components/pages/Channel.stories.tsx index 267c0f741..e0eb548ab 100644 --- a/src/renderer/components/pages/Channel.stories.tsx +++ b/src/renderer/components/pages/Channel.stories.tsx @@ -7,45 +7,56 @@ import ChannelComponent, { ChannelComponentProps } from './Channel' import { DisplayableMessage } from '@zbayapp/nectar' const Template: ComponentStory = args => { - const [messages, setMessages] = useState([ - { - id: 'id', - type: 1, - message: 'Hello', - createdAt: '0', - nickname: 'holmes' - }, - { - id: 'id', - type: 1, - message: 'How are you? My day was awesome. I removed a lot of unused props from container and I simplified code a lot. I like coding, coding is like building things with LEGO. I could admit it\'s a little bit harder and there\'s a lot that can go wrong but I like it anyway.', - createdAt: '0', - nickname: 'holmes' - }, - { - id: 'id', - type: 1, - message: 'Great, thanks!', - createdAt: '0', - nickname: 'bartek' - } - ]) + const [messages, _setMessages] = useState<{ [day: string]: DisplayableMessage[][] }>({ + '28 Oct': [ + [ + { + id: '1', + type: 1, + message: 'Hello', + createdAt: 0, + date: '28 Oct, 10:00', + nickname: 'holmes' + }, + { + id: '2', + type: 1, + message: + "How are you? My day was awesome. I removed a lot of unused props from container and I simplified code a lot. I like coding, coding is like building things with LEGO. I could admit it's a little bit harder and there's a lot that can go wrong but I like it anyway.", + createdAt: 0, + date: '28 Oct, 10:01', + nickname: 'holmes' + } + ], + [ + { + id: '3', + type: 1, + message: 'Great, thanks!', + createdAt: 0, + date: '28 Oct, 10:02', + nickname: 'bartek' + } + ] + ], + Today: [ + [ + { + id: '4', + type: 1, + message: 'Luck, I am your father!', + createdAt: 0, + date: '12:40', + nickname: 'wiktor' + } + ] + ] + }) - const sendMessage = useCallback((message: string) => { - const displayableMessage = { - id: 'id', - type: 1, - message: message, - createdAt: '0', - nickname: 'wiktor' - } - setMessages(messages => [...messages, displayableMessage]) - }, []) + const sendMessage = useCallback((_message: string) => {}, []) + + args.messages = messages - args.messages = [{ - day: 'Today', - messages: messages - }] args.onInputEnter = sendMessage return @@ -90,21 +101,21 @@ const args: ChannelComponentProps = { }, channelSettingsModal: { open: false, - handleOpen: function (_args?: any): any { }, - handleClose: function (): any { } + handleOpen: function (_args?: any): any {}, + handleClose: function (): any {} }, channelInfoModal: { open: false, - handleOpen: function (_args?: any): any { }, - handleClose: function (): any { } + handleOpen: function (_args?: any): any {}, + handleClose: function (): any {} }, - messages: [], - onDelete: function (): void { }, - onInputChange: function (_value: string): void { }, - onInputEnter: function (_message: string): void { }, + messages: {}, + onDelete: function (): void {}, + onInputChange: function (_value: string): void {}, + onInputEnter: function (_message: string): void {}, mutedFlag: false, notificationFilter: '', - openNotificationsTab: function (): void { } + openNotificationsTab: function (): void {} } Component.args = args diff --git a/src/renderer/components/pages/Channel.tsx b/src/renderer/components/pages/Channel.tsx index ac6157b5b..899eb0c30 100644 --- a/src/renderer/components/pages/Channel.tsx +++ b/src/renderer/components/pages/Channel.tsx @@ -12,9 +12,8 @@ import ChannelInputComponent from '../widgets/channels/ChannelInput' import { useModal } from '../../containers/hooks' -import { IChannelInfo } from '@zbayapp/nectar' +import { DisplayableMessage, PublicChannel } from '@zbayapp/nectar' import { Identity } from '@zbayapp/nectar/lib/sagas/identity/identity.slice' -import { MessagesGroupedByDay } from '@zbayapp/nectar/lib/sagas/publicChannels/publicChannels.types' const useStyles = makeStyles(theme => ({ root: {}, @@ -26,10 +25,10 @@ const useStyles = makeStyles(theme => ({ export interface ChannelComponentProps { user: Identity - channel: IChannelInfo + channel: PublicChannel channelSettingsModal: ReturnType channelInfoModal: ReturnType - messages: MessagesGroupedByDay + messages: { [date: string]: DisplayableMessage[][] } onDelete: () => void onInputChange: (value: string) => void onInputEnter: (message: string) => void diff --git a/src/renderer/components/widgets/channels/BaseChannelsList.tsx b/src/renderer/components/widgets/channels/BaseChannelsList.tsx index 435f899db..97e86538e 100644 --- a/src/renderer/components/widgets/channels/BaseChannelsList.tsx +++ b/src/renderer/components/widgets/channels/BaseChannelsList.tsx @@ -1,12 +1,12 @@ import React from 'react' -import { IChannelInfo } from '@zbayapp/nectar' +import { PublicChannel } from '@zbayapp/nectar' import List from '@material-ui/core/List' import ChannelsListItem from '../../../containers/widgets/channels/ChannelsListItem' interface BaseChannelsListProps { - channels: IChannelInfo[] + channels: PublicChannel[] directMessages?: boolean selected: string } diff --git a/src/renderer/components/widgets/channels/BasicMessage.test.tsx b/src/renderer/components/widgets/channels/BasicMessage.test.tsx index d75a490fd..0593fd31e 100644 --- a/src/renderer/components/widgets/channels/BasicMessage.test.tsx +++ b/src/renderer/components/widgets/channels/BasicMessage.test.tsx @@ -19,13 +19,14 @@ describe('BasicMessage', () => { id: 'string', type: 1, message: 'string', - createdAt: 'string', + createdAt: 0, + date: 'string', nickname: 'string' } const result = renderComponent( - + ) @@ -42,10 +43,10 @@ describe('BasicMessage', () => { class="MuiGrid-root MuiGrid-container MuiGrid-wrap-xs-nowrap MuiGrid-align-items-xs-flex-start" >
Jdenticon
@@ -72,7 +73,7 @@ describe('BasicMessage', () => { class="MuiGrid-root MuiGrid-item" >

string

@@ -80,14 +81,18 @@ describe('BasicMessage', () => {
-

- string -

+

+ string +

+
diff --git a/src/renderer/components/widgets/channels/BasicMessage.tsx b/src/renderer/components/widgets/channels/BasicMessage.tsx index e54656cfc..6fac1a8bd 100644 --- a/src/renderer/components/widgets/channels/BasicMessage.tsx +++ b/src/renderer/components/widgets/channels/BasicMessage.tsx @@ -14,6 +14,7 @@ import Jdenticon from 'react-jdenticon' // import SendMessagePopover from '../../../containers/widgets/channels/SendMessagePopover' import { DisplayableMessage } from '@zbayapp/nectar' +import { NestedMessageContent } from './NestedMessageContent' const useStyles = makeStyles((theme: Theme) => ({ messageCard: { @@ -34,12 +35,6 @@ const useStyles = makeStyles((theme: Theme) => ({ marginTop: -4, marginRight: 5 }, - message: { - marginTop: '-3px', - fontSize: '0.855rem', - whiteSpace: 'pre-line', - lineHeight: '21px' - }, statusIcon: { color: theme.palette.colors.lightGray, fontSize: 21, @@ -90,13 +85,13 @@ export const transformToLowercase = (string: string) => { } export interface BasicMessageProps { - message: DisplayableMessage + messages: DisplayableMessage[] // setActionsOpen: (open: boolean) => void // actionsOpen: boolean // allowModeration?: boolean } -export const BasicMessageComponent: React.FC = ({ message }) => { +export const BasicMessageComponent: React.FC = ({ messages }) => { const classes = useStyles({}) // const [anchorEl, setAnchorEl] = React.useState(null) @@ -109,6 +104,8 @@ export const BasicMessageComponent: React.FC = ({ message }) // const handleClose = () => setAnchorEl(null) + const messageDisplayData = messages[0] + return ( = ({ message }) /> */}
- +
@@ -151,12 +148,12 @@ export const BasicMessageComponent: React.FC = ({ message }) > - {message.nickname} + {messageDisplayData.nickname} {status !== 'failed' && ( - {message.createdAt} + {messageDisplayData.date} )} @@ -186,8 +183,10 @@ export const BasicMessageComponent: React.FC = ({ message }) )} */} - - {message.message} + + {messages.map((message, index) => { + return + })} diff --git a/src/renderer/components/widgets/channels/ChannelHeader.tsx b/src/renderer/components/widgets/channels/ChannelHeader.tsx index 0703f9dba..622608431 100644 --- a/src/renderer/components/widgets/channels/ChannelHeader.tsx +++ b/src/renderer/components/widgets/channels/ChannelHeader.tsx @@ -13,7 +13,7 @@ import silencedBlack from '../../../static/images/silencedBlack.svg' import Tooltip from '../../ui/Tooltip/Tooltip' import ChannelMenuActionComponent, { ChannelMenuActionProps } from './ChannelMenuAction' -import { IChannelInfo } from '@zbayapp/nectar' +import { PublicChannel } from '@zbayapp/nectar' const useStyles = makeStyles(theme => ({ root: { @@ -87,7 +87,7 @@ const useStyles = makeStyles(theme => ({ })) export interface ChannelHeaderProps { - channel: IChannelInfo + channel: PublicChannel } export const ChannelHeaderComponent: React.FC = ({ diff --git a/src/renderer/components/widgets/channels/ChannelMessages.test.tsx b/src/renderer/components/widgets/channels/ChannelMessages.test.tsx index 457d65694..c14f0d55a 100644 --- a/src/renderer/components/widgets/channels/ChannelMessages.test.tsx +++ b/src/renderer/components/widgets/channels/ChannelMessages.test.tsx @@ -9,18 +9,16 @@ describe('ChannelMessages', () => { id: 'string', type: 1, message: 'string', - createdAt: '1636995488.44', + createdAt: 1636995488.44, + date: 'string', nickname: 'string' } jest.spyOn(DateTime, 'utc').mockImplementationOnce(() => DateTime.utc(2019, 3, 7, 13, 3, 48)) - const messages = [ - { - day: 'Today', - messages: [message] - } - ] + const messages = { + Today: [[message]] + } const result = renderComponent( @@ -79,10 +77,10 @@ describe('ChannelMessages', () => { class="MuiGrid-root MuiGrid-container MuiGrid-wrap-xs-nowrap MuiGrid-align-items-xs-flex-start" >
Jdenticon
@@ -109,22 +107,26 @@ describe('ChannelMessages', () => { class="MuiGrid-root MuiGrid-item" >

- 1636995488.44 + string

-

- string -

+

+ string +

+
diff --git a/src/renderer/components/widgets/channels/ChannelMessages.tsx b/src/renderer/components/widgets/channels/ChannelMessages.tsx index 5e0339fd1..90d1b0f37 100644 --- a/src/renderer/components/widgets/channels/ChannelMessages.tsx +++ b/src/renderer/components/widgets/channels/ChannelMessages.tsx @@ -4,12 +4,10 @@ import List from '@material-ui/core/List' import { Scrollbars } from 'rc-scrollbars' -import { loadNextMessagesLimit } from '../../../../shared/static' - import MessagesDivider from '../MessagesDivider' import BasicMessageComponent from './BasicMessage' -import { MessagesGroupedByDay } from '@zbayapp/nectar/lib/sagas/publicChannels/publicChannels.types' +import { DisplayableMessage } from '@zbayapp/nectar' const useStyles = makeStyles(theme => ({ list: { @@ -40,17 +38,13 @@ const useStyles = makeStyles(theme => ({ export interface IChannelMessagesProps { channel: string - messages?: MessagesGroupedByDay - newMessagesLoading?: boolean - setNewMessagesLoading?: (arg: boolean) => void + messages?: { [date: string]: DisplayableMessage[][] } } // TODO: scrollbar smart pagination export const ChannelMessagesComponent: React.FC = ({ channel, - messages = [], - newMessagesLoading, - setNewMessagesLoading + messages = {} }) => { const classes = useStyles({}) @@ -80,29 +74,16 @@ export const ChannelMessagesComponent: React.FC = ({ return () => window.removeEventListener('resize', eventListener) }, [channel, messages, scrollbarRef]) - /* Set new position of a scrollbar handle */ - useEffect(() => { - if (scrollbarRef.current && newMessagesLoading) { - const oneMessageHeight = scrollbarRef.current.getScrollHeight() / messages.length - const newMessagesBlockHeight = oneMessageHeight * loadNextMessagesLimit - setTimeout(() => { - scrollbarRef.current.scrollTop(newMessagesBlockHeight) - }) - setNewMessagesLoading(false) - } - }, [newMessagesLoading]) - return ( - {messages.map((dayItem) => { - const messagesArray = dayItem.messages - const displayTitle = dayItem.day + {Object.keys(messages).map(day => { return ( -
- - {messagesArray.map(message => { - return +
+ + {messages[day].map(items => { // Messages merged by sender (DisplayableMessage[]) + const data = items[0] + return })}
) diff --git a/src/renderer/components/widgets/channels/ChannelRegisteredMessage.test.tsx b/src/renderer/components/widgets/channels/ChannelRegisteredMessage.test.tsx index 6c8c0f53e..16b35e109 100644 --- a/src/renderer/components/widgets/channels/ChannelRegisteredMessage.test.tsx +++ b/src/renderer/components/widgets/channels/ChannelRegisteredMessage.test.tsx @@ -13,7 +13,8 @@ describe('ChannelRegisteredMessage', async () => { id: 'string', type: 1, message: 'string', - createdAt: 'string', + createdAt: 0, + date: 'string', nickname: 'string' } const result = renderComponent( @@ -21,7 +22,7 @@ describe('ChannelRegisteredMessage', async () => { { }} + onChannelClick={() => {}} message={message} /> @@ -68,7 +69,7 @@ describe('ChannelRegisteredMessage', async () => {

- string + 0

diff --git a/src/renderer/components/widgets/channels/ChannelRegisteredMessage.tsx b/src/renderer/components/widgets/channels/ChannelRegisteredMessage.tsx index d6f3a13f0..4612947cc 100644 --- a/src/renderer/components/widgets/channels/ChannelRegisteredMessage.tsx +++ b/src/renderer/components/widgets/channels/ChannelRegisteredMessage.tsx @@ -53,7 +53,7 @@ export const ChannelRegisteredMessage: React.FC = } - timestamp={message.createdAt} + timestamp={String(message.createdAt)} /> ({ @@ -90,8 +90,8 @@ const useStyles = makeStyles(theme => ({ interface JoinChannelModalProps { open: boolean handleClose: () => void - joinChannel: (channel: IChannelInfo) => void - publicChannels: IChannelInfo[] + joinChannel: (channel: PublicChannel) => void + publicChannels: PublicChannel[] users: Dictionary } diff --git a/src/renderer/components/widgets/channels/NestedMessageContent.tsx b/src/renderer/components/widgets/channels/NestedMessageContent.tsx new file mode 100644 index 000000000..b4280e202 --- /dev/null +++ b/src/renderer/components/widgets/channels/NestedMessageContent.tsx @@ -0,0 +1,37 @@ +import { Grid, makeStyles, Typography } from '@material-ui/core' +import { DisplayableMessage } from '@zbayapp/nectar' +import React from 'react' + +const useStyles = makeStyles(() => ({ + message: { + marginTop: '-3px', + fontSize: '0.855rem', + whiteSpace: 'pre-line', + lineHeight: '21px' + }, + firstMessage: { + paddingTop: 0 + }, + nextMessage: { + paddingTop: 4 + } +})) + +export interface NestedMessageContentProps { + message: DisplayableMessage + index: number +} + +export const NestedMessageContent: React.FC = ({ message, index }) => { + const classes = useStyles({}) + + const outerDivStyle = index > 0 ? classes.nextMessage : classes.firstMessage + + return ( + + {message.message} + + ) +} + +export default NestedMessageContent diff --git a/src/renderer/containers/pages/Channel.tsx b/src/renderer/containers/pages/Channel.tsx index 8630750f9..2f504e15f 100644 --- a/src/renderer/containers/pages/Channel.tsx +++ b/src/renderer/containers/pages/Channel.tsx @@ -16,7 +16,7 @@ const Channel = () => { const currentChannelAddress = useSelector(publicChannels.selectors.currentChannel) const currentChannel = channels.find(channel => channel?.address === currentChannelAddress) const displayableMessages = useSelector( - publicChannels.selectors.currentChannelMessagesGroupedByDay + publicChannels.selectors.currentChannelMessagesMergedBySender ) const channelSettingsModal = useModal(ModalName.channelSettingsModal) @@ -45,12 +45,12 @@ const Channel = () => { channelSettingsModal={channelSettingsModal} channelInfoModal={channelInfoModal} messages={displayableMessages} - onDelete={function (): void { }} + onDelete={function (): void {}} onInputChange={onInputChange} onInputEnter={onInputEnter} mutedFlag={false} notificationFilter={''} - openNotificationsTab={function (): void { }} + openNotificationsTab={function (): void {}} /> )} diff --git a/src/renderer/containers/widgets/channels/ChannelsPanel.tsx b/src/renderer/containers/widgets/channels/ChannelsPanel.tsx index 6c2349e7b..9545badd7 100644 --- a/src/renderer/containers/widgets/channels/ChannelsPanel.tsx +++ b/src/renderer/containers/widgets/channels/ChannelsPanel.tsx @@ -1,7 +1,7 @@ import React from 'react' import { useSelector } from 'react-redux' import Grid from '@material-ui/core/Grid' -import { publicChannels, IChannelInfo } from '@zbayapp/nectar' +import { publicChannels, PublicChannel } from '@zbayapp/nectar' import BaseChannelsList from '../../../components/widgets/channels/BaseChannelsList' import SidebarHeader from '../../../components/ui/Sidebar/SidebarHeader' @@ -12,7 +12,7 @@ import { useModal } from '../../hooks' import { ModalName } from '../../../sagas/modals/modals.types' interface useChannelPanelDataReturnTypes { - channels: IChannelInfo[] + channels: PublicChannel[] selected: string } diff --git a/src/renderer/containers/widgets/channels/JoinChannelModal.tsx b/src/renderer/containers/widgets/channels/JoinChannelModal.tsx index 4cd89a454..0ca95451b 100644 --- a/src/renderer/containers/widgets/channels/JoinChannelModal.tsx +++ b/src/renderer/containers/widgets/channels/JoinChannelModal.tsx @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from 'react-redux' import { publicChannels } from '@zbayapp/nectar' import JoinChannelModalComponent from '../../../components/widgets/channels/JoinChannelModal' import channelHandlers from '../../../store/handlers/channel' -import { IChannelInfo } from '@zbayapp/nectar/lib/sagas/publicChannels/publicChannels.types' +import { PublicChannel } from '@zbayapp/nectar/lib/sagas/publicChannels/publicChannels.types' import { ModalName } from '../../../sagas/modals/modals.types' import { useModal } from '../../hooks' @@ -20,7 +20,7 @@ const useJoinChannelData = () => { export const useJoinChannelActions = () => { const dispatch = useDispatch() const actions = { - joinChannel: (channel: IChannelInfo) => { + joinChannel: (channel: PublicChannel) => { dispatch(channelHandlers.epics.linkChannelRedirect(channel)) } } diff --git a/src/renderer/sagas/publicChannels/publicChannels.reducer.ts b/src/renderer/sagas/publicChannels/publicChannels.reducer.ts index 5bad52bf7..39e61888f 100644 --- a/src/renderer/sagas/publicChannels/publicChannels.reducer.ts +++ b/src/renderer/sagas/publicChannels/publicChannels.reducer.ts @@ -22,7 +22,7 @@ // message: BasicMessage // } -// interface IChannelInfo { +// interface PublicChannel { // address: string // name: string // description: string @@ -32,7 +32,7 @@ // } // export interface IChannelInfoResponse { -// [name: string]: IChannelInfo +// [name: string]: PublicChannel // } // export const publicChannelsActions = { @@ -46,7 +46,7 @@ // }, // Socket.RESPONSE_FETCH_ALL_MESSAGES // >(Socket.RESPONSE_FETCH_ALL_MESSAGES), -// subscribeForTopic: createAction( +// subscribeForTopic: createAction( // Socket.SUBSCRIBE_FOR_TOPIC // ), // getPublicChannels: createAction(Socket.GET_PUBLIC_CHANNELS),