-
Notifications
You must be signed in to change notification settings - Fork 356
CRNS-116: Channel preview tests and hooks #251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
833ed47
bd502b0
47bea70
a3e5a5a
8f80d79
064d08b
8363ecb
078b5fa
f76c071
d82db82
adad340
114d934
e7d2776
f61cd25
ea7293f
82ed932
b65c1c7
000c79b
716b69b
9fe7c83
c408777
d660779
3f52e4c
12b5df6
ed90646
c621c34
87dbf01
896699c
ab3f107
444f98a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| module.exports = { | ||
| presets: ['@babel/env', '@babel/react', '@babel/preset-flow'], | ||
| plugins: [ | ||
| 'macros', | ||
| '@babel/proposal-class-properties', | ||
| '@babel/transform-runtime', | ||
| 'babel-plugin-styled-components', | ||
| ], | ||
| env: { | ||
| production: { | ||
| presets: [ | ||
| [ | ||
| '@babel/env', | ||
| { | ||
| modules: false, | ||
| }, | ||
| ], | ||
| ], | ||
| }, | ||
| }, | ||
| overrides: [ | ||
| { | ||
| compact: false, | ||
| }, | ||
| ], | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { registerNativeHandlers } from './src/native'; | ||
|
|
||
| registerNativeHandlers({ | ||
| NetInfo: { | ||
| addEventListener: () => {}, | ||
| fetch: () => | ||
| new Promise((resolve) => { | ||
| resolve(); | ||
| }), | ||
| }, | ||
| pickImage: () => null, | ||
| pickDocument: () => null, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| const jestPreset = require('@testing-library/react-native/jest-preset'); | ||
|
|
||
| module.exports = Object.assign(jestPreset, { | ||
| testRegex: [ | ||
| /** | ||
| * If you want to test single file, mention it here | ||
| * e.g., | ||
| * "src/components/ChannelList/__tests__/ChannelList.test.js", | ||
| * "src/components/MessageList/__tests__/MessageList.test.js" | ||
| */ | ||
| ], | ||
| testPathIgnorePatterns: ['/node_modules/', '/examples/', '__snapshots__'], | ||
| moduleNameMapper: { | ||
| 'mock-builders(.*)$': '<rootDir>/src/mock-builders$1', | ||
| '@stream-io/styled-components': | ||
| '<rootDir>/node_modules/@stream-io/styled-components/native/dist/styled-components.native.cjs.js', | ||
| }, | ||
| setupFiles: [...jestPreset.setupFiles, require.resolve('./jest-setup.js')], | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,107 +1,60 @@ | ||
| import React, { PureComponent } from 'react'; | ||
| import React, { useContext, useEffect, useState } from 'react'; | ||
| import PropTypes from 'prop-types'; | ||
|
|
||
| import { withTranslationContext } from '../../context'; | ||
|
|
||
| class ChannelPreview extends PureComponent { | ||
| constructor(props) { | ||
| super(props); | ||
|
|
||
| this.state = { | ||
| unread: 0, | ||
| lastMessage: {}, | ||
| lastRead: new Date(), | ||
| import { ChatContext } from '../../context'; | ||
| import { useLatestMessagePreview } from './hooks/useLatestMessagePreview'; | ||
|
|
||
| /** | ||
| * NOTE: We created an inner component which only receives `client` from the ChatContext. This | ||
| * practice will prevent unnecessary renders of the component when items in ChatContext change | ||
| */ | ||
| const ChannelPreviewWithContext = React.memo((props) => { | ||
| const { channel, client } = props; | ||
| const [lastMessage, setLastMessage] = useState({}); | ||
| const [unread, setUnread] = useState(channel.countUnread()); | ||
| const latestMessage = useLatestMessagePreview(channel, lastMessage); | ||
|
|
||
| useEffect(() => { | ||
| const handleNewMessageEvent = (e) => { | ||
| setLastMessage(e.message); | ||
| setUnread(channel.countUnread()); | ||
| }; | ||
| } | ||
|
|
||
| static propTypes = { | ||
| channel: PropTypes.object.isRequired, | ||
| client: PropTypes.object.isRequired, | ||
| setActiveChannel: PropTypes.func, | ||
| Preview: PropTypes.oneOfType([PropTypes.node, PropTypes.elementType]), | ||
| }; | ||
|
|
||
| static defaultProps = { | ||
| // Preview: ChannelPreviewCountOnly, | ||
| }; | ||
|
|
||
| componentDidMount() { | ||
| // listen to change... | ||
| const channel = this.props.channel; | ||
| this.setState({ unread: channel.countUnread() }); | ||
| channel.on('message.new', this.handleNewMessageEvent); | ||
| channel.on('message.read', this.handleReadEvent); | ||
| } | ||
|
|
||
| componentWillUnmount() { | ||
| const channel = this.props.channel; | ||
| channel.off('message.new', this.handleNewMessageEvent); | ||
| channel.off('message.read', this.handleReadEvent); | ||
| } | ||
|
|
||
| handleReadEvent = (event) => { | ||
| if (event.user.id === this.props.client.userID) { | ||
| this.setState({ unread: this.props.channel.countUnread() }); | ||
| } | ||
| }; | ||
| channel.on('message.new', handleNewMessageEvent); | ||
|
|
||
| handleNewMessageEvent = (event) => { | ||
| const channel = this.props.channel; | ||
| this.setState({ | ||
| lastMessage: event.message, | ||
| unread: channel.countUnread(), | ||
| }); | ||
| }; | ||
|
|
||
| getLatestMessage = () => { | ||
| const { channel, t, tDateTimeParser } = this.props; | ||
| const message = channel.state.messages[channel.state.messages.length - 1]; | ||
| return () => { | ||
| channel.off('message.new', handleNewMessageEvent); | ||
| }; | ||
| }, []); | ||
|
|
||
| const latestMessage = { | ||
| text: '', | ||
| created_at: '', | ||
| messageObject: { ...message }, | ||
| useEffect(() => { | ||
| const handleReadEvent = (e) => { | ||
| if (e.user.id === client.userID) { | ||
| setUnread(0); | ||
| } | ||
| }; | ||
|
|
||
| if (!message) { | ||
| latestMessage.text = t('Nothing yet...'); | ||
| return latestMessage; | ||
| } | ||
| if (message.deleted_at) { | ||
| latestMessage.text = t('Message deleted'); | ||
| return latestMessage; | ||
| } | ||
| channel.on('message.read', handleReadEvent); | ||
|
|
||
| if (message.text) { | ||
| latestMessage.text = message.text; | ||
| } else { | ||
| if (message.command) { | ||
| latestMessage.text = '/' + message.command; | ||
| } else if (message.attachments.length) { | ||
| latestMessage.text = t('🏙 Attachment...'); | ||
| } else { | ||
| latestMessage.text = t('Empty message...'); | ||
| } | ||
| } | ||
| return () => { | ||
| channel.off('message.read', handleReadEvent); | ||
| }; | ||
| }, []); | ||
|
|
||
| if (tDateTimeParser(message.created_at).isSame(new Date(), 'day')) | ||
| latestMessage.created_at = tDateTimeParser(message.created_at).format( | ||
| 'LT', | ||
| ); | ||
| else { | ||
| latestMessage.created_at = tDateTimeParser(message.created_at).format( | ||
| 'L', | ||
| ); | ||
| } | ||
| const { Preview } = props; | ||
| return <Preview {...props} latestMessage={latestMessage} unread={unread} />; | ||
| }); | ||
|
|
||
| return latestMessage; | ||
| }; | ||
| const ChannelPreview = (props) => { | ||
| const { client } = useContext(ChatContext); | ||
| return <ChannelPreviewWithContext {...props} {...{ client }} />; | ||
| }; | ||
|
|
||
| render() { | ||
| const props = { ...this.state, ...this.props }; | ||
| const { Preview } = this.props; | ||
| return <Preview {...props} latestMessage={this.getLatestMessage()} />; | ||
| } | ||
| } | ||
| ChannelPreview.propTypes = { | ||
| channel: PropTypes.object.isRequired, | ||
| client: PropTypes.object.isRequired, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is no longer a required prop as we're pulling it from ChatContext, right?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true, and we're going to axe all these prop types anyways shortly with TS |
||
| setActiveChannel: PropTypes.func, | ||
| Preview: PropTypes.oneOfType([PropTypes.node, PropTypes.elementType]), | ||
| }; | ||
|
|
||
| export default withTranslationContext(ChannelPreview); | ||
| export default ChannelPreview; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason why we're a couple versions behind on RN?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DanC5 Yeah, I can't seem to remember exactly but it was breaking for 0.62 and 0.63. But give it a shot!!