remove user search from chat channel settings (#7015)

This commit is contained in:
Molly Struve 2020-04-02 02:13:51 -05:00 committed by GitHub
parent 9cebaa53e7
commit 7240ccd372
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 0 additions and 944 deletions

View file

@ -1,368 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<ChannelDetails /> as a moderator should render and test snapshot 1`] = `
<div
class="channeldetails"
>
<h1
class="channeldetails__name"
>
channel name
</h1>
<div
class="channeldetails__description"
style={
Object {
"marginBottom": "20px",
}
}
>
<em>
something about this channel
</em>
</div>
<div
class="channeldetails__user"
>
<img
alt="channeluser1 profile"
class="channeldetails__userprofileimage"
data-content="sidecar-user"
/>
<a
data-content="sidecar-user"
href="/channeluser1"
style={
Object {
"color": undefined,
"padding": "3px 0px",
}
}
>
channel user 1
</a>
</div>
<div
class="channeldetails__user"
>
<img
alt="channeluser2 profile"
class="channeldetails__userprofileimage"
data-content="sidecar-user"
/>
<a
data-content="sidecar-user"
href="/channeluser2"
style={
Object {
"color": undefined,
"padding": "3px 0px",
}
}
>
channel user 2
</a>
</div>
<div
class="channeldetails__inviteusers"
>
<h2>
Invite Members
</h2>
<input
onKeyUp={[Function]}
placeholder="Find users"
/>
<div
class="channeldetails__searchresults"
/>
<h2>
Pending Invites:
</h2>
<div
class="channeldetails__pendingusers"
>
<a
data-content="users/pendinguserid1"
href="/pendinguser1"
rel="noopener noreferrer"
target="_blank"
>
@pendinguser1 - pending user 1
</a>
</div>
<div
class="channeldetails__pendingusers"
>
<a
data-content="users/pendinguserid2"
href="/pendinguser2"
rel="noopener noreferrer"
target="_blank"
>
@pendinguser2 - pending user 2
</a>
</div>
<div
style={
Object {
"marginTop": "10px",
}
}
>
Contact yo@dev.to for assistance.
</div>
</div>
</div>
`;
exports[`<ChannelDetails /> as a moderator should search users and populate searched users div 1`] = `
preact-render-spy (1 nodes)
-------
<div class="channeldetails">
<h1 class="channeldetails__name">channel name</h1>
<div
class="channeldetails__description"
style="margin-bottom: 20px;"
>
<em>something about this channel</em>
</div>
<div class="channeldetails__user">
<img
class="channeldetails__userprofileimage"
alt="channeluser1 profile"
data-content="sidecar-user"
/>
<a
href="/channeluser1"
style="padding: 3px 0px;"
data-content="sidecar-user"
>
channel user 1
</a>
</div>
<div class="channeldetails__user">
<img
class="channeldetails__userprofileimage"
alt="channeluser2 profile"
data-content="sidecar-user"
/>
<a
href="/channeluser2"
style="padding: 3px 0px;"
data-content="sidecar-user"
>
channel user 2
</a>
</div>
<div class="channeldetails__inviteusers">
<h2>Invite Members</h2>
<input
onKeyUp={[Function debounced]}
placeholder="Find users"
/>
<div class="channeldetails__searchresults">
<div class="channeldetails__searchedusers">
<a
href="/user_path1"
target="_blank"
rel="noopener noreferrer"
>
<img
src="channeluser1pic.png"
alt="profile_image"
/>
@channeluser1 - i am channel user 1
</a>
<span class="channel__member">
is already in
<em>channel name</em>
</span>
</div>
<div class="channeldetails__searchedusers">
<a
href="/search_path3"
target="_blank"
rel="noopener noreferrer"
>
<img
src="searcheduser3pic.png"
alt="profile_image"
/>
@searcheduser3 - i am searched user 3
</a>
<button
type="button"
onClick={[Function anonymous]}
data-content="searched_userid3"
>
Invite
</button>
</div>
</div>
<h2>Pending Invites:</h2>
<div class="channeldetails__pendingusers">
<a
href="/pendinguser1"
target="_blank"
rel="noopener noreferrer"
data-content="users/pendinguserid1"
>
@pendinguser1 - pending user 1
</a>
</div>
<div class="channeldetails__pendingusers">
<a
href="/pendinguser2"
target="_blank"
rel="noopener noreferrer"
data-content="users/pendinguserid2"
>
@pendinguser2 - pending user 2
</a>
</div>
<div style="margin-top: 10px;">Contact yo@dev.to for assistance.</div>
</div>
</div>
`;
exports[`<ChannelDetails /> as a user should leave channel and show appropriate message 1`] = `
preact-render-spy (1 nodes)
-------
<div class="channeldetails">
<h1 class="channeldetails__name">channel name</h1>
<div
class="channeldetails__description"
style="margin-bottom: 20px;"
>
<em>something about this channel</em>
</div>
<div class="channeldetails__user">
<img
class="channeldetails__userprofileimage"
alt="channeluser1 profile"
data-content="sidecar-user"
/>
<a
href="/channeluser1"
style="padding: 3px 0px;"
data-content="sidecar-user"
>
channel user 1
</a>
</div>
<div class="channeldetails__user">
<img
class="channeldetails__userprofileimage"
alt="channeluser2 profile"
data-content="sidecar-user"
/>
<a
href="/channeluser2"
style="padding: 3px 0px;"
data-content="sidecar-user"
>
channel user 2
</a>
</div>
<div class="channeldetails__leftchannel">
<h2>Danger Zone</h2>
<h3>
You have left this channel
<span
role="img"
aria-label="emoji"
>
😢😢😢
</span>
</h3>
<h4>
This may take a few minutes to be reflected in the sidebar
</h4>
</div>
</div>
`;
exports[`<ChannelDetails /> as a user should render and test snapshot 1`] = `
<div
class="channeldetails"
>
<h1
class="channeldetails__name"
>
channel name
</h1>
<div
class="channeldetails__description"
style={
Object {
"marginBottom": "20px",
}
}
>
<em>
something about this channel
</em>
</div>
<div
class="channeldetails__user"
>
<img
alt="channeluser1 profile"
class="channeldetails__userprofileimage"
data-content="sidecar-user"
/>
<a
data-content="sidecar-user"
href="/channeluser1"
style={
Object {
"color": undefined,
"padding": "3px 0px",
}
}
>
channel user 1
</a>
</div>
<div
class="channeldetails__user"
>
<img
alt="channeluser2 profile"
class="channeldetails__userprofileimage"
data-content="sidecar-user"
/>
<a
data-content="sidecar-user"
href="/channeluser2"
style={
Object {
"color": undefined,
"padding": "3px 0px",
}
}
>
channel user 2
</a>
</div>
<div
class="channeldetails__leavechannel"
>
<h2>
Danger Zone
</h2>
<button
data-content="12345"
onClick={[Function]}
type="button"
>
Leave Channel
</button>
</div>
</div>
`;

View file

@ -1,327 +0,0 @@
import { h } from 'preact';
import render from 'preact-render-to-json';
import { shallow } from 'preact-render-spy';
import { JSDOM } from 'jsdom';
import fetch from 'jest-fetch-mock';
import ChannelDetails from '../channelDetails';
global.fetch = fetch;
const doc = new JSDOM('<!doctype html><html><body></body></html>');
global.document = doc;
global.window = doc.defaultView;
global.window.currentUser = { id: 'modID' };
const channelDetails = mod => {
let id;
if (mod) {
id = 'modID';
} else {
id = 'userID';
}
return {
channel_name: 'channel name',
description: 'something about this channel',
id: '12345',
channel_users: [
{
path: '/user_path1',
title: 'i am channel user 1',
name: 'channel user 1',
username: 'channeluser1',
id: 'userid1',
profile_image_url: 'channeluser1pic.png',
},
{
path: '/user_path2',
title: 'i am channel user 2',
name: 'channel user 2',
username: 'channeluser2',
id: 'userid2',
profile_image_url: 'channeluser2pic.png',
},
],
type_of: 'channel-details',
pending_users_select_fields: [
{
path: '/pending_path1',
title: 'i am pending user 1',
name: 'pending user 1',
username: 'pendinguser1',
id: 'pendinguserid1',
profile_image_url: 'pendinguser1pic.png',
},
{
path: '/pending_path2',
title: 'i am pending user 2',
name: 'pending user 2',
username: 'pendinguser2',
id: 'pendinguserid2',
profile_image_url: 'pendinguser2pic.png',
},
],
channel_mod_ids: id,
};
};
const getChannelDetails = details => (
<ChannelDetails channel={details} activeChannelId={12345} />
);
describe('<ChannelDetails />', () => {
describe('as a moderator', () => {
const moddetails = channelDetails(true);
const context = shallow(getChannelDetails(moddetails));
it('should render and test snapshot', () => {
const tree = render(getChannelDetails(moddetails));
expect(tree).toMatchSnapshot();
});
it('should have the proper elements, attributes and content', () => {
expect(context.find('.channeldetails').exists()).toEqual(true);
expect(context.find('.channeldetails__name').text()).toEqual(
moddetails.channel_name,
);
expect(context.find('.channeldetails__description').text()).toEqual(
moddetails.description,
);
// check user members
const channelmembers = context.find('.channeldetails__user');
expect(channelmembers.exists()).toEqual(true);
for (let i = 0; i < channelmembers.length; i += 1) {
expect(channelmembers.at(i).text()).toEqual(
moddetails.channel_users[i].name,
);
expect(
channelmembers
.at(i)
.childAt(1)
.attr('href'),
).toEqual(`/${moddetails.channel_users[i].username}`);
expect(
channelmembers
.at(i)
.childAt(1)
.attr('data-content'),
).toEqual(`sidecar-user`);
}
// mod only divs
expect(context.find('.channeldetails__searchedusers').exists()).toEqual(
false,
); // no searched users
expect(context.find('.channeldetails__pendingusers').exists()).toEqual(
true,
);
expect(context.find('.channeldetails__inviteusers').exists()).toEqual(
true,
);
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
false,
);
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
false,
);
// check pending members
const pendingusers = context.find('.channeldetails__pendingusers');
for (let i = 0; i < pendingusers.length; i += 1) {
expect(pendingusers.at(i).text()).toEqual(
`@${moddetails.pending_users_select_fields[i].username} - ${moddetails.pending_users_select_fields[i].name}`,
);
expect(
pendingusers
.at(i)
.childAt(0)
.attr('href'),
).toEqual(`/${moddetails.pending_users_select_fields[i].username}`);
expect(
pendingusers
.at(i)
.childAt(0)
.attr('data-content'),
).toEqual(`users/${moddetails.pending_users_select_fields[i].id}`);
}
});
it('should search users and populate searched users div', async () => {
// context.component().triggerUserSearch({ target: { value: 'ma', selectionStart: 2 } })
const searchedusers = {
searchedUsers: [
{
path: '/user_path1',
title: 'i am channel user 1',
user: {
name: 'channel user 1',
username: 'channeluser1',
profile_image_90: 'channeluser1pic.png',
},
id: 'userid1',
},
{
path: '/pending_path1',
title: 'i am pending user 1',
user: {
name: 'pending user 1',
username: 'pendinguser1',
profile_image_90: 'pendinguser1pic.png',
},
id: 'pendinguserid1',
},
{
path: '/search_path3',
title: 'i am searched user 3',
user: {
name: 'searched user 3',
username: 'searcheduser3',
profile_image_90: 'searcheduser3pic.png',
},
id: 'searched_userid3',
},
],
};
context.setState(searchedusers);
context.rerender();
const searchedusersdivs = context.find('.channeldetails__searchedusers');
expect(searchedusersdivs.exists()).toEqual(true);
expect(searchedusersdivs.length).toEqual(2);
let inviteMessage;
let inviteAttr;
let inviteAttrAns;
const included = (list, el) => {
const keys = Object.keys(list);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (list[key].id === el.id) {
return true;
}
}
return false;
};
for (let i = 0; i < searchedusersdivs.length; i += 1) {
if (
!included(
moddetails.pending_users_select_fields,
searchedusers.searchedUsers[i],
)
) {
expect(
searchedusersdivs
.at(i)
.childAt(0)
.attr('href'),
).toEqual(searchedusers.searchedUsers[i].path);
expect(
searchedusersdivs
.at(i)
.childAt(0)
.text(),
).toEqual(
`@${searchedusers.searchedUsers[i].user.username} - ${searchedusers.searchedUsers[i].title}`,
);
if (
included(moddetails.channel_users, searchedusers.searchedUsers[i])
) {
inviteMessage = `is already in ${moddetails.channel_name}`;
inviteAttr = 'className';
inviteAttrAns = 'channel__member';
} else {
inviteMessage = 'Invite';
inviteAttr = 'data-content';
inviteAttrAns = searchedusers.searchedUsers[i].id;
}
expect(
searchedusersdivs
.at(i)
.childAt(2)
.text(),
).toEqual(inviteMessage);
expect(
searchedusersdivs
.at(i)
.childAt(2)
.attr(inviteAttr),
).toEqual(inviteAttrAns);
}
}
const tree = render(context);
expect(tree).toMatchSnapshot();
});
});
describe('as a user', () => {
const userdetails = channelDetails(false);
const context = shallow(getChannelDetails(userdetails));
it('should render and test snapshot', () => {
const tree = render(getChannelDetails(userdetails));
expect(tree).toMatchSnapshot();
});
it('should have the proper elements, attributes and content', () => {
expect(context.find('.channeldetails').exists()).toEqual(true);
expect(context.find('.channeldetails__name').text()).toEqual(
userdetails.channel_name,
);
expect(context.find('.channeldetails__description').text()).toEqual(
userdetails.description,
);
const channelmembers = context.find('.channeldetails__user');
expect(channelmembers.exists()).toEqual(true);
for (let i = 0; i < channelmembers.length; i += 1) {
expect(channelmembers.at(i).text()).toEqual(
userdetails.channel_users[i].name,
);
expect(
channelmembers
.at(i)
.childAt(1)
.attr('href'),
).toEqual(`/${userdetails.channel_users[i].username}`);
expect(
channelmembers
.at(i)
.childAt(1)
.attr('data-content'),
).toEqual(`sidecar-user`);
}
// user only divs
expect(context.find('.channeldetails__searchedusers').exists()).toEqual(
false,
);
expect(context.find('.channeldetails__pendingusers').exists()).toEqual(
false,
);
expect(context.find('.channeldetails__inviteusers').exists()).toEqual(
false,
);
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
false,
);
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
true,
);
});
it('should leave channel and show appropriate message', () => {
// leave channel
context.component().handleLeaveChannelSuccess();
context.rerender();
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
true,
);
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
false,
);
const tree = render(context);
expect(tree).toMatchSnapshot();
});
});
});

View file

@ -1,249 +0,0 @@
import { h, Component } from 'preact';
import PropTypes from 'prop-types';
import debounceAction from '../src/utils/debounceAction';
class ChannelDetails extends Component {
static propTypes = {
channel: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
constructor(props) {
super(props);
this.debouncedUserSearch = debounceAction(
this.triggerUserSearch.bind(this),
{ config: { leading: true } },
);
this.state = {
searchedUsers: [],
hasLeftChannel: false,
};
}
triggerUserSearch = e => {
const component = this;
const query = e.target.value;
if (query.length > 0) {
const searchHash = { per_page: 20, search_fields: query };
const searchParams = new URLSearchParams(searchHash).toString();
fetch(`/search/users?${searchParams}`, {
method: 'GET',
headers: {
Accept: 'application/json',
'X-CSRF-Token': window.csrfToken,
'Content-Type': 'application/json',
},
credentials: 'same-origin',
})
.then(response => response.json())
.then(response => {
component.setState({ searchedUsers: response.result });
});
} else {
component.setState({ searchedUsers: [] });
}
};
triggerInvite = e => {
const component = this;
const id = e.target.dataset.content;
e.target.style.display = 'none';
fetch(`/chat_channel_memberships`, {
method: 'POST',
headers: {
Accept: 'application/json',
'X-CSRF-Token': window.csrfToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({
chat_channel_membership: {
user_id: id,
chat_channel_id: component.props.channel.id,
},
}),
credentials: 'same-origin',
})
.then(response => response)
.then(this.handleInvitationSuccess)
.catch(null);
};
triggerLeaveChannel = e => {
e.preventDefault();
const id = e.target.dataset.content;
fetch(`/chat_channel_memberships/${id}`, {
method: 'DELETE',
headers: {
Accept: 'application/json',
'X-CSRF-Token': window.csrfToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
credentials: 'same-origin',
})
.then(response => response)
.then(this.handleLeaveChannelSuccess)
.catch(null);
};
handleLeaveChannelSuccess = () => {
this.setState({ hasLeftChannel: true });
};
handleInvitationSuccess = response => {
console.log(response); // eslint-disable-line no-console
};
userInList = (list, user) => {
const keys = Object.keys(list);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (user.id === list[key].id) {
return true;
}
}
return false;
};
render() {
const channel = this.props.channel; // eslint-disable-line
const users = Object.values(channel.channel_users).map(user => (
<div className="channeldetails__user">
<img
className="channeldetails__userprofileimage"
src={user.profile_image}
alt={`${user.username} profile`}
data-content="sidecar-user"
/>
<a
href={`/${user.username}`}
style={{ color: user.darker_color, padding: '3px 0px' }}
data-content="sidecar-user"
>
{user.name}
</a>
</div>
));
let subHeader = '';
if (users.length === 25) {
subHeader = <h3>Recently Active Members</h3>;
}
let modSection = '';
let searchedUsers = [];
let pendingInvites = [];
if (channel.channel_mod_ids.includes(window.currentUser.id)) {
// eslint-disable-next-line
searchedUsers = this.state.searchedUsers.map(user => {
if (!this.userInList(channel.pending_users_select_fields, user)) {
let invite = (
<button
type="button"
onClick={this.triggerInvite}
data-content={user.id}
>
Invite
</button>
);
if (this.userInList(channel.channel_users, user)) {
invite = (
<span className="channel__member">
is already in
{' '}
<em>{channel.channel_name}</em>
</span>
);
}
return (
<div className="channeldetails__searchedusers">
<a href={user.path} target="_blank" rel="noopener noreferrer">
<img src={user.user.profile_image_90} alt="profile_image" />
@
{user.user.username}
{' '}
-
{/* prettier-ignore */}
{' '}
{user.title}
</a>
{' '}
{invite}
</div>
);
}
});
pendingInvites = channel.pending_users_select_fields.map(user => (
<div className="channeldetails__pendingusers">
<a
href={`/${user.username}`}
target="_blank"
rel="noopener noreferrer"
data-content={`users/${user.id}`}
>
@
{user.username}
{' '}
-
{' '}
{user.name}
</a>
</div>
));
modSection = (
<div className="channeldetails__inviteusers">
<h2>Invite Members</h2>
<input onKeyUp={this.debouncedUserSearch} placeholder="Find users" />
<div className="channeldetails__searchresults">{searchedUsers}</div>
<h2>Pending Invites:</h2>
{pendingInvites}
<div style={{ marginTop: '10px' }}>
Contact yo@dev.to for assistance.
</div>
</div>
); // eslint-disable-next-line
} else if (this.state.hasLeftChannel) {
modSection = (
<div className="channeldetails__leftchannel">
<h2>Danger Zone</h2>
<h3>
You have left this channel
{' '}
<span role="img" aria-label="emoji">
😢😢😢
</span>
</h3>
<h4>This may take a few minutes to be reflected in the sidebar</h4>
</div>
);
} else {
modSection = (
<div className="channeldetails__leavechannel">
<h2>Danger Zone</h2>
<button
type="button"
onClick={this.triggerLeaveChannel}
data-content={channel.id}
>
Leave Channel
</button>
</div>
);
}
return (
<div className="channeldetails">
<h1 className="channeldetails__name">{channel.channel_name}</h1>
<div
className="channeldetails__description"
style={{ marginBottom: '20px' }}
>
<em>{channel.description || ''}</em>
</div>
{subHeader}
{users}
{modSection}
</div>
);
}
}
export default ChannelDetails;