Skip to content
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

Add a chat switcher to the LHN #282

Merged
merged 85 commits into from
Aug 27, 2020
Merged

Add a chat switcher to the LHN #282

merged 85 commits into from
Aug 27, 2020

Conversation

tgolen
Copy link
Contributor

@tgolen tgolen commented Aug 21, 2020

Fixes #269

  • Refactors the sidebar component to break it up into smaller and more focused pieces
  • Adds a chat switcher
  • Adds a Command+K keyboard shortcut to access the chat switcher

Tests

  1. Press Command+K and verify the chat switcher gets focused
  2. Begin typing names or emails and see the list of people appear
  3. Use the arrow keys to highlight different options
  4. Press the enter key to select an option (or click on an option)

Things left to do

  • style it (@shawnborton )
  • hook up a method to get the reportID and redirect the user to that report

@tgolen tgolen self-assigned this Aug 21, 2020
Copy link
Contributor

@marcaaron marcaaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far! Just left some initial comments mostly around the ChatSwitcher which I'm guessing has some copy/paste stuff going on


// All of the personal details for everyone
// Eslint is disabled here because personalDetails is an object where they keys are email addresses
// so it can't be documented in proptypes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's what PropTypes.objectOf() is for

constructor(props) {
super(props);

this.maxSearchResults = 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a constant can we move it outside the component?

* @param {number} oldFocusedIndex
* @param {number} newFocusedIndex
*/
switchFocusedIndex(oldFocusedIndex, newFocusedIndex) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could track the focused index in state and re-render the options. Seems simpler to do that vs. having an option with a focused property.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. if index === this.state.focusedIndex do whatever we need to do on render or pass focused as a prop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, the web-e component puts this in the state too, and I actually felt it was better to leave it out of the state. If you look at that component, there is a bunch of stuff in state, and I was trying to clean that up. However, I think putting it into state will be fine and I'd like to keep it closely aligned with web-e.

}

/**
* Every time the text changes in the TextInput, update the search value in the state
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does a lot more than this

* @param {string} value
*/
updateSearch(value) {
this.setState({search: value});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this setState call be combined with the one below?

src/page/home/sidebar/ChatSwitcherView.js Show resolved Hide resolved
new RegExp(Str.escapeForRegExp(value), 'i'),
];

// Use a Set so that duplicate values are automatically removed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this statement is false if your Set values are objects. You could use a Map and use something unique like the login as the key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, you're right. I thought this cleared up a bug, but maybe it was something else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I found out that the Set is still good to use here. Looking at the MDN docs, the equality check also works to remove the same instances of an object. Example:

image

The same obj1 is added to the set twice and it is not duplicated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I was presuming that we would not want to add two objects that had the same shape and values. But maybe that is wrong?


// Set the first option to be focused
if (options.length) {
options[0].focused = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More extra logic needed to accommodate the focused property

ref={el => this.textInput = el}
style={[styles.textInput, styles.textInputReversed, styles.flex1]}
value={this.state.search}
onBlur={() => this.state.search === '' && this.props.onBlur()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting. But I think might look cleaner with brackets and a if for early return

src/page/home/sidebar/ChatSwitcherView.js Show resolved Hide resolved
Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level, I have three main comments here:

  • It's not compatible with desktop, but fixing those issues to get React Native to play nice with Electron might be challenging, and probably warrants its own issue/PR. That being said, I do think it's doable: there's an early-stage npm project addressing some of the challenging pieces, such as hotkeys, links, dialogs/alerts, and clipboard. While it doesn't offer stability yet, it's open-source I'm sure the developer would welcome PR's. If we don't like that idea, maybe we could also just work-around it by having separate files when we need to use some Electron-specific code for desktop (i.e: index.desktop.js)
  • Beyond the actual functionality, the download links need to detect the current platform to show the other three.
  • There were a handful of instances where you used underscore functions for which there is a native-javascript equivalent, and I think it might be best to stick with plain JS whenever convenient. In some cases I think it's more performant too, i.e: not extending an object with all the underscore methods like _(myObject), just to use one function.

src/lib/KeyboardShortcut/index.js Show resolved Hide resolved
let cb = events[event.keyCode];
cb = cb[cb.length - 1];

const pressedModifiers = _.all(cb.modifiers, (modifier) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: AFAIK we don't have style guide recommendations on this matter, but I would prefer the pure-js alternative to underscore:

cb.modifiers.every((modifier) => { ... });

}

// The active callback is the last element in the array
let cb = events[event.keyCode];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer const:

const cb = _.last(events[event.keyCode]);

src/page/home/sidebar/AppLinks.js Show resolved Hide resolved
src/page/home/sidebar/AppLinks.js Show resolved Hide resolved
src/page/home/sidebar/ChatSwitcherView.js Outdated Show resolved Hide resolved
src/page/home/sidebar/ChatSwitcherView.js Outdated Show resolved Hide resolved

const propTypes = {
// Safe area insets required for mobile devices margins
// eslint-disable-next-line react/forbid-prop-types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could do this (see here):

insets: PropTypes.objectOf(PropTypes.shape(
    top: PropTypes.number,
    left: PropTypes.number,
    right: PropTypes.number,
    bottom: PropTypes.number,
)),

But this prop is drilled down through several layers, so another alternative that I've used in the past is saving some special or complex prop types that are reused multiple times into a file/module of their own (usually just a directory called types and export a PropType object from each file). Not sure whether that's a good choice here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call

src/page/home/sidebar/SidebarLinks.js Show resolved Hide resolved
src/page/home/sidebar/SidebarLinks.js Show resolved Hide resolved
@quinthar
Copy link

quinthar commented Aug 24, 2020 via email

@tgolen
Copy link
Contributor Author

tgolen commented Aug 26, 2020

Updated with conflic fixes and improvements from Marc's review. The StyleSheet.flatten() and StyleSheet.compose() are great!

Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, just the one PropTypes concern!


// Styles to apply to the text input when it has focus
// eslint-disable-next-line react/forbid-prop-types
styleFocusIn: PropTypes.any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can:

import {ViewPropTypes} from 'react-native';

and then:

styleFocusIn: PropTypes.arrayOf(ViewPropTypes.style),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I tried that, and ViewPropTypes is undefined... Any idea why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe because it's deprecated and not exported from react-native-web: reactrondev/react-native-web-swiper#41

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm... maybe PropTypes.instanceOf(StyleSheet) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB if you can't find a good way to typecheck this, but I'd be shocked if there wasn't

Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, meant to request the small typechecking change

roryabraham
roryabraham previously approved these changes Aug 26, 2020
Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to NAB

@marcaaron
Copy link
Contributor

LGTM and doesn't seem to be any blockers now so I am merging.

@marcaaron marcaaron merged commit 7d04aed into master Aug 27, 2020
@marcaaron marcaaron deleted the tgolen-chat-switcher branch August 27, 2020 22:38
sketchydroide added a commit that referenced this pull request Oct 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

DMs / Add Chat Switcher
5 participants