UX: Several improvements for chat in nightmode (#2430)
* UX: Several improvements for chat in nightmode * FIX: Some react refactoring * FIX: Fixed failing react tests
This commit is contained in:
parent
e2503ec1c2
commit
81c28886c8
12 changed files with 278 additions and 175 deletions
|
|
@ -119,6 +119,7 @@
|
|||
|
||||
.chat__channeltypefilter{
|
||||
padding: 4px 0px 4px;
|
||||
width: calc(100% - 13px);
|
||||
}
|
||||
|
||||
.chat__channeltypefilterbutton{
|
||||
|
|
@ -137,6 +138,11 @@
|
|||
background: lighten($green, 18%);
|
||||
}
|
||||
|
||||
.chat__channeltypefilterbutton--inactive {
|
||||
color: black;
|
||||
color: var(--theme-container-color, black);
|
||||
}
|
||||
|
||||
.chat_chatconfig{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
|
|
@ -303,6 +309,8 @@
|
|||
}
|
||||
|
||||
.activechatchannel__conversation{
|
||||
border-top: 1px solid $outline-color;
|
||||
border-top: var(--theme-container-border, 1px solid $outline-color);
|
||||
order: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -321,7 +329,7 @@
|
|||
font-weight: bold;
|
||||
font-size:14px;
|
||||
background: $light-gray;
|
||||
background: var(--theme-background, $light-gray);
|
||||
background: var(--theme-container-accent-background, $light-gray);
|
||||
a {
|
||||
color: $black;
|
||||
color: var(--theme-color, $black);
|
||||
|
|
@ -365,7 +373,7 @@
|
|||
border-top: 1px solid $outline-color;
|
||||
border-top: var(--theme-container-border, 1px solid $outline-color);
|
||||
background: #ededed;
|
||||
background: var(--theme-background, #ededed);
|
||||
background: var(--theme-container-accent-background, #ededed);
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
}
|
||||
|
|
@ -391,11 +399,12 @@
|
|||
min-width: 45%;
|
||||
// margin-left: -50%;
|
||||
background: white;
|
||||
background: var(--theme-container-accent-background, white);
|
||||
// flex-basis: 80%;
|
||||
z-index: 200;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
max-width:96%;
|
||||
@media screen and ( max-width: 426px ) {
|
||||
padding: 10px;
|
||||
|
|
@ -427,6 +436,7 @@
|
|||
border: 0px;
|
||||
font-size: 36px;
|
||||
color: $medium-gray;
|
||||
color: var(--theme-container-color, $medium-gray);
|
||||
padding:0px;
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
|
|
@ -449,6 +459,7 @@
|
|||
font-size:0.85em;
|
||||
a{
|
||||
color: $dark-gray;
|
||||
color: var(--theme-container-color, $dark-gray);
|
||||
}
|
||||
.activechatchannel__activeArticleDetailsPath{
|
||||
display: inline-block;
|
||||
|
|
@ -495,6 +506,9 @@
|
|||
border-style: initial;
|
||||
border-color: initial;
|
||||
border-image: initial;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -538,17 +552,20 @@
|
|||
right:0px;
|
||||
padding: 19px;
|
||||
background: white;
|
||||
background: var(--theme-container-accent-background, white);
|
||||
z-index: 20;
|
||||
border-top: 1px solid $light-medium-gray;
|
||||
border-bottom: 1px solid $light-medium-gray;
|
||||
border-right: 1px solid $light-medium-gray;
|
||||
button {
|
||||
border: 1px solid $light-medium-gray;
|
||||
padding: 3px 15px;
|
||||
border-radius: 3px;
|
||||
margin-right: 15px;
|
||||
width: 54px;
|
||||
background: #f2f3f5;
|
||||
background: var(--theme-container-background, #f2f3f5);
|
||||
border-radius: 100px !important;
|
||||
border-width: 0;
|
||||
padding: 5px 10px;
|
||||
&.active {
|
||||
border: 2px solid $black;
|
||||
padding: 2px 14px;
|
||||
background-color:$green;
|
||||
&.unicorn-reaction-button{
|
||||
background-color:$purple;
|
||||
|
|
@ -867,6 +884,12 @@
|
|||
margin-left: 0px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
a h1 {
|
||||
color: $black;
|
||||
color: var(--theme-container-color, $black);
|
||||
border-color: #0a0a0a !important;
|
||||
border-color: var(--theme-container-color, #0a0a0a) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.chatmessagebody__currentuser {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,13 @@
|
|||
|
||||
// channel users
|
||||
.channeldetails__user {
|
||||
a {
|
||||
padding: 0 4px !important;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
}
|
||||
padding: 2px 0;
|
||||
margin-bottom: 10px;
|
||||
.channeldetails__userprofileimage {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ $ease-in-cubic : cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|||
$ease-out-cubic : cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
|
||||
body.night-theme {
|
||||
.on-page-nav-butt img, .icon-img, .dropdown-icon, .reaction-button:not(.reacted) img, .image-upload-button button, .icon-image {
|
||||
.on-page-nav-butt img, .icon-img, .dropdown-icon, .reaction-button:not(.reacted) img, .image-upload-button button, .icon-image,
|
||||
.chatchannels__config img, .external-link-img, .group-img {
|
||||
-webkit-filter: invert(95%);
|
||||
filter: invert(95%);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ exports[`<Article /> should load article 1`] = `
|
|||
>
|
||||
<a
|
||||
href="/princesscarolyn/your-approval-means-nothing-to-me-42640"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
|
|
@ -17,6 +18,8 @@ exports[`<Article /> should load article 1`] = `
|
|||
/princesscarolyn/your-approval-means-nothing-to-me-42640
|
||||
</span>
|
||||
<img
|
||||
alt="External Link Icon"
|
||||
class="external-link-img"
|
||||
src=""
|
||||
/>
|
||||
</a>
|
||||
|
|
@ -83,6 +86,7 @@ exports[`<Article /> should load article 1`] = `
|
|||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
data-category="like"
|
||||
src=""
|
||||
/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ exports[`<Channels /> expanded with chat channels should render and test snapsho
|
|||
>
|
||||
<img
|
||||
alt="channel name 1"
|
||||
class="group-img"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
|
|
@ -101,6 +102,7 @@ exports[`<Channels /> expanded with chat channels should render and test snapsho
|
|||
>
|
||||
<img
|
||||
alt="group channel 3"
|
||||
class="group-img"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ exports[`<Chat /> should load chat 1`] = `
|
|||
>
|
||||
<img
|
||||
alt="channel name 1"
|
||||
class="group-img"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
|
|
@ -143,6 +144,7 @@ exports[`<Chat /> should load chat 1`] = `
|
|||
>
|
||||
<img
|
||||
alt="group channel 3"
|
||||
class="group-img"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ exports[`<UserDetails /> for user1 should render and test snapshot 1`] = `
|
|||
target="_blank"
|
||||
>
|
||||
<img
|
||||
class="external-link-img"
|
||||
src=""
|
||||
style={
|
||||
Object {
|
||||
|
|
@ -237,6 +238,7 @@ exports[`<UserDetails /> for user2 should render and test snapshot 1`] = `
|
|||
target="_blank"
|
||||
>
|
||||
<img
|
||||
class="external-link-img"
|
||||
src=""
|
||||
style={
|
||||
Object {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import { deep } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import Article from '../article';
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ describe('<Article />', () => {
|
|||
|
||||
it('should have the proper elements, attributes and values', async () => {
|
||||
await fetch.mockResponseOnce(sampleResponse);
|
||||
const context = shallow(getArticle());
|
||||
const context = deep(getArticle(), { depth: 2 });
|
||||
await flushPromises();
|
||||
|
||||
// checks that article details are placed at their appropriate elements
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
import { h, Component } from 'preact';
|
||||
import heartImage from 'images/emoji/emoji-one-heart.png';
|
||||
import unicornImage from 'images/emoji/emoji-one-unicorn.png';
|
||||
|
|
@ -13,54 +11,56 @@ export default class Article extends Component {
|
|||
reactionCounts: [],
|
||||
userReactions: [],
|
||||
optimisticUserReaction: null,
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
fetch("/reactions?article_id="+this.props.resource.id, {
|
||||
fetch(`/reactions?article_id=${this.props.resource.id}`, {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(this.displayReactions)
|
||||
.catch(this.displayReactionsFailure);
|
||||
.then(response => response.json())
|
||||
.then(this.displayReactions)
|
||||
.catch(this.displayReactionsFailure);
|
||||
}
|
||||
|
||||
displayReactions = response => {
|
||||
this.setState({userReactions:response.reactions})
|
||||
}
|
||||
this.setState({ userReactions: response.reactions });
|
||||
};
|
||||
|
||||
displayReactionsFailure = response => {
|
||||
console.log(response)
|
||||
}
|
||||
console.log(response);
|
||||
};
|
||||
|
||||
handleNewReactionResponse = (response) => {
|
||||
handleNewReactionResponse = response => {
|
||||
let oldUserReactions = this.state.userReactions;
|
||||
let foundReactions = oldUserReactions.filter(obj => {
|
||||
return obj.category === response.category
|
||||
})
|
||||
const foundReactions = oldUserReactions.filter(obj => {
|
||||
return obj.category === response.category;
|
||||
});
|
||||
if (foundReactions.length === 0 && response.result === 'create') {
|
||||
oldUserReactions.push({category: response.category})
|
||||
oldUserReactions.push({ category: response.category });
|
||||
} else {
|
||||
oldUserReactions = oldUserReactions.filter(obj => {
|
||||
return obj.category != response.category
|
||||
})
|
||||
return obj.category != response.category;
|
||||
});
|
||||
}
|
||||
this.setState({userReactions: oldUserReactions, optimisticUserReaction: null})
|
||||
}
|
||||
this.setState({
|
||||
userReactions: oldUserReactions,
|
||||
optimisticUserReaction: null,
|
||||
});
|
||||
};
|
||||
|
||||
handleNewReactionFailure = response => {
|
||||
console.log(response)
|
||||
}
|
||||
console.log(response);
|
||||
};
|
||||
|
||||
handleReactionClick = e => {
|
||||
e.preventDefault();
|
||||
const target = e.target;
|
||||
console.log(target.dataset.category)
|
||||
this.setState({optimisticUserReaction: target.dataset.category })
|
||||
const article = this.props.resource
|
||||
const { target } = e;
|
||||
console.log(target.dataset.category);
|
||||
this.setState({ optimisticUserReaction: target.dataset.category });
|
||||
const article = this.props.resource;
|
||||
fetch('/reactions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -78,69 +78,118 @@ export default class Article extends Component {
|
|||
.then(response => response.json())
|
||||
.then(this.handleNewReactionResponse)
|
||||
.catch(this.handleNewReactionFailure);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
actionButton = (props) => {
|
||||
const types = {
|
||||
"heart": ["heart-reaction-button", "like", heartImage],
|
||||
"unicorn": ["unicorn-reaction-button", "unicorn", unicornImage],
|
||||
"readinglist": ["readinglist-reaction-button", "readinglist", bookmarkImage]
|
||||
};
|
||||
|
||||
const curType = types[props.reaction];
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`${curType[0]} ${props.reactedClass}`}
|
||||
onClick={this.handleReactionClick}
|
||||
data-category={curType[1]}
|
||||
>
|
||||
<img src={curType[2]} data-category={curType[1]} />
|
||||
</button>
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const article = this.props.resource;
|
||||
let heartReactedClass = ''
|
||||
let unicornReactedClass = ''
|
||||
let bookmarkReactedClass = ''
|
||||
const state = this.state;
|
||||
state.userReactions.forEach((reaction) => {
|
||||
if (reaction.category === 'like' || state.optimisticUserReaction === 'like') {
|
||||
heartReactedClass = 'active'
|
||||
let heartReactedClass = '';
|
||||
let unicornReactedClass = '';
|
||||
let bookmarkReactedClass = '';
|
||||
const { state } = this;
|
||||
state.userReactions.forEach(reaction => {
|
||||
if (
|
||||
reaction.category === 'like' ||
|
||||
state.optimisticUserReaction === 'like'
|
||||
) {
|
||||
heartReactedClass = 'active';
|
||||
}
|
||||
if (reaction.category === 'unicorn' || state.optimisticUserReaction === 'unicorn') {
|
||||
unicornReactedClass = 'active'
|
||||
if (
|
||||
reaction.category === 'unicorn' ||
|
||||
state.optimisticUserReaction === 'unicorn'
|
||||
) {
|
||||
unicornReactedClass = 'active';
|
||||
}
|
||||
if (reaction.category === 'readinglist' || state.optimisticUserReaction === 'readinglist') {
|
||||
bookmarkReactedClass = 'active'
|
||||
if (
|
||||
reaction.category === 'readinglist' ||
|
||||
state.optimisticUserReaction === 'readinglist'
|
||||
) {
|
||||
bookmarkReactedClass = 'active';
|
||||
}
|
||||
});
|
||||
let coverImage = '';
|
||||
if (article.cover_image) {
|
||||
coverImage = <section><div class="image image-final" style={{backgroundImage:`url(${article.cover_image}`}}></div></section>
|
||||
coverImage = (
|
||||
<section>
|
||||
<div
|
||||
className="image image-final"
|
||||
style={{ backgroundImage: `url(${article.cover_image}` }}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className='activechatchannel__activeArticle'>
|
||||
<div className="activechatchannel__activeArticleDetails">
|
||||
<a href={article.path} target='_blank'>
|
||||
<span className="activechatchannel__activeArticleDetailsPath">{article.path}</span>
|
||||
<img src={openLink} />
|
||||
</a>
|
||||
</div>
|
||||
<div className="container">
|
||||
{coverImage}
|
||||
<div className="title">
|
||||
<h1>{article.title}</h1>
|
||||
<h3>
|
||||
<a href={'/'+article.user.username} className="author" data-content={'/users/'+article.user.id}>
|
||||
<img className="profile-pic" src={article.user.profile_image_90} alt={article.user.username}/>
|
||||
<span>{article.user.name} </span>
|
||||
<span class="published-at"> | {article.readable_publish_date}</span>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div dangerouslySetInnerHTML={{__html: article.body_html}} ></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="activechatchannel__activeArticleActions">
|
||||
<button className={'heart-reaction-button ' + heartReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='like' >
|
||||
<img src={heartImage} />
|
||||
</button>
|
||||
<button className={'unicorn-reaction-button ' + unicornReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='unicorn'>
|
||||
<img src={unicornImage} data-category='unicorn' />
|
||||
</button>
|
||||
<button className={'readinglist-reaction-button ' + bookmarkReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='readinglist'>
|
||||
<img src={bookmarkImage} data-category='readinglist' />
|
||||
</button>
|
||||
</div>
|
||||
</div>)
|
||||
<div className="activechatchannel__activeArticle">
|
||||
<div className="activechatchannel__activeArticleDetails">
|
||||
<a href={article.path} target="_blank" rel="noopener noreferrer">
|
||||
<span className="activechatchannel__activeArticleDetailsPath">
|
||||
{article.path}
|
||||
</span>
|
||||
<img
|
||||
alt="External Link Icon"
|
||||
className="external-link-img"
|
||||
src={openLink}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className="container">
|
||||
{coverImage}
|
||||
<div className="title">
|
||||
<h1>{article.title}</h1>
|
||||
<h3>
|
||||
<a
|
||||
href={`/${article.user.username}`}
|
||||
className="author"
|
||||
data-content={`/users/${article.user.id}`}
|
||||
>
|
||||
<img
|
||||
className="profile-pic"
|
||||
src={article.user.profile_image_90}
|
||||
alt={article.user.username}
|
||||
/>
|
||||
<span>
|
||||
{article.user.name}
|
||||
{' '}
|
||||
</span>
|
||||
<span className="published-at">
|
||||
{' '}
|
||||
|
|
||||
{' '}
|
||||
{article.readable_publish_date}
|
||||
</span>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div dangerouslySetInnerHTML={{ __html: article.body_html }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="activechatchannel__activeArticleActions">
|
||||
<this.actionButton reaction="heart" reactedClass={heartReactedClass} />
|
||||
<this.actionButton reaction="unicorn" reactedClass={unicornReactedClass} />
|
||||
<this.actionButton reaction="readinglist" reactedClass={bookmarkReactedClass} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ const Channels = ({
|
|||
className="chatchanneltabindicatordirectimage"
|
||||
/>
|
||||
) : (
|
||||
<img alt={channel.channel_name} src={GroupImage} />
|
||||
<img
|
||||
alt={channel.channel_name}
|
||||
src={GroupImage}
|
||||
className="group-img"
|
||||
/>
|
||||
);
|
||||
let channelColor = 'transparent';
|
||||
if (channel.channel_type === 'direct' && isActive) {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export default class Chat extends Component {
|
|||
const filters =
|
||||
this.state.channelTypeFilter === 'all'
|
||||
? {}
|
||||
: { filters: `channel_type:${ this.state.channelTypeFilter}` };
|
||||
: { filters: `channel_type:${this.state.channelTypeFilter}` };
|
||||
getChannels(
|
||||
'',
|
||||
this.state.activeChannelId,
|
||||
|
|
@ -141,11 +141,11 @@ export default class Chat extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
filterForActiveChannel = (channels, id) => channels.filter(channel => channel.id === parseInt(id))[0];
|
||||
filterForActiveChannel = (channels, id) =>
|
||||
channels.filter(channel => channel.id === parseInt(id))[0];
|
||||
|
||||
subscribePusher = channelName => {
|
||||
if (this.state.subscribedPusherChannels.includes(channelName)) {
|
||||
|
||||
} else {
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: channelName,
|
||||
|
|
@ -196,8 +196,7 @@ export default class Chat extends Component {
|
|||
const channel = channels[0];
|
||||
const channelSlug =
|
||||
channel.channel_type === 'direct'
|
||||
? `@${
|
||||
channel.slug
|
||||
? `@${channel.slug
|
||||
.replace(`${window.currentUser.username}/`, '')
|
||||
.replace(`/${window.currentUser.username}`, '')}`
|
||||
: channel.slug;
|
||||
|
|
@ -218,7 +217,9 @@ export default class Chat extends Component {
|
|||
|
||||
loadPaginatedChannels = channels => {
|
||||
const currentChannels = this.state.chatChannels;
|
||||
const currentChannelIds = currentChannels.map((channel, index) => channel.id);
|
||||
const currentChannelIds = currentChannels.map(
|
||||
(channel, index) => channel.id,
|
||||
);
|
||||
const newChannels = currentChannels;
|
||||
channels.forEach((channel, index) => {
|
||||
if (!currentChannelIds.includes(channel.id)) {
|
||||
|
|
@ -343,14 +344,14 @@ export default class Chat extends Component {
|
|||
) {
|
||||
return;
|
||||
}
|
||||
const target = e.target;
|
||||
const { target } = e;
|
||||
if (target.scrollTop + target.offsetHeight + 1800 > target.scrollHeight) {
|
||||
this.setState({ fetchingPaginatedChannels: true });
|
||||
|
||||
const filters =
|
||||
this.state.channelTypeFilter === 'all'
|
||||
? {}
|
||||
: { filters: `channel_type:${ this.state.channelTypeFilter}` };
|
||||
: { filters: `channel_type:${this.state.channelTypeFilter}` };
|
||||
getChannels(
|
||||
this.state.filterQuery,
|
||||
this.state.activeChannelId,
|
||||
|
|
@ -423,7 +424,7 @@ export default class Chat extends Component {
|
|||
|
||||
handleSwitchChannel = e => {
|
||||
e.preventDefault();
|
||||
let target = e.target;
|
||||
let { target } = e;
|
||||
if (!target.dataset.channelId) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
|
@ -457,7 +458,7 @@ export default class Chat extends Component {
|
|||
showAlert: false,
|
||||
});
|
||||
this.setupChannel(id);
|
||||
window.history.replaceState(null, null, `/connect/${ slug}`);
|
||||
window.history.replaceState(null, null, `/connect/${slug}`);
|
||||
if (!this.state.isMobileDevice) {
|
||||
document.getElementById('messageform').focus();
|
||||
}
|
||||
|
|
@ -484,7 +485,7 @@ export default class Chat extends Component {
|
|||
|
||||
triggerNotificationRequest = e => {
|
||||
const context = this;
|
||||
Notification.requestPermission((permission) => {
|
||||
Notification.requestPermission(permission => {
|
||||
if (permission === 'granted') {
|
||||
context.setState({ notificationsPermission: 'granted' });
|
||||
setupNotifications();
|
||||
|
|
@ -503,7 +504,7 @@ export default class Chat extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const target = e.target;
|
||||
const { target } = e;
|
||||
if (target.dataset.content) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
|
@ -520,7 +521,7 @@ export default class Chat extends Component {
|
|||
type_of: 'loading-user',
|
||||
};
|
||||
getContent(
|
||||
`/api/${ target.dataset.content}`,
|
||||
`/api/${target.dataset.content}`,
|
||||
this.setActiveContent,
|
||||
null,
|
||||
);
|
||||
|
|
@ -529,7 +530,7 @@ export default class Chat extends Component {
|
|||
type_of: 'loading-post',
|
||||
};
|
||||
getContent(
|
||||
`/api/${ target.dataset.content}`,
|
||||
`/api/${target.dataset.content}`,
|
||||
this.setActiveContent,
|
||||
null,
|
||||
);
|
||||
|
|
@ -590,7 +591,7 @@ export default class Chat extends Component {
|
|||
channelTypeFilter: type,
|
||||
fetchingPaginatedChannels: false,
|
||||
});
|
||||
const filters = type === 'all' ? {} : { filters: `channel_type:${ type}` };
|
||||
const filters = type === 'all' ? {} : { filters: `channel_type:${type}` };
|
||||
getChannels(
|
||||
this.state.filterQuery,
|
||||
null,
|
||||
|
|
@ -631,37 +632,33 @@ export default class Chat extends Component {
|
|||
return (
|
||||
<div className="chatmessage" style={{ color: 'grey' }}>
|
||||
<div className="chatmessage__body">
|
||||
You and
|
||||
You and
|
||||
{' '}
|
||||
<a
|
||||
href={`/${ channelUsername}`}
|
||||
style={{
|
||||
color:
|
||||
activeChannel.channel_users[channelUsername].darker_color,
|
||||
}}
|
||||
>
|
||||
@
|
||||
<a href={`/${channelUsername}`}>
|
||||
@
|
||||
{channelUsername}
|
||||
</a>
|
||||
{' '}
|
||||
are connected because you both follow each other. All interactions
|
||||
are
|
||||
connected because you both follow each other. All interactions
|
||||
{' '}
|
||||
<em>
|
||||
<b>must</b>
|
||||
</em>
|
||||
{' '}
|
||||
abide by the
|
||||
abide by the
|
||||
{' '}
|
||||
<a href="/code-of-conduct">code of conduct</a>
|
||||
.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} if (activeChannel.channel_type === 'open') {
|
||||
}
|
||||
if (activeChannel.channel_type === 'open') {
|
||||
return (
|
||||
<div className="chatmessage" style={{ color: 'grey' }}>
|
||||
<div className="chatmessage__body">
|
||||
You have joined
|
||||
You have joined
|
||||
{' '}
|
||||
{activeChannel.channel_name}
|
||||
! All interactions
|
||||
|
|
@ -670,7 +667,7 @@ export default class Chat extends Component {
|
|||
<b>must</b>
|
||||
</em>
|
||||
{' '}
|
||||
abide by the
|
||||
abide by the
|
||||
{' '}
|
||||
<a href="/code-of-conduct">code of conduct</a>
|
||||
.
|
||||
|
|
@ -697,7 +694,7 @@ export default class Chat extends Component {
|
|||
const filters =
|
||||
this.state.channelTypeFilter === 'all'
|
||||
? {}
|
||||
: { filters: `channel_type:${ this.state.channelTypeFilter}` };
|
||||
: { filters: `channel_type:${this.state.channelTypeFilter}` };
|
||||
getChannels(
|
||||
e.target.value,
|
||||
null,
|
||||
|
|
@ -714,7 +711,7 @@ export default class Chat extends Component {
|
|||
|
||||
renderChatChannels = () => {
|
||||
if (this.state.showChannelsList) {
|
||||
const notificationsPermission = this.state.notificationsPermission;
|
||||
const { notificationsPermission } = this.state;
|
||||
let notificationsButton = '';
|
||||
let notificationsState = '';
|
||||
let invitesButton = '';
|
||||
|
|
@ -814,29 +811,26 @@ export default class Chat extends Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="chat__channels">
|
||||
{notificationsButton}
|
||||
<button
|
||||
className="chat__channelstogglebutt"
|
||||
onClick={this.toggleExpand}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{'>'}
|
||||
</button>
|
||||
<Channels
|
||||
incomingVideoCallChannelIds={
|
||||
this.state.incomingVideoCallChannelIds
|
||||
}
|
||||
activeChannelId={this.state.activeChannelId}
|
||||
chatChannels={this.state.chatChannels}
|
||||
handleSwitchChannel={this.handleSwitchChannel}
|
||||
expanded={this.state.expanded}
|
||||
/>
|
||||
{notificationsState}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="chat__channels">
|
||||
{notificationsButton}
|
||||
<button
|
||||
className="chat__channelstogglebutt"
|
||||
onClick={this.toggleExpand}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{'>'}
|
||||
</button>
|
||||
<Channels
|
||||
incomingVideoCallChannelIds={this.state.incomingVideoCallChannelIds}
|
||||
activeChannelId={this.state.activeChannelId}
|
||||
chatChannels={this.state.chatChannels}
|
||||
handleSwitchChannel={this.handleSwitchChannel}
|
||||
expanded={this.state.expanded}
|
||||
/>
|
||||
{notificationsState}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
|
@ -888,7 +882,7 @@ export default class Chat extends Component {
|
|||
.replace(`/${window.currentUser.username}`, '');
|
||||
channelHeaderInner = (
|
||||
<a
|
||||
href={`/${ username}`}
|
||||
href={`/${username}`}
|
||||
onClick={this.triggerActiveContent}
|
||||
data-content={`users/by_username?url=${username}`}
|
||||
>
|
||||
|
|
@ -899,7 +893,7 @@ export default class Chat extends Component {
|
|||
} else {
|
||||
channelHeaderInner = (
|
||||
<a
|
||||
href={`/${ currentChannel.adjusted_slug}`}
|
||||
href={`/${currentChannel.adjusted_slug}`}
|
||||
onClick={this.triggerActiveContent}
|
||||
data-content="channel-details"
|
||||
>
|
||||
|
|
@ -948,11 +942,9 @@ export default class Chat extends Component {
|
|||
}
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
`chat chat--${
|
||||
className={`chat chat--${
|
||||
this.state.expanded ? 'expanded' : 'contracted'
|
||||
}${detectIOSSafariClass}`
|
||||
}
|
||||
}${detectIOSSafariClass}`}
|
||||
data-no-instant
|
||||
>
|
||||
{this.renderChatChannels()}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ function blockChat(activeChannelId) {
|
|||
formData.append('chat_id', activeChannelId);
|
||||
formData.append('controller', 'chat_channels');
|
||||
|
||||
getCsrfToken()
|
||||
.then(sendFetch('block-chat', formData));
|
||||
getCsrfToken().then(sendFetch('block-chat', formData));
|
||||
}
|
||||
|
||||
export default class UserDetails extends Component {
|
||||
|
|
@ -44,6 +43,7 @@ export default class UserDetails extends Component {
|
|||
socialIcons.push(
|
||||
<a href={user.website_url} target="_blank">
|
||||
<img
|
||||
className="external-link-img"
|
||||
src={websiteImage}
|
||||
style={{ width: '30px', margin: '5px 15px 15px 0px' }}
|
||||
/>
|
||||
|
|
@ -95,36 +95,54 @@ export default class UserDetails extends Component {
|
|||
Block User
|
||||
</button>
|
||||
|
||||
<button onClick={() => {
|
||||
var modal = document.getElementById("userdetails__reportabuse");
|
||||
if (modal.style.display === "none") {
|
||||
modal.style.display = "block";
|
||||
window.location.href = `#userdetails__reportabuse`;
|
||||
|
||||
} else {
|
||||
modal.style.display = "none";
|
||||
window.location.href = `#`;
|
||||
}
|
||||
}}>
|
||||
<button
|
||||
onClick={() => {
|
||||
const modal = document.getElementById('userdetails__reportabuse');
|
||||
if (modal.style.display === 'none') {
|
||||
modal.style.display = 'block';
|
||||
window.location.href = `#userdetails__reportabuse`;
|
||||
} else {
|
||||
modal.style.display = 'none';
|
||||
window.location.href = `#`;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Report Abuse
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div id="userdetails__reportabuse" style="display:none">
|
||||
<div className="userdetails__reportabuse">
|
||||
<p>Reporting abuse will: </p>
|
||||
<ul>
|
||||
<li>close this chat and prevent this user from re-opening chat with you</li>
|
||||
<li>give the DEV team your consent to read messages in this chat to understand your report</li>
|
||||
<li>
|
||||
close this chat and prevent this user from re-opening chat with
|
||||
you
|
||||
</li>
|
||||
<li>
|
||||
give the DEV team your consent to read messages in this chat to
|
||||
understand your report
|
||||
</li>
|
||||
</ul>
|
||||
<h5>Are you sure?</h5>
|
||||
<a href="/report-abuse" onClick={() => {
|
||||
blockChat(channelId);
|
||||
}}>Yes</a>
|
||||
<a class="no" onClick={() => {
|
||||
document.getElementById("userdetails__reportabuse").style.display = "none";
|
||||
window.location.href = `#`;
|
||||
}}>No</a>
|
||||
<a
|
||||
href="/report-abuse"
|
||||
onClick={() => {
|
||||
blockChat(channelId);
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</a>
|
||||
<a
|
||||
className="no"
|
||||
onClick={() => {
|
||||
document.getElementById(
|
||||
'userdetails__reportabuse',
|
||||
).style.display = 'none';
|
||||
window.location.href = `#`;
|
||||
}}
|
||||
>
|
||||
No
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue