Skip to content
This repository has been archived by the owner on Oct 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #2964 from withspectrum/send-notifications-for-wat…
Browse files Browse the repository at this point in the history
…ercoolers

Send notifications for watercooler threads
  • Loading branch information
brianlovin committed Apr 30, 2018
2 parents 1db9dd4 + 1e856d3 commit 621766f
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 30 deletions.
18 changes: 2 additions & 16 deletions api/mutations/message/addMessage.js
Expand Up @@ -8,10 +8,7 @@ import { storeMessage, getMessage } from '../../models/message';
import { setDirectMessageThreadLastActive } from '../../models/directMessageThread';
import { setUserLastSeenInDirectMessageThread } from '../../models/usersDirectMessageThreads';
import { createMemberInChannel } from '../../models/usersChannels';
import {
createParticipantInThread,
createParticipantWithoutNotificationsInThread,
} from '../../models/usersThreads';
import { createParticipantInThread } from '../../models/usersThreads';
import addCommunityMember from '../communityMember/addCommunityMember';
import { trackUserThreadLastSeenQueue } from 'shared/bull/queues';
import { toJSON } from 'shared/draft-utils';
Expand Down Expand Up @@ -179,17 +176,6 @@ export default async (
);
}

const participantPromise = async () => {
if (thread.watercooler) {
return await createParticipantWithoutNotificationsInThread(
message.threadId,
currentUser.id
);
} else {
return await createParticipantInThread(message.threadId, currentUser.id);
}
};

// dummy async function that will run if the user is already a member of the
// channel where the message is being sent
let membershipPromise = async () => await {};
Expand Down Expand Up @@ -220,7 +206,7 @@ export default async (
}

return membershipPromise()
.then(() => participantPromise())
.then(() => createParticipantInThread(message.threadId, currentUser.id))
.then(() => messagePromise())
.then(dbMessage => {
const contextPermissions = {
Expand Down
26 changes: 13 additions & 13 deletions src/views/thread/components/sidebar.js
Expand Up @@ -125,21 +125,21 @@ class Sidebar extends React.Component<Props> {
src={thread.community.profilePhoto}
/>
<SidebarCommunityName>{thread.community.name}</SidebarCommunityName>

<SidebarChannelPill>
<PillLink to={`/${thread.community.slug}/${thread.channel.slug}`}>
{thread.channel.isPrivate && (
<Lock>
<Icon glyph="private" size={12} />
</Lock>
)}
<PillLabel isPrivate={thread.channel.isPrivate}>
{thread.channel.name}
</PillLabel>
</PillLink>
</SidebarChannelPill>
</Link>

<SidebarChannelPill>
<PillLink to={`/${thread.community.slug}/${thread.channel.slug}`}>
{thread.channel.isPrivate && (
<Lock>
<Icon glyph="private" size={12} />
</Lock>
)}
<PillLabel isPrivate={thread.channel.isPrivate}>
{thread.channel.name}
</PillLabel>
</PillLink>
</SidebarChannelPill>

<SidebarCommunityDescription>
{renderDescriptionWithLinks(thread.community.description)}
</SidebarCommunityDescription>
Expand Down
179 changes: 179 additions & 0 deletions src/views/thread/components/watercoolerActionBar.js
@@ -0,0 +1,179 @@
// @flow
import * as React from 'react';
import { connect } from 'react-redux';
import Clipboard from 'react-clipboard.js';
import { addToastWithTimeout } from '../../../actions/toasts';
import { openModal } from '../../../actions/modals';
import Icon from '../../../components/icons';
import compose from 'recompose/compose';
import { track } from '../../../helpers/events';
import type { GetThreadType } from 'shared/graphql/queries/thread/getThread';
import toggleThreadNotificationsMutation from 'shared/graphql/mutations/thread/toggleThreadNotifications';
import {
FollowButton,
ShareButtons,
ShareButton,
WatercoolerActionBarContainer,
} from '../style';

type Props = {
thread: GetThreadType,
currentUser: Object,
dispatch: Function,
toggleThreadNotifications: Function,
};

type State = {
notificationStateLoading: boolean,
};

class WatercoolerActionBar extends React.Component<Props, State> {
state = { notificationStateLoading: false };

toggleNotification = () => {
const { thread, dispatch, toggleThreadNotifications } = this.props;
const threadId = thread.id;

this.setState({
notificationStateLoading: true,
});

toggleThreadNotifications({
threadId,
})
.then(({ data: { toggleThreadNotifications } }) => {
this.setState({
notificationStateLoading: false,
});

if (toggleThreadNotifications.receiveNotifications) {
track('thread', 'notifications turned on', null);
return dispatch(
addToastWithTimeout('success', 'Notifications activated!')
);
} else {
track('thread', 'notifications turned off', null);
return dispatch(
addToastWithTimeout('neutral', 'Notifications turned off')
);
}
})
.catch(err => {
this.setState({
notificationStateLoading: true,
});
dispatch(addToastWithTimeout('error', err.message));
});
};

render() {
const { thread, currentUser } = this.props;
const { notificationStateLoading } = this.state;

return (
<WatercoolerActionBarContainer>
<div style={{ display: 'flex' }}>
{currentUser ? (
<FollowButton
currentUser={currentUser}
icon={
thread.receiveNotifications
? 'notification-fill'
: 'notification'
}
tipText={
thread.receiveNotifications
? 'Turn off notifications'
: 'Get notified about replies'
}
tipLocation={'top-right'}
loading={notificationStateLoading}
onClick={this.toggleNotification}
dataCy="thread-notifications-toggle"
>
{thread.receiveNotifications ? 'Subscribed' : 'Get notifications'}
</FollowButton>
) : (
<FollowButton
currentUser={currentUser}
icon={'notification'}
tipText={'Get notified about replies'}
tipLocation={'top-right'}
dataCy="thread-notifications-login-capture"
onClick={() =>
this.props.dispatch(openModal('CHAT_INPUT_LOGIN_MODAL', {}))
}
>
Notify me
</FollowButton>
)}
{!thread.channel.isPrivate && (
<ShareButtons>
<ShareButton
facebook
tipText={'Share'}
tipLocation={'top-left'}
data-cy="thread-facebook-button"
>
<a
href={`https://www.facebook.com/sharer/sharer.php?u=https://spectrum.chat/thread/${
thread.id
}&t=${thread.content.title}`}
target="_blank"
rel="noopener noreferrer"
>
<Icon glyph={'facebook'} size={24} />
</a>
</ShareButton>

<ShareButton
twitter
tipText={'Tweet'}
tipLocation={'top-left'}
data-cy="thread-tweet-button"
>
<a
href={`https://twitter.com/share?text=${
thread.content.title
} on @withspectrum&url=https://spectrum.chat/thread/${
thread.id
}`}
target="_blank"
rel="noopener noreferrer"
>
<Icon glyph={'twitter'} size={24} />
</a>
</ShareButton>

<Clipboard
style={{ background: 'none' }}
data-clipboard-text={`https://spectrum.chat/thread/${
thread.id
}`}
onSuccess={() =>
this.props.dispatch(
addToastWithTimeout('success', 'Copied to clipboard')
)
}
>
<ShareButton
tipText={'Copy link'}
tipLocation={'top-left'}
data-cy="thread-copy-link-button"
>
<a>
<Icon glyph={'link'} size={24} />
</a>
</ShareButton>
</Clipboard>
</ShareButtons>
)}
</div>
</WatercoolerActionBarContainer>
);
}
}

export default compose(connect(), toggleThreadNotificationsMutation)(
WatercoolerActionBar
);
7 changes: 7 additions & 0 deletions src/views/thread/container.js
Expand Up @@ -36,6 +36,7 @@ import {
WatercoolerTitle,
WatercoolerAvatar,
} from './style';
import WatercoolerActionBar from './components/watercoolerActionBar';

type Props = {
data: {
Expand Down Expand Up @@ -412,6 +413,12 @@ class ThreadContainer extends React.Component<Props, State> {
Jump in to the conversation below or introduce yourself!
</WatercoolerDescription>
</WatercoolerIntroContainer>

<WatercoolerActionBar
thread={thread}
currentUser={currentUser}
/>

{!isEditing && (
<Messages
threadMessageCount={thread.messageCount}
Expand Down
5 changes: 4 additions & 1 deletion src/views/thread/style.js
Expand Up @@ -574,6 +574,10 @@ export const ActionBarContainer = styled.div`
}
`;

export const WatercoolerActionBarContainer = styled(ActionBarContainer)`
margin-bottom: 16px;
`;

export const FollowButton = styled(Button)`
background: ${props => props.theme.bg.default};
border: 1px solid ${props => props.theme.bg.border};
Expand Down Expand Up @@ -741,7 +745,6 @@ export const WatercoolerIntroContainer = styled.div`
align-items: center;
justify-content: center;
padding: 32px 32px 36px;
border-bottom: 1px solid ${props => props.theme.bg.border};
background: ${props => props.theme.bg.default};
flex: auto;
flex-direction: column;
Expand Down

0 comments on commit 621766f

Please sign in to comment.