diff --git a/.env_sample b/.env_sample
index ed0de8d83..50100c7a5 100644
--- a/.env_sample
+++ b/.env_sample
@@ -123,13 +123,6 @@ GA_TRACKING_ID="Optional"
# (https://mailchimp.com/developer/)
MAILCHIMP_API_KEY="Optional-valid"
-# Pusher for DEV Connect/notfications
-# (https://pusher.com/docs)
-PUSHER_APP_ID=
-PUSHER_CLUSTER=
-PUSHER_KEY=
-PUSHER_SECRET=
-
# Google recaptcha (Optional)
# (https://developers.google.com/recaptcha/intro)
RECAPTCHA_SECRET=
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index d20ddcd13..dacf06539 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -18,6 +18,5 @@ require:
Rails/HasManyOrHasOneDependent:
Exclude:
- 'app/models/article.rb'
- - 'app/models/chat_channel.rb'
- 'app/models/organization.rb'
- 'app/models/user.rb'
diff --git a/Gemfile b/Gemfile
index e0432adf0..26b9cf47f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -48,6 +48,7 @@ gem "honeycomb-beeline", "~> 2.7.1" # Monitoring and Observability gem
gem "html_truncator", "~> 0.4" # Truncate an HTML string properly
gem "htmlentities", "~> 4.3", ">= 4.3.4" # A module for encoding and decoding (X)HTML entities
gem "httparty", "~> 0.20" # Makes http fun! Also, makes consuming restful web services dead easy
+gem "httpclient", "~> 2.8.3" # Gives something like the functionality of libwww-perl (LWP) in Ruby
gem "i18n-js", "~> 3.9.0" # Helps with internationalization in Rails.
gem "imgproxy", "~> 2.0" # A gem that easily generates imgproxy URLs for your images
gem "inline_svg", "~> 1.7" # Embed SVG documents in your Rails views and style them with CSS
@@ -74,7 +75,6 @@ gem "pg_search", "~> 2.3.5" # PgSearch builds Active Record named scopes that ta
gem "pghero", "~> 2.8" # Dashboard for Postgres
gem "puma", "~> 5.5.2" # Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
gem "pundit", "~> 2.1" # Object oriented authorization for Rails applications
-gem "pusher", "~> 2.0" # Ruby library for Pusher Channels HTTP API
gem "rack-attack", "~> 6.5.0" # Used to throttle requests to prevent brute force attacks
gem "rack-cors", "~> 1.1" # Middleware that will make Rack-based apps CORS compatible
gem "rack-timeout", "~> 0.6" # Rack middleware which aborts requests that have been running for longer than a specified timeout
diff --git a/Gemfile.lock b/Gemfile.lock
index 88eeb2b8c..3a1b9bd2e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -561,11 +561,6 @@ GEM
activesupport (>= 3.0.0)
pundit-matchers (1.7.0)
rspec-rails (>= 3.0.0)
- pusher (2.0.2)
- httpclient (~> 2.8)
- multi_json (~> 1.15)
- pusher-signature (~> 0.1.8)
- pusher-signature (0.1.8)
raabro (1.4.0)
racc (1.6.0)
rack (2.2.3)
@@ -946,6 +941,7 @@ DEPENDENCIES
html_truncator (~> 0.4)
htmlentities (~> 4.3, >= 4.3.4)
httparty (~> 0.20)
+ httpclient (~> 2.8.3)
hypershield (~> 0.2.2)
i18n-js (~> 3.9.0)
i18n-tasks (~> 0.9.35)
@@ -982,7 +978,6 @@ DEPENDENCIES
puma (~> 5.5.2)
pundit (~> 2.1)
pundit-matchers (~> 1.7)
- pusher (~> 2.0)
rack-attack (~> 6.5.0)
rack-cors (~> 1.1)
rack-host-redirect (~> 1.3)
diff --git a/app/assets/javascripts/initializePage.js b/app/assets/javascripts/initializePage.js
index 78d6ed4dc..6f2930e7b 100644
--- a/app/assets/javascripts/initializePage.js
+++ b/app/assets/javascripts/initializePage.js
@@ -1,6 +1,6 @@
/*
global initializeLocalStorageRender, initializeBodyData,
- initializeAllChatButtons, initializeAllTagEditButtons, initializeUserFollowButts,
+ initializeAllTagEditButtons, initializeUserFollowButts,
initializeBaseTracking, initializeCommentsPage,
initializeArticleDate, initializeArticleReactions, initNotifications,
initializeCommentDate, initializeSettings,
@@ -50,7 +50,6 @@ function initializePage() {
clearInterval(waitingForDataLoad);
if (document.body.getAttribute('data-user-status') === 'logged-in') {
initializeBaseUserData();
- initializeAllChatButtons();
initializeAllTagEditButtons();
}
initializeBroadcast();
diff --git a/app/assets/javascripts/initializers/initializeAllChatButtons.js b/app/assets/javascripts/initializers/initializeAllChatButtons.js
deleted file mode 100644
index 352478d33..000000000
--- a/app/assets/javascripts/initializers/initializeAllChatButtons.js
+++ /dev/null
@@ -1,119 +0,0 @@
-'use strict';
-
-function showChatModal(modal) {
- // eslint-disable-next-line no-param-reassign
- modal.style.display = 'block';
- document.getElementById('new-message').focus();
-}
-
-function hideChatModal(modal) {
- // eslint-disable-next-line no-param-reassign
- modal.style.display = 'none';
-}
-
-function toggleModal() {
- var modal = document.getElementsByClassName('crayons-modal')[0];
- modal.classList.toggle('hidden');
-}
-
-function initModal() {
- var modal = document.getElementsByClassName('crayons-modal')[0];
- modal
- .getElementsByClassName('close-modal')[0]
- .addEventListener('click', toggleModal);
- modal
- .getElementsByClassName('crayons-modal__overlay')[0]
- .addEventListener('click', toggleModal);
-}
-
-function handleChatButtonPress(form) {
- var message = document.getElementById('new-message').value;
- var formDataInfo = JSON.parse(form.dataset.info);
- var formData = new FormData();
-
- if (message.replace(/\s/g, '').length === 0) {
- return;
- }
-
- formData.append('user_id', formDataInfo.id);
- formData.append('message', message);
- formData.append('controller', 'chat_channels');
-
- getCsrfToken()
- .then(sendFetch('chat-creation', formData))
- .then(() => {
- window.location.href = `/connect/@${formDataInfo.username}`;
- });
-}
-
-function addButtonClickHandle(response, button, modalInfo) {
- var linkWrap = document.getElementById('user-connect-redirect');
- var form = document.getElementById('new-message-form');
- button.classList.add('showing');
- if (modalInfo.showChat === 'open' && response !== 'mutual') {
- linkWrap.removeAttribute('href'); // remove link
- button.addEventListener('click', toggleModal);
- // eslint-disable-next-line no-param-reassign
- button.classList.remove('hidden'); // show button
- linkWrap.classList.remove('hidden'); // show button
- form.onsubmit = () => {
- handleChatButtonPress(form);
- return false;
- };
- } else if (response === 'mutual') {
- button.removeEventListener('click', toggleModal);
- // eslint-disable-next-line no-param-reassign
- button.classList.remove('hidden'); // show button
- linkWrap.classList.remove('hidden'); // show button
- }
-}
-
-function fetchButton(button, modalInfo) {
- var dataRequester;
- // button.dataset.fetched = 'fetched'; // telling initialize that this button has been fetched
- if (window.XMLHttpRequest) {
- dataRequester = new XMLHttpRequest();
- } else {
- dataRequester = new ActiveXObject('Microsoft.XMLHTTP');
- }
- dataRequester.onreadystatechange = () => {
- if (
- dataRequester.readyState === XMLHttpRequest.DONE &&
- dataRequester.status === 200
- ) {
- addButtonClickHandle(dataRequester.response, button, modalInfo);
- }
- };
- dataRequester.open(
- 'GET',
- '/follows/' + modalInfo.id + '?followable_type=' + modalInfo.className,
- );
- dataRequester.send();
-}
-
-function initializeChatButton(button, modalInfo) {
- // if user logged out, do nothing
- var user = userData();
- if (user === null || user.id === modalInfo.id) {
- return;
- }
- fetchButton(button, modalInfo);
-}
-
-// finds all elements with chat action button class
-function initializeAllChatButtons() {
- var buttons = document.getElementsByClassName('chat-action-button');
- var modal = document.getElementById('new-message-form');
- var i;
-
- if (!modal) {
- return;
- }
-
- var modalInfo = JSON.parse(modal.dataset.info);
- initModal();
-
- for (i = 0; i < buttons.length; i += 1) {
- initializeChatButton(buttons[i], modalInfo);
- }
-}
diff --git a/app/assets/javascripts/utilities/sendFetch.js b/app/assets/javascripts/utilities/sendFetch.js
index bcb7c0b05..333aa7ed2 100644
--- a/app/assets/javascripts/utilities/sendFetch.js
+++ b/app/assets/javascripts/utilities/sendFetch.js
@@ -46,12 +46,6 @@ function sendFetch(switchStatement, body) {
addTokenToBody: true,
body,
});
- case 'chat-creation':
- return fetchCallback({
- url: '/chat_channels/create_chat',
- addTokenToBody: true,
- body,
- });
case 'block-user':
return fetchCallback({
url: '/user_blocks',
diff --git a/app/assets/stylesheets/chat.scss b/app/assets/stylesheets/chat.scss
deleted file mode 100644
index 97b48d233..000000000
--- a/app/assets/stylesheets/chat.scss
+++ /dev/null
@@ -1,1344 +0,0 @@
-@import 'variables';
-@import 'mixins';
-@import 'config/import';
-
-// High level classes
-.chat-page-wrapper {
- margin: 0px auto 0px;
- width: 100%;
- max-width: calc(1540px + 10vw);
-
- --layout-chat-left-sidebar-width: 260px;
-}
-
-.live-chat {
- &.live-chat--iossafari {
- height: calc(100vh - 56px);
- }
-
- overflow-y: hidden;
-}
-
-.live-chat {
- padding: 0;
- width: 100%;
-}
-
-.chat {
- display: flex;
- height: calc(100 * var(--vh) - var(--header-height));
- position: relative;
- overflow-x: hidden;
- overflow-y: hidden;
-
- &.chat--iossafari {
- height: 100%;
- }
-}
-
-.chat__channels {
- box-sizing: border-box;
- height: inherit;
- padding: var(--su-3);
- position: relative;
- width: 100%;
- overflow-y: auto;
- @media screen and (min-width: $breakpoint-m) {
- min-width: var(--layout-chat-left-sidebar-width);
- max-width: var(--layout-chat-left-sidebar-width);
- }
-}
-
-.chat__channelssearchtoggle {
- background: transparent;
- border: 0;
- margin-left: 2px;
- svg {
- vertical-align: -5px;
- fill: var(--indicator-default-color);
- }
-}
-
-.chat__notificationsbutton {
- border: 0px;
- font-size: 12px;
- padding: 15px 0px;
- width: 100%;
- color: darken($green, 30%);
- font-weight: bold;
- width: 95%;
- border-radius: 3px;
- border: 1px solid darken($green, 30%);
- box-shadow: 3px 3px 0px darken($green, 30%);
- background: lighten($green, 30%);
- margin-bottom: 5px;
-
- &:hover {
- @include themeable(
- background,
- theme-container-background-hover,
- lighten($green, 20%)
- );
- }
-}
-
-.chat__channels--placeholder {
- .chat__channelstogglebutt--placeholderunexpanded {
- display: none;
- }
-
- @media screen and (max-width: 599px) {
- width: 45px;
- min-width: 45px;
-
- input {
- display: none;
- }
-
- .chat__channelstogglebutt--placeholderunexpanded {
- display: block;
- width: 100%;
- }
- }
-}
-
-.chat__channels input {
- width: 100%;
-}
-
-.chat__channeltypefilter {
- width: 100%;
- margin-top: 15px;
-}
-
-.chat__channeltypefilterbutton {
- margin: 1px;
- @media screen and (min-width: 1300px) {
- margin: 5px 4px;
- }
-}
-
-.chat_chatconfig {
- position: absolute;
- bottom: 0px;
- left: 0px;
- right: 6px;
- font-size: 12px;
- padding: 3px 12px;
- display: inline-block;
- border-radius: 3px;
- background: var(--body-bg);
- border: 1px solid $light-medium-gray;
- font-weight: bold;
- cursor: default;
-}
-
-.chat_chatconfig--on {
- color: $green;
-}
-
-.chat_chatconfig--off {
- color: $red;
-}
-
-.chat__channels--hidden {
- display: none;
-}
-
-.active-channel__back-btn {
- display: inherit;
-
- @media screen and (min-width: $breakpoint-m) {
- display: none;
- }
-}
-
-.chat__activechat {
- height: inherit;
- width: 100%;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- transform: translateX(0);
- transition: transform 0.22s linear;
- z-index: var(--z-elevate);
-
- @media screen and (min-width: $breakpoint-m) {
- position: inherit;
- }
-}
-
-.chat__activechat--hidden {
- transform: translateX(100%);
- transition: transform 0.18s linear;
-
- @media screen and (min-width: $breakpoint-m) {
- transform: translateX(0);
- }
-}
-
-.activechatchannel {
- height: inherit;
- max-height: inherit;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- background: var(--card-bg);
- flex-flow: row nowrap;
- position: relative;
-
- @include themeable(
- border-left,
- theme-container-border,
- 1px solid $outline-color
- );
-
- @media screen and (min-width: 1540px) {
- @include themeable(
- border,
- theme-container-border,
- 1px solid $outline-color
- );
- border-top: 0px;
- }
-}
-
-.activechatchannel__conversation {
- position: relative;
- order: 1;
- display: flex;
- flex-direction: column;
- flex: 0 1 auto;
- width: 100%;
- min-width: 50%;
- @media screen and (min-width: 1440px) {
- min-width: 35%;
- }
- @media screen and (max-width: 426px) {
- overflow-x: hidden;
- }
-}
-
-.active-channel__header {
- align-items: center;
- box-shadow: 0 0 0 1px var(--card-border);
- box-sizing: border-box;
- display: flex;
- height: var(--header-height);
- position: relative;
- padding: var(--su-4);
- justify-content: space-between;
-}
-
-.active-channel__title {
- font-weight: var(--fw-bold);
- font-size: var(--fs-base);
- color: var(--body-color);
-}
-
-.activechatchannel__messages {
- padding-top: var(--su-2);
- padding-bottom: var(--su-2);
- font-size: var(--fs-base);
- flex-grow: 1;
- height: 300px;
- // Setting it to scroll so there is no jump when it's auto. Also, since it's chat,
- // it will almost always need scrolling right away.
- overflow-y: scroll;
- overflow-x: hidden;
- text-align: left;
- overscroll-behavior-y: contain;
- -webkit-overflow-scrolling: touch;
-}
-
-.activechatchannel__alerts {
- position: relative;
-}
-
-.chatalert__default {
- align-items: center;
- background-color: rgba(0, 0, 0, 0.5);
- color: white;
- display: flex;
- height: 25px;
- justify-content: center;
- position: absolute;
- top: -25px;
- width: 100%;
- font-size: 13px;
-}
-
-.chatalert__default--hidden {
- display: none;
-}
-
-.activechatchannel__form {
- width: 100%;
- position: relative;
-}
-
-.activechatchannel__activecontent {
- order: 2;
- flex: 0 1 auto;
- @include themeable(border, theme-border, 1px solid $outline-color);
- padding: 13px;
- min-width: 50%;
- overflow-x: hidden;
- @media screen and (min-width: 1440px) {
- min-width: 45%;
- }
- -webkit-overflow-scrolling: touch;
- background: var(--body-bg);
- z-index: 200;
- position: relative;
- box-sizing: border-box;
- overflow-y: auto;
- max-width: 100%;
-
- @media screen and (max-width: 426px) {
- padding: 10px;
- min-width: 50%;
- width: calc(100%);
- position: fixed;
- height: 100%;
- margin-left: 0;
- margin-top: 0;
- }
-
- @media screen and (min-width: 1000px) {
- h2 {
- font-size: 2rem;
- }
- margin-left: initial;
- padding: 18px;
- max-width: 480px;
- }
-
- @media screen and (min-width: 1300px) {
- margin-left: initial;
- padding: 18px;
- width: 750px;
- max-width: 750px;
- }
-}
-
-.chat--video-visible {
- .activechatchannel__conversation {
- min-width: 20%;
- }
- .activechatchannel__activecontent {
- &.activechatchannel__activecontent--video {
- width: 380px;
- min-width: 380px;
- @media screen and (max-width: 426px) {
- width: calc(100% - 16px);
- min-width: calc(100% - 16px);
- }
- iframe {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- height: 100%;
- width: 100%;
- border: 0px;
- }
- }
- width: 300px;
- min-width: 300px;
- @media screen and (min-width: 1000px) {
- width: 400px;
- min-width: 400px;
- }
- @media screen and (min-width: 1500px) {
- width: 750px;
- min-width: 750px;
- }
- }
-}
-
-.chat--content-visible .activechatchannel__conversation {
- max-width: 52%;
-}
-
-.chat--content-visible
- .activechatchannel__activecontent.activechatchannel__activecontent--video {
- width: 180px;
- min-width: 180px;
-}
-
-.live-chat-wrapper .activechatchannel__activecontent {
- min-width: 310px;
- margin-left: -180px;
- max-width: 96%;
- padding: 13px;
-}
-
-.chat--content-visible-full {
- .activechatchannel__activecontent.activechatchannel__activecontent--sidecar {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- width: 100%;
- min-width: 100%;
- }
- .activechatchannel__activecontent.activechatchannel__activecontent--video {
- position: absolute;
- right: 0;
- bottom: 0;
- width: 200px;
- min-width: 200px;
- height: 300px;
- z-index: 250;
- }
-}
-
-.chat--video-visible-full {
- .activechatchannel__activecontent.activechatchannel__activecontent--video {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- width: 100%;
- min-width: 100%;
- }
- .activechatchannel__activecontent.activechatchannel__activecontent--sidecar {
- display: none;
- }
-}
-
-.activechatchannel__activecontentexitbutton {
- font-size: 30px;
- position: absolute;
- margin-left: 80%;
- margin-top: -4px;
- left: 4px;
- top: 4px;
- z-index: 10;
- padding: 0px;
- height: 30px;
- width: 30px;
- line-height: 0;
- @media screen and (max-width: 800px) {
- &.activechatchannel__activecontentexitbutton--fullscreen {
- display: none;
- }
- }
-}
-
-.activechatchannel__activeArticle {
- position: absolute;
- top: 0px;
- left: 0;
- right: 0;
- bottom: 0;
-}
-
-.activechatchannel__activeArticle iframe {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- height: 100%;
- width: 100%;
- border: 0px;
-}
-
-.activechatchannel__activecontentuserdetails {
- margin-top: 20px;
- font-family: var(--ff-monospace);
- font-size: 0.9em;
-
- .key {
- color: $medium-gray;
- margin-bottom: 3px;
- font-size: 0.9em;
- }
-}
-
-.userdetails__blockreport {
- margin: 10px 0;
-
- button {
- background-color: rgb(255, 0, 0);
- color: rgb(255, 255, 254);
- font-size: 1em;
- cursor: pointer;
- padding: 5px;
- margin: 2px 5px;
- border-radius: 3px;
- border-width: 0px;
- border-style: initial;
- border-color: initial;
- border-image: initial;
-
- &:first-child {
- margin-left: 0;
- }
- }
-}
-
-.userdetails__reportabuse,
-.userdetails__blockmsg {
- a {
- background-color: rgb(255, 0, 0);
- color: rgb(255, 255, 254);
- font-size: 1em;
- cursor: pointer;
- padding: 5px;
- margin: 2px 5px;
- border-radius: 3px;
- border-width: 0px;
- border-style: initial;
- border-color: initial;
- border-image: initial;
- }
-
- .no {
- background-color: rgb(78, 87, 239);
- }
-}
-
-.chatchannels {
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- height: auto;
- justify-content: space-between;
- width: 100%;
-}
-
-.chatchannels__channelslist {
- flex-grow: 1;
- overflow-y: auto;
- overflow-x: hidden;
- margin: var(--su-4) auto;
- width: 100%;
- -webkit-overflow-scrolling: touch;
-}
-
-.chatchannels__channelslistheader {
- background: lighten($purple, 5%);
- border: 1px solid darken($purple, 20%);
- font-size: 12px;
- color: $dark-purple;
- box-sizing: border-box;
- padding: 5px;
- width: 98%;
- border-radius: 3px;
-}
-
-.chatchannels__channelslistfooter {
- font-size: 12px;
- color: $medium-gray;
- padding: 10px;
- opacity: 0.8;
- padding-bottom: 70px;
-}
-
-.chatchannels__config {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- background: var(--body-bg);
- border-top: 1px solid $light-medium-gray;
- padding: var(--su-3);
- font-weight: bold;
- cursor: pointer;
-
- button {
- opacity: 0.6;
- border: none;
- height: 18px;
- width: 18px;
- background-size: cover;
- background-color: transparent;
- }
-
- ul {
- padding: 12px 10px;
- }
-
- &:hover {
- .chatchannels__configmenu {
- display: block;
- }
- }
-}
-
-.chatchannels__configmenu {
- position: absolute;
- bottom: 42px;
- min-width: 150px;
- left: 0;
- right: 0;
- background: $lightest-gray;
- border-top: 1px solid $light-medium-gray;
- font-size: 13px;
-
- li {
- list-style: none;
- a {
- color: $dark-gray;
- display: block;
- padding: 5px 0px;
- }
- }
-}
-
-.chatchannels__misc {
- height: 70px;
- border-top: 1px solid #c9c9c9;
-}
-
-// Chatmessage
-.chatmessage {
- padding: var(--su-2) var(--su-6);
- display: flex;
- max-width: 100%;
- @media not all and (pointer: coarse) {
- &:hover {
- @include themeable(
- background,
- theme-container-background-hover,
- $light-gray
- );
-
- .chatmessagebody__username--link {
- @include themeable(
- background,
- theme-container-background-hover,
- transparent
- );
- }
- }
- }
-}
-
-.chat__channelinvitationsindicator a,
-.chat__channelinvitationsindicator button {
- background: linear-gradient(10deg, darken($green, 25%), darken($green, 15%));
- text-align: center;
- padding: 30px 0px;
- display: block;
- border-radius: var(--radius);
- margin: 3px 0px;
- border: 0px;
- width: 94%;
- color: white;
- font-size: 1.1em;
- font-weight: var(--fw-bold);
- -webkit-appearance: unset;
-}
-
-.chatchanneltabbutton {
- border: none;
- width: 100%;
- background: transparent;
- box-sizing: border-box;
- color: var(--body-color);
- display: block;
- position: relative;
- padding: 0;
-
- .crayons-indicator {
- vertical-align: -1px;
- margin-right: var(--su-1);
- }
-}
-
-.chatchanneltab {
- display: inline-block;
- width: 100%;
- background: inherit;
- text-align: start;
- border-radius: var(--radius);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- box-sizing: border-box;
- border: 1px solid transparent;
- font-size: 13px;
- padding: var(--su-3);
- display: flex;
- align-items: center;
-}
-
-.chatchanneltab--active {
- border: 1px solid var(--base-30);
- background: var(--base-10);
- img {
- border: 1px solid var(--base-30);
- }
-}
-
-.chatchanneltab__name {
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.chatchanneltab--new {
- border: 1px solid var(--accent-brand-darker);
- color: var(--accent-brand-darker);
-}
-
-.chatchanneltab--video {
- background: lighten($green, 10%);
- animation: small-pulser 0.5s linear infinite;
-}
-
-.chatchanneltabindicator {
- display: inline-block;
- min-height: 0.3em;
- min-width: 0.3em;
- margin-right: 5px;
- flex-shrink: 0;
-
- img {
- height: calc(22px + 0.3vw);
- width: calc(22px + 0.3vw);
- vertical-align: calc(-6px - 0.14vw);
- border-radius: 100px;
- border: 1px solid var(--base-30);
- background: white;
- }
-
- .chatchanneltabgroupicon {
- display: inline-block;
- margin-left: calc(20px + 0.3vw);
- }
-}
-
-.chatchanneltabindicator .chatchanneltabindicatorgroupimage {
- border-radius: var(--radius);
-}
-
-.chatchanneltabindicator--new img {
- border: 1px solid var(--accent-brand);
-}
-
-.chatmessage__body {
- flex-grow: 1;
- max-width: calc(100% - 37px);
-}
-
-.message__info {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
-}
-
-.chatmessagebody__username {
- font-size: var(--fs-base);
- font-weight: var(--fw-medium);
- margin-right: var(--su-2);
-}
-
-.chatmessage__timestamp {
- font-size: var(--fs-s);
- color: var(--base-60);
-}
-
-.chatmessage__bodytext {
- overflow-wrap: break-word;
- word-wrap: break-word;
- word-break: break-word;
-
- pre {
- background: #29292e;
- }
-
- code {
- background: #29292e;
- padding: 0.1em 0.3em;
- border-radius: 2px;
- color: #eff0f9;
- font-size: 0.95em;
- vertical-align: 0.05em;
- max-width: 100%;
- line-height: 1.4em;
- font-family: var(--ff-monospace);
- }
-}
-
-.chatmessage__profilepic {
- margin-right: var(--su-2);
-}
-
-.chatmessagebody__profileimage {
- height: var(--su-7);
- width: var(--su-7);
- border-radius: 100%;
-}
-
-.chatmessagebody__username--link {
- color: inherit;
- border-radius: 3px;
- padding: 0px 2px;
- display: inline-block;
-
- &:hover {
- @include themeable(
- background,
- theme-container-background-hover,
- transparent
- );
- }
-}
-
-.chatmessagebody__message {
- p {
- margin-top: 0;
- margin-bottom: 9px;
-
- &:last-child {
- margin-bottom: 0;
- }
- }
-
- blockquote {
- border-left: 4px solid $black;
- margin-left: 0px;
- padding-left: 8px;
- }
-
- a h1 {
- color: var(--card-color);
- border-color: var(--card-color);
- }
-
- img {
- max-width: 100%;
- }
-}
-
-.chatmessagebody__currentuser {
- background: black;
- color: white;
- padding: 1px 5px;
- border-radius: 2px;
-}
-
-// Messagecomposer
-.messagecomposer {
- display: flex;
- height: inherit;
- align-items: stretch;
- position: relative;
- height: auto;
- padding: var(--su-4);
-
- textarea {
- margin-right: var(--su-4);
- }
-}
-
-.messagelist__sentinel {
- height: 5px;
-}
-
-.chatcodeeditor {
- position: absolute;
- top: 40px;
- left: 0px;
- right: 24px;
- bottom: 0px;
-}
-
-.chatcodeeditor__header {
- position: absolute;
- top: -27px;
- left: 35px;
- font-family: var(--ff-monospace);
- @include themeable(color, theme-color, $dark-gray);
-}
-
-.cursorelement {
- border-left: 3px solid $red;
- animation: blinker 1s linear infinite;
- padding: 0px;
- z-index: 0;
-}
-
-@keyframes blinker {
- 50% {
- opacity: 0;
- }
-}
-
-@keyframes pulser {
- 50% {
- opacity: 0.8;
- box-shadow: 2px 2px 0px $green;
- padding: 18px;
- }
-}
-
-@keyframes small-pulser {
- 50% {
- opacity: 0.6;
- box-shadow: 2px 2px 0px $green;
- }
-}
-
-.chatchanneljumpback {
- position: relative;
-}
-
-.chatchanneljumpback__messages {
- position: absolute;
- bottom: 12px;
- right: 8px;
- background: var(--body-bg);
- color: var(--body-color);
- border: 2px solid $black;
- padding: 7px 15px;
- border-radius: 20px;
- cursor: pointer;
- font-size: 13px;
- text-transform: uppercase;
- font-weight: bold;
- z-index: 7;
-}
-
-.chatchanneljumpback__hide {
- display: none;
-}
-
-.message__info__actions {
- display: grid;
- grid-template-columns: 19fr 1fr;
-}
-
-.message__actions {
- position: relative;
- justify-content: end;
- -webkit-justify-content: flex-end;
-
- .ellipsis__menubutton img {
- height: 17px;
- vertical-align: middle;
- color: var(--theme-color, #0a0a0a);
- }
-
- &:hover {
- .ellipsis__menubutton {
- opacity: 1;
- }
- }
-
- &:focus-within {
- .ellipsis__menubutton {
- opacity: 1;
- }
- }
-
- img {
- height: 100%;
- opacity: 0.6;
- }
-
- .messagebody__dropdownmenu {
- position: absolute;
- background-color: var(--theme-container-background, #fff);
- border-style: solid;
- border-color: var(--theme-color, #0a0a0a);
- border-radius: 5px;
- border-width: 1px;
- top: 100%;
- right: 0;
-
- button {
- width: 100%;
- text-align: left;
- }
- }
-}
-
-.message__actions span {
- margin-left: 7px;
- font-size: var(--fs-s);
- font-weight: bold;
- cursor: pointer;
-}
-
-.chatmessage:hover .message__actions {
- display: -webkit-flex;
- display: flex;
-}
-
-.chatchannels__richlink {
- border: 1px solid darken($light-medium-gray, 15%);
- border-radius: 3px;
- box-shadow: 2px 2px 0px darken($light-medium-gray, 15%);
- color: $black;
- display: block;
- max-width: 670px;
- padding: 0px;
- margin-bottom: 6px;
- background: var(--card-bg);
- font-size: 0.9em;
- &.chatchannels__richlink--base {
- h1 {
- margin: 18px auto;
- }
- }
- .chatchannels__richlinkmainimage {
- position: relative;
- width: 100%;
- margin: auto;
- background: transparent no-repeat center center;
- background-size: cover;
- z-index: 2;
- padding-top: 42%;
- }
- h1 {
- margin-top: 8px;
- padding: 0px calc(10px + 0.2vw);
- line-height: 1.1em;
- font-size: 1.8em;
- img {
- height: 1.2em;
- width: 1.2em;
- margin-right: 5px;
- vertical-align: -0.25em;
- &.chatchannels__richlinkprofilepic {
- border-radius: 100px;
- border: 1px solid var(--card-color-tertiary);
- }
- }
- }
- h4 {
- margin-top: 12px;
- margin-bottom: 15px;
- color: var(--card-color-tertiary);
- font-weight: 500;
- padding: 0px calc(10px + 0.2vw);
- img {
- height: 22px;
- width: 22px;
- border-radius: 100px;
- margin-right: 3px;
- border: 1px solid var(--card-color-tertiary);
- vertical-align: -6px;
- }
- }
-}
-
-.delete-actions__container {
- margin-top: var(--su-4);
-}
-
-.message__delete__button {
- margin-right: var(--su-2);
-}
-
-.message__delete__modal__hide {
- display: none;
-}
-
-.composer-container__edit {
- height: auto;
- padding: var(--su-4);
- display: flex;
- flex-direction: column;
-}
-
-.composer-textarea__edit {
- height: 80px;
- max-height: 8rem;
- margin-bottom: var(--su-4);
-}
-
-.composer-textarea {
- height: auto;
- margin-bottom: var(--su-4);
- min-height: 2.5rem;
- resize: vertical;
- max-height: 8rem;
- overflow: hidden;
-}
-
-.composer-btn-group {
- button {
- margin-right: var(--su-2);
-
- &:last-child {
- margin-right: 0;
- }
- }
-}
-
-.mention__list {
- position: absolute;
- background: var(--card-bg);
- display: none;
- z-index: 1;
- border-top: 1px solid #dbdbdb;
- bottom: 90px;
- width: 100%;
- max-height: 280px;
- overflow-x: scroll;
-}
-.mention__list .mention__user {
- padding: 5px 10px;
- border-bottom: 1px solid #dbdbdb;
- cursor: pointer;
-}
-.compose__outer__container {
- position: relative;
- box-shadow: 0 0 0 1px var(--card-border);
-}
-.mention__user__image {
- height: 25px;
- width: 25px;
- margin-right: 6px;
- border-radius: 20px;
- align-self: center;
-}
-.mention__visible {
- display: block;
-}
-.mention__user {
- display: grid;
- grid-template-columns: 30px 1fr;
-}
-.mention__user p {
- margin: 0px;
- font-size: 9px;
- color: gray;
- width: max-content;
-}
-.mentioned-all {
- color: rgb(213, 138, 0);
-}
-
-.active__message__list {
- background: var(--theme-container-accent-background, #f5f6f7);
-}
-.chatmessage__action {
- &:hover {
- background: none;
- }
-
- .chatmessage__bodytext {
- margin: 0;
- font-size: 12px;
- font-style: italic;
- color: var(--card-color-tertiary);
- a {
- text-decoration: none;
- color: var(--card-color-tertiary);
- &:hover {
- text-decoration: underline;
- }
- }
- }
-}
-.joining-message {
- display: grid;
- margin-top: 30px;
- justify-content: center;
- h3,
- h2 {
- width: 90%;
- margin-top: 10px;
- text-align: center;
- justify-self: center;
- }
-}
-.user-picture,
-.send-request {
- display: flex;
- justify-content: center;
- margin-top: 10vh;
-}
-.user-picture {
- .chatmessage__profilepic {
- .chatmessagebody__profileimage {
- width: 50px;
- height: 50px;
- border: 1px solid var(--base-30);
- }
- }
-}
-
-.loading-user {
- height: '210px';
- width: '210px';
- margin: ' 15px auto';
- display: 'block';
- border-radius: '500px';
- background-color: '#f5f6f7';
-}
-.request-card {
- display: grid;
- grid-template-columns: 200px 1fr;
-}
-
-.request-actions {
- justify-content: space-between;
- display: flex;
-}
-
-.request-message {
- width: 100%;
-
- @media screen and (min-width: $breakpoint-s) {
- width: 60%;
- }
-}
-
-.channel_details {
- margin-top: 30px;
-}
-.channel-request-card {
- display: flex;
- justify-content: space-between;
- flex-wrap: wrap;
-}
-.request_manager_header {
- margin-top: 30px;
-}
-
-.requests-badge {
- position: absolute;
- height: 17px;
- width: 17px;
- padding: 2px;
- margin-left: -10px;
- margin-top: -2px;
-}
-
-.chat_channel-member-list {
- height: 300px;
- overflow-y: scroll;
-}
-
-.member-list-item {
- justify-content: space-between;
-
- .admin-emoji {
- width: 6%;
- }
-
- .admin-emoji-button {
- width: 10%;
- }
-}
-
-.connect-draw {
- margin-top: 30px;
- .draw-title {
- display: flex;
- justify-content: flex-start;
- }
- .connect-draw__colors {
- z-index: 2;
- margin: 5px 20px;
- text-align: center;
- pointer-events: all;
- }
-
- .connect-draw__color {
- height: 30px;
- width: 30px;
- margin-right: 10px;
- border-radius: 50%;
- border: none;
- }
- .color:hover {
- opacity: 0.7;
- cursor: pointer;
- }
-
- .color:focus {
- outline: 0;
- }
- .connect-draw__draw-area {
- display: grid;
-
- .connect-draw__draw {
- border: 1px solid black;
- background-color: white;
- justify-self: center;
- }
- .connect-draw__actions {
- margin: 20px 0px;
- display: flex;
- button {
- margin-left: 10px;
- }
- }
- }
-}
-
-.report__abuse-options {
- .crayons-field + .crayons-field {
- margin-top: var(--su-2);
- }
-}
-
-.report__abuse__button {
- width: 135px;
-}
-.reported__message {
- border: 1px solid;
- max-height: 300px;
- overflow: scroll;
-}
-
-.membership-section {
- position: relative;
-
- .membership-actions {
- position: relative;
-
- .membership-management__dropdown-memu {
- display: none;
- position: absolute;
- background-color: var(--theme-container-background, #fff);
- border-style: solid;
- border-color: var(--theme-color, #0a0a0a);
- border-radius: 5px;
- border-width: 1px;
- z-index: 100;
- width: 200px;
- right: 78px;
- top: 20px;
-
- button {
- width: 100%;
- text-align: left;
- }
-
- &:hover {
- display: block;
- }
- }
-
- .membership-management__dropdown-button {
- height: 17px;
- cursor: pointer;
- color: var(--theme-color, #0a0a0a);
-
- &:hover + .membership-management__dropdown-memu {
- display: block;
- }
-
- img {
- height: 100%;
- opacity: 0.6;
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/connect/_channel-details.scss b/app/assets/stylesheets/connect/_channel-details.scss
deleted file mode 100644
index 852a3f06d..000000000
--- a/app/assets/stylesheets/connect/_channel-details.scss
+++ /dev/null
@@ -1,134 +0,0 @@
-@import '../variables';
-
-.channeldetails {
- .channeldetails__name {
- font-family: var(--ff-sans-serif);
- font-size: 48px;
- }
-
- .channeldetails__description {
- font-family: var(--ff-sans-serif);
- color: $dark-gray;
- }
-
- // 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;
- margin-right: 6px;
- border-radius: 20px;
- vertical-align: -6px;
- }
- a {
- font-family: var(--ff-sans-serif);
- }
- }
-
- .channeldetails__inviteusers {
- h2 {
- font-family: var(--ff-sans-serif);
- }
-
- // find users
- input {
- border-radius: 3px;
- border: 1px solid #dbdbdb;
- box-sizing: border-box;
- padding: 8px;
- margin-left: 2px;
- font-size: 18px;
- -webkit-appearance: none;
- }
-
- .channeldetails__searchresults {
- padding: 5px 0;
-
- .channeldetails__searchedusers {
- padding: 1px 0;
-
- // profile pic
- img {
- height: 22px;
- width: 22px;
- margin-right: 6px;
- border-radius: 20px;
- vertical-align: -6px;
- }
-
- a {
- font-size: 14px;
- font-family: var(--ff-sans-serif);
- }
-
- // invite button
- button {
- width: 45px;
- height: 24px;
- background-color: $purple;
- border-radius: 3px;
- color: $white;
- }
-
- // in channel message
- span {
- color: $dark-gray;
- font-size: 14px;
- font-family: var(--ff-sans-serif);
- }
- }
- }
-
- .channeldetails__pendingusers {
- a {
- font-size: 18px;
- font-family: var(--ff-sans-serif);
- }
- }
- }
-
- .channeldetails__leavechannel {
- // Danger Zone
- h2 {
- color: $red;
- font-family: $helvetica-condensed;
- font-size: 2.5em;
- }
- // leave channel
- button {
- width: 180px;
- padding: 3px 0px;
- border-radius: 3px;
- background-color: $red;
- color: $white;
- font-size: 1.2em;
- font-weight: bold;
- cursor: pointer;
- }
- }
-
- .channeldetails__leftchannel {
- h2 {
- font-family: var(--ff-sans-serif);
- font-size: 32px;
- }
- h3 {
- font-family: var(--ff-sans-serif);
- font-size: 18px;
- }
- h4 {
- font-family: var(--ff-sans-serif);
- font-size: 18px;
- }
- p {
- font-family: var(--ff-sans-serif);
- }
- }
-}
diff --git a/app/assets/stylesheets/minimal.scss b/app/assets/stylesheets/minimal.scss
index 56fe1ac67..6388f0558 100644
--- a/app/assets/stylesheets/minimal.scss
+++ b/app/assets/stylesheets/minimal.scss
@@ -19,8 +19,6 @@
@import 'ltags/LiquidTags';
-@import 'chat';
-
@import 'email_subscriptions';
@import 'runtime';
diff --git a/app/assets/stylesheets/scaffolds.scss b/app/assets/stylesheets/scaffolds.scss
index c311e80f6..43adee8a5 100644
--- a/app/assets/stylesheets/scaffolds.scss
+++ b/app/assets/stylesheets/scaffolds.scss
@@ -46,7 +46,6 @@ body.dark-theme {
.image-upload-button button,
.icon-image,
.dev-badge,
- .chatchannels__config img,
.message__actions img {
-webkit-filter: invert(95%);
filter: invert(95%);
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index 102237786..e60d26669 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -8,7 +8,6 @@ module Admin
articles: "https://admin.forem.com/docs/forem-basics/posts",
badges: "https://admin.forem.com/docs/forem-basics/badges",
badge_achievements: "https://admin.forem.com/docs/forem-basics/badges",
- chat_channels: "https://admin.forem.com/docs/advanced-customization/chat-channels",
display_ads: "https://admin.forem.com/docs/advanced-customization/display-ads",
feedback_messages: "https://admin.forem.com/docs/advanced-customization/reports",
html_variants: "https://admin.forem.com/docs/advanced-customization/html-variants",
diff --git a/app/controllers/admin/chat_channels_controller.rb b/app/controllers/admin/chat_channels_controller.rb
deleted file mode 100644
index 4a585f539..000000000
--- a/app/controllers/admin/chat_channels_controller.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-module Admin
- class ChatChannelsController < Admin::ApplicationController
- layout "admin"
-
- CHAT_ALLOWED_PARAMS = %i[usernames_string channel_name username_string].freeze
-
- def index
- @q = ChatChannel.where(channel_type: "invite_only").includes(:users).ransack(params[:q])
- @group_chat_channels = @q.result.page(params[:page]).per(50)
- end
-
- def create
- ChatChannels::CreateWithUsers.call(
- users: users_by_param,
- channel_type: "invite_only",
- contrived_name: chat_channel_params[:channel_name],
- membership_role: "mod",
- )
- redirect_back(fallback_location: admin_chat_channels_path)
- end
-
- def update
- @chat_channel = ChatChannel.find(params[:id])
- @chat_channel.invite_users(users: users_by_param)
- redirect_back(fallback_location: admin_chat_channels_path)
- end
-
- def remove_user
- @chat_channel = ChatChannel.find(params[:id])
- @chat_channel.remove_user(user_by_param)
- redirect_back(fallback_location: admin_chat_channels_path)
- end
-
- def destroy
- @chat_channel = ChatChannel.find(params[:id])
- if @chat_channel.users.count.zero?
- @chat_channel.destroy
- flash[:success] = "Channel was successfully deleted."
- else
- flash[:alert] = "Channel NOT deleted, because it still has users."
- end
- redirect_back(fallback_location: admin_chat_channels_path)
- end
-
- private
-
- def users_by_param
- User.where(username: chat_channel_params[:usernames_string].downcase.delete(" ").split(","))
- end
-
- def user_by_param
- User.find_by(username: chat_channel_params[:username_string])
- end
-
- def chat_channel_params
- params.require(:chat_channel).permit(CHAT_ALLOWED_PARAMS)
- end
- end
-end
diff --git a/app/controllers/chat_channel_memberships_controller.rb b/app/controllers/chat_channel_memberships_controller.rb
deleted file mode 100644
index b55e393b8..000000000
--- a/app/controllers/chat_channel_memberships_controller.rb
+++ /dev/null
@@ -1,285 +0,0 @@
-class ChatChannelMembershipsController < ApplicationController
- before_action :authenticate_user!
- after_action :verify_authorized, except: %w[join_channel request_details]
-
- include MessagesHelper
- include ChatChannelMembershipsHelper
-
- rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
- rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
-
- def index
- skip_authorization
- memberships = current_user.chat_channel_memberships.includes(:chat_channel)
- @pending_invites = memberships.filter_by_status("pending")
- end
-
- def find_by_chat_channel_id
- @membership = ChatChannelMembership.where(chat_channel_id: params[:chat_channel_id],
- user_id: current_user.id).first!
- authorize @membership
- render json: @membership.to_json(
- only: %i[id status viewable_by chat_channel_id last_opened_at],
- methods: %i[channel_text channel_last_message_at channel_status channel_username
- channel_type channel_text channel_name channel_image channel_modified_slug channel_messages_count],
- )
- end
-
- def chat_channel_info
- @membership = ChatChannelMembership.find(params[:id])
- authorize @membership
- @channel = @membership.chat_channel
- invite_cache_key = "chat-channel-invite-#{@channel.id}"
- invitation_slug = Rails.cache.fetch(invite_cache_key, expires_in: 80.hours) do
- "invitation-link-#{SecureRandom.hex(3)}"
- end
- @invitation_link = "/join_channel_invitation/#{@channel.slug}?invitation_slug=#{invitation_slug}"
- end
-
- def create_membership_request
- chat_channel = ChatChannel.find_by(id: channel_membership_params[:chat_channel_id])
- authorize chat_channel, :update?
- message = ChatChannels::SendInvitation.call(
- channel_membership_params[:invitation_usernames],
- current_user,
- chat_channel,
- )
-
- render json: { success: true, message: message, data: {} }, status: :ok
- end
-
- def join_channel
- membership_params = params[:chat_channel_membership]
- chat_channel = ChatChannel.find(membership_params[:chat_channel_id])
- existing_membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: chat_channel.id)
- if existing_membership.present? && %w[active joining_request].exclude?(existing_membership.status)
- status = existing_membership.update(status: "joining_request", role: "member")
- else
- membership = ChatChannelMembership.new(user_id: current_user.id, chat_channel_id: chat_channel.id,
- role: "member", status: "joining_request")
- status = membership.save
- end
- if status
- render json: { status: "success", message: "Request Sent" }, status: :ok
- else
- render json: { status: 400, message: "Unable to join channel" }, status: :bad_request
- end
- end
-
- def remove_membership
- @chat_channel = ChatChannel.find(params[:chat_channel_id])
- authorize @chat_channel, :update?
- @chat_channel_membership = @chat_channel.chat_channel_memberships.find(params[:membership_id])
- if params[:status] == "pending"
- @chat_channel_membership.destroy
- message = "Invitation removed."
- else
- membership = @chat_channel_membership
- message = "@#{current_user.username} removed @#{membership.user.username} from #{membership.channel_name}"
- send_chat_action_message(
- message, current_user, @chat_channel_membership.chat_channel_id, "removed_from_channel"
- )
- @chat_channel_membership.update(status: "removed_from_channel")
- message = "Removed #{@chat_channel_membership.user.name}"
- end
-
- render json: { status: "success", message: message, success: true }, status: :ok
- end
-
- def add_membership
- @chat_channel = ChatChannel.find(params[:chat_channel_id])
- authorize @chat_channel, :update?
- @chat_channel_membership = @chat_channel.chat_channel_memberships.find(params[:membership_id])
-
- return unless permitted_params[:user_action].present? && @chat_channel_membership.status == "joining_request"
-
- respond_to_invitation(@chat_channel_membership.status)
- end
-
- def update
- @chat_channel_membership = ChatChannelMembership.find(params[:id])
- authorize @chat_channel_membership
- respond_to_invitation(@chat_channel_membership.status)
- end
-
- def update_membership
- @chat_channel_membership = ChatChannelMembership.find(params[:id])
- authorize @chat_channel_membership
- @chat_channel_membership.update(permitted_params)
- if @chat_channel_membership.errors.any?
- render json: { success: false, errors: @chat_channel_membership.errors.full_messages,
- message: "Failed to update settings." }, status: :bad_request
- else
- render json: { success: true, message: "Personal settings updated." }, status: :ok
- end
- end
-
- def leave_membership
- chat_channel_membership = ChatChannelMembership.find_by(id: params[:id])
- authorize chat_channel_membership
- channel_name = chat_channel_membership.chat_channel.channel_name
- send_chat_action_message("@#{current_user.username} left #{chat_channel_membership.channel_name}", current_user,
- chat_channel_membership.chat_channel_id, "left_channel")
- chat_channel_membership.update(status: "left_channel")
- message = "You have left the channel #{channel_name}. It may take a moment to be removed from your list."
- if chat_channel_membership.errors.any?
- render json: { success: false, message: "Failed to update membership",
- errors: chat_channel_membership.errors.full_messages }, status: :bad_request
- else
- render json: { success: true, message: message }, status: :ok
- end
- end
-
- def request_details
- user_chat_channels = ChatChannel.includes(:chat_channel_memberships).where(
- chat_channel_memberships: { user_id: current_user.id, role: "mod", status: "active" },
- )
- @memberships = user_chat_channels.flat_map(&:requested_memberships)
- @user_invitations = ChatChannelMembership.where(
- user_id: current_user.id,
- status: %w[pending],
- ).order("created_at DESC")
- end
-
- def update_membership_role
- @chat_channel = ChatChannel.find_by(id: params[:id])
- authorize @chat_channel, :update?
- membership = ChatChannelMembership.find_by(
- id: channel_membership_params[:membership_id],
- chat_channel_id: @chat_channel.id,
- )
-
- membership.update(role: channel_membership_params[:role])
- if membership.errors.any?
- render json: {
- success: false,
- message: "Failed to update membership",
- errors: chat_channel_membership.errors.full_messages
- }, status: :bad_request
- else
- role = membership.reload.role
- send_chat_action_message(
- "@#{membership.user.username} role is updated as #{role}",
- current_user, @chat_channel.id,
- "updated"
- )
-
- render json: { success: true, message: "User Membership is updated" }, status: :ok
- end
- end
-
- def join_channel_invitation
- @chat_channel = ChatChannel.find_by(slug: params[:channel_slug])
- authorize @chat_channel
- invite_cache_key = "chat-channel-invite-#{@chat_channel.id}"
- invitation_slug = Rails.cache.read(invite_cache_key)
- existing_membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: @chat_channel.id)
- redirect_to URI.parse("/connect/#{@chat_channel.slug}").path if existing_membership&.status == "active"
- @link_expired = true if invitation_slug != params[:invitation_slug]
- end
-
- def joining_invitation_response
- chat_channel = ChatChannel.find_by(id: params[:chat_channel_id])
- authorize chat_channel
- if params[:user_action] == "accept"
- membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: chat_channel.id)
- if !membership
- membership = ChatChannelMembership.create(user_id: current_user.id, chat_channel_id: chat_channel.id)
- unless membership&.errors&.any?
- send_chat_action_message("@#{membership.user.username} join the channel", current_user, chat_channel.id,
- "joined")
- end
- elsif membership.status != "active"
- # This check checks if the user already has the chatChannelMembership with the status pending, joining_request
- # Then update it to as active.
- membership.update(role: "member", status: "active")
- send_chat_action_message("@#{membership.user.username} join the channel", current_user,
- membership.chat_channel_id, "joined")
- end
-
- if membership&.errors&.any?
- flash[:settings_notice] = membership.errors.full_messages
- redirect_to root_path
- end
-
- redirect_to connect_path(chat_channel.slug)
- else
- redirect_to root_path
- end
- end
-
- private
-
- def permitted_params
- params.require(:chat_channel_membership).permit(:user_action, :show_global_badge_notification)
- end
-
- def channel_membership_params
- params.require(:chat_channel_membership).permit(:chat_channel_id, :invitation_usernames, :membership_id, :role)
- end
-
- def respond_to_invitation(previous_status)
- if permitted_params[:user_action] == "accept"
- @chat_channel_membership.update(status: "active")
- channel_name = @chat_channel_membership.chat_channel.channel_name
-
- if previous_status == "pending"
- send_chat_action_message(
- "@#{current_user.username} joined #{@chat_channel_membership.channel_name}",
- current_user,
- @chat_channel_membership.chat_channel_id,
- "joined",
- )
-
- notice = "Invitation to #{channel_name} accepted. It may take a moment to show up in your list."
- else
- send_chat_action_message(
- "@#{current_user.username} added @#{@chat_channel_membership.user.username}",
- current_user,
- @chat_channel_membership.chat_channel_id,
- "joined",
- )
-
- NotifyMailer
- .with(membership: @chat_channel_membership, inviter: @chat_channel_membership.user)
- .channel_invite_email
- .deliver_later
-
- notice = "Accepted request of #{@chat_channel_membership.user.username} to join #{channel_name}."
- end
- else
- @chat_channel_membership.update(status: "rejected")
- notice = "Invitation rejected."
- end
-
- membership_user = format_membership(@chat_channel_membership)
- flash[:settings_notice] = notice
-
- respond_to do |format|
- format.html { redirect_to chat_channel_memberships_path }
- format.json do
- render json: {
- status: "success",
- message: flash[:settings_notice],
- success: true,
- membership: membership_user
- }, status: :ok
- end
- end
- end
-
- def send_chat_action_message(message, user, channel_id, action)
- temp_message_id = SecureRandom.hex(20)
- message = Message.create("message_markdown" => message, "user_id" => user.id, "chat_channel_id" => channel_id,
- "chat_action" => action)
- pusher_message_created(false, message, temp_message_id) unless message.left_channel?
- end
-
- def user_not_authorized
- render json: { success: false, message: "User not authorized" }, status: :unauthorized
- end
-
- def record_not_found
- render json: { success: false, message: "not found" }, status: :not_found
- end
-end
diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb
deleted file mode 100644
index 35842d49b..000000000
--- a/app/controllers/chat_channels_controller.rb
+++ /dev/null
@@ -1,268 +0,0 @@
-class ChatChannelsController < ApplicationController
- before_action :authenticate_user!, only: %i[moderate]
- before_action :set_channel, only: %i[show update update_channel open moderate]
- after_action :verify_authorized
-
- include MessagesHelper
- include ChatChannelsHelper
-
- CHANNEL_ATTRIBUTES_FOR_SERIALIZATION = %i[id description channel_name].freeze
- private_constant :CHANNEL_ATTRIBUTES_FOR_SERIALIZATION
-
- def index
- case params[:state]
- when "unopened"
- authorize ChatChannel
- @chat_channels_memberships = unopened_json_response
- render "index", formats: :json
- when "unopened_ids"
- authorize ChatChannel
- @unopened_ids = unopened_ids_response
- render json: { unopened_ids: @unopened_ids }
- when "pending"
- authorize ChatChannel
- @chat_channels_memberships = pending_json_response
- render "index", formats: :json
- when "joining_request"
- authorize ChatChannel
- @chat_channels_memberships = joining_request_json_response
- render "index", formats: :json
- else
- skip_authorization
- render_channels_html
- end
- end
-
- def show
- @chat_messages = @chat_channel.messages
- .includes(:user)
- .order(created_at: :desc)
- .offset(params[:message_offset])
- .limit(50)
- end
-
- def create
- authorize ChatChannel
- @chat_channel = current_user.chat_channels.create(
- channel_type: "invite_only",
- channel_name: chat_channel_params[:channel_name],
- slug: chat_channel_params[:slug],
- )
- render_chat_channel
- end
-
- def update
- chat_channel = ChatChannels::UpdateChannel.call(@chat_channel, chat_channel_params)
- if chat_channel.errors.any?
- flash[:error] = chat_channel.errors.full_messages.to_sentence
- else
- if chat_channel_params[:discoverable].to_i.zero?
- ChatChannelMembership.create(user_id: Settings::General.mascot_user_id, chat_channel_id: chat_channel.id,
- role: "member", status: "active")
- else
- ChatChannelMembership.find_by(user_id: Settings::General.mascot_user_id)&.destroy
- end
- flash[:settings_notice] = "Channel settings updated."
- end
- current_user_membership = @chat_channel.mod_memberships.find_by!(user: current_user)
-
- redirect_to edit_chat_channel_membership_path(current_user_membership)
- end
-
- def update_channel
- @chat_channel.update(chat_channel_params)
- if @chat_channel.errors.any?
- render json: { success: false, errors: @chat_channel.errors.full_messages,
- message: "Channel settings updation failed. Try again later." }, success: :bad_request
- else
- if chat_channel_params[:discoverable]
- ChatChannelMembership.create(user_id: Settings::General.mascot_user_id, chat_channel_id: @chat_channel.id,
- role: "member", status: "active")
- else
- ChatChannelMembership.find_by(user_id: Settings::General.mascot_user_id)&.destroy
- end
- render json: { success: true, message: "Channel settings updated.", data: {} }, success: :ok
- end
- end
-
- def open
- membership = @chat_channel.chat_channel_memberships.where(user_id: current_user.id).first
- membership.update(last_opened_at: 1.second.from_now, has_unopened_messages: false)
- send_open_notification
- render json: { status: "success", channel: params[:id] }, status: :ok
- end
-
- def moderate
- chat_channel = ChatChannel.find_by(id: params[:id])
- authorize chat_channel
- command, username = chat_channel_params[:command].split
- case command
- when "/ban"
- user = User.find_by(username: username)
- membership = user&.chat_channel_memberships&.find_by(chat_channel: chat_channel)
- if user && membership
- user.add_role(:suspended)
- user.messages.where(chat_channel: chat_channel).delete_all
- membership.update(status: "removed_from_channel")
- Pusher.trigger(chat_channel.pusher_channels, "user-banned", { userId: user.id }.to_json)
- render json: { status: "moderation-success", message: "#{username} was suspended.", userId: user.id,
- chatChannelId: chat_channel.id }, status: :ok
- else
- render json: {
- status: "error",
- message: "Suspend failed. user with username '#{username}' not found in this channel."
- }, status: :bad_request
- end
- when "/unban"
- user = User.find_by(username: username)
- if user
- user.remove_role(:suspended)
- render json: { status: "moderation-success", message: "#{username} was unsuspended." }, status: :ok
- else
- render json: {
- status: "error",
- message: "Unsuspend failed. User with username '#{username}' not found in this channel."
- }, status: :bad_request
- end
- when "/clearchannel"
- @chat_channel.clear_channel
- render json: { status: "success", message: "cleared!" }, status: :ok
- else
- render json: { status: "error", message: "invalid command" }, status: :bad_request
- end
- end
-
- def create_chat
- chat_recipient = User.find(params[:user_id])
- valid_listing = Listing.where(user_id: params[:user_id], contact_via_connect: true).limit(1)
- authorize ChatChannel
-
- if chat_recipient.setting.inbox_type == "open" || valid_listing.length == 1
- chat = ChatChannels::CreateWithUsers.call(users: [current_user, chat_recipient], channel_type: "direct")
- message_markdown = params[:message]
- message = Message.new(
- chat_channel: chat,
- message_markdown: message_markdown,
- user: current_user,
- )
- chat.messages.append(message)
- render json: { status: "success", message: "chat channel created!" }, status: :ok
- else
- render json: { status: "error", message: "not allowed!" }, status: :bad_request
- end
- rescue StandardError => e
- render json: { status: "error", message: e.message }, status: :bad_request
- end
-
- def block_chat
- chat_channel = ChatChannel.find(params[:chat_id])
- authorize chat_channel
- chat_channel.status = "blocked"
- chat_channel.save
- render json: { status: "success", message: "chat channel blocked" }, status: :ok
- end
-
- # NOTE: this is part of an effort of moving some things from the external to
- # the internal API. No behavior was changes as part of this refactoring, so
- # this action is a bit unusual.
- def channel_info
- skip_authorization
-
- @chat_channel =
- ChatChannel
- .select(CHANNEL_ATTRIBUTES_FOR_SERIALIZATION)
- .find_by(id: params[:id])
-
- return if @chat_channel&.has_member?(current_user)
-
- render json: { error: "not found", status: 404 }, status: :not_found
- end
-
- def create_channel
- chat_channel_params = params[:chat_channel]
- chat_channel_name = chat_channel_params[:channel_name].split.join("-")
- chat_channel = ChatChannel.new(
- channel_type: "invite_only",
- channel_name: chat_channel_params[:channel_name],
- slug: "#{chat_channel_name}-#{SecureRandom.hex(5)}",
- )
- authorize chat_channel
- chat_channel.save
- membership = chat_channel.chat_channel_memberships.new(user_id: current_user.id, role: "mod")
- if membership.save
- message = ChatChannels::SendInvitation.call(
- chat_channel_params[:invitation_usernames],
- current_user,
- chat_channel,
- )
-
- send_chat_action_message(
- "channel is created by #{current_user.username}",
- current_user, membership.chat_channel_id,
- "chat channel is created"
- )
- render json: {
- success: true,
- message: "Channel is created #{message ? "& #{message}" : nil}"
- }, status: :ok
- else
- render json: {
- success: false,
- message: membership.errors_as_sentence
- }, status: 445
- end
- end
-
- private
-
- def set_channel
- @chat_channel = ChatChannel.find_by(id: params[:id]) || not_found
- authorize @chat_channel
- end
-
- def chat_channel_params
- params.require(:chat_channel).permit(policy(ChatChannel).permitted_attributes)
- end
-
- def render_channels_html
- return unless current_user && params[:slug]
-
- slug = if params[:slug]&.start_with?("@")
- [current_user.username, params[:slug].delete("@")].sort.join("/")
- else
- params[:slug]
- end
- chat_channel = ChatChannel.find_by(slug: slug)
- return unless chat_channel
-
- membership = chat_channel.chat_channel_memberships.find_by(user_id: current_user.id)
- @active_channel = membership&.status == "active" ? chat_channel : nil
- end
-
- def render_chat_channel
- if @chat_channel.valid?
- render json: { status: "success",
- chat_channel: @chat_channel.to_json(only: %i[channel_name slug]) },
- status: :ok
- else
- render json: { errors: @chat_channel.errors.full_messages }
- end
- end
-
- def send_open_notification
- adjusted_slug = if @chat_channel.group?
- @chat_channel.adjusted_slug
- else
- @chat_channel.adjusted_slug(current_user)
- end
- payload = { channel_type: @chat_channel.channel_type, adjusted_slug: adjusted_slug }.to_json
- Pusher.trigger(ChatChannel.pm_notifications_channel(session_current_user_id), "message-opened", payload)
- end
-
- def send_chat_action_message(message, user, channel_id, action)
- temp_message_id = SecureRandom.hex(20)
- message = Message.create(message_markdown: message, user_id: user.id, chat_channel_id: channel_id,
- chat_action: action)
- pusher_message_created(false, message, temp_message_id)
- end
-end
diff --git a/app/controllers/concerns/listings_toolkit.rb b/app/controllers/concerns/listings_toolkit.rb
index 6a93538e1..0ef3b154d 100644
--- a/app/controllers/concerns/listings_toolkit.rb
+++ b/app/controllers/concerns/listings_toolkit.rb
@@ -80,7 +80,7 @@ module ListingsToolkit
ALLOWED_PARAMS = %i[
title body_markdown listing_category_id tag_list
- expires_at contact_via_connect location organization_id action
+ expires_at location organization_id action
].freeze
# Filter for a set of known safe params
diff --git a/app/controllers/email_subscriptions_controller.rb b/app/controllers/email_subscriptions_controller.rb
index c8dc37d3b..9748b589a 100644
--- a/app/controllers/email_subscriptions_controller.rb
+++ b/app/controllers/email_subscriptions_controller.rb
@@ -19,7 +19,6 @@ class EmailSubscriptionsController < ApplicationController
email_comment_notifications: "comment notifications",
email_follower_notifications: "follower notifications",
email_mention_notifications: "mention notifications",
- email_connect_messages: "#{Settings::Community.community_name} connect messages",
email_unread_notifications: "unread notifications",
email_badge_notifications: "badge notifications"
}.freeze
diff --git a/app/controllers/listings_controller.rb b/app/controllers/listings_controller.rb
index 73f99e363..3f480247d 100644
--- a/app/controllers/listings_controller.rb
+++ b/app/controllers/listings_controller.rb
@@ -3,7 +3,7 @@ class ListingsController < ApplicationController
INDEX_JSON_OPTIONS = {
only: %i[
- title processed_html tag_list category id user_id slug contact_via_connect location bumped_at
+ title processed_html tag_list category id user_id slug location bumped_at
originally_published_at
],
methods: %i[category],
diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb
deleted file mode 100644
index 9f22cd42d..000000000
--- a/app/controllers/messages_controller.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-class MessagesController < ApplicationController
- before_action :set_message, only: %i[destroy update]
- before_action :authenticate_user!, only: %i[create]
- include MessagesHelper
-
- def create
- @message = Message.new(message_params)
- @message.user_id = session_current_user_id
- @temp_message_id = (0...20).map { ("a".."z").to_a[rand(8)] }.join
- authorize @message
-
- # sending temp message only to sender
- pusher_message_created(true, @message, @temp_message_id)
- if @message.save
- pusher_message_created(false, @message, @temp_message_id)
- notify_mentioned_users(@mentioned_users_id)
- render json: { status: "success", message: { temp_id: @temp_message_id, id: @message.id } }, status: :created
- else
- render json: {
- status: "error",
- message: {
- chat_channel_id: @message.chat_channel_id,
- message: @message.errors.full_messages,
- type: "error"
- }
- }, status: :unauthorized
- end
- end
-
- def destroy
- authorize @message
-
- if @message.valid?
- begin
- Pusher.trigger(@message.chat_channel.pusher_channels, "message-deleted", @message.to_json)
- rescue Pusher::Error => e
- Honeybadger.notify(e)
- end
- end
-
- if @message.destroy
- render json: { status: "success", message: "Message was deleted" }
- else
- render json: {
- status: "error",
- message: {
- chat_channel_id: @message.chat_channel_id,
- message: @message.errors.full_messages,
- type: "error"
- }
- }, status: :unauthorized
- end
- end
-
- def update
- authorize @message
-
- if @message.update(permitted_attributes(@message).merge(edited_at: Time.zone.now))
- if @message.valid?
- begin
- message_json = create_pusher_payload(@message, "")
- Pusher.trigger(@message.chat_channel.pusher_channels, "message-edited", message_json)
- rescue Pusher::Error => e
- Honeybadger.notify(e)
- end
- end
- render json: { status: "success", message: "Message was edited" }
- else
- render json: {
- status: "error",
- message: {
- chat_channel_id: @message.chat_channel_id,
- message: @message.errors.full_messages,
- type: "error"
- }
- }, status: :unauthorized
- end
- end
-
- private
-
- def message_params
- @mentioned_users_id = params[:message][:mentioned_users_id]
- params.require(:message).permit(:message_markdown, :user_id, :chat_channel_id)
- end
-
- def set_message
- @message = Message.find(params[:id])
- end
-
- def user_not_authorized
- respond_to do |format|
- format.json do
- render json: {
- status: "error",
- message: {
- chat_channel_id: message_params[:chat_channel_id],
- message: "You can not do that because you are suspended",
- type: "error"
- }
- }, status: :unauthorized
- end
- end
- end
-
- def notify_mentioned_users(user_ids)
- # If @all is mentioned then we get an array of all of the channel's users IDs from the channel
- # https://github.com/forem/forem/blob/9bdef4d4ae0b41612001a62c2409121b654bf71f/app/javascript/chat/chat.jsx#L1562
- return unless user_ids
-
- message_json = create_pusher_payload(@message, @temp_message_id)
-
- user_ids.each do |id|
- Pusher.trigger(ChatChannel.pm_notifications_channel(id), "mentioned", message_json)
- end
- end
-end
diff --git a/app/controllers/moderations_controller.rb b/app/controllers/moderations_controller.rb
index 16933070a..143b6ff5c 100644
--- a/app/controllers/moderations_controller.rb
+++ b/app/controllers/moderations_controller.rb
@@ -22,7 +22,6 @@ class ModerationsController < ApplicationController
@articles = articles.includes(:user).to_json(JSON_OPTIONS)
@tag = Tag.find_by(name: params[:tag]) || not_found if params[:tag].present?
@current_user_tags = current_user.moderator_for_tags
- @community_mod_channel = current_user.chat_channels.find_by("channel_name LIKE ?", "Community Mods: Team%")
end
def article
diff --git a/app/controllers/pusher_controller.rb b/app/controllers/pusher_controller.rb
deleted file mode 100644
index 38092aceb..000000000
--- a/app/controllers/pusher_controller.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class PusherController < ApplicationController
- def auth
- if valid_channel
- response = Pusher.authenticate(params[:channel_name], params[:socket_id],
- user_id: current_user.id) # => required
- render json: response
- else
- render json: { text: "Forbidden", status: "403" }
- end
- end
-
- def valid_channel
- valid_private_dm_channel || valid_private_group_channel
- end
-
- def valid_private_dm_channel
- current_user && params[:channel_name] == ChatChannel.pm_notifications_channel(current_user.id)
- end
-
- def valid_private_group_channel
- return false unless params[:channel_name].include?("private-channel-")
-
- id = params[:channel_name].split("-").last
- channel = ChatChannel.find(id)
- channel.has_member?(current_user)
- end
-end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index d9a96043f..155d8f808 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,17 +1,8 @@
class SearchController < ApplicationController
- before_action :authenticate_user!, only: %i[tags chat_channels reactions usernames]
+ before_action :authenticate_user!, only: %i[tags reactions usernames]
before_action :format_integer_params
before_action :sanitize_params, only: %i[listings reactions feed_content]
- CHAT_CHANNEL_PARAMS = %i[
- channel_status
- channel_type
- page
- per_page
- status
- user_id
- ].freeze
-
LISTINGS_PARAMS = [
:category,
:listing_search,
@@ -65,23 +56,6 @@ class SearchController < ApplicationController
render json: { result: result }
end
- def chat_channels
- user_ids =
- if chat_channel_params[:user_id].present?
- [current_user.id, Settings::General.mascot_user_id, chat_channel_params[:user_id]].reject(&:blank?)
- else
- [current_user.id]
- end
-
- result = Search::ChatChannelMembership.search_documents(
- user_ids: user_ids,
- page: chat_channel_params[:page],
- per_page: chat_channel_params[:per_page],
- )
-
- render json: { result: result }
- end
-
def listings
result = Search::Listing.search_documents(
category: listing_params[:category],
@@ -193,10 +167,6 @@ class SearchController < ApplicationController
)
end
- def chat_channel_params
- params.permit(CHAT_CHANNEL_PARAMS)
- end
-
def listing_params
params.permit(LISTINGS_PARAMS)
end
diff --git a/app/controllers/user_blocks_controller.rb b/app/controllers/user_blocks_controller.rb
index 20e484b45..232babe16 100644
--- a/app/controllers/user_blocks_controller.rb
+++ b/app/controllers/user_blocks_controller.rb
@@ -19,7 +19,6 @@ class UserBlocksController < ApplicationController
@user_block.config = "default"
if @user_block.save
- UserBlocks::ChannelHandler.new(@user_block).block_chat_channel
current_user.stop_following(@user_block.blocked)
@user_block.blocked.stop_following(current_user)
render json: { result: "blocked" }
@@ -39,7 +38,6 @@ class UserBlocksController < ApplicationController
authorize @user_block
if @user_block.destroy
- UserBlocks::ChannelHandler.new(@user_block).unblock_chat_channel
render json: { result: "unblocked" }
else
render json: { error: @user_block.errors_as_sentence, status: 422 }, status: :unprocessable_entity
diff --git a/app/controllers/users/notification_settings_controller.rb b/app/controllers/users/notification_settings_controller.rb
index 5a4daf5be..6cf2c216e 100644
--- a/app/controllers/users/notification_settings_controller.rb
+++ b/app/controllers/users/notification_settings_controller.rb
@@ -7,7 +7,6 @@ module Users
ALLOWED_PARAMS = %i[email_badge_notifications
email_comment_notifications
email_community_mod_newsletter
- email_connect_messages
email_digest_periodic
email_follower_notifications
email_membership_newsletter
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3bcc3ea75..4174af3a7 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,5 +1,5 @@
module ApplicationHelper
- # rubocop:disable Performance/OpenStruct
+ # rubocop:disable Style/OpenStructUse, Performance/OpenStruct
USER_COLORS = ["#19063A", "#dce9f3"].freeze
DELETED_USER = OpenStruct.new(
@@ -11,7 +11,7 @@ module ApplicationHelper
twitter_username: nil,
github_username: nil,
)
- # rubocop:enable Performance/OpenStruct
+ # rubocop:enable Style/OpenStructUse, Performance/OpenStruct
LARGE_USERBASE_THRESHOLD = 1000
diff --git a/app/helpers/chat_channel_memberships_helper.rb b/app/helpers/chat_channel_memberships_helper.rb
deleted file mode 100644
index df74ba335..000000000
--- a/app/helpers/chat_channel_memberships_helper.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module ChatChannelMembershipsHelper
- def formatted_membership_user(memberships)
- memberships.map do |membership|
- {
- name: membership.user.name,
- username: membership.user.username,
- user_id: membership.user.id,
- membership_id: membership.id,
- role: membership.role,
- status: membership.status,
- image: Images::Profile.call(membership.user.profile_image_url, length: 90),
- chat_channel_name: membership.chat_channel.channel_name,
- chat_channel_id: membership.chat_channel.id,
- slug: membership.chat_channel.slug
- }
- end
- end
-
- def membership_users(memberships)
- memberships.includes(:user).map do |membership|
- format_membership(membership)
- end
- end
-
- def format_membership(membership)
- {
- name: membership.user.name,
- username: membership.user.username,
- user_id: membership.user.id,
- membership_id: membership.id,
- role: membership.role,
- status: membership.status,
- image: Images::Profile.call(membership.user.profile_image_url, length: 90)
- }
- end
-end
diff --git a/app/helpers/chat_channels_helper.rb b/app/helpers/chat_channels_helper.rb
deleted file mode 100644
index 1b1a13b6f..000000000
--- a/app/helpers/chat_channels_helper.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module ChatChannelsHelper
- def unopened_json_response
- if session_current_user_id
- ChatChannelMembership.where(user_id: session_current_user_id)
- .where(has_unopened_messages: true)
- .where(show_global_badge_notification: true)
- .where.not(status: %w[removed_from_channel left_channel])
- .includes(%i[chat_channel user])
- .order("chat_channel_memberships.updated_at" => :desc)
- else
- ChatChannelMembership.none
- end
- end
-
- def pending_json_response
- if current_user
- current_user
- .chat_channel_memberships.includes(:chat_channel)
- .where(status: "pending")
- .order("chat_channel_memberships.updated_at" => :desc)
- else
- ChatChannelMembership.none
- end
- end
-
- def unopened_ids_response
- ChatChannelMembership.where(user_id: session_current_user_id).includes(:chat_channel)
- .where(has_unopened_messages: true).where.not(status: %w[removed_from_channel
- left_channel]).pluck(:chat_channel_id)
- end
-
- def joining_request_json_response
- requested_memberships_id = current_user
- .chat_channel_memberships
- .includes(:chat_channel)
- .where(chat_channels: { discoverable: true }, role: "mod")
- .pluck(:chat_channel_id)
- .flat_map { |membership_id| ChatChannel.find_by(id: membership_id).requested_memberships.ids }
-
- ChatChannelMembership
- .includes(%i[user chat_channel])
- .where(id: requested_memberships_id)
- end
-end
diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb
deleted file mode 100644
index 46098d6b5..000000000
--- a/app/helpers/messages_helper.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-module MessagesHelper
- def create_pusher_payload(new_message, temp_id)
- payload = {
- temp_id: temp_id,
- id: new_message.id,
- user_id: new_message.user.id,
- chat_channel_id: new_message.chat_channel.id,
- chat_channel_adjusted_slug: new_message.chat_channel.adjusted_slug(current_user, "sender"),
- channel_type: new_message.chat_channel.channel_type,
- username: new_message.user.username,
- profile_image_url: Images::Profile.call(new_message.user.profile_image_url, length: 90),
- message: new_message.message_html,
- markdown: new_message.message_markdown,
- edited_at: new_message.edited_at,
- timestamp: Time.current,
- color: new_message.preferred_user_color,
- reception_method: "pushed",
- action: new_message.chat_action
- }
-
- if new_message.chat_channel.group?
- payload[:chat_channel_adjusted_slug] = new_message.chat_channel.adjusted_slug
- end
- payload.to_json
- end
-
- def pusher_message_created(is_single, message, temp_message_id)
- return unless message.valid?
-
- begin
- message_json = create_pusher_payload(message, temp_message_id)
- if is_single
- Pusher.trigger(ChatChannel.pm_notifications_channel(message.user_id), "message-created", message_json)
- else
- Pusher.trigger(message.chat_channel.pusher_channels, "message-created", message_json)
- end
- rescue Pusher::Error => e
- Honeybadger.notify(e)
- end
- end
-end
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index 78e98a74e..3d8007ba7 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -23,6 +23,6 @@ module NotificationsHelper
)
else
I18n.t(action, user: key_to_link.call("user"))
- end.html_safe
+ end.html_safe # rubocop:disable Rails/OutputSafety
end
end
diff --git a/app/javascript/chat/ChatChannelSettings/ActiveMembershipsSection.jsx b/app/javascript/chat/ChatChannelSettings/ActiveMembershipsSection.jsx
deleted file mode 100644
index 54165c455..000000000
--- a/app/javascript/chat/ChatChannelSettings/ActiveMembershipsSection.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { defaultMembershipPropType } from '../../common-prop-types/membership-prop-type';
-import { Membership } from './Membership';
-import { Button } from '@crayons';
-
-export const ActiveMembershipsSection = ({
- activeMemberships,
- removeMembership,
- currentMembershipRole,
- toggleScreens,
-}) => {
- const activeMembershipList = activeMemberships.slice(0, 4);
-
- return (
-
-
Members
- {activeMembershipList.map((activeMembership) => (
-
- ))}
-
-
- View All
-
-
-
- );
-};
-
-ActiveMembershipsSection.propTypes = {
- activeMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- removeMembership: PropTypes.func.isRequired,
- currentMembershipRole: PropTypes.string.isRequired,
- toggleScreens: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/ChannelDescriptionSection.jsx b/app/javascript/chat/ChatChannelSettings/ChannelDescriptionSection.jsx
deleted file mode 100644
index fded19b28..000000000
--- a/app/javascript/chat/ChatChannelSettings/ChannelDescriptionSection.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const ChannelDescriptionSection = ({
- channelName,
- channelDescription,
- currentMembershipRole,
-}) => {
- return (
-
-
{channelName}
-
{channelDescription}
-
You are a channel {currentMembershipRole}
-
- );
-};
-
-ChannelDescriptionSection.propTypes = {
- channelName: PropTypes.string.isRequired,
- currentMembershipRole: PropTypes.string.isRequired,
- channelDescription: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/ChatChannelMembershipSection.jsx b/app/javascript/chat/ChatChannelSettings/ChatChannelMembershipSection.jsx
deleted file mode 100644
index 8eca79010..000000000
--- a/app/javascript/chat/ChatChannelSettings/ChatChannelMembershipSection.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { defaultMembershipPropType } from '../../common-prop-types/membership-prop-type';
-import { ActiveMembershipsSection } from './ActiveMembershipsSection';
-import { PendingMembershipSection } from './PendingMembershipSection';
-import { RequestedMembershipSection } from './RequestedMembershipSection';
-
-export const ChatChannelMembershipSection = ({
- pendingMemberships,
- requestedMemberships,
- chatChannelAcceptMembership,
- activeMemberships,
- removeMembership,
- currentMembershipRole,
- toggleScreens,
-}) => {
- return (
-
- );
-};
-
-ChatChannelMembershipSection.propTypes = {
- pendingMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- requestedMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- activeMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- removeMembership: PropTypes.func.isRequired,
- chatChannelAcceptMembership: PropTypes.func.isRequired,
- currentMembershipRole: PropTypes.string.isRequired,
- toggleScreens: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/ChatChannelSettings.jsx b/app/javascript/chat/ChatChannelSettings/ChatChannelSettings.jsx
deleted file mode 100644
index 9d143eef8..000000000
--- a/app/javascript/chat/ChatChannelSettings/ChatChannelSettings.jsx
+++ /dev/null
@@ -1,440 +0,0 @@
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-
-import {
- getChannelDetails,
- updatePersonalChatChannelNotificationSettings,
- rejectChatChannelJoiningRequest,
- acceptChatChannelJoiningRequest,
- updateChatChannelDescription,
- sendChatChannelInvitation,
- leaveChatChannelMembership,
- updateMembershipRole,
-} from '../actions/chat_channel_setting_actions';
-
-import { addSnackbarItem } from '../../Snackbar';
-import { ManageActiveMembership } from './MembershipManager/ManageActiveMembership';
-import { ChatChannelSettingsSection } from './ChatChannelSettingsSection';
-
-export class ChatChannelSettings extends Component {
- static propTypes = {
- handleLeavingChannel: PropTypes.func.isRequired,
- activeMembershipId: PropTypes.number.isRequired,
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- successMessages: null,
- errorMessages: null,
- activeMemberships: [],
- pendingMemberships: [],
- requestedMemberships: [],
- chatChannel: null,
- currentMembership: null,
- activeMembershipId: null,
- channelDescription: null,
- channelDiscoverable: null,
- invitationUsernames: null,
- showGlobalBadgeNotification: null,
- displaySettings: true,
- displayMembershipManager: false,
- invitationLink: null,
- };
- }
-
- componentDidMount() {
- this.updateChannelDetails();
- }
-
- componentWillReceiveProps() {
- const { activeMembershipId } = this.props;
- this.setState({
- activeMembershipId,
- });
- }
-
- updateChannelDetails = () => {
- const { activeMembershipId } = this.props;
-
- getChannelDetails(activeMembershipId)
- .then((response) => {
- if (response.success) {
- const { result } = response;
- this.setState({
- chatChannel: result.chat_channel,
- activeMemberships: result.memberships.active,
- pendingMemberships: result.memberships.pending,
- requestedMemberships: result.memberships.requested,
- currentMembership: result.current_membership,
- channelDescription: result.chat_channel.description,
- channelDiscoverable: result.chat_channel.discoverable,
- showGlobalBadgeNotification:
- result.current_membership.show_global_badge_notification,
- invitationLink: result.invitation_link,
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
- })
- .catch((error) => {
- this.setState({
- successMessages: null,
- errorMessages: error.message,
- });
- });
- };
-
- handleDescriptionChange = (e) => {
- const description = e.target.value;
- this.setState({
- channelDescription: description,
- });
- };
-
- handlePersonChannelSetting = (e) => {
- const status = e.target.checked;
- this.setState({
- showGlobalBadgeNotification: status,
- });
- };
-
- updateCurrentMembershipNotificationSettings = async () => {
- const { currentMembership, showGlobalBadgeNotification } = this.state;
- const response = await updatePersonalChatChannelNotificationSettings(
- currentMembership.id,
- showGlobalBadgeNotification,
- );
- const { message } = response;
- if (response.success) {
- this.setState((prevState) => {
- return {
- errorMessages: null,
- successMessages: response.message,
- currentMembership: {
- ...prevState.currentMembership,
- show_global_badge_notification: showGlobalBadgeNotification,
- },
- };
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- showGlobalBadgeNotification:
- currentMembership.show_global_badge_notification,
- });
- }
- addSnackbarItem({ message });
- };
-
- chatChannelRemoveMembership = async (membershipId, membershipStatus) => {
- const { chatChannel } = this.state;
- const response = await rejectChatChannelJoiningRequest(
- chatChannel.id,
- membershipId,
- membershipStatus,
- );
- return response;
- };
-
- filterMemberships = (memberships, membershipId) => {
- const filteredMembership = memberships.filter(
- (membership) => membership.membership_id !== Number(membershipId),
- );
- return filteredMembership;
- };
-
- removeMembership = async (e) => {
- const { membershipId, membershipStatus } = e.target.dataset;
- const response = await this.chatChannelRemoveMembership(
- membershipId,
- membershipStatus,
- );
- const { message } = response;
- this.updateMemberships(membershipId, response, membershipStatus);
- addSnackbarItem({ message });
- };
-
- updateMemberships = (membershipId, response, membershipStatus) => {
- if (response.success) {
- this.updateChannelDetails();
- this.setState((prevState) => {
- return {
- errorMessages: null,
- successMessages: response.message,
- activeMemberships:
- membershipStatus === 'active'
- ? this.filterMemberships(
- prevState.activeMemberships,
- membershipId,
- )
- : prevState.activeMemberships,
- pendingMemberships:
- membershipStatus === 'pending'
- ? this.filterMemberships(
- prevState.pendingMemberships,
- membershipId,
- )
- : prevState.pendingMemberships,
- requestedMemberships:
- membershipStatus === 'joining_request'
- ? this.filterMemberships(
- prevState.requestedMemberships,
- membershipId,
- )
- : prevState.requestedMembership,
- };
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
- };
-
- chatChannelAcceptMembership = async (e) => {
- const { chatChannel } = this.state;
- const { membershipId } = e.target.dataset;
- const response = await acceptChatChannelJoiningRequest(
- chatChannel.id,
- membershipId,
- );
- const { message } = response;
- if (response.success) {
- this.setState((prevState) => {
- const filteredRequestedMemberships = prevState.requestedMemberships.filter(
- (requestedMembership) =>
- requestedMembership.membership_id !== Number(membershipId),
- );
- const updatedActiveMembership = [
- ...prevState.activeMemberships,
- response.membership,
- ];
- return {
- errorMessages: null,
- successMessages: response.message,
- requestedMemberships: filteredRequestedMemberships,
- activeMemberships: updatedActiveMembership,
- };
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
- addSnackbarItem({ message });
- };
-
- handleChannelDiscoverableStatus = (e) => {
- const status = e.target.checked;
- this.setState({
- channelDiscoverable: status,
- });
- };
-
- handleChannelDescriptionChanges = async () => {
- const { chatChannel, channelDescription, channelDiscoverable } = this.state;
- const { id } = chatChannel;
- const response = await updateChatChannelDescription(
- id,
- channelDescription,
- channelDiscoverable,
- );
- const { message } = response;
-
- if (response.success) {
- this.updateChannelDetails();
- this.setState((prevState) => {
- return {
- errorMessages: null,
- successMessages: response.message,
- chatChannel: {
- ...prevState,
- description: channelDescription,
- discoverable: channelDiscoverable,
- },
- };
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- channelDiscoverable: chatChannel.discoverable,
- });
- }
- addSnackbarItem({ message });
- };
-
- handleInvitationUsernames = (e) => {
- const invitationUsernameValue = e.target.value;
- this.setState({
- invitationUsernames: invitationUsernameValue,
- });
- };
-
- handleChannelInvitations = async () => {
- const { invitationUsernames, chatChannel } = this.state;
- const { id } = chatChannel;
- const response = await sendChatChannelInvitation(id, invitationUsernames);
- const { message } = response;
- if (response.success) {
- this.updateChannelDetails();
- this.setState({
- errorMessages: null,
- successMessages: response.message,
- invitationUsernames: null,
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
- addSnackbarItem({ message });
- };
-
- handleleaveChannelMembership = async () => {
- // eslint-disable-next-line no-restricted-globals
- const actionStatus = confirm(
- 'Are you absolutely sure you want to leave this channel? This action is permanent.',
- );
- const { currentMembership } = this.state;
- if (actionStatus) {
- const response = await leaveChatChannelMembership(currentMembership.id);
- const { message } = response;
- if (response.success) {
- this.setState({
- successMessages: message,
- errorMessages: null,
- });
- this.props.handleLeavingChannel(currentMembership.id);
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
- addSnackbarItem({ message });
- }
- };
-
- toggleScreens = () => {
- const { displaySettings, displayMembershipManager } = this.state;
-
- this.setState({
- displaySettings: !displaySettings,
- displayMembershipManager: !displayMembershipManager,
- });
- };
-
- handleUpdateMembershipRole = async (e) => {
- const { membershipId, role } = e.target.dataset;
- const { chatChannel } = this.state;
- const response = await updateMembershipRole(
- membershipId,
- chatChannel.id,
- role,
- );
- const { message } = response;
- if (response.success) {
- this.updateChannelDetails();
- this.setState((prevState) => {
- const { activeMemberships } = prevState;
- const updatedActiveMemberships = activeMemberships.map(
- (activeMembership) => {
- if (activeMembership.membership_id === Number(membershipId)) {
- return { ...activeMembership, role };
- }
- return activeMembership;
- },
- );
- return {
- ...prevState,
- activeMemberships: updatedActiveMemberships,
- errorMessages: null,
- successMessages: response.message,
- };
- });
- } else {
- this.setState({
- successMessages: null,
- errorMessages: response.message,
- });
- }
-
- addSnackbarItem({ message });
- };
-
- render() {
- const {
- chatChannel,
- currentMembership,
- activeMemberships,
- pendingMemberships,
- requestedMemberships,
- channelDescription,
- channelDiscoverable,
- invitationUsernames,
- showGlobalBadgeNotification,
- displaySettings,
- invitationLink,
- } = this.state;
-
- if (!chatChannel) {
- return null;
- }
-
- return (
-
-
- {displaySettings ? (
-
- ) : (
-
- )}
-
-
- );
- }
-}
diff --git a/app/javascript/chat/ChatChannelSettings/ChatChannelSettingsSection.jsx b/app/javascript/chat/ChatChannelSettings/ChatChannelSettingsSection.jsx
deleted file mode 100644
index c0be562b9..000000000
--- a/app/javascript/chat/ChatChannelSettings/ChatChannelSettingsSection.jsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { ModSection } from './ModSection';
-import { PersonalSettings } from './PersonalSetting';
-import { LeaveMembershipSection } from './LeaveMembershipSection';
-import { ModFaqSection } from './ModFaqSection';
-import { ChannelDescriptionSection } from './ChannelDescriptionSection';
-import { ChatChannelMembershipSection } from './ChatChannelMembershipSection';
-
-export const ChatChannelSettingsSection = ({
- channelDiscoverable,
- updateCurrentMembershipNotificationSettings,
- handleleaveChannelMembership,
- handlePersonChannelSetting,
- handleChannelDescriptionChanges,
- handleChannelDiscoverableStatus,
- handleDescriptionChange,
- handleChannelInvitations,
- handleInvitationUsernames,
- toggleScreens,
- removeMembership,
- chatChannelAcceptMembership,
- channelDescription,
- chatChannel,
- currentMembership,
- activeMemberships,
- pendingMemberships,
- requestedMemberships,
- invitationUsernames,
- showGlobalBadgeNotification,
-}) => (
-
-);
-
-ChatChannelSettingsSection.propTypes = {
- chatChannel: PropTypes.isRequired,
- currentMembership: PropTypes.isRequired,
- activeMemberships: PropTypes.isRequired,
- pendingMemberships: PropTypes.isRequired,
- requestedMemberships: PropTypes.isRequired,
- invitationUsernames: PropTypes.string.isRequired,
- channelDescription: PropTypes.string.isRequired,
- channelDiscoverable: PropTypes.bool.isRequired,
- showGlobalBadgeNotification: PropTypes.bool.isRequired,
- handleleaveChannelMembership: PropTypes.func.isRequired,
- chatChannelAcceptMembership: PropTypes.func.isRequired,
- removeMembership: PropTypes.func.isRequired,
- toggleScreens: PropTypes.func.isRequired,
- handleInvitationUsernames: PropTypes.func.isRequired,
- handleChannelInvitations: PropTypes.func.isRequired,
- handleDescriptionChange: PropTypes.func.isRequired,
- handleChannelDiscoverableStatus: PropTypes.func.isRequired,
- handleChannelDescriptionChanges: PropTypes.func.isRequired,
- handlePersonChannelSetting: PropTypes.func.isRequired,
- updateCurrentMembershipNotificationSettings: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/InviteForm.jsx b/app/javascript/chat/ChatChannelSettings/InviteForm.jsx
deleted file mode 100644
index 86325d38c..000000000
--- a/app/javascript/chat/ChatChannelSettings/InviteForm.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-export const InviteForm = ({
- handleChannelInvitations,
- invitationUsernames,
- handleInvitationUsernames,
-}) => {
- return (
-
-
-
- Usernames to invite
-
-
-
-
-
- Submit
-
-
-
- );
-};
-
-InviteForm.propTypes = {
- handleInvitationUsernames: PropTypes.func.isRequired,
- handleChannelInvitations: PropTypes.func.isRequired,
- invitationUsernames: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/LeaveMembershipSection.jsx b/app/javascript/chat/ChatChannelSettings/LeaveMembershipSection.jsx
deleted file mode 100644
index 6c3644955..000000000
--- a/app/javascript/chat/ChatChannelSettings/LeaveMembershipSection.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { h } from 'preact';
-import PropsType from 'prop-types';
-import { Button } from '@crayons';
-
-export const LeaveMembershipSection = ({
- handleleaveChannelMembership,
- currentMembershipRole,
-}) => {
- if (currentMembershipRole === 'mod') {
- return null;
- }
-
- return (
-
-
Danger Zone
-
-
- Leave Channel
-
-
-
- );
-};
-
-LeaveMembershipSection.propTypes = {
- handleleaveChannelMembership: PropsType.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/Membership.jsx b/app/javascript/chat/ChatChannelSettings/Membership.jsx
deleted file mode 100644
index 7b7737988..000000000
--- a/app/javascript/chat/ChatChannelSettings/Membership.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { defaultMembershipPropType } from '../../common-prop-types/membership-prop-type';
-import { Button } from '@crayons';
-
-export const Membership = ({
- membership,
- removeMembership,
- membershipType,
- chatChannelAcceptMembership,
- currentMembershipRole,
-}) => {
- return (
-
-
-
-
-
- {membership.name}
-
- {membershipType === 'requested' ? (
-
- +
-
- ) : null}
- {membership.role !== 'mod' && currentMembershipRole === 'mod' ? (
-
- x
-
- ) : null}
-
- );
-};
-
-Membership.propTypes = {
- membership: PropTypes.objectOf(defaultMembershipPropType).isRequired,
- removeMembership: PropTypes.func.isRequired,
- membershipType: PropTypes.func.isRequired,
- chatChannelAcceptMembership: PropTypes.func.isRequired,
- currentMembershipRole: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/MembershipManager/InvitationLinkManager.jsx b/app/javascript/chat/ChatChannelSettings/MembershipManager/InvitationLinkManager.jsx
deleted file mode 100644
index feea5e249..000000000
--- a/app/javascript/chat/ChatChannelSettings/MembershipManager/InvitationLinkManager.jsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/* global Runtime */
-
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-
-import { Button } from '@crayons';
-
-const CopyIcon = () => (
-
- Copy Invitation Url
-
-
-);
-
-export class InvitationLinkManager extends Component {
- static propTypes = {
- invitationLink: PropTypes.string.isRequired,
- currentMembership: PropTypes.isRequired,
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- invitationLink: props.invitationLink,
- showImageCopiedMessage: false,
- currentMembership: props.currentMembership,
- };
- }
-
- copyText = () => {
- this.imageMarkdownInput = document.getElementById(
- 'chat-channel-unviation-url',
- );
-
- Runtime.copyToClipboard(this.imageMarkdownInput.value).then(() => {
- this.setState({ showImageCopiedMessage: true });
- });
- };
-
- render() {
- const {
- showImageCopiedMessage,
- invitationLink,
- currentMembership,
- } = this.state;
-
- if (currentMembership.role !== 'mod') {
- return null;
- }
-
- return (
-
-
Invitation Link
-
-
-
-
- Copied!
-
-
-
- );
- }
-}
diff --git a/app/javascript/chat/ChatChannelSettings/MembershipManager/ManageActiveMembership.jsx b/app/javascript/chat/ChatChannelSettings/MembershipManager/ManageActiveMembership.jsx
deleted file mode 100644
index f6c315f28..000000000
--- a/app/javascript/chat/ChatChannelSettings/MembershipManager/ManageActiveMembership.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-
-import { MembershipSection } from './MembershipSection';
-import { InvitationLinkManager } from './InvitationLinkManager';
-
-export class ManageActiveMembership extends Component {
- static propTypes = {
- activeMemberships: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- }),
- ).isRequired,
- currentMembership: PropTypes.isRequired,
- invitationLink: PropTypes.string.isRequired,
- removeMembership: PropTypes.func.isRequired,
- handleUpdateMembershipRole: PropTypes.func.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- activeMemberships: props.activeMemberships,
- searchMembers: null,
- listAllMemberShips: props.activeMemberships,
- currentMembership: props.currentMembership,
- invitationLink: props.invitationLink,
- removeMembership: props.removeMembership,
- handleUpdateMembershipRole: props.handleUpdateMembershipRole,
- };
- }
-
- componentWillReceiveProps() {
- const {
- activeMemberships,
- currentMembership,
- removeMembership,
- invitationLink,
- } = this.props;
- this.setState({
- listAllMemberShips: activeMemberships,
- currentMembership,
- invitationLink,
- removeMembership,
- activeMemberships,
- searchMembers: null,
- });
- }
-
- searchTheMembershipUser = (e) => {
- const query = e.target?.value?.toLowerCase();
-
- this.setState((prevState) => {
- const filteredActiveMemberships = prevState.activeMemberships.filter(
- (activeMembership) => {
- const value = activeMembership.name.toLowerCase();
- return value.includes(query);
- },
- );
-
- return {
- searchMembers: query,
- listAllMemberShips: filteredActiveMemberships,
- };
- });
- };
-
- render() {
- const {
- searchMembers,
- listAllMemberShips,
- currentMembership,
- invitationLink,
- removeMembership,
- handleUpdateMembershipRole,
- activeMemberships,
- } = this.state;
-
- const membershipCount = activeMemberships.length;
- return (
-
-
-
Chat Channel Membership manager
-
-
-
-
- );
- }
-}
diff --git a/app/javascript/chat/ChatChannelSettings/MembershipManager/Membership.jsx b/app/javascript/chat/ChatChannelSettings/MembershipManager/Membership.jsx
deleted file mode 100644
index 3a2fba273..000000000
--- a/app/javascript/chat/ChatChannelSettings/MembershipManager/Membership.jsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import adminEmoji from '../../../../assets/images/twemoji/fire.svg';
-import { Button } from '@crayons';
-
-export const Membership = ({
- membership,
- currentMembership,
- removeMembership,
- handleUpdateMembershipRole,
- showActionButton,
-}) => {
- const addAsModButton =
- membership.role === 'member' ? (
-
- Promote to Mod
-
- ) : null;
-
- const addAsMemberButton =
- membership.role === 'mod' ? (
-
- Remove Mod
-
- ) : null;
-
- const removeMembershipButton =
- membership.role === 'member' ? (
-
-
-
-
-
- ) : null;
-
- const dropdown =
- currentMembership.role === 'mod' && showActionButton ? (
-
- {removeMembershipButton}
- {addAsModButton}
- {addAsMemberButton}
-
- ) : null;
-
- return (
-
- );
-};
-
-Membership.propTypes = {
- membership: PropTypes.objectOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- }),
- ).isRequired,
- currentMembership: PropTypes.isRequired,
- removeMembership: PropTypes.func.isRequired,
- handleUpdateMembershipRole: PropTypes.func.isRequired,
- showActionButton: PropTypes.bool.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/MembershipManager/MembershipSection.jsx b/app/javascript/chat/ChatChannelSettings/MembershipManager/MembershipSection.jsx
deleted file mode 100644
index 477dab148..000000000
--- a/app/javascript/chat/ChatChannelSettings/MembershipManager/MembershipSection.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Membership } from './Membership';
-
-export const MembershipSection = ({
- memberships,
- currentMembership,
- removeMembership,
- handleUpdateMembershipRole,
- membershipCount,
-}) => {
- if (!memberships || memberships.length === 0) {
- return No membership
;
- }
-
- return (
-
- {memberships.map((activeMembership) => (
- {}}
- className="active-member"
- currentMembership={currentMembership}
- removeMembership={removeMembership}
- handleUpdateMembershipRole={handleUpdateMembershipRole}
- showActionButton={membershipCount > 1}
- />
- ))}
-
- );
-};
-
-MembershipSection.propType = {
- memberships: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- }),
- ).isRequired,
- currentMembership: PropTypes.isRequired,
- removeMembership: PropTypes.func.isRequired,
- handleUpdateMembershipRole: PropTypes.func.isRequired,
- membershipCount: PropTypes.number.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/ModFaqSection.jsx b/app/javascript/chat/ChatChannelSettings/ModFaqSection.jsx
deleted file mode 100644
index 9b743ac36..000000000
--- a/app/javascript/chat/ChatChannelSettings/ModFaqSection.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const ModFaqSection = ({ currentMembershipRole }) => {
- if (currentMembershipRole === 'member') {
- return null;
- }
-
- return (
-
- );
-};
-
-ModFaqSection.propTypes = {
- currentMembershipRole: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/ModSection.jsx b/app/javascript/chat/ChatChannelSettings/ModSection.jsx
deleted file mode 100644
index c69355409..000000000
--- a/app/javascript/chat/ChatChannelSettings/ModSection.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { InviteForm } from './InviteForm';
-import { SettingsForm } from './SettingsForm';
-
-export const ModSection = ({
- handleChannelInvitations,
- invitationUsernames,
- handleInvitationUsernames,
- channelDescription,
- handleDescriptionChange,
- channelDiscoverable,
- handleChannelDiscoverableStatus,
- handleChannelDescriptionChanges,
- currentMembershipRole,
-}) => {
- if (currentMembershipRole === 'member') {
- return null;
- }
-
- return (
-
-
-
-
- );
-};
-
-ModSection.propTypes = {
- handleInvitationUsernames: PropTypes.func.isRequired,
- handleChannelInvitations: PropTypes.func.isRequired,
- invitationUsernames: PropTypes.func.isRequired,
- channelDescription: PropTypes.string.isRequired,
- handleDescriptionChange: PropTypes.func.isRequired,
- handleChannelDiscoverableStatus: PropTypes.func.isRequired,
- handleChannelDescriptionChanges: PropTypes.func.isRequired,
- channelDiscoverable: PropTypes.bool.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/PendingMembershipSection.jsx b/app/javascript/chat/ChatChannelSettings/PendingMembershipSection.jsx
deleted file mode 100644
index 7d8b81ebe..000000000
--- a/app/javascript/chat/ChatChannelSettings/PendingMembershipSection.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { defaultMembershipPropType } from '../../common-prop-types/membership-prop-type';
-import { Membership } from './Membership';
-
-export const PendingMembershipSection = ({
- pendingMemberships,
- removeMembership,
- currentMembershipRole,
-}) => {
- if (currentMembershipRole === 'member') {
- return null;
- }
-
- return (
-
-
Pending Invitations
- {pendingMemberships && pendingMemberships.length > 0
- ? pendingMemberships.map((pendingMembership) => (
-
- ))
- : null}
-
- );
-};
-
-PendingMembershipSection.propTypes = {
- pendingMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- removeMembership: PropTypes.func.isRequired,
- currentMembershipRole: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/PersonalSetting.jsx b/app/javascript/chat/ChatChannelSettings/PersonalSetting.jsx
deleted file mode 100644
index 7806aec8c..000000000
--- a/app/javascript/chat/ChatChannelSettings/PersonalSetting.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-export const PersonalSettings = ({
- handlePersonChannelSetting,
- showGlobalBadgeNotification,
- updateCurrentMembershipNotificationSettings,
-}) => {
- return (
-
-
Personal Settings
-
Notifications
-
-
-
- Receive Notifications for New Messages
-
-
-
-
- Submit
-
-
-
- );
-};
-
-PersonalSettings.propTypes = {
- updateCurrentMembershipNotificationSettings: PropTypes.func.isRequired,
- showGlobalBadgeNotification: PropTypes.bool.isRequired,
- handlePersonChannelSetting: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/RequestedMembershipSection.jsx b/app/javascript/chat/ChatChannelSettings/RequestedMembershipSection.jsx
deleted file mode 100644
index c4a5965d0..000000000
--- a/app/javascript/chat/ChatChannelSettings/RequestedMembershipSection.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { defaultMembershipPropType } from '../../common-prop-types/membership-prop-type';
-
-import { Membership } from './Membership';
-
-export const RequestedMembershipSection = ({
- requestedMemberships,
- removeMembership,
- chatChannelAcceptMembership,
- currentMembershipRole,
-}) => {
- if (currentMembershipRole === 'member') {
- return null;
- }
-
- return (
-
-
Joining Request
- {requestedMemberships && requestedMemberships.length > 0
- ? requestedMemberships.map((pendingMembership) => (
-
- ))
- : null}
-
- );
-};
-
-RequestedMembershipSection.propTypes = {
- requestedMemberships: PropTypes.arrayOf(defaultMembershipPropType).isRequired,
- removeMembership: PropTypes.func.isRequired,
- chatChannelAcceptMembership: PropTypes.func.isRequired,
- currentMembershipRole: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/ChatChannelSettings/SettingsForm.jsx b/app/javascript/chat/ChatChannelSettings/SettingsForm.jsx
deleted file mode 100644
index b28549a26..000000000
--- a/app/javascript/chat/ChatChannelSettings/SettingsForm.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-export const SettingsForm = ({
- channelDescription,
- handleDescriptionChange,
- channelDiscoverable,
- handleChannelDiscoverableStatus,
- handleChannelDescriptionChanges,
-}) => {
- return (
-
-
Channel Settings
-
-
- Description
-
-
-
-
-
-
- Channel Discoverable
-
-
-
-
- Submit
-
-
-
- );
-};
-
-SettingsForm.propTypes = {
- channelDescription: PropTypes.string.isRequired,
- handleDescriptionChange: PropTypes.func.isRequired,
- handleChannelDiscoverableStatus: PropTypes.func.isRequired,
- handleChannelDescriptionChanges: PropTypes.func.isRequired,
- channelDiscoverable: PropTypes.bool.isRequired,
-};
diff --git a/app/javascript/chat/ReportAbuse/index.jsx b/app/javascript/chat/ReportAbuse/index.jsx
deleted file mode 100644
index c6834c560..000000000
--- a/app/javascript/chat/ReportAbuse/index.jsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import { h, Fragment } from 'preact';
-import PropTypes from 'prop-types';
-import { useState } from 'preact/hooks';
-import { reportAbuse, blockUser } from '../actions/requestActions';
-import { addSnackbarItem } from '../../Snackbar';
-import { Button, FormField, RadioButton } from '@crayons';
-
-/**
- * This component render the report abuse
- *
- * @param {object} props
- * @param {object} props.data
- * @param {function} props.closeReportAbuseForm
- *
- * @component
- *
- * @example
- *
- *
- *
- */
-export function ReportAbuse({ data, closeReportAbuseForm }) {
- const [category, setCategory] = useState(null);
-
- const handleChange = (e) => {
- setCategory(e.target.value);
- };
-
- const handleSubmit = async () => {
- const response = await reportAbuse(
- data.message,
- 'connect',
- category,
- data.user_id,
- );
- const { success, message } = response;
- if (success) {
- const confirmBlock = window.confirm(
- `The message will be reported.\n\nWould you like to block this person as well?\n\nThis will:
- - prevent them from commenting on your posts
- - block all notifications from them
- - prevent them from messaging you via chat`,
- );
-
- if (confirmBlock) {
- const response = await blockUser(data.user_id);
- if (response.result === 'blocked') {
- addSnackbarItem({
- message:
- 'Your report has been submitted and the user has been blocked',
- });
- }
- } else {
- addSnackbarItem({ message: 'Your report has been submitted.' });
- }
- closeReportAbuseForm();
- } else {
- addSnackbarItem({ message });
- }
- };
-
- return (
-
-
- Report Abuse
-
- Thank you for reporting any abuse that violates our{' '}
- code of conduct or{' '}
- terms and conditions . We continue to try to make
- this environment a great one for everybody.
-
-
- Why is this content inappropriate?
-
-
-
- Rude or vulgar
-
-
-
-
-
- Harassment or hate speech
-
-
-
-
-
- Spam or copyright issue
-
-
-
-
-
- Inappropriate listings message/category
-
-
- Message to Report
-
-
- Report Message
-
-
-
-
- );
-}
-
-ReportAbuse.propTypes = {
- resource: PropTypes.shape({
- data: PropTypes.shape({
- user_id: PropTypes.number.isRequired,
- message: PropTypes.element.isRequired,
- }),
- }).isRequired,
-};
diff --git a/app/javascript/chat/RequestManager/ChannelRequestSection.jsx b/app/javascript/chat/RequestManager/ChannelRequestSection.jsx
deleted file mode 100644
index e83d1f69d..000000000
--- a/app/javascript/chat/RequestManager/ChannelRequestSection.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { RequestListItem } from './RequestListItem';
-
-export const ChannelRequestSection = ({
- channelRequests,
- handleRequestApproval,
- handleRequestRejection,
-}) => {
- if (channelRequests.length < 0) {
- return null;
- }
-
- return (
-
- {channelRequests &&
- channelRequests.map((channelPendingRequest) => {
- return (
-
- );
- })}
-
- );
-};
-
-ChannelRequestSection.propTypes = {
- channelRequests: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- channel_name: PropTypes.string.isRequired,
- }),
- ).isRequired,
- handleRequestApproval: PropTypes.func.isRequired,
- handleRequestRejection: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/RequestManager/HeaderSection.jsx b/app/javascript/chat/RequestManager/HeaderSection.jsx
deleted file mode 100644
index 4cd4e840d..000000000
--- a/app/javascript/chat/RequestManager/HeaderSection.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-
-export const HeaderSection = ({}) => (
-
-
- Request Center{' '}
-
- 🤝
-
-
-
-);
diff --git a/app/javascript/chat/RequestManager/PersonalInvitationListItem.jsx b/app/javascript/chat/RequestManager/PersonalInvitationListItem.jsx
deleted file mode 100644
index afd595245..000000000
--- a/app/javascript/chat/RequestManager/PersonalInvitationListItem.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { Button } from '@crayons';
-
-export const PendingInvitationListItem = ({ request, updateMembership }) => (
-
-
-
- You got invitation to join {request.chat_channel_name} .
-
-
-
- {' '}
- Reject
-
-
- {' '}
- Accept
-
-
-
-
-);
-
-PendingInvitationListItem.propTypes = {
- request: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- chat_channel_name: PropTypes.string.isRequired,
- }),
- ).isRequired,
- updateMembership: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/RequestManager/PersonalInvitationSection.jsx b/app/javascript/chat/RequestManager/PersonalInvitationSection.jsx
deleted file mode 100644
index 7e2199454..000000000
--- a/app/javascript/chat/RequestManager/PersonalInvitationSection.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { PendingInvitationListItem } from './PersonalInvitationListItem';
-
-export const PersonalInvitationSection = ({
- userInvitations,
- updateMembership,
-}) => {
- if (!userInvitations || userInvitations?.length < 0) {
- return null;
- }
-
- return (
-
- {userInvitations &&
- userInvitations.map((userInvitation) => {
- return (
-
- );
- })}
-
- );
-};
-
-PersonalInvitationSection.propTypes = {
- userInvitations: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- channel_name: PropTypes.string.isRequired,
- }),
- ).isRequired,
- updateMembership: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/RequestManager/RequestListItem.jsx b/app/javascript/chat/RequestManager/RequestListItem.jsx
deleted file mode 100644
index d14792918..000000000
--- a/app/javascript/chat/RequestManager/RequestListItem.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { Button } from '@crayons';
-
-export const RequestListItem = ({
- request,
- handleRequestRejection,
- handleRequestApproval,
-}) => (
-
-
-
- {request.name} requested to join{' '}
- {request.chat_channel_name}
-
-
-
- Reject
-
-
- Accept
-
-
-
-
-);
-
-RequestListItem.propTypes = {
- request: PropTypes.arrayOf(
- PropTypes.shape({
- name: PropTypes.string.isRequired,
- membership_id: PropTypes.number.isRequired,
- user_id: PropTypes.number.isRequired,
- role: PropTypes.string.isRequired,
- image: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- status: PropTypes.string.isRequired,
- chat_channel_name: PropTypes.string.isRequired,
- }),
- ).isRequired,
- handleRequestRejection: PropTypes.func.isRequired,
- handleRequestApproval: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/RequestManager/RequestManager.jsx b/app/javascript/chat/RequestManager/RequestManager.jsx
deleted file mode 100644
index 21072ca60..000000000
--- a/app/javascript/chat/RequestManager/RequestManager.jsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-
-import { addSnackbarItem } from '../../Snackbar';
-import {
- getChannelRequestInfo,
- updateMembership,
- acceptJoiningRequest,
- rejectJoiningRequest,
-} from '../actions/requestActions';
-import { HeaderSection } from './HeaderSection';
-import { ChannelRequestSection } from './ChannelRequestSection';
-import { PersonalInvitationSection } from './PersonalInvitationSection';
-
-export class RequestManager extends Component {
- static propTypes = {
- resource: PropTypes.shape({
- data: PropTypes.object,
- }).isRequired,
- updateRequestCount: PropTypes.func.isRequired,
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- updateRequestCount: props.updateRequestCount,
- channelJoiningRequests: [],
- userInvitations: [],
- };
- }
-
- componentWillReceiveProps() {
- this.setState({
- updateRequestCount: this.props.updateRequestCount,
- });
- }
-
- componentDidMount() {
- getChannelRequestInfo().then((response) => {
- const { result } = response;
- const { user_joining_requests, channel_joining_memberships } = result;
- this.setState({
- channelJoiningRequests: channel_joining_memberships,
- userInvitations: user_joining_requests,
- });
- });
- }
-
- handleIUpdateMembership = async (e) => {
- const {
- membershipId,
- userAction,
- channelSlug,
- channelId,
- } = e.target.dataset;
- const response = await updateMembership(membershipId, userAction);
- const { success, membership, message } = response;
- const { updateRequestCount } = this.state;
- if (success) {
- this.setState((prevState) => {
- const filteredUserInvitations = prevState.userInvitations.filter(
- (userInvitation) =>
- userInvitation.membership_id !== membership.membership_id,
- );
-
- return {
- userInvitations: filteredUserInvitations,
- };
- });
- if (userAction === 'accept') {
- updateRequestCount(true, { channelSlug, channelId });
- }
- updateRequestCount();
- addSnackbarItem({ message });
- } else {
- addSnackbarItem({ message });
- }
- };
-
- handleAcceptJoingRequest = async (e) => {
- const { membershipId, channelId } = e.target.dataset;
- const response = await acceptJoiningRequest(channelId, membershipId);
- const { success, message, membership } = response;
- const { updateRequestCount } = this.state;
-
- if (success) {
- this.setState((prevState) => {
- const formattedChannelJoiningRequests = prevState.channelJoiningRequests.filter(
- (channelJoiningRequest) =>
- channelJoiningRequest.membership_id !== membership.membership_id,
- );
- return {
- channelJoiningRequests: formattedChannelJoiningRequests,
- };
- });
-
- updateRequestCount();
- addSnackbarItem({ message });
- } else {
- addSnackbarItem({ message });
- }
- };
-
- handleRejectJoingRequest = async (e) => {
- const { membershipId, channelId } = e.target.dataset;
- const response = await rejectJoiningRequest(channelId, membershipId);
- const { success, message } = response;
- const { updateRequestCount } = this.state;
-
- if (success) {
- this.setState((prevState) => {
- const formattedChannelJoiningRequests = prevState.channelJoiningRequests.filter(
- (channelJoiningRequest) =>
- channelJoiningRequest.membership_id !== Number(membershipId),
- );
- return {
- channelJoiningRequests: formattedChannelJoiningRequests,
- };
- });
-
- updateRequestCount();
- addSnackbarItem({ message });
- } else {
- addSnackbarItem({ message });
- }
- };
-
- render() {
- const { channelJoiningRequests, userInvitations } = this.state;
-
- return (
-
-
-
- {channelJoiningRequests.length <= 0 && userInvitations.length <= 0 ? (
-
You have no pending invitations.
- ) : null}
-
-
-
-
- );
- }
-}
diff --git a/app/javascript/chat/__tests__/ManageActiveMembership.test.jsx b/app/javascript/chat/__tests__/ManageActiveMembership.test.jsx
deleted file mode 100644
index 1036db1ed..000000000
--- a/app/javascript/chat/__tests__/ManageActiveMembership.test.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ManageActiveMembership } from '../ChatChannelSettings/MembershipManager/ManageActiveMembership';
-
-const currentModMembership = {
- name: 'dummy user',
- username: 'dummyuser',
- user_id: 1,
- chat_channel_id: 2,
- status: 'active',
- role: 'mod',
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText, queryByPlaceholderText } = render(
- ,
- );
-
- expect(queryByText('Chat Channel Membership manager')).toBeDefined();
- expect(queryByPlaceholderText('Search Member...')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/Membership.test.jsx b/app/javascript/chat/__tests__/Membership.test.jsx
deleted file mode 100644
index 737f9a317..000000000
--- a/app/javascript/chat/__tests__/Membership.test.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { Membership } from '../ChatChannelSettings/MembershipManager/Membership';
-
-const membershipData = {
- name: 'dummy Name',
- user_id: 1,
- chat_channel_id: 2,
- membership_id: 1,
- username: 'dummyuser',
-};
-
-const currentModMembership = {
- name: 'dummy user',
- username: 'dummyuser',
- user_id: 1,
- chat_channel_id: 2,
- status: 'active',
- role: 'mod',
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render(
- ,
- );
-
- expect(queryByText('dummy user')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/PersonalInvitationListItem.test.jsx b/app/javascript/chat/__tests__/PersonalInvitationListItem.test.jsx
deleted file mode 100644
index 9c8c003ce..000000000
--- a/app/javascript/chat/__tests__/PersonalInvitationListItem.test.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { PersonalInvitationSection } from '../RequestManager/PersonalInvitationSection';
-
-const data = {
- request: {
- name: 'Demo name',
- membership_id: 11,
- user_id: 10,
- role: 'member',
- image: '/image',
- username: 'demousername',
- status: 'pending',
- chat_channel_name: 'demo channel',
- },
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { queryByText } = render(
- ,
- );
-
- expect(
- queryByText(
- `${data.request.name} wants to join ${data.request.chat_channel_name}`,
- ),
- ).toBeDefined();
-
- expect(queryByText('Reject', { selector: 'button' })).toBeDefined();
-
- expect(queryByText('Accept', { selector: 'button' })).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/PersonalInvitationSection.test.jsx b/app/javascript/chat/__tests__/PersonalInvitationSection.test.jsx
deleted file mode 100644
index 5fd9098f9..000000000
--- a/app/javascript/chat/__tests__/PersonalInvitationSection.test.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { PersonalInvitationSection } from '../RequestManager/PersonalInvitationSection';
-
-const data = {
- userInvitations: [
- {
- name: 'Demo name',
- membership_id: 11,
- user_id: 10,
- role: 'member',
- image: '/image',
- username: 'demousername',
- status: 'joining_request',
- chat_channel_name: 'demo channel',
- },
- ],
- noUserInvitations: [],
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { getByTestId } = render(
- ,
- );
-
- const userInvitationsWrapper = getByTestId('user-invitations');
- expect(
- Number(userInvitationsWrapper.dataset.activeCount),
- ).toBeGreaterThanOrEqual(1);
- });
-});
diff --git a/app/javascript/chat/__tests__/RequestListItem.test.jsx b/app/javascript/chat/__tests__/RequestListItem.test.jsx
deleted file mode 100644
index e0fbde278..000000000
--- a/app/javascript/chat/__tests__/RequestListItem.test.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { RequestListItem } from '../RequestManager/RequestListItem';
-
-const data = {
- request: {
- name: 'Demo name',
- membership_id: 11,
- user_id: 10,
- role: 'member',
- image: '/image',
- username: 'demousername',
- status: 'joining_request',
- chat_channel_name: 'demo channel',
- },
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { queryByText } = render( );
-
- expect(
- queryByText(
- `${data.request.name} wants to join ${data.request.chat_channel_name}`,
- ),
- ).toBeDefined();
-
- expect(queryByText('Reject', { selector: 'button' })).toBeDefined();
-
- expect(queryByText('Accept', { selector: 'button' })).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/activeMembershipsSection.test.jsx b/app/javascript/chat/__tests__/activeMembershipsSection.test.jsx
deleted file mode 100644
index f8c62b4f8..000000000
--- a/app/javascript/chat/__tests__/activeMembershipsSection.test.jsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ActiveMembershipsSection } from '../ChatChannelSettings/ActiveMembershipsSection';
-
-function getEmptyMembershipData() {
- return {
- activeMemberships: [],
- currentMembershipRole: 'mod',
- };
-}
-
-function getMembershipData() {
- return {
- activeMemberships: [
- {
- name: 'test user',
- username: 'testusername',
- user_id: '1',
- membership_id: '2',
- role: 'mod',
- status: 'active',
- image: '',
- },
- ],
- membershipType: 'active',
- currentMembershipRole: 'mod',
- };
-}
-
-describe(' ', () => {
- it('should have no a11y violations when there are no members', async () => {
- const {
- activeMemberships,
- currentMembershipRole,
- } = getEmptyMembershipData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have no a11y violations when there are members', async () => {
- const { activeMemberships, currentMembershipRole } = getMembershipData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have a title', () => {
- const {
- activeMemberships,
- currentMembershipRole,
- } = getEmptyMembershipData();
- const { queryByText } = render(
- ,
- );
-
- expect(queryByText).toBeDefined();
- });
-
- it('should not render the membership list', () => {
- const {
- activeMemberships,
- currentMembershipRole,
- } = getEmptyMembershipData();
- const { getByTestId } = render(
- ,
- );
-
- // no users to be found
- const activeMembershipsWrapper = getByTestId('active-memberships');
-
- expect(Number(activeMembershipsWrapper.dataset.activeCount)).toEqual(0);
- });
-
- it('should render the membership list', () => {
- const { activeMemberships, currentMembershipRole } = getMembershipData();
- const { getByTestId } = render(
- ,
- );
-
- // the other fields aren't necessary to test as this is handled in the
- // tests.
- const activeMembershipsWrapper = getByTestId('active-memberships');
-
- expect(
- Number(activeMembershipsWrapper.dataset.activeCount),
- ).toBeGreaterThanOrEqual(1);
- });
-});
diff --git a/app/javascript/chat/__tests__/alert.test.jsx b/app/javascript/chat/__tests__/alert.test.jsx
deleted file mode 100644
index 14c846da9..000000000
--- a/app/javascript/chat/__tests__/alert.test.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { Alert } from '../alert';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render an alert', () => {
- const { queryByRole } = render( );
-
- expect(queryByRole('alert')).toBeDefined();
- });
-
- it('should not render an alert', () => {
- const { queryByRole } = render( );
-
- const alert = queryByRole('alert');
-
- expect(alert).toBeNull();
- });
-});
diff --git a/app/javascript/chat/__tests__/article.test.jsx b/app/javascript/chat/__tests__/article.test.jsx
deleted file mode 100644
index 0080576ec..000000000
--- a/app/javascript/chat/__tests__/article.test.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import fetch from 'jest-fetch-mock';
-import { axe } from 'jest-axe';
-import { Article } from '../article';
-
-global.fetch = fetch;
-
-const getArticle = () => {
- return {
- title: 'Your approval means nothing to me',
- type_of: 'article',
- path: '/princesscarolyn/your-approval-means-nothing-to-me-42640',
- };
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', async () => {
- const { queryByTitle } = render( );
-
- expect(queryByTitle('Your approval means nothing to me')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/channelButton.test.jsx b/app/javascript/chat/__tests__/channelButton.test.jsx
deleted file mode 100644
index 5df8998da..000000000
--- a/app/javascript/chat/__tests__/channelButton.test.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChannelButton } from '../components/ChannelButton';
-
-const getChannel = () => {
- return {
- channel_name: 'test',
- channel_color: '#00FFFF',
- channel_type: 'invite_only',
- channel_modified_slug: '@test34',
- id: 34,
- chat_channel_id: 23,
- status: 'active',
- };
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { getByText } = render( );
- const button = getByText('test');
-
- expect(button.dataset.channelSlug).toEqual('@test34');
- expect(button.dataset.channelId).toEqual('23');
- expect(button.dataset.channelStatus).toEqual('active');
- expect(button.dataset.channelName).toEqual('test');
- expect(button.dataset.content).toEqual('sidecar-channel-request');
- });
-});
diff --git a/app/javascript/chat/__tests__/channelRequest.test.jsx b/app/javascript/chat/__tests__/channelRequest.test.jsx
deleted file mode 100644
index 5dd16ff62..000000000
--- a/app/javascript/chat/__tests__/channelRequest.test.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChannelRequest } from '../channelRequest';
-
-const getResource = () => {
- return {
- user: {
- name: 'Sarthak',
- username: 'sarthak9',
- },
- channel: {
- name: 'IronMan',
- },
- };
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText, queryByAltText } = render(
- ,
- );
-
- expect(queryByText('Hey Sarthak !')).toBeDefined();
- expect(
- queryByText(
- 'You are not a member of this group yet. Send a request to join.',
- ),
- ).toBeDefined();
- expect(queryByAltText('sarthak9 profile')).toBeDefined();
- expect(queryByAltText('IronMan profile')).toBeDefined();
- expect(queryByText('Join IronMan', { selector: 'button' })).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/channelRequestSection.test.jsx b/app/javascript/chat/__tests__/channelRequestSection.test.jsx
deleted file mode 100644
index d37c8cef6..000000000
--- a/app/javascript/chat/__tests__/channelRequestSection.test.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChannelRequestSection } from '../RequestManager/ChannelRequestSection';
-
-const data = {
- channelRequests: [
- {
- name: 'Demo name',
- membership_id: 11,
- user_id: 10,
- role: 'member',
- image: '/image',
- username: 'demousername',
- status: 'joining_request',
- chat_channel_name: 'demo channel',
- },
- ],
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { getByTestId } = render(
- ,
- );
-
- const channelRequestsWrapper = getByTestId('chat-channel-joining-request');
- expect(
- Number(channelRequestsWrapper.dataset.activeCount),
- ).toBeGreaterThanOrEqual(1);
- });
-});
diff --git a/app/javascript/chat/__tests__/channels.test.jsx b/app/javascript/chat/__tests__/channels.test.jsx
deleted file mode 100644
index 0d3018914..000000000
--- a/app/javascript/chat/__tests__/channels.test.jsx
+++ /dev/null
@@ -1,171 +0,0 @@
-import { h } from 'preact';
-import { render, fireEvent } from '@testing-library/preact';
-import { JSDOM } from 'jsdom';
-import { axe } from 'jest-axe';
-import { Channels } from '../channels';
-
-const doc = new JSDOM('');
-global.document = doc;
-global.window = doc.defaultView;
-global.window.currentUser = { id: 'fake_username' };
-
-let channelSwitched = false;
-
-const fakeSwitchChannel = () => {
- channelSwitched = !channelSwitched;
-};
-
-const fakeChannels = [
- {
- channel_name: 'channel name 1',
- last_opened_at: 'September 2, 2018',
- channel_users: [],
- last_message_at: 'September 21, 2018',
- channel_type: 'group',
- slug: '0',
- channel_modified_slug: '@0',
- id: 12345,
- status: 'active',
- messages_count: 124,
- },
- {
- channel_name: 'group channel 2',
- status: 'active',
- last_opened_at: 'September 12, 2018',
- channel_users: [
- {
- profile_image: 'fake_profile_image',
- darker_color: '#111111',
- last_opened_at: 'some last open date',
- },
- {
- profile_image: 'fake_profile_pic',
- darker_color: '#222222',
- last_opened_at: 'some other last open date',
- },
- ],
- last_message_at: 'September 14, 2018',
- channel_type: 'direct',
- slug: '1',
- channel_modified_slug: '@1',
- id: 12345,
- messages_count: 83,
- },
- {
- channel_name: 'group channel 3',
- last_opened_at: 'September 30, 2018',
- channel_users: [
- {
- profile_image: 'fake_profile_image',
- darker_color: '#111111',
- last_opened_at: 'some last open date',
- },
- {
- profile_image: 'fake_profile_pic',
- darker_color: '#222222',
- last_opened_at: 'some other last open date',
- },
- ],
- last_message_at: 'September 29, 2018',
- channel_type: 'group',
- status: 'active',
- slug: '2',
- channel_modified_slug: '@2',
- id: 67890,
- messages_count: 56,
- },
-];
-
-const getChannels = (mod, chatChannels) => (
-
-);
-
-describe(' ', () => {
- describe('expanded', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getChannels(true, fakeChannels));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render with chat channels', () => {
- const { getByText, getByRole, queryByRole } = render(
- getChannels(true, fakeChannels),
- );
-
- // welcome message should not exist because there are channels
- expect(queryByRole('alert')).toBeNull();
-
- // configFooter should exist
- fireEvent.click(
- getByRole('button', { name: /configuration navigation menu/i }),
- );
- const settings = getByText('Settings');
- expect(settings.getAttribute('href')).toEqual('/settings');
-
- const reportAbuse = getByText('Report Abuse');
- expect(reportAbuse.getAttribute('href')).toEqual('/report-abuse');
- });
-
- it('should render without chat channels', () => {
- const { getByText, getByRole } = render(getChannels(true, []));
-
- // should show "Welcome to Connect message....."
- getByRole('alert');
-
- fireEvent.click(
- getByRole('button', { name: /configuration navigation menu/i }),
- );
- const settings = getByText('Settings');
- expect(settings.getAttribute('href')).toEqual('/settings');
-
- const reportAbuse = getByText('Report Abuse');
- expect(reportAbuse.getAttribute('href')).toEqual('/report-abuse');
- });
- });
-
- describe('not expanded', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getChannels(false, fakeChannels));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have the proper elements, attributes, and content', () => {
- const { queryByTestId } = render(getChannels(false, fakeChannels));
-
- // should have group names but no user names
- // TODO: I don't understand the comment above. To revisit.
- expect(queryByTestId('chat-channels-list')).toBeDefined();
- });
- });
-
- describe('without chat channels', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getChannels(false, []));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render without chat channels', () => {
- const { getByTestId } = render(getChannels(false, []));
-
- // should have nothing but empty str
- const chatChannelList = getByTestId('chat-channels-list');
-
- expect(chatChannelList.textContent).toEqual('');
- });
- });
-});
diff --git a/app/javascript/chat/__tests__/chat.test.jsx b/app/javascript/chat/__tests__/chat.test.jsx
deleted file mode 100644
index 6a2ce6a47..000000000
--- a/app/javascript/chat/__tests__/chat.test.jsx
+++ /dev/null
@@ -1,244 +0,0 @@
-import { h } from 'preact';
-import { fireEvent, render } from '@testing-library/preact';
-import fetch from 'jest-fetch-mock';
-import { JSDOM } from 'jsdom';
-import { axe } from 'jest-axe';
-import { Chat } from '../chat';
-
-const doc = new JSDOM('');
-global.document = doc;
-global.window = doc.defaultView;
-
-// mock observer and user ID
-window.IntersectionObserver = jest.fn(function intersectionObserverMock() {
- this.observe = jest.fn();
-});
-global.window.currentUser = { id: 'some_id' };
-
-function getRootData() {
- return {
- chatChannels: JSON.stringify([
- {
- channel_name: 'channel name 1',
- last_opened_at: 'September 2, 2018',
- channel_users: [],
- last_message_at: 'September 21, 2018',
- channel_type: 'group',
- slug: '0',
- id: 12345,
- messages_count: 124,
- },
- {
- channel_name: 'group channel 2',
- last_opened_at: 'September 12, 2018',
- channel_users: [
- {
- profile_image: 'fake_profile_image',
- darker_color: '#111111',
- last_opened_at: 'some last open date',
- },
- {
- profile_image: 'fake_profile_pic',
- darker_color: '#222222',
- last_opened_at: 'some other last open date',
- },
- ],
- last_message_at: 'September 14, 2018',
- channel_type: 'direct',
- slug: '1',
- id: 34561,
- messages_count: 83,
- },
- {
- channel_name: 'group channel 3',
- last_opened_at: 'September 30, 2018',
- channel_users: [
- {
- profile_image: 'fake_profile_image',
- darker_color: '#111111',
- last_opened_at: 'some last open date',
- },
- {
- profile_image: 'fake_profile_pic',
- darker_color: '#222222',
- last_opened_at: 'some other last open date',
- },
- ],
- last_message_at: 'September 29, 2018',
- channel_type: 'group',
- slug: '2',
- id: 67890,
- messages_count: 56,
- },
- ]),
- chatOptions: JSON.stringify({
- showChannelsList: true,
- showTimestamp: true,
- activeChannelId: 34561,
- }),
- githubToken: 'somegithubtoken',
- pusherKey: 'somepusherkey',
- tagModerator: JSON.stringify({ isTagModerator: true }),
- };
-}
-
-function getMockResponse() {
- return JSON.stringify({
- result: [
- {
- id: 117921,
- status: 'active',
- viewable_by: 9597,
- chat_channel_id: 51923,
- last_opened_at: '2020-06-07T15:51:12.033Z',
- channel_text:
- 'Tag Moderators tag-moderators Nick Taylor (he/him) Ben Greenberg Jess Lee (she/her) Katie Nelson ☞ Desigan Chinniah ☜',
- channel_last_message_at: '2020-06-07T02:13:01.230Z',
- channel_status: 'active',
- channel_type: 'invite_only',
- channel_username: null,
- channel_name: 'Tag Moderators',
- channel_image:
- 'https://practicaldev-herokuapp-com.freetls.fastly.net/assets/organization-d83b2b577749cb1cb5c615003fc0d379f0bacc3be6cc1f541ac5655a9d770855.svg',
- channel_modified_slug: 'tag-moderators',
- channel_discoverable: false,
- channel_messages_count: 3287,
- last_indexed_at: '2020-06-07T15:51:11.100Z',
- },
- {
- id: 209670,
- status: 'active',
- viewable_by: 9597,
- chat_channel_id: 100437,
- last_opened_at: '2020-06-07T16:05:41.636Z',
- channel_text:
- '#react mods react-mods-5en7 Nick Taylor (he/him) Michael Tharrington (he/him) Chris Achard',
- channel_last_message_at: '2020-06-05T17:03:19.872Z',
- channel_status: 'active',
- channel_type: 'invite_only',
- channel_username: null,
- channel_name: '#react mods',
- channel_image:
- 'https://practicaldev-herokuapp-com.freetls.fastly.net/assets/organization-d83b2b577749cb1cb5c615003fc0d379f0bacc3be6cc1f541ac5655a9d770855.svg',
- channel_modified_slug: 'react-mods-5en7',
- channel_discoverable: false,
- channel_messages_count: 7,
- last_indexed_at: '2020-06-07T16:05:40.723Z',
- },
- {
- id: 204169,
- status: 'active',
- viewable_by: 9597,
- chat_channel_id: 101735,
- last_opened_at: '2017-01-01T05:00:00.000Z',
- channel_text:
- 'Direct carolskelly nickytonline carolskelly/nickytonline Nick Taylor (he/him) Carol Skelly',
- channel_last_message_at: '2020-03-28T00:57:52.210Z',
- channel_status: 'active',
- channel_type: 'direct',
- channel_username: 'carolskelly',
- channel_name: '@carolskelly',
- channel_image:
- 'https://res.cloudinary.com/practicaldev/image/fetch/s--lQ_RERs9--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/11343/jDcwvKh7.jpg',
- channel_modified_slug: '@carolskelly',
- channel_messages_count: 0,
- last_indexed_at: '2020-04-04T00:57:52.331Z',
- },
- ],
- });
-}
-
-describe(' ', () => {
- const csrfToken = 'this-is-a-csrf-token';
-
- beforeAll(() => {
- global.Pusher = jest.fn(() => ({
- subscribe: jest.fn(() => ({
- bind: jest.fn(),
- })),
- }));
- global.fetch = fetch;
- global.getCsrfToken = async () => csrfToken;
- });
-
- afterAll(() => {
- delete global.Pusher;
- delete global.fetch;
- delete global.getCsrfToken;
- });
-
- it('should have no a11y violations', async () => {
- fetch.mockResponse(getMockResponse());
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render expanded', () => {
- fetch.mockResponse(getMockResponse());
- const { getByTestId, getByText, getByRole } = render(
- ,
- );
- const chat = getByTestId('chat');
-
- expect(chat.getAttribute('aria-expanded')).toEqual('true');
-
- // chat filtering
- getByText('all', { selector: 'button' });
- getByText('direct', { selector: 'button' });
- getByText('group', { selector: 'button' });
-
- // renderActiveChatChannel
- const activeChat = getByTestId('active-chat');
-
- expect(activeChat).not.toBeNull();
-
- getByText('Scroll to Bottom', { selector: '[type="button"]' });
-
- // Delete modal should be visible
- getByRole('dialog', {
- selector: '[aria-hidden="false"]',
- });
- getByText('Are you sure, you want to delete this message?');
- getByText('Cancel', { selector: '[type="button"]' });
- getByText('Delete', { selector: '[type="button"]' });
- });
-
- it('should collapse and expand chat channels properly', async () => {
- fetch.mockResponse(getMockResponse());
- const { queryByText } = render( );
-
- // // chat channels
- expect(
- queryByText('all', {
- selector: 'button',
- }),
- ).toBeDefined();
- expect(
- queryByText('direct', {
- selector: 'button',
- }),
- ).toBeDefined();
- expect(
- queryByText('group', {
- selector: 'button',
- }),
- ).toBeDefined();
- });
-
- it('should show mention pop-up on keyUp @', async () => {
- const { getByLabelText, getByTestId } = render( );
-
- const inputField = getByLabelText('Compose a message');
-
- expect(inputField).toBeDefined();
- fireEvent.change(inputField, { target: { value: '@' } });
-
- const mentionModal = getByTestId('mentionList');
- const allButton = getByTestId('all');
-
- expect(mentionModal).toBeDefined();
- expect(allButton).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/chatChannelDescription.test.jsx b/app/javascript/chat/__tests__/chatChannelDescription.test.jsx
deleted file mode 100644
index fbef70877..000000000
--- a/app/javascript/chat/__tests__/chatChannelDescription.test.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChannelDescriptionSection } from '../ChatChannelSettings/ChannelDescriptionSection';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render(
- ,
- );
-
- expect(queryByText('some name')).toBeDefined();
- expect(queryByText('some description')).toBeDefined();
- expect(queryByText('You are a channel member')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/chatChannelMembersection.test.jsx b/app/javascript/chat/__tests__/chatChannelMembersection.test.jsx
deleted file mode 100644
index 74e2bba62..000000000
--- a/app/javascript/chat/__tests__/chatChannelMembersection.test.jsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChatChannelMembershipSection } from '../ChatChannelSettings/ChatChannelMembershipSection';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render when no memberships', () => {
- const { getByText, getByTestId } = render(
- ,
- );
-
- getByTestId('active-memberships');
- const activeMemberships = getByTestId('active-memberships');
-
- expect(Number(activeMemberships.dataset.activeCount)).toEqual(0);
-
- getByText('Members');
- });
-
- it('should render with memberships', () => {
- const { getByText, getByTestId } = render(
- ,
- );
-
- getByTestId('active-memberships');
- const activeMemberships = getByTestId('active-memberships');
-
- expect(Number(activeMemberships.dataset.activeCount)).toEqual(2);
-
- getByText('Members', {
- selector: '[data-testid="active-memberships"] *',
- });
-
- const pendingMemberships = getByTestId('pending-memberships');
-
- expect(Number(pendingMemberships.dataset.pendingCount)).toEqual(1);
-
- getByText('Pending Invitations', {
- selector: '[data-testid="pending-memberships"] *',
- });
-
- const requestedMemberships = getByTestId('requested-memberships');
-
- expect(Number(requestedMemberships.dataset.requestedCount)).toEqual(3);
-
- getByText('Joining Request', {
- selector: '[data-testid="requested-memberships"] *',
- });
- });
-});
diff --git a/app/javascript/chat/__tests__/chatChannelSettingActions.test.js b/app/javascript/chat/__tests__/chatChannelSettingActions.test.js
deleted file mode 100644
index 72eb6d4f2..000000000
--- a/app/javascript/chat/__tests__/chatChannelSettingActions.test.js
+++ /dev/null
@@ -1,226 +0,0 @@
-import fetch from 'jest-fetch-mock';
-import {
- getChannelDetails,
- updatePersonalChatChannelNotificationSettings,
- rejectChatChannelJoiningRequest,
- acceptChatChannelJoiningRequest,
- updateChatChannelDescription,
- sendChatChannelInvitation,
- leaveChatChannelMembership,
- updateMembershipRole,
-} from '../actions/chat_channel_setting_actions';
-
-/* global globalThis */
-
-describe('Chat channel API requests', () => {
- const csrfToken = 'this-is-a-csrf-token';
- const chanChannelMembershipId = 26; // Just a random chatChannelMembershipId ID.
- const channelId = 2;
-
- beforeAll(() => {
- globalThis.fetch = fetch;
- globalThis.getCsrfToken = async () => csrfToken;
- });
- afterAll(() => {
- delete globalThis.fetch;
- delete globalThis.getCsrfToken;
- });
-
- afterEach(() => {
- jest.restoreAllMocks();
- });
-
- describe('get chat channel info', () => {
- it('should have success response with channel details', async () => {
- const response = {
- success: true,
- current_membership: {
- user_id: 1,
- id: 2,
- chat_channel_id: 1,
- status: 'active',
- role: 'mod',
- },
- chat_channel: {
- name: 'dummy channel',
- description: 'some dummy description',
- discoverable: true,
- status: 'active',
- },
- memberships: {
- active_memberships: [],
- pending_memberships: [],
- requested_memberships: [],
- },
- };
-
- fetch.mockResponse(JSON.stringify(response));
-
- const chatChannelDetails = await getChannelDetails(
- chanChannelMembershipId,
- );
- expect(chatChannelDetails).toEqual(response);
- });
-
- it('not found channel', async () => {
- const response = {
- success: false,
- message: 'not found',
- };
-
- fetch.mockResponse(JSON.stringify(response));
-
- const chatChannelDetails = await getChannelDetails(
- chanChannelMembershipId,
- );
- expect(chatChannelDetails).toEqual(response);
- });
- });
-
- describe('Update chat channel notification', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'user settings updated' };
- fetch.mockResponse(JSON.stringify(response));
-
- const updateProfile = await updatePersonalChatChannelNotificationSettings(
- chanChannelMembershipId,
- true,
- );
- expect(updateProfile).toEqual(response);
- });
-
- it('should return not found error', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const updateProfile = await updatePersonalChatChannelNotificationSettings(
- '',
- true,
- );
- expect(updateProfile).toEqual(response);
- });
- });
-
- describe('reject chat channel membership', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'user removed' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await rejectChatChannelJoiningRequest(
- channelId,
- chanChannelMembershipId,
- 'pending',
- );
- expect(result).toEqual(response);
- });
-
- it('should return not found error', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await rejectChatChannelJoiningRequest('', '', 'pending');
- expect(result).toEqual(response);
- });
- });
-
- describe('Accept chat channel membership', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'added to chat channel' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await acceptChatChannelJoiningRequest(
- channelId,
- chanChannelMembershipId,
- );
- expect(result).toEqual(response);
- });
-
- it('should return not found error', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await acceptChatChannelJoiningRequest('', '');
- expect(result).toEqual(response);
- });
- });
-
- describe('update chat channel', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'channel is updated' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await updateChatChannelDescription(
- channelId,
- 'some description',
- true,
- );
- expect(result).toEqual(response);
- });
- });
-
- describe('Send inbvitation for join chat channel', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'added to chat channel' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await sendChatChannelInvitation(channelId, 'dummyuser');
- expect(result).toEqual(response);
- });
-
- it('should not send any invitation', async () => {
- const response = { success: true, message: 'no invitation sent' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await sendChatChannelInvitation(channelId, '');
- expect(result).toEqual(response);
- });
-
- it('should return not found error', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await sendChatChannelInvitation('', '');
- expect(result).toEqual(response);
- });
- });
-
- describe('Leave chat channel', () => {
- it('should have success', async () => {
- const response = { success: true, message: 'user left the channel' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await leaveChatChannelMembership(chanChannelMembershipId);
- expect(result).toEqual(response);
- });
-
- it('should return not found error', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await leaveChatChannelMembership('');
- expect(result).toEqual(response);
- });
- });
-
- describe('Update the membership role', () => {
- it('should have the success response', async () => {
- const response = { success: true, message: 'user membership is updated' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await updateMembershipRole(
- chanChannelMembershipId,
- channelId,
- 'mod',
- );
- expect(result).toEqual(response);
- });
-
- it('should return the not found', async () => {
- const response = { success: false, message: 'not found' };
- fetch.mockResponse(JSON.stringify(response));
-
- const result = await updateMembershipRole('', '', 'mod');
- expect(result).toEqual(response);
- });
- });
-});
diff --git a/app/javascript/chat/__tests__/chatChannelSettings.test.jsx b/app/javascript/chat/__tests__/chatChannelSettings.test.jsx
deleted file mode 100644
index a336b8392..000000000
--- a/app/javascript/chat/__tests__/chatChannelSettings.test.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ChatChannelSettings } from '../ChatChannelSettings/ChatChannelSettings';
-
-// TODO: These tests are imcomplete, but currently
-// this is simply a migration to preact-testing-library.
-// More tests should be added here.
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render if there are no channels', () => {
- const { container } = render(
- ,
- );
-
- expect(container.firstElementChild).toBeNull();
- });
-});
diff --git a/app/javascript/chat/__tests__/compose.test.jsx b/app/javascript/chat/__tests__/compose.test.jsx
deleted file mode 100644
index 4616af81f..000000000
--- a/app/javascript/chat/__tests__/compose.test.jsx
+++ /dev/null
@@ -1,234 +0,0 @@
-import { h } from 'preact';
-import { render, fireEvent, createEvent } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { Compose } from '../compose';
-
-let submitNoMessage = false;
-let submitWithMessage = false;
-let textfieldIsEmpty = true;
-
-const handleSubmitEmpty = () => {
- submitNoMessage = true;
- submitWithMessage = false;
- textfieldIsEmpty = true;
-};
-
-const handleSubmitFake = () => {
- submitNoMessage = false;
- submitWithMessage = true;
- textfieldIsEmpty = true;
-};
-
-const handleKeyDownFake = (e) => {
- const enterPressed = e.keyCode === 13;
- const shiftPressed = e.shiftKey;
- if (!enterPressed) {
- textfieldIsEmpty = false;
- } else if (textfieldIsEmpty && !shiftPressed) {
- handleSubmitEmpty();
- } else if (textfieldIsEmpty && shiftPressed) {
- textfieldIsEmpty = false;
- } else {
- handleSubmitFake();
- }
-};
-
-const getCompose = (tf, props = {}) => {
- // true -> not empty, false -> empty
- if (tf) {
- return (
-
- );
- }
- return (
-
- );
-};
-
-describe(' ', () => {
- afterEach(() => {
- submitNoMessage = false;
- submitWithMessage = false;
- textfieldIsEmpty = true;
- });
-
- it('should have no a11y violations', async () => {
- const { container } = render(getCompose(false));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- describe('behavior with no message', () => {
- it('should click submit', () => {
- const { getByText } = render(getCompose(false));
- const button = getByText(/Send/i);
-
- button.click();
- expect(submitNoMessage).toEqual(true);
- expect(submitWithMessage).toEqual(false);
- expect(textfieldIsEmpty).toEqual(true);
- });
-
- it('should press enter', () => {
- const { getByLabelText } = render(getCompose(false));
- const input = getByLabelText('Compose a message');
-
- fireEvent.keyDown(input, { keyCode: 13 });
-
- expect(submitNoMessage).toEqual(true);
- expect(submitWithMessage).toEqual(false);
- expect(textfieldIsEmpty).toEqual(true);
- });
-
- it('should pressed enter and shift', () => {
- const { getByLabelText } = render(getCompose(false));
- const input = getByLabelText('Compose a message');
-
- fireEvent.keyDown(input, { keyCode: 13 });
- fireEvent.keyDown(input, { keyCode: 16 });
-
- expect(textfieldIsEmpty).toEqual(false);
- });
- });
-
- describe('behavior with message', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getCompose(true));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have proper elements, attributes and values', () => {
- const { getByLabelText, getByText } = render(getCompose(true));
-
- const input = getByLabelText('Compose a message');
-
- expect(input.textContent).toEqual('');
- expect(input.getAttribute('maxLength')).toEqual('1000');
- expect(input.getAttribute('placeholder')).toContain('Write message to');
-
- // Ensure send button is pressent
- getByText(/send/i);
- });
-
- it('should click submit and check for empty textarea', () => {
- const { getByLabelText, getByText } = render(getCompose(true));
- const input = getByLabelText('Compose a message');
- const sendButton = getByText(/send/i);
-
- fireEvent.keyDown(input, { keyCode: 69 });
- expect(textfieldIsEmpty).toEqual(false);
-
- sendButton.click();
-
- expect(submitNoMessage).toEqual(false);
- expect(submitWithMessage).toEqual(true);
- expect(textfieldIsEmpty).toEqual(true);
- });
-
- it('should press enter and check for empty textarea', () => {
- const { getByLabelText } = render(getCompose(true));
- const input = getByLabelText('Compose a message');
-
- fireEvent.keyDown(input, { keyCode: 69 });
- fireEvent.keyDown(input, { keyCode: 13 });
-
- expect(submitNoMessage).toEqual(false);
- expect(submitWithMessage).toEqual(true);
- expect(textfieldIsEmpty).toEqual(true);
- });
- });
-
- // Check for the actual input value after pressing enter
- it('should press enter and check for empty input', () => {
- const compose = getCompose(true);
- const { getByTestId, rerender } = render(compose);
-
- const input = getByTestId('messageform');
-
- fireEvent(input, createEvent('input', input, { target: { value: 'T' } }));
-
- expect(input.value).toBe('T');
-
- fireEvent.keyDown(input, { keyCode: 13 });
-
- rerender(compose);
-
- expect(input.value).toBe('');
- });
-
- // Check for the actual input value after clicking send
- it('should click send and check for empty input', () => {
- const compose = getCompose(true);
- const { getByTestId, getByText, rerender } = render(compose);
-
- const input = getByTestId('messageform');
- const sendButton = getByText(/send/i);
-
- fireEvent(input, createEvent('input', input, { target: { value: 'T' } }));
-
- expect(input.value).toBe('T');
-
- sendButton.click();
-
- rerender(compose);
-
- expect(input.value).toBe('');
- });
-
- // Check for the actual input value after saving an edit
- it('should click send edit and check for empty input', () => {
- const compose = getCompose(true, {
- markdownEdited: false,
- startEditing: true,
- editMessageMarkdown: 'Test',
- handleSubmitOnClickEdit: () => null,
- });
- const { getByTestId, getByText, rerender } = render(compose);
-
- const input = getByTestId('messageform');
- const saveButton = getByText(/save/i);
-
- expect(input.value).toBe('Test');
-
- saveButton.click();
-
- rerender(compose);
-
- expect(input.value).toBe('');
- });
-
- // Check for the actual input value after canceling an edit
- it('should click close edit and check for empty input', () => {
- const compose = getCompose(true, {
- markdownEdited: false,
- startEditing: true,
- editMessageMarkdown: 'Test',
- handleEditMessageClose: () => null,
- });
- const { getByTestId, getByText, rerender } = render(compose);
-
- const input = getByTestId('messageform');
- const closeButton = getByText(/close/i);
-
- expect(input.value).toBe('Test');
-
- closeButton.click();
-
- rerender(compose);
-
- expect(input.value).toBe('');
- });
-});
diff --git a/app/javascript/chat/__tests__/content.test.jsx b/app/javascript/chat/__tests__/content.test.jsx
deleted file mode 100644
index 64cf12ccd..000000000
--- a/app/javascript/chat/__tests__/content.test.jsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { Content } from '../content';
-
-const getChannelRequestData = () => ({
- onTriggerContent: jest.fn(),
- type_of: 'channel-request',
- activeChannelId: 12345,
- pusherKey: 'ASDFGHJKL',
- githubToken: '',
- data: {
- channel: {
- name: 'bobby',
- },
- user: {
- username: 'spongebob',
- },
- },
-});
-
-const getLoadingUserData = () => ({
- onTriggerContent: jest.fn(),
- type_of: 'loading-user',
- activeChannelId: 1235,
- pusherKey: 'ASDFGHJKL',
- githubToken: '',
- data: {
- user: {
- username: 'spongebob',
- },
- },
-});
-
-describe(' ', () => {
- describe('as loading-user', () => {
- it('should have no a11y violations', async () => {
- const channelRequestResource = getChannelRequestData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const channelRequestResource = getChannelRequestData();
- const { queryByText, queryByTitle } = render(
- ,
- );
-
- // Ensure the two buttons render
- expect(queryByTitle('exit')).toBeDefined();
- expect(queryByTitle('fullscreen')).toBeDefined();
-
- // Simple check if the component to request joining a channel appears.
- // The component itself is tested it in it's own test suite.
- expect(
- queryByText(
- 'You are not a member of this group yet. Send a request to join.',
- ),
- ).toBeDefined();
- });
- });
-
- describe('as channel-request', () => {
- it('should have no a11y violations', async () => {
- const loadinUserResource = getLoadingUserData();
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const loadinUserResource = getLoadingUserData();
- const { queryByTitle } = render(
- ,
- );
-
- // Ensure the two buttons render
- expect(queryByTitle('exit')).toBeDefined();
- expect(queryByTitle('fullscreen')).toBeDefined();
- expect(queryByTitle('Loading user')).toBeDefined();
- });
- });
- /*
- testing only as loading user since components that Content uses
- are independently tested
- */
-});
diff --git a/app/javascript/chat/__tests__/draw.test.jsx b/app/javascript/chat/__tests__/draw.test.jsx
deleted file mode 100644
index b4187db95..000000000
--- a/app/javascript/chat/__tests__/draw.test.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { Draw } from '../draw';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render( );
-
- expect(queryByText('Connect Draw')).not.toBeNull();
- expect(queryByText('Clear')).not.toBeNull();
- expect(queryByText('Send')).not.toBeNull();
- });
-});
diff --git a/app/javascript/chat/__tests__/invitationLinkManager.test.jsx b/app/javascript/chat/__tests__/invitationLinkManager.test.jsx
deleted file mode 100644
index 53bc2ff5a..000000000
--- a/app/javascript/chat/__tests__/invitationLinkManager.test.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { InviationLinkManager } from '../ChatChannelSettings/MembershipManager/InvitationLinkManager';
-
-const currentModMembership = {
- name: 'dummy user',
- username: 'dummyuser',
- user_id: 1,
- chat_channel_id: 2,
- status: 'active',
- role: 'mod',
-};
-
-const currentMemberMembership = {
- name: 'dummy member',
- username: 'dummymember',
- user_id: 1,
- chat_channel_id: 2,
- status: 'active',
- role: 'member',
-};
-
-const svg = (
-
- Copy Invitation Url
-
-
-);
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render(
- ,
- );
-
- expect(queryByText('https://dummy-invitation.link')).toBeDefined();
- expect(queryByText('Invitation Link')).toBeDefined();
- });
-
- it('should not render', () => {
- const { rerender } = render(
- ,
- );
-
- expect(rerender()).toEqual(undefined);
- });
-});
diff --git a/app/javascript/chat/__tests__/inviteForm.test.jsx b/app/javascript/chat/__tests__/inviteForm.test.jsx
deleted file mode 100644
index bdb6b2f68..000000000
--- a/app/javascript/chat/__tests__/inviteForm.test.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { InviteForm } from '../ChatChannelSettings/InviteForm';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render with no usernames', () => {
- const { queryByLabelText, queryByText } = render(
- ,
- );
-
- expect(queryByLabelText('Usernames to invite')).toBeDefined();
- expect(queryByText('Submit')).toBeDefined();
- });
-
- it('should render with usernames to invite', () => {
- const { getByLabelText } = render(
- ,
- );
-
- const input = getByLabelText('Usernames to invite');
-
- expect(input.value).toEqual('@bobbytables, @xss, @owasp');
- });
-});
diff --git a/app/javascript/chat/__tests__/leaveMembershipSection.test.jsx b/app/javascript/chat/__tests__/leaveMembershipSection.test.jsx
deleted file mode 100644
index a760874cc..000000000
--- a/app/javascript/chat/__tests__/leaveMembershipSection.test.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { LeaveMembershipSection } from '../ChatChannelSettings/LeaveMembershipSection';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render( );
-
- expect(queryByText('Danger Zone')).toBeDefined();
- expect(queryByText('Leave Channel')).toBeDefined();
- });
-
- it('should have user leave channel when leave button is clicked', () => {
- const leaveHandler = jest.fn();
- const { getByText } = render(
- ,
- );
- const leaveButton = getByText('Leave Channel');
-
- leaveButton.click();
-
- expect(leaveHandler).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/app/javascript/chat/__tests__/message.test.jsx b/app/javascript/chat/__tests__/message.test.jsx
deleted file mode 100644
index 6fdedad9f..000000000
--- a/app/javascript/chat/__tests__/message.test.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import '@testing-library/jest-dom';
-import { axe } from 'jest-axe';
-import { Message } from '../message';
-
-const msg = {
- username: 'asdf',
- used_id: 12345,
- message: 'WE BUILT THIS CITY',
- color: '#00FFFF',
-};
-
-const getMessage = (message, props) => (
-
-);
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getMessage(msg));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { getByText, getByAltText } = render(getMessage(msg));
-
- getByAltText('asdf profile');
- getByText(msg.message);
-
- const profileLink = getByText(msg.username);
-
- expect(profileLink.parentElement).toHaveStyle({ color: msg.color });
- });
-
- it('should highlight @mentions to the logged in user', () => {
- const testMessage = {
- username: 'testUser',
- user_id: 456,
- message: "hello @testUser
",
- };
-
- const { getByText } = render(
- getMessage(testMessage, { currentUserId: testMessage.user_id }),
- );
-
- const profileLink = getByText(`@${testMessage.username}`);
-
- expect(profileLink.parentElement.innerHTML).toMatch(
- new RegExp(`@${testMessage.username} `, 'i'),
- );
- });
-});
diff --git a/app/javascript/chat/__tests__/modFaqSection.test.jsx b/app/javascript/chat/__tests__/modFaqSection.test.jsx
deleted file mode 100644
index 00e7ebc24..000000000
--- a/app/javascript/chat/__tests__/modFaqSection.test.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ModFaqSection } from '../ChatChannelSettings/ModFaqSection';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render', () => {
- const { queryByText } = render( );
-
- expect(
- queryByText(/^Questions about Connect Channel moderation\? Contact/),
- ).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/modSection.test.jsx b/app/javascript/chat/__tests__/modSection.test.jsx
deleted file mode 100644
index 219e082bc..000000000
--- a/app/javascript/chat/__tests__/modSection.test.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ModSection } from '../ChatChannelSettings/ModSection';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render( );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render if the membership role is a moderator', () => {
- const { queryByTestId } = render(
- ,
- );
-
- // the and have their own tests.
- expect(queryByTestId('invite-form')).toBeDefined();
- expect(queryByTestId('settings-form')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/pendingMembershipsSection.test.jsx b/app/javascript/chat/__tests__/pendingMembershipsSection.test.jsx
deleted file mode 100644
index 6f553b91e..000000000
--- a/app/javascript/chat/__tests__/pendingMembershipsSection.test.jsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { PendingMembershipSection } from '../ChatChannelSettings/PendingMembershipSection';
-
-function getEmptyMembershipData() {
- return {
- activeMemberships: [],
- currentMembershipRole: 'mod',
- };
-}
-
-function getMembershipData() {
- return {
- pendingMemberships: [
- {
- name: 'test user',
- username: 'testusername',
- user_id: '1',
- membership_id: '2',
- role: 'mod',
- status: 'active',
- image: '',
- },
- ],
- membershipType: 'active',
- currentMembershipRole: 'mod',
- };
-}
-
-describe(' ', () => {
- it('should have no a11y violations when there are no members', async () => {
- const {
- pendingMemberships,
- currentMembershipRole,
- } = getEmptyMembershipData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have no a11y violations when there are members', async () => {
- const { pendingMemberships, currentMembershipRole } = getMembershipData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should not render the membership list', () => {
- const {
- pendingMemberships,
- currentMembershipRole,
- } = getEmptyMembershipData();
- const { getByTestId } = render(
- ,
- );
-
- // no users to be found
- const pendingMembershipsWrapper = getByTestId('pending-memberships');
-
- expect(Number(pendingMembershipsWrapper.dataset.pendingCount)).toEqual(0);
- });
-
- it('should render the membership list', () => {
- const { pendingMemberships, currentMembershipRole } = getMembershipData();
- const { getByTestId } = render(
- ,
- );
-
- // no users to be found
- const pendingMembershipsWrapper = getByTestId('pending-memberships');
-
- expect(
- Number(pendingMembershipsWrapper.dataset.pendingCount),
- ).toBeGreaterThanOrEqual(1);
- });
-});
diff --git a/app/javascript/chat/__tests__/personalSetting.test.jsx b/app/javascript/chat/__tests__/personalSetting.test.jsx
deleted file mode 100644
index b7ce3b196..000000000
--- a/app/javascript/chat/__tests__/personalSetting.test.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { PersonalSettng } from '../ChatChannelSettings/PersonalSetting';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { queryByText, queryByLabelText } = render(
- ,
- );
-
- // get the section header
- expect(queryByText('Personal Settings')).toBeDefined();
-
- // get the subsection header
- expect(queryByText('Notifications')).toBeDefined();
-
- // form fields
- expect(
- queryByLabelText('Receive Notifications for New Messages'),
- ).toBeDefined();
- expect(queryByText('Submit', { selector: 'button' })).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/reportAbuse.test.jsx b/app/javascript/chat/__tests__/reportAbuse.test.jsx
deleted file mode 100644
index cd5063a53..000000000
--- a/app/javascript/chat/__tests__/reportAbuse.test.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ReportAbuse } from '../ReportAbuse';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the component', () => {
- const { getByText, getByLabelText } = render(
- ,
- );
-
- expect(getByText('Report Abuse')).toBeDefined();
-
- const vulgarInput = getByLabelText('Rude or vulgar');
- expect(vulgarInput.value).toEqual('rude or vulgar');
-
- const harassmentInput = getByLabelText('Harassment or hate speech');
- expect(harassmentInput.value).toEqual('harassment');
-
- const listingsInput = getByLabelText(
- 'Inappropriate listings message/category',
- );
- expect(listingsInput.value).toEqual('listings');
-
- const spamInput = getByLabelText('Spam or copyright issue');
- expect(spamInput.value).toEqual('spam');
-
- expect(getByText('Report Message')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/requestManager.test.jsx b/app/javascript/chat/__tests__/requestManager.test.jsx
deleted file mode 100644
index 1690481d5..000000000
--- a/app/javascript/chat/__tests__/requestManager.test.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import fetch from 'jest-fetch-mock';
-import { axe } from 'jest-axe';
-import { beforeEach } from '@jest/globals';
-import { RequestManager } from '../RequestManager/RequestManager';
-import '@testing-library/jest-dom';
-
-function getData() {
- const data = [
- {
- resource: {},
- },
- ];
-
- return data;
-}
-
-// TODO: There needs to be some better tests in here in regards to different data: empty, some data etc.
-describe(' ', () => {
- beforeEach(() => {
- const csrfToken = 'this-is-a-csrf-token';
-
- window.fetch = fetch;
- window.getCsrfToken = async () => csrfToken;
-
- fetch.mockResponse(
- JSON.stringify({
- result: { user_joining_requests: [], channel_joining_memberships: [] },
- }),
- );
- });
-
- it('should have no a11y violations', async () => {
- const { container } = render(
- ,
- );
-
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have the proper elements', () => {
- const { getByText } = render(
- ,
- );
-
- expect(getByText('You have no pending invitations.')).toBeInTheDocument();
- });
-});
diff --git a/app/javascript/chat/__tests__/requestedMembershipSection.test.jsx b/app/javascript/chat/__tests__/requestedMembershipSection.test.jsx
deleted file mode 100644
index d9ef9b2b3..000000000
--- a/app/javascript/chat/__tests__/requestedMembershipSection.test.jsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { RequestedMembershipSection } from '../ChatChannelSettings/RequestedMembershipSection';
-
-function getEmptyMembershipRequestsData() {
- return {
- requestedMemberships: [],
- currentMembershipRole: 'mod',
- };
-}
-
-function getMembershipData() {
- return {
- requestedMemberships: [
- {
- name: 'test user',
- username: 'testusername',
- user_id: '1',
- membership_id: '2',
- role: 'member',
- status: 'requested',
- image: '',
- },
- ],
- membershipType: 'requested',
- currentMembershipRole: 'mod',
- };
-}
-
-describe(' ', () => {
- it('should have no a11y violations when there are no requested memberships', async () => {
- const {
- requestedMemberships,
- currentMembershipRole,
- } = getEmptyMembershipRequestsData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should have no a11y violations when there are requested memberships', async () => {
- const { requestedMemberships, currentMembershipRole } = getMembershipData();
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should not render the membership list', () => {
- const {
- requestedMemberships,
- currentMembershipRole,
- } = getEmptyMembershipRequestsData();
- const { getByText, queryByText } = render(
- ,
- );
-
- getByText('Joining Request');
-
- expect(
- queryByText('+', { selector: 'button[data-membership-id]' }),
- ).toBeNull();
- });
-
- it('should render the membership list', () => {
- const { requestedMemberships, currentMembershipRole } = getMembershipData();
- const { queryByText } = render(
- ,
- );
-
- expect(queryByText('Joining Request')).toBeDefined();
- expect(
- queryByText('+', { selector: 'button[data-membership-id]' }),
- ).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/settingsForm.test.jsx b/app/javascript/chat/__tests__/settingsForm.test.jsx
deleted file mode 100644
index 40d121eca..000000000
--- a/app/javascript/chat/__tests__/settingsForm.test.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { SettingsForm } from '../ChatChannelSettings/SettingsForm';
-
-const data = {
- channelDescription: 'some description test',
- channelDiscoverable: true,
-};
-
-const getSettingsForm = (channelDetails) => {
- return (
-
- );
-};
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(getSettingsForm(data));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render the the component', () => {
- const { queryByText, queryByLabelText } = render(getSettingsForm(data));
-
- // title
- expect(queryByText('Channel Settings')).toBeDefined();
-
- // description of channel
- expect(queryByLabelText('Description')).toBeDefined();
-
- // whether or not the channel is discoverable
- expect(queryByLabelText('Channel Discoverable')).toBeDefined();
-
- // submit buttton
- expect(queryByText('Submit')).toBeDefined();
- });
-});
diff --git a/app/javascript/chat/__tests__/util.test.js b/app/javascript/chat/__tests__/util.test.js
deleted file mode 100644
index d3cb76a28..000000000
--- a/app/javascript/chat/__tests__/util.test.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { getUserDataAndCsrfToken } from '../util';
-
-const ERROR_MESSAGE = "Couldn't find user data on page.";
-
-describe('Chat utilities', () => {
- describe('getUserDataAndCsrfToken', () => {
- afterEach(() => {
- document.head.innerHTML = '';
- document.body.removeAttribute('data-user');
- });
-
- test('should reject if no user or csrf token found.', async () => {
- await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
- ERROR_MESSAGE,
- );
- });
-
- test('should reject if csrf token found but no user.', async () => {
- document.head.innerHTML =
- ' ';
- await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
- ERROR_MESSAGE,
- );
- });
-
- test('should reject if user found but no csrf token found.', async () => {
- document.body.setAttribute('data-user', '{}');
- await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
- ERROR_MESSAGE,
- );
- });
-
- test('should resolve if user and csrf token found.', async () => {
- const csrfToken = 'some-csrf-token';
- const currentUser = {
- id: 41,
- name: 'Guy Fieri',
- username: 'guyfieri',
- profile_image_90:
- '/uploads/user/profile_image/41/0841dbe2-208c-4daa-b498-b2f01f3d37b2.png',
- followed_tag_names: [],
- followed_tags: '[]',
- reading_list_ids: [48, 49, 34, 51, 64, 56],
- saw_onboarding: true,
- checked_code_of_conduct: false,
- display_sponsors: true,
- trusted: false,
- };
- document.head.innerHTML = ` `;
- document.body.setAttribute('data-user', JSON.stringify(currentUser));
-
- expect(await getUserDataAndCsrfToken(document)).toEqual({
- currentUser,
- csrfToken,
- });
- });
- });
-});
diff --git a/app/javascript/chat/actionMessage.jsx b/app/javascript/chat/actionMessage.jsx
deleted file mode 100644
index c81139a19..000000000
--- a/app/javascript/chat/actionMessage.jsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { adjustTimestamp } from './util';
-
-export const ActionMessage = ({
- user,
- message,
- color,
- timestamp,
- profileImageUrl,
- onContentTrigger,
-}) => {
- const spanStyle = { color };
-
- const messageArea = (
-
- );
-
- return (
-
-
-
-
-
-
-
- {user}
-
-
-
- {`${adjustTimestamp(timestamp)}`}
-
-
-
-
{messageArea}
-
-
- );
-};
-
-ActionMessage.propTypes = {
- user: PropTypes.string.isRequired,
- color: PropTypes.string.isRequired,
- message: PropTypes.string.isRequired,
- timestamp: PropTypes.string,
- profileImageUrl: PropTypes.string,
- onContentTrigger: PropTypes.func.isRequired,
-};
-
-ActionMessage.defaultProps = {
- profileImageUrl: '',
- timestamp: null,
-};
diff --git a/app/javascript/chat/actions/actions.js b/app/javascript/chat/actions/actions.js
deleted file mode 100644
index 5c31561af..000000000
--- a/app/javascript/chat/actions/actions.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import { createDataHash } from '../util';
-
-export function getAllMessages(channelId, messageOffset, successCb, failureCb) {
- fetch(`/chat_channels/${channelId}?message_offset=${messageOffset}`, {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function sendMessage(messageObject, successCb, failureCb) {
- fetch('/messages', {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'X-CSRF-Token': window.csrfToken,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- message: {
- message_markdown: messageObject.message,
- user_id: window.currentUser.id,
- chat_channel_id: messageObject.activeChannelId,
- mentioned_users_id: messageObject.mentionedUsersId,
- },
- }),
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function editMessage(editedMessage, successCb, failureCb) {
- fetch(`/messages/${editedMessage.id}`, {
- method: 'PATCH',
- headers: {
- Accept: 'application/json',
- 'X-CSRF-Token': window.csrfToken,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- message: {
- message_markdown: editedMessage.message,
- user_id: window.currentUser.id,
- chat_channel_id: editedMessage.activeChannelId,
- },
- }),
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function sendOpen(activeChannelId, successCb, failureCb) {
- fetch(`/chat_channels/${activeChannelId}/open`, {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'X-CSRF-Token': window.csrfToken,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({}),
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function conductModeration(
- activeChannelId,
- message,
- successCb,
- failureCb,
-) {
- fetch(`/chat_channels/${activeChannelId}/moderate`, {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'X-CSRF-Token': window.csrfToken,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- chat_channel: {
- command: message,
- },
- }),
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function getChannels(
- searchParams,
- additionalFilters,
- successCb,
- _failureCb,
-) {
- return createDataHash(additionalFilters, searchParams).then((response) => {
- if (
- searchParams.retrievalID === null ||
- response.result.filter(
- (e) => e.chat_channel_id === searchParams.retrievalID,
- ).length === 1
- ) {
- successCb(response.result, searchParams.query);
- } else {
- fetch(
- `/chat_channel_memberships/find_by_chat_channel_id?chat_channel_id=${searchParams.retrievalID}`,
- {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- credentials: 'same-origin',
- },
- )
- .then((individualResponse) => individualResponse.json())
- .then((json) => {
- response.result.unshift(json);
- successCb(response.result, searchParams.query);
- });
- }
- });
-}
-
-export function getUnopenedChannelIds(successCb) {
- fetch('/chat_channels?state=unopened_ids', {
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then((json) => {
- successCb(json.unopened_ids);
- });
-}
-
-export function getContent(url, successCb, failureCb) {
- fetch(url, {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function getJSONContents(url, successCb, failureCb) {
- fetch(url, {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-export function deleteMessage(messageId, successCb, failureCb) {
- fetch(`/messages/${messageId}`, {
- method: 'DELETE',
- headers: {
- Accept: 'application/json',
- 'X-CSRF-Token': window.csrfToken,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- message: {
- user_id: window.currentUser.id,
- },
- }),
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
diff --git a/app/javascript/chat/actions/chat_channel_setting_actions.js b/app/javascript/chat/actions/chat_channel_setting_actions.js
deleted file mode 100644
index a9fa05635..000000000
--- a/app/javascript/chat/actions/chat_channel_setting_actions.js
+++ /dev/null
@@ -1,186 +0,0 @@
-import { request } from '../../utilities/http';
-
-/**
- * This function will get all details of the chat channel accrding to the membership role.
- *
- * @param {number} chatChannelMembershipId Current User chat channel membership ID
- */
-export async function getChannelDetails(chatChannelMembershipId) {
- const response = await request(
- `/chat_channel_memberships/chat_channel_info/${chatChannelMembershipId}`,
- );
-
- return response.json();
-}
-
-/**
- * This function is used to update the notification settings.
- *
- * @param {number} membershipId Current user Chat Channel membership Id.
- * @param {boolean} notificationBadge Boolean value for the notification
- */
-export async function updatePersonalChatChannelNotificationSettings(
- membershipId,
- notificationBadge,
-) {
- const response = await request(
- `/chat_channel_memberships/update_membership/${membershipId}`,
- {
- method: 'PATCH',
- body: {
- chat_channel_membership: {
- show_global_badge_notification: notificationBadge,
- },
- },
- },
- );
-
- return response.json();
-}
-
-/**
- * This function is used to reject chat channel joining request & pending requests.
- *
- * @param { number } channelId Active Chat Channel ID
- * @param { number } membershipId Requested user membership Id
- * @param { string } membershipStatus Requested user membership status
- */
-export async function rejectChatChannelJoiningRequest(
- channelId,
- membershipId,
- membershipStatus,
-) {
- const response = await request(
- `/chat_channel_memberships/remove_membership`,
- {
- method: 'POST',
- body: {
- status: membershipStatus || 'pending',
- chat_channel_id: channelId,
- membership_id: membershipId,
- },
- },
- );
-
- return response.json();
-}
-
-/**
- *
- * @param {number} channelId Active chat channel Id
- * @param {number} membershipId Chat channel joining request membership id
- */
-export async function acceptChatChannelJoiningRequest(channelId, membershipId) {
- const response = await request(`/chat_channel_memberships/add_membership`, {
- method: 'POST',
- body: {
- chat_channel_id: channelId,
- membership_id: membershipId,
- chat_channel_membership: {
- user_action: 'accept',
- },
- },
- });
-
- return response.json();
-}
-
-export async function updateChatChannelDescription(
- channelId,
- description,
- discoverable,
-) {
- const response = await request(`/chat_channels/update_channel/${channelId}`, {
- method: 'PATCH',
- body: { chat_channel: { description, discoverable } },
- credentials: 'same-origin',
- });
-
- return response.json();
-}
-
-/**
- * Send Active chat channel invitation
- *
- * @param {numner} channelId Active chat channel
- * @param {string} invitationUsernames UserNames coma seprated
- */
-export async function sendChatChannelInvitation(
- channelId,
- invitationUsernames,
-) {
- const response = await request(
- `/chat_channel_memberships/create_membership_request`,
- {
- method: 'POST',
- body: {
- chat_channel_membership: {
- chat_channel_id: channelId,
- invitation_usernames: invitationUsernames,
- },
- },
- },
- );
-
- return response.json();
-}
-
-/**
- * This function is used to leave the chat channel.
- *
- * @param {number} membershipId Current User Chat channel membership id
- */
-export async function leaveChatChannelMembership(membershipId) {
- const response = await request(
- `/chat_channel_memberships/leave_membership/${membershipId}`,
- {
- method: 'PATCH',
- },
- );
-
- return response.json();
-}
-
-/**
- * This function is used to update the membership role
- * @param {number} membershipId selected User Chat channel membership id
- * @param {number} chatChannelId Current chat chaneel id
- * @param {string} role updated role for the membership
- */
-export async function updateMembershipRole(membershipId, chatChannelId, role) {
- const response = await request(
- `/chat_channel_memberships/update_membership_role/${chatChannelId}`,
- {
- method: 'PATCH',
- body: {
- chat_channel_membership: {
- chat_channel_id: chatChannelId,
- membership_id: membershipId,
- role,
- },
- },
- },
- );
-
- return response.json();
-}
-
-/**
- * Create Chat Channel
- * @param {string} channelName
- * @param {string} userNames
- */
-
-export async function createChannel(channelName, userNames) {
- const response = await request(`/create_channel`, {
- method: 'POST',
- body: {
- chat_channel: {
- channel_name: channelName,
- invitation_usernames: userNames,
- },
- },
- });
-
- return response.json();
-}
diff --git a/app/javascript/chat/actions/requestActions.js b/app/javascript/chat/actions/requestActions.js
deleted file mode 100644
index 72b652273..000000000
--- a/app/javascript/chat/actions/requestActions.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { request } from '../../utilities/http';
-
-/**
- *
- * @param {channelId} channelId
- * @param {membershipId} membershipId
- */
-export async function rejectJoiningRequest(channelId, membershipId) {
- const response = await request(
- `/chat_channel_memberships/remove_membership`,
- {
- method: 'POST',
- body: {
- status: 'pending',
- chat_channel_id: channelId,
- membership_id: membershipId,
- },
- credentials: 'same-origin',
- },
- );
-
- return response.json();
-}
-
-/**
- * This function is responsible for the Accept joining request for channel
- * @param {number} channelId
- * @param {number} membershipId
- */
-
-export async function acceptJoiningRequest(channelId, membershipId) {
- const response = await request(`/chat_channel_memberships/add_membership`, {
- method: 'POST',
- body: {
- chat_channel_id: channelId,
- membership_id: membershipId,
- chat_channel_membership: {
- user_action: 'accept',
- },
- },
- credentials: 'same-origin',
- });
-
- return response.json();
-}
-
-export function sendChannelRequest(id, successCb, failureCb) {
- request(`/join_chat_channel`, {
- method: 'POST',
- body: {
- chat_channel_membership: {
- chat_channel_id: id,
- },
- },
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb)
- .catch(failureCb);
-}
-
-/**
- * This function will get all the request realted to user and channel
- */
-
-export async function getChannelRequestInfo() {
- const response = await request(`/channel_request_info/`, {
- method: 'GET',
- credentials: 'same-origin',
- });
-
- return response.json();
-}
-
-/**
- * This function handle user action on chat channel invitations
- *
- * @param {number} membershipId
- * @param {string} userAction
- */
-
-export async function updateMembership(membershipId, userAction) {
- const response = await request(`/chat_channel_memberships/${membershipId}`, {
- method: 'PUT',
- credentials: 'same-origin',
- body: {
- chat_channel_membership: {
- user_action: userAction,
- },
- },
- });
-
- return response.json();
-}
-
-/**
- *
- * @param {string} feedback_message
- * @param {string} type_of_feedback
- * @param {string} category
- * @param {string} reported_url
- */
-export async function reportAbuse(
- feedback_message,
- feedback_type,
- category,
- offender_id,
-) {
- const response = await request('/feedback_messages', {
- method: 'POST',
- body: {
- feedback_message: {
- message: feedback_message,
- feedback_type,
- category,
- offender_id,
- },
- },
- });
-
- return response.json();
-}
-
-/**
- * Blocks a user with the given ID from using Connect
- *
- * @param {number} userId
- *
- *
- */
-
-export async function blockUser(userId) {
- const response = await request('/user_blocks', {
- method: 'POST',
- body: {
- user_block: {
- blocked_id: userId,
- },
- },
- });
-
- return response.json();
-}
diff --git a/app/javascript/chat/alert.jsx b/app/javascript/chat/alert.jsx
deleted file mode 100644
index eed1d5988..000000000
--- a/app/javascript/chat/alert.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const Alert = ({ showAlert }) => {
- const otherClassname = showAlert ? '' : 'chatalert__default--hidden';
-
- return (
-
- More new messages below
-
- );
-};
-
-Alert.propTypes = {
- showAlert: PropTypes.bool.isRequired,
-};
diff --git a/app/javascript/chat/article.jsx b/app/javascript/chat/article.jsx
deleted file mode 100644
index c389074f8..000000000
--- a/app/javascript/chat/article.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const Article = ({ resource: article }) => (
-
-
-
-);
-
-Article.propTypes = {
- resource: PropTypes.shape({
- id: PropTypes.string,
- }).isRequired,
-};
diff --git a/app/javascript/chat/channelRequest.jsx b/app/javascript/chat/channelRequest.jsx
deleted file mode 100644
index 42b8c5ed4..000000000
--- a/app/javascript/chat/channelRequest.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-export const ChannelRequest = ({ resource: data, handleJoiningRequest }) => (
-
-
-
Hey {data.user.name} !
- You are not a member of this group yet. Send a request to join.
-
-
-
-
-
-
-
-
- {data.channel.status !== 'joining_request' ? (
-
- {' '}
- Join {data.channel.name}{' '}
-
- ) : (
- Requested Already
- )}
-
-
-);
-
-ChannelRequest.propTypes = {
- resource: PropTypes.shape({
- data: PropTypes.object,
- }).isRequired,
- handleJoiningRequest: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/channels.jsx b/app/javascript/chat/channels.jsx
deleted file mode 100644
index f85bb31d2..000000000
--- a/app/javascript/chat/channels.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { ChannelButton } from './components/ChannelButton';
-import { ConfigMenu } from './configMenu';
-import { channelSorter } from './util';
-
-export const Channels = ({
- activeChannelId,
- chatChannels,
- unopenedChannelIds,
- handleSwitchChannel,
- expanded,
- filterQuery = '',
- channelsLoaded,
- currentUserId,
- triggerActiveContent,
-}) => {
- const sortedChatChannels = channelSorter(
- chatChannels,
- currentUserId,
- filterQuery,
- );
- const discoverableChannels = sortedChatChannels.discoverableChannels.map(
- (channel) => {
- return (
-
- );
- },
- );
- const channels = sortedChatChannels.activeChannels.map((channel) => {
- const isActive = parseInt(activeChannelId, 10) === channel.chat_channel_id;
- const isUnopened =
- !isActive && unopenedChannelIds.includes(channel.chat_channel_id);
- const newMessagesIndicator = isUnopened ? 'new' : 'old';
- const otherClassname = isActive
- ? 'chatchanneltab--active'
- : 'chatchanneltab--inactive';
-
- return (
-
- );
- });
- let topNotice = '';
- if (
- expanded &&
- filterQuery.length === 0 &&
- channelsLoaded &&
- (channels.length === 0 || channels[0].messages_count === 0)
- ) {
- topNotice = (
-
-
- 👋
- {' '}
- Welcome to
- Connect ! You may message anyone you mutually follow.
-
- );
- }
-
- let channelsListFooter = '';
- if (channels.length === 30) {
- channelsListFooter = (
- ...
- );
- }
- return (
-
-
- {topNotice}
- {channels}
- {discoverableChannels.length > 0 && filterQuery.length > 0 ? (
-
-
- Global Channel Search
-
- {discoverableChannels}
-
- ) : (
- ''
- )}
- {channelsListFooter}
-
-
-
-
- );
-};
-
-Channels.propTypes = {
- activeChannelId: PropTypes.number.isRequired,
- chatChannels: PropTypes.arrayOf(PropTypes.objectOf()).isRequired,
- unopenedChannelIds: PropTypes.arrayOf().isRequired,
- handleSwitchChannel: PropTypes.func.isRequired,
- triggerActiveContent: PropTypes.func.isRequired,
- expanded: PropTypes.bool.isRequired,
- filterQuery: PropTypes.string.isRequired,
- channelsLoaded: PropTypes.bool.isRequired,
- currentUserId: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/chat.jsx b/app/javascript/chat/chat.jsx
deleted file mode 100644
index 4c01958d8..000000000
--- a/app/javascript/chat/chat.jsx
+++ /dev/null
@@ -1,1981 +0,0 @@
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-import { setupPusher } from '../utilities/connect';
-import { notifyUser } from '../utilities/connect/newMessageNotify';
-import { debounceAction } from '../utilities/debounceAction';
-import { addSnackbarItem } from '../Snackbar';
-import { processImageUpload } from '../article-form/actions';
-import {
- conductModeration,
- getAllMessages,
- sendMessage,
- sendOpen,
- getChannels,
- getUnopenedChannelIds,
- getContent,
- deleteMessage,
- editMessage,
-} from './actions/actions';
-import { CreateChatModal } from './components/CreateChatModal';
-import { ChannelFilterButton } from './components/ChannelFilterButton';
-import {
- sendChannelRequest,
- rejectJoiningRequest,
- acceptJoiningRequest,
- getChannelRequestInfo,
-} from './actions/requestActions';
-import {
- hideMessages,
- scrollToBottom,
- setupObserver,
- getCurrentUser,
-} from './util';
-import { Alert } from './alert';
-import { Channels } from './channels';
-import { Compose } from './compose';
-import { Message } from './message';
-import { ActionMessage } from './actionMessage';
-import { Content } from './content';
-import { DragAndDropZone } from '@utilities/dragAndDrop';
-import { dragAndUpload } from '@utilities/dragAndUpload';
-import { Button } from '@crayons';
-
-const NARROW_WIDTH_LIMIT = 767;
-const WIDE_WIDTH_LIMIT = 1600;
-
-export class Chat extends Component {
- static propTypes = {
- pusherKey: PropTypes.number.isRequired,
- chatChannels: PropTypes.string.isRequired,
- chatOptions: PropTypes.string.isRequired,
- githubToken: PropTypes.string.isRequired,
- tagModerator: PropTypes.shape({ isTagModerator: PropTypes.bool.isRequired })
- .isRequired,
- };
-
- constructor(props) {
- super(props);
- const chatChannels = JSON.parse(props.chatChannels);
- const chatOptions = JSON.parse(props.chatOptions);
-
- this.debouncedChannelFilter = debounceAction(
- this.triggerChannelFilter.bind(this),
- );
-
- this.state = {
- appDomain: document.body.dataset.appDomain,
- messages: [],
- scrolled: false,
- showAlert: false,
- chatChannels,
- unopenedChannelIds: [],
- filterQuery: '',
- channelTypeFilter: 'all',
- channelsLoaded: false,
- channelPaginationNum: 0,
- fetchingPaginatedChannels: false,
- activeChannelId: chatOptions.activeChannelId,
- activeChannel: null,
- showChannelsList: chatOptions.showChannelsList,
- showTimestamp: chatOptions.showTimestamp,
- currentUserId: chatOptions.currentUserId,
- notificationsPermission: null,
- activeContent: {},
- fullscreenContent: null,
- expanded: window.innerWidth > NARROW_WIDTH_LIMIT,
- isMobileDevice: typeof window.orientation !== 'undefined',
- subscribedPusherChannels: [],
- messageOffset: 0,
- showDeleteModal: false,
- messageDeleteId: null,
- allMessagesLoaded: false,
- currentMessageLocation: 0,
- startEditing: false,
- activeEditMessage: {},
- markdownEdited: false,
- searchShowing: false,
- channelUsers: [],
- showMemberlist: false,
- memberFilterQuery: null,
- rerenderIfUnchangedCheck: null,
- userRequestCount: 0,
- openModal: false,
- isTagModerator: JSON.parse(props.tagModerator).isTagModerator,
- };
- if (chatOptions.activeChannelId) {
- getAllMessages(chatOptions.activeChannelId, 0, this.receiveAllMessages);
- }
- }
-
- componentDidMount() {
- const {
- chatChannels,
- activeChannelId,
- showChannelsList,
- channelTypeFilter,
- isMobileDevice,
- channelPaginationNum,
- currentUserId,
- appDomain,
- } = this.state;
-
- this.setupChannels(chatChannels);
-
- const channelsForPusherSub = chatChannels.filter(
- this.channelTypeFilterFn('open'),
- );
- this.subscribeChannelsToPusher(
- channelsForPusherSub,
- (channel) => `open-channel--${appDomain}-${channel.chat_channel_id}`,
- );
-
- setupObserver(this.observerCallback);
-
- this.subscribePusher(
- `private-message-notifications--${appDomain}-${currentUserId}`,
- );
-
- if (activeChannelId) {
- sendOpen(activeChannelId, this.handleChannelOpenSuccess, null);
- }
- if (showChannelsList) {
- const filters =
- channelTypeFilter === 'all'
- ? {}
- : { filters: `channel_type:${channelTypeFilter}` };
- const searchParams = {
- query: '',
- retrievalID: activeChannelId,
- searchType: '',
- paginationNumber: channelPaginationNum,
- };
- if (activeChannelId !== null) {
- searchParams.searchType = 'discoverable';
- }
- getChannels(searchParams, filters, this.loadChannels);
- getUnopenedChannelIds(this.markUnopenedChannelIds);
- }
- if (!isMobileDevice) {
- document.getElementById('messageform').focus();
- }
- if (document.getElementById('chatchannels__channelslist')) {
- document
- .getElementById('chatchannels__channelslist')
- .addEventListener('scroll', this.handleChannelScroll);
- }
-
- this.handleRequestCount();
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- if (
- this.state.rerenderIfUnchangedCheck !== nextState.rerenderIfUnchangedCheck
- ) {
- return false;
- }
- }
-
- componentDidUpdate() {
- const { scrolled, currentMessageLocation } = this.state;
- const messageList = document.getElementById('messagelist');
- if (messageList) {
- if (!scrolled) {
- scrollToBottom();
- }
- }
-
- if (currentMessageLocation && messageList.scrollTop === 0) {
- messageList.scrollTop =
- messageList.scrollHeight - (currentMessageLocation + 30);
- }
- }
-
- handleRequestCount = () => {
- getChannelRequestInfo().then((response) => {
- const { result } = response;
- const { user_joining_requests, channel_joining_memberships } = result;
- const totalRequest =
- user_joining_requests?.length + channel_joining_memberships?.length;
- this.setState({
- userRequestCount: totalRequest,
- });
- });
- };
-
- filterForActiveChannel = (channels, id, currentUserId) =>
- channels.filter(
- (channel) =>
- channel.chat_channel_id === parseInt(id, 10) &&
- channel.viewable_by === parseInt(currentUserId, 10),
- )[0];
-
- subscribePusher = (channelName) => {
- const { subscribedPusherChannels } = this.state;
- const { pusherKey } = this.props;
- if (!subscribedPusherChannels.includes(channelName)) {
- setupPusher(pusherKey, {
- channelId: channelName,
- messageCreated: this.receiveNewMessage,
- messageDeleted: this.removeMessage,
- messageEdited: this.updateMessage,
- channelCleared: this.clearChannel,
- redactUserMessages: this.redactUserMessages,
- channelError: this.channelError,
- mentioned: this.mentioned,
- messageOpened: this.messageOpened,
- });
- const subscriptions = subscribedPusherChannels;
- subscriptions.push(channelName);
- this.setState({ subscribedPusherChannels: subscriptions });
- }
- };
-
- mentioned = () => {};
-
- messageOpened = () => {};
-
- loadChannels = (channels, query) => {
- const { activeChannelId, appDomain } = this.state;
- const activeChannel =
- this.state.activeChannel ||
- channels.filter(
- (channel) => channel.chat_channel_id === activeChannelId,
- )[0];
- if (activeChannelId && query.length === 0) {
- this.setState({
- chatChannels: channels,
- scrolled: false,
- channelsLoaded: true,
- channelPaginationNum: 0,
- filterQuery: '',
- activeChannel:
- activeChannel ||
- this.filterForActiveChannel(channels, activeChannelId),
- });
- this.setupChannel(activeChannelId, activeChannel);
- } else if (activeChannelId) {
- this.setState({
- scrolled: false,
- chatChannels: channels,
- channelsLoaded: true,
- channelPaginationNum: 0,
- filterQuery: query,
- activeChannel:
- activeChannel ||
- this.filterForActiveChannel(channels, activeChannelId),
- });
- this.setupChannel(activeChannelId, activeChannel);
- } else if (channels.length > 0) {
- this.setState({
- chatChannels: channels,
- channelsLoaded: true,
- channelPaginationNum: 0,
- filterQuery: query || '',
- scrolled: false,
- });
-
- this.triggerSwitchChannel(
- channels[0].chat_channel_id,
- channels[0].channel_modified_slug,
- channels,
- );
- this.setupChannels(channels);
- } else {
- this.setState({ channelsLoaded: true });
- }
- this.subscribeChannelsToPusher(
- channels.filter(this.channelTypeFilterFn('open')),
- (channel) => `open-channel--${appDomain}-${channel.chat_channel_id}`,
- );
- this.subscribeChannelsToPusher(
- channels.filter(this.channelTypeFilterFn('invite_only')),
- (channel) => `private-channel--${appDomain}-${channel.chat_channel_id}`,
- );
- const chatChannelsList = document.getElementById(
- 'chatchannels__channelslist',
- );
-
- if (chatChannelsList) {
- chatChannelsList.scrollTop = 0;
- }
- };
-
- markUnopenedChannelIds = (ids) => {
- this.setState({ unopenedChannelIds: ids });
- };
-
- subscribeChannelsToPusher = (channels, channelNameFn) => {
- channels.forEach((channel) => {
- this.subscribePusher(channelNameFn(channel));
- });
- };
-
- channelTypeFilterFn = (type) => (channel) => {
- return channel.channel_type === type;
- };
-
- setupChannels = (channels) => {
- const { activeChannel } = this.state;
- channels.forEach((channel, index) => {
- if (index < 3) {
- this.setupChannel(channel.chat_channel_id, activeChannel);
- }
- });
- };
-
- loadPaginatedChannels = (channels) => {
- const { state } = this;
- const currentChannels = state.chatChannels;
- const currentChannelIds = currentChannels.map((channel) => channel.id);
- const newChannels = currentChannels;
- channels.forEach((channel) => {
- if (!currentChannelIds.includes(channel.id)) {
- newChannels.push(channel);
- }
- });
- if (
- currentChannels.length === newChannels.length &&
- state.channelPaginationNum > 3
- ) {
- return;
- }
- this.setState({
- chatChannels: newChannels,
- fetchingPaginatedChannels: false,
- channelPaginationNum: state.channelPaginationNum + 1,
- });
- };
-
- setupChannel = (channelId, activeChannel) => {
- const { messages, messageOffset, appDomain } = this.state;
- if (
- !messages[channelId] ||
- messages[channelId].length === 0 ||
- messages[channelId][0].reception_method === 'pushed'
- ) {
- getAllMessages(channelId, messageOffset, this.receiveAllMessages);
- }
- if (
- activeChannel &&
- activeChannel.channel_type !== 'direct' &&
- activeChannel.chat_channel_id === channelId
- ) {
- getContent(
- `/chat_channels/${channelId}/channel_info`,
- this.setOpenChannelUsers,
- null,
- );
- if (activeChannel.channel_type === 'open')
- this.subscribePusher(`open-channel--${appDomain}-${channelId}`);
- }
- this.subscribePusher(`private-channel--${appDomain}-${channelId}`);
- };
-
- setOpenChannelUsers = (res) => {
- const { activeChannelId, activeChannel } = this.state;
- Object.filter = (obj, predicate) =>
- Object.fromEntries(Object.entries(obj).filter(predicate));
- const leftUser = Object.filter(
- res.channel_users,
- ([username]) => username !== window.currentUser.username,
- );
- if (activeChannel && activeChannel.channel_type === 'open') {
- this.setState({
- channelUsers: {
- [activeChannelId]: leftUser,
- },
- });
- } else {
- this.setState({
- channelUsers: {
- [activeChannelId]: {
- all: { username: 'all', name: 'To notify everyone here' },
- ...leftUser,
- },
- },
- });
- }
- };
-
- observerCallback = (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting && this.state.scrolled === true) {
- this.setState({ scrolled: false, showAlert: false });
- } else if (this.state.scrolled === false) {
- this.setState({
- scrolled: true,
- rerenderIfUnchangedCheck: Math.random(),
- });
- }
- });
- };
-
- channelError = (_error) => {
- this.setState({
- subscribedPusherChannels: [],
- });
- };
-
- receiveAllMessages = (res) => {
- const { chatChannelId, messages } = res;
- this.setState((prevState) => ({
- messages: { ...prevState.messages, [chatChannelId]: messages },
- scrolled: false,
- }));
- };
-
- removeMessage = (message) => {
- const { activeChannelId } = this.state;
- this.setState((prevState) => ({
- messages: {
- [activeChannelId]: [
- ...prevState.messages[activeChannelId].filter(
- (oldmessage) => oldmessage.id !== message.id,
- ),
- ],
- },
- }));
- };
-
- updateMessage = (message) => {
- const { activeChannelId } = this.state;
- if (message.chat_channel_id === activeChannelId) {
- this.setState(({ messages }) => {
- const newMessages = messages;
- const foundIndex = messages[activeChannelId].findIndex(
- (oldMessage) => oldMessage.id === message.id,
- );
- newMessages[activeChannelId][foundIndex] = message;
- return { messages: newMessages };
- });
- }
- };
-
- receiveNewMessage = (message) => {
- const {
- messages,
- activeChannelId,
- chatChannels,
- currentUserId,
- unopenedChannelIds,
- } = this.state;
-
- const receivedChatChannelId = message.chat_channel_id;
- const messageList = document.getElementById('messagelist');
- let newMessages = [];
- const nearBottom =
- messageList.scrollTop + messageList.offsetHeight + 400 >
- messageList.scrollHeight;
-
- if (nearBottom) {
- scrollToBottom();
- }
-
- // If I'm not sender and tab is not active
- if (message.user_id !== currentUserId && document.hidden) {
- notifyUser();
- }
-
- if (
- message.temp_id &&
- messages[receivedChatChannelId] &&
- messages[receivedChatChannelId].findIndex(
- (oldmessage) => oldmessage.temp_id === message.temp_id,
- ) > -1
- ) {
- // Remove reduntant messages
- return;
- }
-
- if (messages[receivedChatChannelId]) {
- newMessages = messages[receivedChatChannelId].slice();
- newMessages.push(message);
- if (newMessages.length > 150) {
- newMessages.shift();
- }
- }
-
- // Show alert if message received and you have scrolled up
- const newShowAlert =
- activeChannelId === receivedChatChannelId
- ? { showAlert: !nearBottom }
- : {};
-
- let newMessageChannelIndex = 0;
- let newMessageChannel = null;
- const newChannelsObj = chatChannels.map((channel, index) => {
- if (receivedChatChannelId === channel.chat_channel_id) {
- newMessageChannelIndex = index;
- newMessageChannel = channel;
- return { ...channel, channel_last_message_at: new Date() };
- }
- return channel;
- });
-
- if (newMessageChannelIndex > 0) {
- newChannelsObj.splice(newMessageChannelIndex, 1);
- newChannelsObj.unshift(newMessageChannel);
- }
-
- // Mark messages read
- if (receivedChatChannelId === activeChannelId) {
- sendOpen(receivedChatChannelId, this.handleChannelOpenSuccess, null);
- } else {
- const newUnopenedChannels = unopenedChannelIds;
- if (!unopenedChannelIds.includes(receivedChatChannelId)) {
- newUnopenedChannels.push(receivedChatChannelId);
- }
- this.setState({
- unopenedChannelIds: newUnopenedChannels,
- });
- }
-
- // Updating the messages
- this.setState((prevState) => ({
- ...newShowAlert,
- chatChannels: newChannelsObj,
- messages: {
- ...prevState.messages,
- [receivedChatChannelId]: newMessages,
- },
- }));
- };
-
- redactUserMessages = (res) => {
- const { messages } = this.state;
- const newMessages = hideMessages(messages, res.userId);
- this.setState({ messages: newMessages });
- };
-
- clearChannel = (res) => {
- this.setState((prevState) => ({
- messages: { ...prevState.messages, [res.chat_channel_id]: [] },
- }));
- };
-
- handleChannelScroll = (e) => {
- const {
- fetchingPaginatedChannels,
- chatChannels,
- channelTypeFilter,
- filterQuery,
- activeChannelId,
- channelPaginationNum,
- } = this.state;
-
- if (fetchingPaginatedChannels || chatChannels.length < 30) {
- return;
- }
- const { target } = e;
- if (target.scrollTop + target.offsetHeight + 1800 > target.scrollHeight) {
- this.setState({ fetchingPaginatedChannels: true });
-
- const filters =
- channelTypeFilter === 'all'
- ? {}
- : { filters: `channel_type:${channelTypeFilter}` };
- const searchParams = {
- query: filterQuery,
- retrievalID: activeChannelId,
- searchType: '',
- paginationNumber: channelPaginationNum,
- };
- getChannels(searchParams, filters, this.loadPaginatedChannels);
- }
- };
-
- handleKeyDown = (e) => {
- const {
- showMemberlist,
- activeContent,
- activeChannelId,
- messages,
- currentUserId,
- } = this.state;
- const enterPressed = e.keyCode === 13;
- const leftPressed = e.keyCode === 37;
- const rightPressed = e.keyCode === 39;
- const escPressed = e.keyCode === 27;
- const targetValue = e.target.value;
- const messageIsEmpty = targetValue.length === 0;
- const shiftPressed = e.shiftKey;
- const upArrowPressed = e.keyCode === 38;
- const deletePressed = e.keyCode === 46;
-
- if (enterPressed) {
- if (showMemberlist) {
- e.preventDefault();
- const selectedUser = document.getElementsByClassName(
- 'active__message__list',
- )[0];
- this.addUserName({ target: selectedUser });
- } else if (messageIsEmpty) {
- e.preventDefault();
- } else if (!messageIsEmpty && !shiftPressed) {
- e.preventDefault();
- this.handleMessageSubmit(e.target.value);
- }
- }
- if (e.target.value.includes('@')) {
- if (e.keyCode === 40 || e.keyCode === 38) {
- e.preventDefault();
- }
- }
- if (
- leftPressed &&
- activeContent[activeChannelId] &&
- e.target.value === '' &&
- document.getElementById('activecontent-iframe')
- ) {
- e.preventDefault();
- try {
- e.target.value = document.getElementById(
- 'activecontent-iframe',
- ).contentWindow.location.href;
- } catch (err) {
- e.target.value = activeContent[activeChannelId].path;
- }
- }
- if (
- rightPressed &&
- !activeContent[activeChannelId] &&
- e.target.value === ''
- ) {
- e.preventDefault();
- const richLinks = document.getElementsByClassName(
- 'chatchannels__richlink',
- );
- if (richLinks.length === 0) {
- return;
- }
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: richLinks[richLinks.length - 1].href,
- type_of: 'article',
- });
- }
- if (escPressed && activeContent[activeChannelId]) {
- this.setActiveContentState(activeChannelId, null);
- this.setState({
- fullscreenContent: null,
- expanded: window.innerWidth > NARROW_WIDTH_LIMIT,
- });
- }
- if (messageIsEmpty) {
- const messagesByCurrentUser = messages[activeChannelId]?.filter(
- (message) => message.user_id === currentUserId,
- );
- const lastMessage =
- messagesByCurrentUser?.[messagesByCurrentUser.length - 1];
-
- if (lastMessage) {
- if (upArrowPressed) {
- this.triggerEditMessage(lastMessage.id);
- } else if (deletePressed) {
- this.triggerDeleteMessage(lastMessage.id);
- }
- }
- }
- };
-
- handleKeyDownEdit = (e) => {
- const enterPressed = e.keyCode === 13;
- const targetValue = e.target.value;
- const messageIsEmpty = targetValue.length === 0;
- const shiftPressed = e.shiftKey;
-
- if (enterPressed) {
- if (messageIsEmpty) {
- e.preventDefault();
- } else if (!messageIsEmpty && !shiftPressed) {
- e.preventDefault();
- this.handleMessageSubmitEdit(e.target.value);
- }
- }
- };
-
- handleMessageSubmitEdit = (message) => {
- const { activeChannelId, activeEditMessage } = this.state;
- const editedMessage = {
- activeChannelId,
- id: activeEditMessage.id,
- message,
- };
- editMessage(editedMessage, this.handleSuccess, this.handleFailure);
- this.handleEditMessageClose();
- };
-
- handleMessageSubmit = (message) => {
- const { activeChannelId } = this.state;
- scrollToBottom();
- // should check if user has the privilege
- if (message.startsWith('/code')) {
- this.setActiveContentState(activeChannelId, { type_of: 'code_editor' });
- } else if (message.startsWith('/play ')) {
- const messageObject = {
- activeChannelId,
- message,
- mentionedUsersId: this.getMentionedUsers(message),
- };
- sendMessage(messageObject, this.handleSuccess, this.handleFailure);
- } else if (message.startsWith('/new')) {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: '/new',
- type_of: 'article',
- });
- } else if (message.startsWith('/search')) {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: `/search?q=${message.replace('/search ', '')}`,
- type_of: 'article',
- });
- } else if (message.startsWith('/s ')) {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: `/search?q=${message.replace('/s ', '')}`,
- type_of: 'article',
- });
- } else if (message.startsWith('/ban ') || message.startsWith('/unban ')) {
- conductModeration(
- activeChannelId,
- message,
- this.handleSuccess,
- this.handleFailure,
- );
- } else if (message.startsWith('/draw')) {
- this.setActiveContent({
- sendCanvasImage: this.sendCanvasImage,
- type_of: 'draw',
- });
- } else if (message.startsWith('/')) {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: message,
- type_of: 'article',
- });
- } else if (message.startsWith('/github')) {
- const args = message.split('/github ')[1].trim();
- this.setActiveContentState(activeChannelId, { type_of: 'github', args });
- } else {
- const messageObject = {
- activeChannelId,
- message,
- mentionedUsersId: this.getMentionedUsers(message),
- };
- this.setState({ scrolled: false, showAlert: false });
- sendMessage(messageObject, this.handleSuccess, this.handleFailure);
- }
- };
- hideChannelList = () => {
- const chatContainer =
- document.getElementsByClassName('chat__activechat')[0];
- chatContainer.classList.remove('chat__activechat--hidden');
- };
- handleSwitchChannel = (e) => {
- e.preventDefault();
- let { target } = e;
- this.hideChannelList();
- if (!target.dataset.channelId) {
- target = target.parentElement;
- }
- this.triggerSwitchChannel(
- parseInt(target.dataset.channelId, 10),
- target.dataset.channelSlug,
- );
- };
-
- triggerSwitchChannel = (id, slug, channels) => {
- const {
- chatChannels,
- isMobileDevice,
- unopenedChannelIds,
- activeChannelId,
- currentUserId,
- } = this.state;
- const channelList = channels || chatChannels;
- const newUnopenedChannelIds = unopenedChannelIds;
- const index = newUnopenedChannelIds.indexOf(id);
- if (index > -1) {
- newUnopenedChannelIds.splice(index, 1);
- }
-
- const updatedActiveChannel = this.filterForActiveChannel(
- channelList,
- id,
- currentUserId,
- );
-
- this.setState({
- activeChannel: updatedActiveChannel,
- activeChannelId: parseInt(id, 10),
- scrolled: false,
- showAlert: false,
- allMessagesLoaded: false,
- showMemberlist: false,
- unopenedChannelIds: unopenedChannelIds.filter(
- (unopenedId) => unopenedId !== id,
- ),
- });
-
- this.setupChannel(id, updatedActiveChannel);
- const params = new URLSearchParams(window.location.search);
-
- if (params.get('ref') === 'group_invite') {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: '/chat_channel_memberships',
- type_of: 'article',
- });
- }
- window.history.replaceState(null, null, `/connect/${slug}`);
- if (!isMobileDevice) {
- document.getElementById('messageform').focus();
- }
- if (window.ga && ga.create) {
- ga('send', 'pageview', window.location.pathname + window.location.search);
- }
- sendOpen(id, this.handleChannelOpenSuccess, null);
- };
-
- handleSubmitOnClick = (e) => {
- e.preventDefault();
- const message = document.getElementById('messageform').value;
- if (message.length > 0) {
- this.handleMessageSubmit(message);
- }
- };
-
- handleSubmitOnClickEdit = (e) => {
- e.preventDefault();
- const message = document.getElementById('messageform').value;
- if (message.length > 0) {
- this.handleMessageSubmitEdit(message);
- }
- };
-
- triggerDeleteMessage = (messageId) => {
- this.setState({ messageDeleteId: messageId });
- this.setState({ showDeleteModal: true });
- };
-
- triggerEditMessage = (messageId) => {
- const { messages, activeChannelId } = this.state;
- this.setState({
- activeEditMessage: messages[activeChannelId].filter(
- (message) => message.id === messageId,
- )[0],
- });
- this.setState({ startEditing: true });
- };
-
- handleSuccess = (response) => {
- const { activeChannelId } = this.state;
- scrollToBottom();
- if (response.status === 'success') {
- if (response.message.temp_id) {
- this.setState(({ messages }) => {
- const newMessages = messages;
- const foundIndex = messages[activeChannelId].findIndex(
- (message) => message.temp_id === response.message.temp_id,
- );
- if (foundIndex > 0) {
- newMessages[activeChannelId][foundIndex].id = response.message.id;
- }
- return { messages: newMessages };
- });
- }
- } else if (response.status === 'moderation-success') {
- addSnackbarItem({ message: response.message, addCloseButton: true });
- } else if (response.status === 'error') {
- addSnackbarItem({ message: response.message, addCloseButton: true });
- }
- };
-
- handleRequestRejection = (e) => {
- rejectJoiningRequest(
- e.target.dataset.channelId,
- e.target.dataset.membershipId,
- this.handleJoiningManagerSuccess(e.target.dataset.membershipId),
- null,
- );
- };
-
- handleRequestApproval = (e) => {
- acceptJoiningRequest(
- e.target.dataset.channelId,
- e.target.dataset.membershipId,
- this.handleJoiningManagerSuccess(e.target.dataset.membershipId),
- null,
- );
- };
-
- handleUpdateRequestCount = (isAccepted = false, acceptedInfo) => {
- if (isAccepted) {
- const searchParams = {
- query: '',
- retrievalID: null,
- searchType: '',
- paginationNumber: 0,
- };
- getChannels(searchParams, 'all', this.loadChannels);
- this.triggerSwitchChannel(
- parseInt(acceptedInfo.channelId, 10),
- acceptedInfo.channelSlug,
- this.state.chatChannels,
- );
- }
-
- this.setState((prevState) => {
- return {
- userRequestCount: prevState.userRequestCount - 1,
- };
- });
- };
-
- triggerActiveContent = (e) => {
- if (
- // Trying to open in new tab
- e.ctrlKey ||
- e.shiftKey ||
- e.metaKey || // apple
- (e.button && e.button === 1) // middle click, >IE9 + everyone else
- ) {
- return false;
- }
- const { target } = e;
- const content =
- target.dataset.content || target.parentElement.dataset.content;
- if (content) {
- e.preventDefault();
- e.stopPropagation();
- this.hideChannelList();
-
- const { activeChannelId, activeChannel } = this.state;
-
- if (content.startsWith('chat_channels/')) {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-user',
- });
- getContent(`/${content}/channel_info`, this.setActiveContent, null);
- } else if (content === 'sidecar-channel-request') {
- this.setActiveContent({
- data: {
- user: getCurrentUser(),
- channel: {
- id: target.dataset.channelId,
- name: target.dataset.channelName,
- status: target.dataset.channelStatus,
- },
- },
- handleJoiningRequest: this.handleJoiningRequest,
- type_of: 'channel-request',
- });
- } else if (content === 'sidecar-joining-request-manager') {
- this.setActiveContent({
- data: {},
- type_of: 'channel-request-manager',
- updateRequestCount: this.handleUpdateRequestCount,
- });
- } else if (content === 'sidecar_all') {
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: `/chat_channel_memberships/${activeChannel.id}/edit`,
- type_of: 'article',
- });
- } else if (
- content.startsWith('sidecar') ||
- content.startsWith('article')
- ) {
- // article is legacy which can be removed shortly
- this.setActiveContentState(activeChannelId, {
- type_of: 'loading-post',
- });
- this.setActiveContent({
- path: target.href || target.parentElement.href,
- type_of: 'article',
- });
- } else if (target.dataset.content === 'exit') {
- this.setActiveContentState(activeChannelId, null);
- this.setState({
- fullscreenContent: null,
- expanded: window.innerWidth > NARROW_WIDTH_LIMIT,
- });
- } else if (target.dataset.content === 'fullscreen') {
- const mode =
- this.state.fullscreenContent === 'sidecar' ? null : 'sidecar';
- this.setState({
- fullscreenContent: mode,
- expanded: mode === null || window.innerWidth > WIDE_WIDTH_LIMIT,
- });
- } else if (target.dataset.content === 'chat_channel_setting') {
- this.setActiveContent({
- data: {},
- type_of: 'chat-channel-setting',
- activeMembershipId: activeChannel.id,
- handleLeavingChannel: this.handleLeavingChannel,
- });
- }
- }
- return false;
- };
-
- setActiveContentState = (channelId, state) => {
- this.setState((prevState) => ({
- activeContent: {
- ...prevState.activeContent,
- [channelId]: state,
- },
- }));
- };
-
- closeReportAbuseForm = () => {
- const { activeChannelId } = this.state;
- this.setActiveContentState(activeChannelId, null);
- this.setState({
- fullscreenContent: null,
- expanded: window.innerWidth > NARROW_WIDTH_LIMIT,
- });
- };
-
- setActiveContent = (response) => {
- const { activeChannelId } = this.state;
- this.setActiveContentState(activeChannelId, response);
- setTimeout(() => {
- document.getElementById('chat_activecontent').scrollTop = 0;
- document.getElementById('chat').scrollLeft = 1000;
- }, 3);
- setTimeout(() => {
- document.getElementById('chat_activecontent').scrollTop = 0;
- document.getElementById('chat').scrollLeft = 1000;
- }, 10);
- };
-
- handleChannelOpenSuccess = (response) => {
- this.setState(({ chatChannels }) => {
- const newChannelsObj = chatChannels.map((channel) => {
- if (parseInt(response.channel, 10) === channel.chat_channel_id) {
- return { ...channel, last_opened_at: new Date() };
- }
- return channel;
- });
- return { chatChannels: newChannelsObj };
- });
- };
-
- handleLeavingChannel = (leftChannelId) => {
- const { chatChannels } = this.state;
- this.triggerSwitchChannel(
- chatChannels[1].chat_channel_id,
- chatChannels[1].channel_modified_slug,
- chatChannels,
- );
- this.setState((prevState) => ({
- chatChannels: prevState.chatChannels.filter(
- (channel) => channel.id !== leftChannelId,
- ),
- }));
- this.setActiveContentState(chatChannels[1].chat_channel_id, null);
- };
-
- triggerChannelTypeFilter = (e) => {
- const { filterQuery } = this.state;
- const type = e.target.dataset.channelType;
- this.setState({
- channelTypeFilter: type,
- fetchingPaginatedChannels: false,
- });
- const filters = type === 'all' ? {} : { filters: `channel_type:${type}` };
- const searchParams = {
- query: filterQuery,
- retrievalID: null,
- searchType: '',
- paginationNumber: 0,
- };
- if (filterQuery && type !== 'direct') {
- searchParams.searchType = 'discoverable';
- getChannels(searchParams, filters, this.loadChannels);
- } else {
- getChannels(searchParams, filters, this.loadChannels);
- }
- };
-
- handleFailure = (err) => {
- // eslint-disable-next-line no-console
- console.error(err);
- addSnackbarItem({ message: err, addCloseButton: true });
- };
-
- renderMessages = () => {
- const {
- activeChannelId,
- messages,
- showTimestamp,
- activeChannel,
- currentUserId,
- } = this.state;
- if (!messages[activeChannelId]) {
- return '';
- }
- if (messages[activeChannelId].length === 0 && activeChannel) {
- if (activeChannel.channel_type === 'direct') {
- return (
-
- );
- }
- if (activeChannel.channel_type === 'open') {
- return (
-
-
- You have joined {activeChannel.channel_name}! All interactions{' '}
-
- must
- {' '}
- abide by the
code of conduct .
-
-
- );
- }
- }
- return messages[activeChannelId].map((message) =>
- message.action ? (
-
- ) : (
-
- ),
- );
- };
- triggerReportMessage = (messageId) => {
- const { activeChannelId, messages } = this.state;
-
- this.setActiveContent({
- data: messages[activeChannelId].find(
- (message) => message.id === messageId,
- ),
- type_of: 'message-report-abuse',
- });
- };
- triggerChannelFilter = (e) => {
- const { channelTypeFilter } = this.state;
- const filters =
- channelTypeFilter === 'all'
- ? {}
- : { filters: `channel_type:${channelTypeFilter}` };
- const searchParams = {
- query: e.target.value,
- retrievalID: null,
- searchType: '',
- paginationNumber: 0,
- };
- if (e.target.value) {
- searchParams.searchType = 'discoverable';
- getChannels(searchParams, filters, this.loadChannels);
- } else {
- getChannels(searchParams, filters, this.loadChannels);
- }
- };
-
- toggleExpand = () => {
- this.setState((prevState) => ({ expanded: !prevState.expanded }));
- };
-
- toggleSearchShowing = () => {
- if (!this.state.searchShowing) {
- setTimeout(() => {
- document.getElementById('chatchannelsearchbar').focus();
- }, 100);
- } else {
- const searchParams = {
- query: '',
- retrievalID: null,
- searchType: '',
- paginationNumber: 0,
- };
- getChannels(searchParams, 'all', this.loadChannels);
- this.setState({ filterQuery: '' });
- }
- this.setState({ searchShowing: !this.state.searchShowing });
- };
-
- renderChatChannels = () => {
- const { state } = this;
- if (state.showChannelsList) {
- const { notificationsPermission } = state;
- const notificationsButton = '';
- let notificationsState = '';
- const invitesButton = '';
- const joiningRequestButton = '';
- if (notificationsPermission === 'granted') {
- notificationsState = (
-
- Notifications On
-
- );
- } else if (notificationsPermission === 'denied') {
- notificationsState = (
-
- Notifications Off
-
- );
- }
-
- return (
-
- {notificationsButton}
-
- {invitesButton}
- {joiningRequestButton}
-
-
-
-
-
-
-
-
- {this.state.userRequestCount > 0 ? (
-
- {this.state.userRequestCount}
-
- ) : null}
-
- {this.state.isTagModerator ? (
-
-
-
-
-
- ) : null}
- {this.state.openModal ? (
-
- ) : (
- ''
- )}
-
-
- {notificationsState}
-
- );
- }
- return '';
- };
-
- toggleModalCreateChannel = () => {
- const { openModal } = this.state;
- this.setState({ openModal: !openModal });
- };
-
- navigateToChannelsList = () => {
- const chatContainer =
- document.getElementsByClassName('chat__activechat')[0];
-
- chatContainer.classList.add('chat__activechat--hidden');
- };
-
- handleCreateChannelSuccess = () => {
- this.toggleModalCreateChannel();
- const searchParams = {
- query: '',
- retrievalID: null,
- searchType: '',
- paginationNumber: 0,
- };
- getChannels(searchParams, {}, this.loadChannels);
- };
-
- handleMessageScroll = () => {
- const { allMessagesLoaded, messages, activeChannelId, messageOffset } =
- this.state;
-
- if (!messages[activeChannelId]) {
- return;
- }
-
- const jumpbackButton = document.getElementById('jumpback_button');
-
- if (this.scroller) {
- const scrolledRatio =
- (this.scroller.scrollTop + this.scroller.clientHeight) /
- this.scroller.scrollHeight;
-
- if (scrolledRatio < 0.5) {
- jumpbackButton.classList.remove('chatchanneljumpback__hide');
- } else if (scrolledRatio > 0.6) {
- jumpbackButton.classList.add('chatchanneljumpback__hide');
- }
-
- if (this.scroller.scrollTop === 0 && !allMessagesLoaded) {
- getAllMessages(
- activeChannelId,
- messageOffset + messages[activeChannelId].length,
- this.addMoreMessages,
- );
- const curretPosition = this.scroller.scrollHeight;
- this.setState({ currentMessageLocation: curretPosition });
- }
- }
- };
-
- addMoreMessages = (res) => {
- const { chatChannelId, messages } = res;
-
- if (messages.length > 0) {
- this.setState((prevState) => ({
- messages: {
- [chatChannelId]: [...messages, ...prevState.messages[chatChannelId]],
- },
- }));
- } else {
- this.setState({ allMessagesLoaded: true });
- }
- };
-
- jumpBacktoBottom = () => {
- scrollToBottom();
- document
- .getElementById('jumpback_button')
- .classList.remove('chatchanneljumpback__hide');
- };
-
- handleDragOver = (event) => {
- event.preventDefault();
- event.currentTarget.classList.add('opacity-25');
- };
-
- handleDragExit = (event) => {
- event.preventDefault();
- event.currentTarget.classList.remove('opacity-25');
- };
-
- handleImageDrop = (event) => {
- event.preventDefault();
- const { files } = event.dataTransfer;
- event.currentTarget.classList.remove('opacity-25');
- processImageUpload(files, this.handleImageSuccess, this.handleImageFailure);
- };
- sendCanvasImage = (files) => {
- dragAndUpload([files], this.handleImageSuccess, this.handleImageFailure);
- };
- handleImageSuccess = (res) => {
- const { links, image } = res;
- const mLink = `![${image[0].name}](${links[0]})`;
- const el = document.getElementById('messageform');
- const start = el.selectionStart;
- const end = el.selectionEnd;
- const text = el.value;
- let before = text.substring(0, start);
- before = text.substring(0, before.lastIndexOf('@') + 1);
- const after = text.substring(end, text.length);
- el.value = `${before + mLink} ${after}`;
- el.selectionStart = start + mLink.length + 1;
- el.selectionEnd = el.selectionStart;
- el.focus();
- };
- handleImageFailure = (e) => {
- addSnackbarItem({ message: e.message, addCloseButton: true });
- };
- handleDragHover(e) {
- e.preventDefault();
- const messageArea = document.getElementById('messagelist');
- messageArea.classList.add('opacity-25');
- }
- handleDragExit(e) {
- e.preventDefault();
- const messageArea = document.getElementById('messagelist');
- messageArea.classList.remove('opacity-25');
- }
- renderActiveChatChannel = (channelHeader) => {
- const { state } = this;
- const channelName = state.activeChannel
- ? state.activeChannel.channel_name
- : ' ';
- const connectAnnouncement = (
-
- );
- return (
-
-
- {connectAnnouncement}
- {channelHeader}
-
- {
- this.scroller = scroller;
- }}
- id="messagelist"
- >
- {this.renderMessages()}
-
-
-
-
- {
- if (e.keyCode === 13) this.jumpBacktoBottom();
- }}
- >
- Scroll to Bottom
-
-
- {this.renderDeleteModal()}
-
- {this.renderChannelMembersList()}
-
-
-
-
-
-
- );
- };
-
- handleFilePaste = (e) => {
- if (!e.clipboardData || !e.clipboardData.items) {
- return;
- }
- const items = [];
- for (let i = 0; i < e.clipboardData.items.length; i++) {
- const item = e.clipboardData.items[i];
- if (item.kind !== 'file') {
- continue;
- }
- items.push(item);
- }
- if (items && items.length > 0) {
- processImageUpload(
- [items[0].getAsFile()],
- this.handleImageSuccess,
- this.handleImageFailure,
- );
- }
- };
-
- handleMention = (e) => {
- const { activeChannel } = this.state;
- const mention = e.keyCode === 64;
- if (mention && activeChannel.channel_type !== 'direct') {
- const memberListElement = document.getElementById('mentionList');
- memberListElement.focus();
- this.setState({ showMemberlist: true });
- }
- };
-
- handleKeyUp = (e) => {
- const { startEditing, activeChannel, showMemberlist } = this.state;
- const enterPressed = e.keyCode === 13;
- if (enterPressed && showMemberlist)
- this.setState({ showMemberlist: false });
- if (activeChannel?.channel_type !== 'direct') {
- if (startEditing) {
- this.setState({ markdownEdited: true });
- }
- if (!e.target.value.includes('@') && showMemberlist) {
- this.setState({ showMemberlist: false });
- } else {
- this.setQuery(e.target);
- this.listHighlightManager(e.keyCode);
- }
- }
- };
-
- setQuery = (e) => {
- const { showMemberlist } = this.state;
- if (showMemberlist) {
- const before = e.value.substring(0, e.selectionStart);
- const query = before.substring(
- before.lastIndexOf('@') + 1,
- e.selectionStart,
- );
-
- if (query.includes(' ') || before.lastIndexOf('@') < 0)
- this.setState({ showMemberlist: false });
- else {
- this.setState({ showMemberlist: true });
- this.setState({ memberFilterQuery: query });
- }
- }
- };
-
- addUserName = (e) => {
- const name =
- e.target.dataset.content || e.target.parentElement.dataset.content;
- const el = document.getElementById('messageform');
- const start = el.selectionStart;
- const end = el.selectionEnd;
- const text = el.value;
- let before = text.substring(0, start);
- before = text.substring(0, before.lastIndexOf('@') + 1);
- const after = text.substring(end, text.length);
- el.value = `${before + name} ${after}`;
- el.selectionStart = start + name.length + 1;
- el.selectionEnd = start + name.length + 1;
- el.dispatchEvent(new Event('input'));
- el.focus();
- this.setState({ showMemberlist: false });
- };
-
- listHighlightManager = (keyCode) => {
- const mentionList = document.getElementById('mentionList');
- const activeElement = document.getElementsByClassName(
- 'active__message__list',
- )[0];
- if (mentionList.children.length > 0) {
- if (keyCode === 40 && activeElement) {
- if (activeElement.nextElementSibling) {
- activeElement.classList.remove('active__message__list');
- activeElement.nextElementSibling.classList.add(
- 'active__message__list',
- );
- }
- } else if (keyCode === 38 && activeElement) {
- if (activeElement.previousElementSibling) {
- activeElement.classList.remove('active__message__list');
- activeElement.previousElementSibling.classList.add(
- 'active__message__list',
- );
- }
- } else {
- mentionList.children[0].classList.add('active__message__list');
- }
- }
- };
-
- getMentionedUsers = (message) => {
- const { channelUsers, activeChannelId, activeChannel } = this.state;
- if (channelUsers[activeChannelId]) {
- if (message.includes('@all') && activeChannel.channel_type !== 'open') {
- return Array.from(
- Object.values(channelUsers[activeChannelId]).filter(
- (user) => user.id,
- ),
- (user) => user.id,
- );
- }
- return Array.from(
- Object.values(channelUsers[activeChannelId]).filter((user) =>
- message.includes(user.username),
- ),
- (user) => user.id,
- );
- }
- return null;
- };
-
- renderChannelMembersList = () => {
- const { showMemberlist, activeChannelId, channelUsers, memberFilterQuery } =
- this.state;
-
- const filterRegx = new RegExp(memberFilterQuery, 'gi');
-
- return (
-
- {showMemberlist
- ? Object.values(channelUsers[activeChannelId])
- .filter((user) => user.username.match(filterRegx))
- .map((user) => (
-
{
- if (e.keyCode === 13) this.addUserName();
- }}
- >
-
-
- {'@'}
- {user.username}
- {user.name}
-
-
- ))
- : ' '}
-
- );
- };
-
- handleEditMessageClose = () => {
- this.setState({
- startEditing: false,
- markdownEdited: false,
- activeEditMessage: { message: '', markdown: '' },
- });
- };
-
- renderDeleteModal = () => {
- const { showDeleteModal } = this.state;
- return (
-
-
-
-
Are you sure, you want to delete this message?
-
- {
- if (e.keyCode === 13) this.handleMessageDelete();
- }}
- >
- Delete
-
- {
- if (e.keyCode === 13) this.handleCloseDeleteModal();
- }}
- >
- Cancel
-
-
-
-
-
-
- );
- };
-
- handleCloseDeleteModal = () => {
- this.setState({ showDeleteModal: false, messageDeleteId: null });
- };
-
- handleMessageDelete = () => {
- const { messageDeleteId } = this.state;
- deleteMessage(messageDeleteId);
- this.setState({ showDeleteModal: false });
- };
-
- handleJoiningRequest = (e) => {
- sendChannelRequest(
- e.target.dataset.channelId,
- this.handleJoiningRequestSuccess,
- this.handleFailure,
- );
- };
-
- handleJoiningRequestSuccess = () => {
- const { activeChannelId } = this.state;
- this.setActiveContentState(activeChannelId, null);
- this.setState({ fullscreenContent: null });
- this.toggleSearchShowing();
- };
-
- renderChannelBackNav = () => {
- return (
- {
- if (e.keyCode === 13) this.navigateToChannelsList(e);
- }}
- tabIndex="0"
- >
-
-
-
-
- );
- };
-
- renderChannelHeaderInner = () => {
- const { activeChannel } = this.state;
- if (activeChannel.channel_type === 'direct') {
- return (
-
- {activeChannel.channel_modified_slug}
-
- );
- }
- return (
-
- {activeChannel.channel_name}
-
- );
- };
-
- renderChannelConfigImage = () => {
- const { activeContent, activeChannel, activeChannelId } = this.state;
- if (
- activeContent[activeChannelId] &&
- activeContent[activeChannelId].type_of
- ) {
- return '';
- }
-
- const dataContent =
- activeChannel.channel_type === 'direct'
- ? 'sidecar-user'
- : `chat_channel_setting`;
-
- const contentLink =
- activeChannel.channel_type === 'direct'
- ? `/${activeChannel.channel_username}`
- : '#/';
-
- return (
- {
- if (e.keyCode === 13) this.triggerActiveContent(e);
- }}
- tabIndex="0"
- href={contentLink}
- data-content={dataContent}
- >
-
-
-
-
- );
- };
-
- render() {
- const { state } = this;
- let channelHeader =
;
- if (state.activeChannel) {
- channelHeader = (
-
- {this.renderChannelBackNav()}
- {this.renderChannelHeaderInner()}
- {this.renderChannelConfigImage()}
-
- );
- }
- let fullscreenMode = '';
- if (state.fullscreenContent === 'sidecar') {
- fullscreenMode = 'chat--content-visible-full';
- } else if (state.fullscreenContent === 'video') {
- fullscreenMode = 'chat--video-visible-full';
- }
- return (
-
- {this.renderChatChannels()}
-
- {this.renderActiveChatChannel(channelHeader)}
-
-
- );
- }
-}
diff --git a/app/javascript/chat/components/ChannelButton.jsx b/app/javascript/chat/components/ChannelButton.jsx
deleted file mode 100644
index a79647096..000000000
--- a/app/javascript/chat/components/ChannelButton.jsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import { h, createRef } from 'preact';
-import { useEffect } from 'preact/hooks';
-import PropTypes from 'prop-types';
-import { defaultChannelPropTypes } from '../../common-prop-types/channel-list-prop-type';
-import { ChannelImage } from './ChannelImage';
-import { Button } from '@crayons';
-
-/**
- * Render a button to switch focus to a channel
- *
- * @param {object} props
- *
- * @component
- *
- * @example
- *
- *
- *
- */
-
-export function ChannelButton(props) {
- const buttonRef = createRef();
- const { isActiveChannel = false } = props;
-
- useEffect(() => {
- if (isActiveChannel) {
- buttonRef.current.click();
- }
- }, [isActiveChannel, buttonRef]);
-
- const {
- channel,
- handleSwitchChannel,
- otherClassname,
- newMessagesIndicator,
- isUnopened,
- discoverableChannel,
- triggerActiveContent,
- } = props;
-
- return (
-
-
- {isUnopened ? (
-
- ) : null}
- {channel.channel_name}
-
- );
-}
-
-ChannelButton.propTypes = {
- channel: defaultChannelPropTypes,
- discoverableChannel: PropTypes.bool,
- handleSwitchChannel: PropTypes.func,
- triggerActiveContent: PropTypes.func,
- newMessagesIndicator: PropTypes.string,
- otherClassname: PropTypes.string,
- isUnopened: PropTypes.string,
-};
-
-ChannelButton.defaultProps = {
- otherClassname: '',
- isUnopened: '',
- newMessagesIndicator: '',
- discoverableChannel: false,
- handleSwitchChannel: null,
- triggerActiveContent: null,
-};
diff --git a/app/javascript/chat/components/ChannelFilterButton.jsx b/app/javascript/chat/components/ChannelFilterButton.jsx
deleted file mode 100644
index ccd483d00..000000000
--- a/app/javascript/chat/components/ChannelFilterButton.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-/**
- * This component renders a button that is used for filtering chat channels.
- *
- * @param {object} props
- * @param {string} props.type - The type of chat channel selected
- * @param {string} props.name - Used for testing and is displayed to the user on the button
- * @param {boolean} props.active - Should the button have the `active` CSS class`?
- * @param {function} props.onClick - Fired with the onClick trigger
- *
- * @component
- *
- * @example
- *
- */
-
-export function ChannelFilterButton({ type, name, active, onClick }) {
- return (
-
- {name}
-
- );
-}
-
-ChannelFilterButton.propTypes = {
- type: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- active: PropTypes.bool.isRequired,
- onClick: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/components/ChannelImage.jsx b/app/javascript/chat/components/ChannelImage.jsx
deleted file mode 100644
index 47aa35cb9..000000000
--- a/app/javascript/chat/components/ChannelImage.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { defaultChannelPropTypes } from '../../common-prop-types/channel-list-prop-type';
-
-/**
- * Returns an image to help users identify chat channels
- *
- * @param {object} channel - Contains information about the channel this image represents
- * @param {string} newMessagesIndicator - Used to construct a CSS classname
- * @param {boolean} discoverableChannel - Used to determine which CSS class should be applied
- *
- * @example
- *
- */
-
-export function ChannelImage({
- channel,
- newMessagesIndicator,
- discoverableChannel,
-}) {
- return (
-
-
-
- );
-}
-
-ChannelImage.propTypes = {
- channel: defaultChannelPropTypes,
- newMessagesIndicator: PropTypes.string,
- discoverableChannel: PropTypes.bool,
-};
diff --git a/app/javascript/chat/components/ConnectStateProvider.jsx b/app/javascript/chat/components/ConnectStateProvider.jsx
deleted file mode 100644
index d7a7c62c0..000000000
--- a/app/javascript/chat/components/ConnectStateProvider.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h, createContext } from 'preact';
-import { useReducer } from 'preact/hooks';
-
-const store = createContext();
-const { Provider } = store;
-
-/**
- * Provides state management for the Connect feature of Forem.
- *
- * @param {object} props
- * @param {JSX.Element} props.children Child React elements
- * @param {object} props.initialState The initial value to store as state
- * @param {Function} props.reducer Given the current state and an action, returns the new state
- */
-function ConnectStateProvider({ children, initialState, reducer }) {
- const [state, dispatch] = useReducer(reducer, initialState);
-
- return {children} ;
-}
-
-export { store, ConnectStateProvider };
diff --git a/app/javascript/chat/components/CreateChatModal.jsx b/app/javascript/chat/components/CreateChatModal.jsx
deleted file mode 100644
index 740e86356..000000000
--- a/app/javascript/chat/components/CreateChatModal.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { h } from 'preact';
-import { useState } from 'preact/hooks';
-import PropTypes from 'prop-types';
-import { createChannel } from '../actions/chat_channel_setting_actions';
-import { addSnackbarItem } from '../../Snackbar';
-import { Modal, Button } from '@crayons';
-
-/**
- *
- * This component is used to create a chat channel. At the moment only support for tag_moderator user types.
- *
- * @param {object} props
- * @param {function} props.toggleModalCreateChannel
- * @param {function} props.handleCreateChannelSuccess
- *
- * @component
- *
- * @example
- *
- *
- *
- */
-
-export function CreateChatModal({
- toggleModalCreateChannel,
- handleCreateChannelSuccess,
-}) {
- const [channelName, setchannelName] = useState(undefined);
- const [userNames, setUserNames] = useState(undefined);
-
- const handleCreateChannel = async (e) => {
- e.preventDefault();
- const result = await createChannel(channelName, userNames);
- if (result.success) {
- handleCreateChannelSuccess();
- addSnackbarItem({ message: result.message });
- } else {
- addSnackbarItem({ message: result.message });
- }
- };
-
- return (
-
-
-
- Channel Name
-
- setchannelName(e.target.value)}
- />
-
- Invite Users
-
- setUserNames(e.target.value)}
- />
-
-
- Create
-
-
-
- );
-}
-
-CreateChatModal.propTypes = {
- toggleModalCreateChannel: PropTypes.func.isRequired,
- handleCreateChannelSuccess: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/components/__tests__/ConnectStateProvider.test.jsx b/app/javascript/chat/components/__tests__/ConnectStateProvider.test.jsx
deleted file mode 100644
index d43ba2b17..000000000
--- a/app/javascript/chat/components/__tests__/ConnectStateProvider.test.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { h } from 'preact';
-import { renderHook, act } from '@testing-library/preact-hooks';
-import { useContext } from 'preact/hooks';
-import { store, ConnectStateProvider } from '../ConnectStateProvider';
-
-// There is no need to test for accessibility for the store or ConnectStateProvider as they
-// relate only to state management.
-
-describe(' ', () => {
- it('should initialize Connect state with given initialState', async () => {
- const initialState = {
- channel: {
- channelId: 1,
- channelName: 'test',
- },
- showSidecar: false,
- };
-
- const wrapper = ({ children }) => (
- state}
- >
- {children}
-
- );
- const { result } = renderHook(() => useContext(store), { wrapper });
-
- expect(result.current.state).toEqual(initialState);
- });
-
- it('should dispatch an action', async () => {
- const reducer = jest.fn((state, _action) => {
- return state;
- });
- const action = { type: 'some action' };
- const initialState = {
- channel: {
- channelId: 1,
- channelName: 'test',
- },
- showSidecar: false,
- };
-
- const wrapper = ({ children }) => (
-
- {children}
-
- );
-
- const { result } = renderHook(() => useContext(store), { wrapper });
-
- act(() => {
- result.current.dispatch(action);
- });
-
- expect(reducer).toHaveBeenCalledTimes(1);
- expect(reducer).toHaveBeenCalledWith(initialState, action);
- });
-});
diff --git a/app/javascript/chat/compose.jsx b/app/javascript/chat/compose.jsx
deleted file mode 100644
index 830cf2cf8..000000000
--- a/app/javascript/chat/compose.jsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import { h } from 'preact';
-import {
- useState,
- useEffect,
- useMemo,
- useRef,
- useLayoutEffect,
-} from 'preact/hooks';
-import PropTypes from 'prop-types';
-import { useTextAreaAutoResize } from '@utilities/textAreaUtils';
-
-export const Compose = ({
- handleKeyDown,
- handleKeyDownEdit,
- handleSubmitOnClick,
- handleSubmitOnClickEdit,
- handleMention,
- handleKeyUp,
- startEditing,
- markdownEdited,
- editMessageMarkdown,
- handleEditMessageClose,
- handleFilePaste,
- activeChannelName,
-}) => {
- const [value, setValue] = useState('');
- const textAreaRef = useRef(null);
-
- const { setTextArea } = useTextAreaAutoResize();
-
- useLayoutEffect(() => {
- if (textAreaRef.current) {
- setTextArea(textAreaRef.current);
- }
- }, [setTextArea]);
-
- useEffect(() => {
- if (!markdownEdited && startEditing) {
- setValue(editMessageMarkdown);
- }
- }, [markdownEdited, startEditing, editMessageMarkdown]);
-
- const onKeyDown = (event) => {
- const shiftPressed = event.shiftKey;
- if (startEditing) handleKeyDownEdit(event);
- else handleKeyDown(event);
-
- if (event.keyCode === 13 && !shiftPressed) {
- event.preventDefault();
- setValue('');
- }
- };
-
- const placeholder = useMemo(
- () =>
- startEditing ? "Let's connect" : `Write message to ${activeChannelName}`,
- [startEditing, activeChannelName],
- );
- const label = useMemo(
- () => (startEditing ? "Let's connect" : 'Compose a message'),
- [startEditing],
- );
- const saveButtonText = useMemo(
- () => (startEditing ? 'Save' : 'Send'),
- [startEditing],
- );
-
- return (
-
- );
-};
-
-Compose.propTypes = {
- handleKeyDown: PropTypes.func.isRequired,
- handleKeyDownEdit: PropTypes.func.isRequired,
- handleSubmitOnClick: PropTypes.func.isRequired,
- handleSubmitOnClickEdit: PropTypes.func.isRequired,
- handleMention: PropTypes.func.isRequired,
- handleKeyUp: PropTypes.func.isRequired,
- startEditing: PropTypes.bool.isRequired,
- markdownEdited: PropTypes.bool.isRequired,
- editMessageMarkdown: PropTypes.string.isRequired,
- handleEditMessageClose: PropTypes.func.isRequired,
- handleFilePaste: PropTypes.func.isRequired,
- activeChannelName: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/configMenu.jsx b/app/javascript/chat/configMenu.jsx
deleted file mode 100644
index 616bc1e7c..000000000
--- a/app/javascript/chat/configMenu.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { h, Component, createRef } from 'preact';
-// eslint-disable-next-line import/no-unresolved
-import ConfigImage from 'images/overflow-horizontal.svg';
-
-export class ConfigMenu extends Component {
- constructor() {
- super();
- this.state = { visible: false };
- this.firstNavLink = createRef();
- this.configMenuButton = createRef();
- }
-
- handleClick = () => {
- this.setState(
- (prevState) => ({ visible: !prevState.visible }),
- () => {
- this.state.visible
- ? this.firstNavLink.current.focus()
- : this.configMenuButton.current.focus();
- },
- );
- };
-
- render() {
- const { visible } = this.state;
-
- return (
-
-
- {visible && (
-
-
-
- )}
-
- );
- }
-}
diff --git a/app/javascript/chat/content.jsx b/app/javascript/chat/content.jsx
deleted file mode 100644
index bdec04d84..000000000
--- a/app/javascript/chat/content.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import { h, Component } from 'preact';
-import PropTypes from 'prop-types';
-import { Article } from './article';
-import { ChannelRequest } from './channelRequest';
-import { RequestManager } from './RequestManager/RequestManager';
-import { ChatChannelSettings } from './ChatChannelSettings/ChatChannelSettings';
-import { Draw } from './draw';
-import { ReportAbuse } from './ReportAbuse';
-
-const smartSvgIcon = (content, d) => (
-
-
-
-
-);
-
-export class Content extends Component {
- static propTypes = {
- resource: PropTypes.shape({
- data: PropTypes.any,
- type_of: PropTypes.string.isRequired,
- handleRequestRejection: PropTypes.func,
- handleRequestApproval: PropTypes.func,
- handleJoiningRequest: PropTypes.func,
- activeMembershipId: PropTypes.func,
- sendCanvasImage: PropTypes.func,
- }).isRequired,
- fullscreen: PropTypes.bool.isRequired,
- onTriggerContent: PropTypes.func.isRequired,
- updateRequestCount: PropTypes.func.isRequired,
- closeReportAbuseForm: PropTypes.func.isRequired,
- };
-
- render() {
- const { onTriggerContent, fullscreen, resource, closeReportAbuseForm } =
- this.props;
- if (!resource) {
- return '';
- }
- return (
-
-
- {smartSvgIcon(
- 'exit',
- 'M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z',
- )}
-
-
- {' '}
- {fullscreen
- ? smartSvgIcon(
- 'fullscreen',
- 'M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z',
- )
- : smartSvgIcon(
- 'fullscreen',
- 'M20 3h2v6h-2V5h-4V3h4zM4 3h4v2H4v4H2V3h2zm16 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z',
- )}
-
-
-
- );
- }
-}
-
-function Display({ resource, closeReportAbuseForm }) {
- switch (resource.type_of) {
- case 'loading-user':
- return
;
- case 'article':
- return ;
- case 'draw':
- return ;
- case 'channel-request':
- return (
-
- );
- case 'channel-request-manager':
- return (
-
- );
- case 'chat-channel-setting':
- return (
-
- );
- case 'message-report-abuse':
- return (
-
- );
- default:
- return null;
- }
-}
diff --git a/app/javascript/chat/draw/index.jsx b/app/javascript/chat/draw/index.jsx
deleted file mode 100644
index 0601d1726..000000000
--- a/app/javascript/chat/draw/index.jsx
+++ /dev/null
@@ -1,187 +0,0 @@
-import { h } from 'preact';
-import { useRef, useEffect, useState } from 'preact/hooks';
-import PropTypes from 'prop-types';
-import { chatDrawPalettes } from '../../utilities/Constants';
-import { Button } from '@crayons';
-
-/**
- * Draw function is wrapped in this component
- *
- * @example
- *
- *
- *
- * @param {object} props
- * @param {function} props.sendCanvasImage
- */
-export function Draw({ sendCanvasImage }) {
- const canvasRef = useRef(null);
- const canvasWidth = useRef(null);
- const [isDrawing, setIsDrawing] = useState(false);
- const [drawColor, setDrawColor] = useState('#F58F8E');
- const [coordinates, setCoordinates] = useState({});
- const [sendButtonDisabled, setSendButtonDisabled] = useState(true);
- const prevCoordinates = usePrevious(coordinates);
-
- const handleCanvasSend = () => {
- const canvas = canvasRef.current;
- canvas.toBlob((blob) => {
- sendCanvasImage(new File([blob], 'draw.png'));
- });
- };
-
- const handleMouseDown = (e) => {
- setCoordinates({ x: e.offsetX, y: e.offsetY });
- setIsDrawing(true);
- };
-
- const handleImageDrop = (e) => {
- e.preventDefault();
- if (!canvasRef.current) {
- return;
- }
- const canvas = canvasRef.current;
- const context = canvas.getContext('2d');
- canvas.classList.remove('opacity-25');
-
- const { files } = e.dataTransfer;
- const img = new Image();
- img.src = URL.createObjectURL(files[0]);
-
- img.onload = () => {
- const scale = Math.min(
- canvas.width / img.width,
- canvas.height / img.height,
- );
- setSendButtonDisabled(false);
- const x = canvas.width / 2 - (img.width / 2) * scale;
- const y = canvas.height / 2 - (img.height / 2) * scale;
- context.drawImage(img, x, y, img.width * scale, img.height * scale);
- };
- };
-
- const handleClearCanvas = () => {
- setSendButtonDisabled(true);
- if (!canvasRef.current) {
- return;
- }
- const context = canvasRef.current.getContext('2d');
- context.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
- };
-
- const handleDragHover = (e) => {
- e.preventDefault();
- canvasRef.current.classList.add('opacity-25');
- };
-
- const handleChangeColor = (e) => {
- setDrawColor(e.target.style.backgroundColor);
- };
-
- const handleDragExit = (e) => {
- e.preventDefault();
- canvasRef.current.classList.remove('opacity-25');
- canvasRef.current.classList.add('opacity-100');
- };
-
- const handleMouseMove = (e) => {
- if (isDrawing) {
- setSendButtonDisabled(false);
- setCoordinates({ x: e.offsetX, y: e.offsetY });
- }
- };
-
- const handleMouseUp = () => {
- setCoordinates({});
- setIsDrawing(false);
- };
-
- useEffect(() => {
- canvasRef.current.width = canvasWidth.current.clientWidth;
- }, [canvasWidth]);
-
- useEffect(() => {
- if (!canvasRef.current) {
- return;
- }
- const context = canvasRef.current.getContext('2d');
-
- if (isDrawing) {
- context.beginPath();
- context.strokeStyle = drawColor;
- context.lineWidth = 2;
- context.moveTo(prevCoordinates.x, prevCoordinates.y);
- context.lineTo(coordinates.x, coordinates.y);
- context.stroke();
- context.closePath();
- }
- }, [drawColor, isDrawing, coordinates, prevCoordinates]);
-
- return (
-
-
-
Connect Draw
-
- {chatDrawPalettes.map((color) => (
-
- ))}
-
-
-
-
-
-
- Clear
-
-
- Send
-
-
-
-
- );
-}
-
-function usePrevious(value) {
- const ref = useRef();
- useEffect(() => {
- ref.current = value;
- }, [value]);
-
- return ref.current;
-}
-Draw.propTypes = {
- sendCanvasImage: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/chat/message.jsx b/app/javascript/chat/message.jsx
deleted file mode 100644
index dc91dcf39..000000000
--- a/app/javascript/chat/message.jsx
+++ /dev/null
@@ -1,213 +0,0 @@
-import { h } from 'preact';
-import { useState, useRef, useLayoutEffect } from 'preact/hooks';
-import PropTypes from 'prop-types';
-// eslint-disable-next-line import/no-unresolved
-import ThreeDotsIcon from 'images/overflow-horizontal.svg';
-import { adjustTimestamp } from './util';
-import { ErrorMessage } from './messages/errorMessage';
-import { Button } from '@crayons';
-import { initializeDropdown } from '@utilities/dropdownUtils';
-
-export const Message = ({
- currentUserId,
- id,
- user,
- userID,
- message,
- color,
- type,
- editedAt,
- timestamp,
- profileImageUrl,
- onContentTrigger,
- onDeleteMessageTrigger,
- onReportMessageTrigger,
- onEditMessageTrigger,
-}) => {
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
- const messageWrapperRef = useRef(null);
- const spanStyle = { color };
-
- const triggerElementId = `message-dropdown-trigger-${id}`;
- const dropdownContentId = `message-dropdown-${id}`;
-
- useLayoutEffect(() => {
- initializeDropdown({
- triggerElementId,
- dropdownContentId,
- onOpen: () => setIsDropdownOpen(true),
- onClose: () => setIsDropdownOpen(false),
- });
- }, [triggerElementId, dropdownContentId]);
-
- if (type === 'error') {
- return ;
- }
-
- const MessageArea = () => {
- if (userID === currentUserId) {
- message = message.replace(`@${user}`, `@${user} `);
- }
-
- return (
-
- );
- };
-
- const dropdown = (
-
-
-
-
-
-
-
-
- onEditMessageTrigger(id)}
- >
- Edit
-
-
-
- onDeleteMessageTrigger(id)}
- >
- Delete
-
-
-
-
-
- );
- const dropdownReport = (
-
-
-
-
-
-
- onReportMessageTrigger(id)}
- >
- Report Abuse
-
-
-
- );
-
- return (
-
-
-
-
-
-
-
- {user}
-
-
- {editedAt ? (
-
- {`${adjustTimestamp(editedAt)}`}
- (edited)
-
- ) : (
- ' '
- )}
-
- {timestamp && !editedAt ? (
-
- {`${adjustTimestamp(timestamp)}`}
-
- ) : (
- ' '
- )}
-
- {userID === currentUserId ? dropdown : dropdownReport}
-
-
-
-
-
-
- );
-};
-
-Message.propTypes = {
- currentUserId: PropTypes.number.isRequired,
- id: PropTypes.number.isRequired,
- user: PropTypes.string.isRequired,
- userID: PropTypes.number.isRequired,
- color: PropTypes.string.isRequired,
- message: PropTypes.string.isRequired,
- type: PropTypes.string,
- timestamp: PropTypes.string,
- editedAt: PropTypes.number.isRequired,
- profileImageUrl: PropTypes.string,
- onContentTrigger: PropTypes.func.isRequired,
- onDeleteMessageTrigger: PropTypes.func.isRequired,
- onEditMessageTrigger: PropTypes.func.isRequired,
- onReportMessageTrigger: PropTypes.func.isRequired,
-};
-
-Message.defaultProps = {
- type: 'normalMessage',
- timestamp: null,
- profileImageUrl: '',
-};
diff --git a/app/javascript/chat/messages/errorMessage.jsx b/app/javascript/chat/messages/errorMessage.jsx
deleted file mode 100644
index 593f811d2..000000000
--- a/app/javascript/chat/messages/errorMessage.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const ErrorMessage = ({ message }) => {
- const errorStyle = { color: 'darksalmon', 'font-size': '13px' };
- return (
-
-
- Sorry
-
- {`@${window.currentUser.username}`}
-
- {` ${message}`}
-
-
- );
-};
-
-ErrorMessage.propTypes = {
- message: PropTypes.string.isRequired,
-};
diff --git a/app/javascript/chat/util.js b/app/javascript/chat/util.js
deleted file mode 100644
index e2f8f5ec4..000000000
--- a/app/javascript/chat/util.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import { fetchSearch } from '../utilities/search';
-
-import 'intersection-observer';
-
-export function getCsrfToken() {
- const element = document.querySelector(`meta[name='csrf-token']`);
-
- return element !== null ? element.content : undefined;
-}
-
-const getWaitOnUserDataHandler = ({ resolve, reject, waitTime = 20 }) => {
- let totalTimeWaiting = 0;
-
- return function waitingOnUserData() {
- if (totalTimeWaiting === 3000) {
- reject(new Error("Couldn't find user data on page."));
- return;
- }
-
- const csrfToken = getCsrfToken(document);
- const { user } = document.body.dataset;
-
- if (user && csrfToken !== undefined) {
- const currentUser = JSON.parse(user);
-
- resolve({ currentUser, csrfToken });
- return;
- }
-
- totalTimeWaiting += waitTime;
- setTimeout(waitingOnUserData, waitTime);
- };
-};
-
-export const getCurrentUser = () => {
- const { user } = document.body.dataset;
- return JSON.parse(user);
-};
-
-export function getUserDataAndCsrfToken() {
- return new Promise((resolve, reject) => {
- getWaitOnUserDataHandler({ resolve, reject })();
- });
-}
-
-export function scrollToBottom() {
- const element = document.getElementById('messagelist');
- element.scrollTop = element.scrollHeight;
-}
-
-export function setupObserver(callback) {
- const sentinel = document.getElementById('messagelist__sentinel');
- const somethingObserver = new IntersectionObserver(callback, {
- threshold: [0, 1],
- });
-
- somethingObserver.observe(sentinel);
-
- window.addEventListener('beforeunload', () => {
- somethingObserver.disconnect();
- });
-
- if (typeof instantClick !== 'undefined') {
- InstantClick.on('change', () => {
- somethingObserver.disconnect();
- });
- }
-}
-
-export function hideMessages(messages, userId) {
- const cleanedMessages = Object.keys(messages).reduce(
- (accumulator, channelId) => {
- const newMessages = messages[channelId].map((message) => {
- if (message.user_id === userId) {
- const messageClone = Object.assign({ type: 'hidden' }, message);
- messageClone.message = '';
- messageClone.messageColor = 'lightgray';
- return messageClone;
- }
- return message;
- });
- return { ...accumulator, [channelId]: newMessages };
- },
- {},
- );
- return cleanedMessages;
-}
-
-export function adjustTimestamp(timestamp) {
- let time = new Date(timestamp);
- const options = {
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- };
- time = new Intl.DateTimeFormat('en-US', options).format(time);
- return time;
-}
-
-export const channelSorter = (channels, currentUserId, filterQuery) => {
- const activeChannels = channels.filter(
- (channel) =>
- channel.viewable_by === currentUserId && channel.status === 'active',
- );
- const joiningChannels = channels.filter(
- (channel) => channel.status === 'joining_request',
- );
- const ChannelIds = [
- [...new Set(activeChannels.map((x) => x.chat_channel_id))],
- [...new Set(joiningChannels.map((x) => x.chat_channel_id))],
- ];
- const discoverableChannels = channels
- .filter(
- (channel) =>
- (channel.status === 'joining_request' && filterQuery) ||
- (!ChannelIds[1].includes(channel.chat_channel_id) &&
- channel.viewable_by !== currentUserId),
- )
- .filter((channel) => !ChannelIds[0].includes(channel.chat_channel_id));
- return { activeChannels, discoverableChannels };
-};
-
-export const createDataHash = (additionalFilters, searchParams) => {
- const dataHash = {};
- if (additionalFilters.filters) {
- const [key, value] = additionalFilters.filters.split(':');
- dataHash[key] = value;
- }
- dataHash.per_page = 30;
- dataHash.page = searchParams.paginationNumber;
- if (searchParams.searchType === 'discoverable') {
- dataHash.user_id = 'all';
- }
- return fetchSearch('chat_channels', dataHash);
-};
diff --git a/app/javascript/common-prop-types/channel-list-prop-type.js b/app/javascript/common-prop-types/channel-list-prop-type.js
deleted file mode 100644
index bf7753770..000000000
--- a/app/javascript/common-prop-types/channel-list-prop-type.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import PropTypes from 'prop-types';
-
-export const defaultChannelPropTypes = PropTypes.shape({
- channel: PropTypes.shape({
- channel_name: PropTypes.string,
- channel_color: PropTypes.string,
- channel_type: PropTypes.string,
- channel_modified_slug: PropTypes.string,
- id: PropTypes.number,
- chat_channel_id: PropTypes.number,
- status: PropTypes.string,
- channel_image: PropTypes.string,
- }).isRequired,
-});
diff --git a/app/javascript/listings/__tests__/ContactViaConnect.test.jsx b/app/javascript/listings/__tests__/ContactViaConnect.test.jsx
deleted file mode 100644
index 680771eb0..000000000
--- a/app/javascript/listings/__tests__/ContactViaConnect.test.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { h } from 'preact';
-import { render, fireEvent } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { ContactViaConnect } from '../components/ContactViaConnect';
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const onChange = jest.fn;
- const { container } = render(
- ,
- );
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render a checked check box opting in to open DMs', () => {
- const onChange = jest.fn();
- const { getByText } = render(
- ,
- );
-
- expect(getByText('Allow Users to message me via Connect.')).toBeDefined();
- });
-
- it('should fire a change event when clicking the checkbox', () => {
- const onChange = jest.fn();
- const { getByText } = render(
- ,
- );
-
- const checkbox = getByText('Allow Users to message me via Connect.');
-
- fireEvent.click(checkbox);
-
- expect(onChange).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/app/javascript/listings/__tests__/MessageModal.test.jsx b/app/javascript/listings/__tests__/MessageModal.test.jsx
deleted file mode 100644
index 51ec56f9c..000000000
--- a/app/javascript/listings/__tests__/MessageModal.test.jsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { axe } from 'jest-axe';
-import { MessageModal } from '../components/MessageModal';
-
-const getDefaultListing = () => ({
- id: 22,
- category: 'misc',
- location: 'West Refugio',
- processed_html:
- '\u003cp\u003eEius et ullam. Dolores et qui. Quis \u003cstrong\u003equi\u003c/strong\u003e omnis.\u003c/p\u003e\n',
- slug: 'illo-iure-quos-perspiciatis-5hk7',
- title: 'Illo iure quos perspiciatis.',
- tags: ['go', 'git'],
- user_id: 1,
- author: {
- name: 'Mrs. Yoko Christiansen',
- username: 'mrschristiansenyoko',
- profile_image_90:
- '/uploads/user/profile_image/7/4b1c980a-beb0-4a5f-b3f2-acc91adc503c.png',
- },
-});
-
-const getProps = () => ({
- currentUserId: 1,
- message: 'Something',
- onChangeDraftingMessage: jest.fn(),
- onSubmit: jest.fn(),
-});
-
-const renderMessageModal = (listing) =>
- render( );
-
-describe(' ', () => {
- it('should have no a11y violations', async () => {
- const { container } = render(renderMessageModal(getDefaultListing()));
- const results = await axe(container);
-
- expect(results).toHaveNoViolations();
- });
-
- it('should render a text-area', () => {
- const { queryByTestId } = renderMessageModal(getDefaultListing());
-
- expect(queryByTestId('listing-new-message')).toBeDefined();
- });
-
- describe('When the current user is the author', () => {
- const listingWithCurrentUserId = {
- ...getDefaultListing(),
- user_id: 1,
- };
-
- it('should show the information about contact with the current user', () => {
- const { queryByText } = renderMessageModal(listingWithCurrentUserId);
-
- expect(
- queryByText(
- 'This is your active listing. Any member can contact you via this form.',
- ),
- ).toBeDefined();
- });
- });
-
- describe('When current user is not the author', () => {
- const listingWithDifferentCurrentUserId = {
- ...getDefaultListing(),
- user_id: 111,
- };
-
- it('should show the message to contact the author', () => {
- const { queryByText } = renderMessageModal(
- listingWithDifferentCurrentUserId,
- );
-
- expect(
- queryByText(
- `Contact ${listingWithDifferentCurrentUserId.author.name} via DEV Connect`,
- ),
- ).toBeDefined();
- });
- });
-});
diff --git a/app/javascript/listings/__tests__/Modal.test.jsx b/app/javascript/listings/__tests__/Modal.test.jsx
index 9e2079cce..10d107e70 100644
--- a/app/javascript/listings/__tests__/Modal.test.jsx
+++ b/app/javascript/listings/__tests__/Modal.test.jsx
@@ -64,23 +64,4 @@ describe(' ', () => {
const results = await axe(container);
expect(results).toHaveNoViolations();
});
-
- it('should render the MessageModal component when the listing.contact_via_connect is true', () => {
- const listingWithContactViaConnectTrue = {
- ...getDefaultListing(),
- contact_via_connect: true,
- };
- const { queryByTestId } = renderModal(listingWithContactViaConnectTrue);
-
- expect(queryByTestId('listings-message-modal')).toBeDefined();
- });
-
- it('should not render the MessageModal when the listing.contact_via_connect is false', () => {
- const listingWithContactViaConnectFalse = {
- ...getDefaultListing(),
- contact_via_connect: false,
- };
- const { queryByTestId } = renderModal(listingWithContactViaConnectFalse);
- expect(queryByTestId('listings-message-modal')).toBeNull();
- });
});
diff --git a/app/javascript/listings/__tests__/SingleListing.test.jsx b/app/javascript/listings/__tests__/SingleListing.test.jsx
index cea8b1e40..5dbbeb79f 100644
--- a/app/javascript/listings/__tests__/SingleListing.test.jsx
+++ b/app/javascript/listings/__tests__/SingleListing.test.jsx
@@ -9,7 +9,6 @@ import { SingleListing } from '../singleListing/SingleListing';
const listing = {
id: 22,
category: 'misc',
- contact_via_connect: true,
location: 'West Refugio',
processed_html:
'\u003cp\u003eEius et ullam. Dolores et qui. Quis \u003cstrong\u003equi\u003c/strong\u003e omnis.\u003c/p\u003e\n',
diff --git a/app/javascript/listings/components/ContactViaConnect.jsx b/app/javascript/listings/components/ContactViaConnect.jsx
deleted file mode 100644
index c7c75c3cf..000000000
--- a/app/javascript/listings/components/ContactViaConnect.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-export const ContactViaConnect = ({ onChange, checked }) => (
-
-
-
-
- Connect messaging
-
- Allow Users to message me via Connect.
-
-
-
-);
-
-ContactViaConnect.propTypes = {
- onChange: PropTypes.func.isRequired,
- checked: PropTypes.bool.isRequired,
-};
diff --git a/app/javascript/listings/components/MessageModal.jsx b/app/javascript/listings/components/MessageModal.jsx
deleted file mode 100644
index b39f00057..000000000
--- a/app/javascript/listings/components/MessageModal.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import { Button } from '@crayons';
-
-export const MessageModal = ({
- currentUserId,
- message,
- listing,
- onSubmit,
- onChangeDraftingMessage,
-}) => {
- const isCurrentUserOnListing = listing.user_id === currentUserId;
-
- return (
-
- );
-};
-
-MessageModal.propTypes = {
- currentUserId: PropTypes.number.isRequired,
- message: PropTypes.string.isRequired,
- listing: PropTypes.shape({
- author: PropTypes.shape({
- name: PropTypes.string.isRequired,
- }).isRequired,
- user_id: PropTypes.number.isRequired,
- }).isRequired,
- onSubmit: PropTypes.func.isRequired,
- onChangeDraftingMessage: PropTypes.func.isRequired,
-};
diff --git a/app/javascript/listings/components/Modal.jsx b/app/javascript/listings/components/Modal.jsx
index c824208be..833a73c4c 100644
--- a/app/javascript/listings/components/Modal.jsx
+++ b/app/javascript/listings/components/Modal.jsx
@@ -1,22 +1,16 @@
import { h } from 'preact';
import PropTypes from 'prop-types';
import { SingleListing } from '../singleListing/SingleListing';
-import { MessageModal } from './MessageModal';
import { Modal as CrayonsModal } from '@crayons';
export const Modal = ({
currentUserId,
onAddTag,
- onChangeDraftingMessage,
onClick,
onChangeCategory,
onOpenModal,
- onSubmit,
listing,
- message,
}) => {
- const shouldRenderMessageModal = listing && listing.contact_via_connect;
-
return (
- {shouldRenderMessageModal && (
-
-
-
- )}
);
@@ -52,13 +36,10 @@ export const Modal = ({
Modal.propTypes = {
listing: PropTypes.isRequired,
onAddTag: PropTypes.func.isRequired,
- onChangeDraftingMessage: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
onChangeCategory: PropTypes.func.isRequired,
onOpenModal: PropTypes.func.isRequired,
- onSubmit: PropTypes.func.isRequired,
currentUserId: PropTypes.number,
- message: PropTypes.string.isRequired,
};
Modal.defaultProps = {
diff --git a/app/javascript/listings/listings.jsx b/app/javascript/listings/listings.jsx
index 029e06c3d..db37385bf 100644
--- a/app/javascript/listings/listings.jsx
+++ b/app/javascript/listings/listings.jsx
@@ -22,7 +22,6 @@ export class Listings extends Component {
initialFetch: true,
currentUserId: null,
openedListing: null,
- message: '',
slug: null,
page: 0,
showNextPageButton: false,
@@ -145,41 +144,6 @@ export class Listings extends Component {
this.setLocation(null, null, listing.category, listing.slug);
};
- handleDraftingMessage = (e) => {
- e.preventDefault();
- this.setState({ message: e.target.value });
- };
-
- handleSubmitMessage = (e) => {
- e.preventDefault();
- const { message, openedListing } = this.state;
- if (message.replace(/\s/g, '').length === 0) {
- return;
- }
- const formData = new FormData();
- formData.append('user_id', openedListing.user_id);
- formData.append('message', `**re: ${openedListing.title}** ${message}`);
- formData.append('controller', 'chat_channels');
-
- const destination = `/connect/@${openedListing.author.username}`;
- const metaTag = document.querySelector("meta[name='csrf-token']");
- window
- .fetch('/chat_channels/create_chat', {
- method: 'POST',
- headers: {
- 'X-CSRF-Token': metaTag.getAttribute('content'),
- },
- body: formData,
- credentials: 'same-origin',
- })
- .then(() => {
- window.location.href = destination;
- })
- .catch((error) => {
- Honeybadger.notify(error);
- });
- };
-
handleQuery = (e) => {
const { tags, category } = this.state;
this.setState({ query: e.target.value, page: 0 });
@@ -264,7 +228,6 @@ export class Listings extends Component {
openedListing,
showNextPageButton,
initialFetch,
- message,
isModalOpen,
} = this.state;
@@ -280,7 +243,6 @@ export class Listings extends Component {
categories={allCategories}
category={category}
onSelectCategory={this.selectCategory}
- message={message}
onKeyUp={this.debouncedListingSearch}
onClearQuery={this.clearQuery}
onRemoveTag={this.removeTag}
@@ -301,13 +263,10 @@ export class Listings extends Component {
)}
diff --git a/app/javascript/listings/singleListing/listingPropTypes.js b/app/javascript/listings/singleListing/listingPropTypes.js
index cb12d4d5e..ec65d97b1 100644
--- a/app/javascript/listings/singleListing/listingPropTypes.js
+++ b/app/javascript/listings/singleListing/listingPropTypes.js
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
export const listingPropTypes = PropTypes.shape({
id: PropTypes.number,
category: PropTypes.string,
- contact_via_connect: PropTypes.bool,
location: PropTypes.string,
processed_html: PropTypes.string,
slug: PropTypes.string,
diff --git a/app/javascript/packs/Chat.jsx b/app/javascript/packs/Chat.jsx
deleted file mode 100644
index a46edf553..000000000
--- a/app/javascript/packs/Chat.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h, render } from 'preact';
-import { Chat } from '../chat/chat';
-import { Snackbar } from '../Snackbar/Snackbar';
-
-function loadElement() {
- const root = document.getElementById('chat');
-
- if (root) {
- render( , document.getElementById('snack-zone'));
- render( , root);
-
- const placeholder = document.getElementById('chat_placeholder');
-
- if (placeholder) {
- root.removeChild(placeholder);
- }
- }
-}
-
-window.InstantClick.on('change', () => {
- loadElement();
-});
-
-loadElement();
diff --git a/app/javascript/packs/Onboarding.jsx b/app/javascript/packs/Onboarding.jsx
index b65a0587b..f47ff1c78 100644
--- a/app/javascript/packs/Onboarding.jsx
+++ b/app/javascript/packs/Onboarding.jsx
@@ -1,6 +1,5 @@
import { h, render } from 'preact';
-import { getUserDataAndCsrfToken } from '../chat/util';
-import { getUnopenedChannels } from '../utilities/connect';
+import { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';
HTMLDocument.prototype.ready = new Promise((resolve) => {
if (document.readyState !== 'loading') {
@@ -37,7 +36,6 @@ document.ready.then(
window.currentUser = currentUser;
window.csrfToken = csrfToken;
- getUnopenedChannels();
renderPage();
})
.catch((error) => {
diff --git a/app/javascript/packs/articleForm.jsx b/app/javascript/packs/articleForm.jsx
index 067ea6c48..b3b43c812 100644
--- a/app/javascript/packs/articleForm.jsx
+++ b/app/javascript/packs/articleForm.jsx
@@ -1,7 +1,7 @@
import { h, render } from 'preact';
-import { getUserDataAndCsrfToken } from '../chat/util';
import { ArticleForm } from '../article-form/articleForm';
import { Snackbar } from '../Snackbar';
+import { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';
HTMLDocument.prototype.ready = new Promise((resolve) => {
if (document.readyState !== 'loading') {
diff --git a/app/javascript/packs/base.jsx b/app/javascript/packs/base.jsx
index d24254db0..44489da42 100644
--- a/app/javascript/packs/base.jsx
+++ b/app/javascript/packs/base.jsx
@@ -111,7 +111,6 @@ window.Forem = {
function getPageEntries() {
return Object.entries({
'notifications-index': document.getElementById('notifications-link'),
- 'chat_channels-index': document.getElementById('connect-link'),
'moderations-index': document.getElementById('moderation-link'),
'stories-search': document.getElementById('search-link'),
});
diff --git a/app/javascript/packs/onboardingRedirectCheck.jsx b/app/javascript/packs/onboardingRedirectCheck.jsx
index c42e079ad..139f3db50 100644
--- a/app/javascript/packs/onboardingRedirectCheck.jsx
+++ b/app/javascript/packs/onboardingRedirectCheck.jsx
@@ -1,5 +1,4 @@
-import { getUserDataAndCsrfToken } from '../chat/util';
-import { getUnopenedChannels } from '../utilities/connect';
+import { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';
HTMLDocument.prototype.ready = new Promise((resolve) => {
if (document.readyState !== 'loading') {
@@ -40,7 +39,6 @@ document.ready.then(
.then(({ currentUser, csrfToken }) => {
window.currentUser = currentUser;
window.csrfToken = csrfToken;
- getUnopenedChannels();
if (redirectableLocation() && onboardCreator(currentUser)) {
window.location = `${window.location.origin}/admin/creator_settings/new?referrer=${window.location}`;
diff --git a/app/javascript/profileDropdown/flagButton.js b/app/javascript/profileDropdown/flagButton.js
index f27be6eed..64fc6b0cc 100644
--- a/app/javascript/profileDropdown/flagButton.js
+++ b/app/javascript/profileDropdown/flagButton.js
@@ -1,7 +1,7 @@
/* global userData */
/* eslint-disable no-alert, import/order */
import { request } from '@utilities/http';
-import { getUserDataAndCsrfToken } from '../chat/util';
+import { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';
function addFlagUserBehavior(flagButton) {
const { profileUserId, profileUserName } = flagButton.dataset;
diff --git a/app/javascript/utilities/__tests__/getUserDataAndCsrfToken.test.js b/app/javascript/utilities/__tests__/getUserDataAndCsrfToken.test.js
new file mode 100644
index 000000000..a2aebed8b
--- /dev/null
+++ b/app/javascript/utilities/__tests__/getUserDataAndCsrfToken.test.js
@@ -0,0 +1,56 @@
+import { getUserDataAndCsrfToken } from '../getUserDataAndCsrfToken';
+
+const ERROR_MESSAGE = "Couldn't find user data on page.";
+
+describe('getUserDataAndCsrfToken', () => {
+ afterEach(() => {
+ document.head.innerHTML = '';
+ document.body.removeAttribute('data-user');
+ });
+
+ test('should reject if no user or csrf token found.', async () => {
+ await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
+ ERROR_MESSAGE,
+ );
+ });
+
+ test('should reject if csrf token found but no user.', async () => {
+ document.head.innerHTML =
+ ' ';
+ await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
+ ERROR_MESSAGE,
+ );
+ });
+
+ test('should reject if user found but no csrf token found.', async () => {
+ document.body.setAttribute('data-user', '{}');
+ await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
+ ERROR_MESSAGE,
+ );
+ });
+
+ test('should resolve if user and csrf token found.', async () => {
+ const csrfToken = 'some-csrf-token';
+ const currentUser = {
+ id: 41,
+ name: 'Guy Fieri',
+ username: 'guyfieri',
+ profile_image_90:
+ '/uploads/user/profile_image/41/0841dbe2-208c-4daa-b498-b2f01f3d37b2.png',
+ followed_tag_names: [],
+ followed_tags: '[]',
+ reading_list_ids: [48, 49, 34, 51, 64, 56],
+ saw_onboarding: true,
+ checked_code_of_conduct: false,
+ display_sponsors: true,
+ trusted: false,
+ };
+ document.head.innerHTML = ` `;
+ document.body.setAttribute('data-user', JSON.stringify(currentUser));
+
+ expect(await getUserDataAndCsrfToken(document)).toEqual({
+ currentUser,
+ csrfToken,
+ });
+ });
+});
diff --git a/app/javascript/utilities/connect/getUnopenedChannels.jsx b/app/javascript/utilities/connect/getUnopenedChannels.jsx
deleted file mode 100644
index 10454aaf9..000000000
--- a/app/javascript/utilities/connect/getUnopenedChannels.jsx
+++ /dev/null
@@ -1,236 +0,0 @@
-import { h, render, Component } from 'preact';
-import PropTypes from 'prop-types';
-import { setupPusher } from './pusher';
-
-/* global userData */
-
-class UnopenedChannelNotice extends Component {
- propTypes = {
- pusherKey: PropTypes.Object,
- };
-
- static defaultProps = {
- pusherKey: undefined,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- visible: false,
- unopenedChannels: [],
- };
- }
-
- componentDidMount() {
- const { pusherKey } = this.props;
- const { appDomain } = document.body.dataset;
- setupPusher(pusherKey, {
- channelId: `private-message-notifications--${appDomain}-${window.currentUser.id}`,
- messageCreated: this.receiveNewMessage,
- messageDeleted: this.removeMessage,
- messageEdited: this.updateMessage,
- mentioned: this.mentionedMessage,
- messageOpened: this.messageOpened,
- });
- this.fetchUnopenedChannel(this.updateMessageNotification);
-
- if (document.getElementById('connect-link')) {
- document.getElementById('connect-link').onclick = () => {
- // Hack, should probably be its own component in future
- document.getElementById('connect-number')?.classList.add('hidden');
- this.setState({ visible: false });
- };
- }
- }
-
- updateMessageNotification = (unopenedChannels) => {
- const number = document.getElementById('connect-number');
- this.setState({ unopenedChannels });
- if (unopenedChannels.length > 0) {
- if (unopenedChannels[0].adjusted_slug === `@${userData().username}`) {
- return;
- }
- number?.classList.remove('hidden');
- number.innerHTML = unopenedChannels.length;
- document.getElementById(
- 'connect-link',
- ).href = `/connect/${unopenedChannels[0].adjusted_slug}`;
- InstantClick.preload(
- document.getElementById('connect-link').href,
- 'force',
- );
- } else {
- number?.classList.add('hidden');
- }
- };
-
- removeMessage = () => {};
-
- updateMessage = () => {};
-
- mentionedMessage = (e) => {
- if (window.location.pathname.startsWith('/connect')) {
- return;
- }
-
- this.setState((prevState) => ({
- unopenedChannels: prevState.unopenedChannels.map((unopenedChannel) =>
- unopenedChannel.adjusted_slug === e.chat_channel_adjusted_slug
- ? { ...unopenedChannel, request_type: 'mentioned' }
- : unopenedChannel,
- ),
- visible: true,
- }));
-
- this.hideNotice();
- };
-
- messageOpened = (e) => {
- const { unopenedChannels } = this.state;
- if (
- !window.location.pathname.startsWith('/connect') ||
- !window.location.pathname.includes(e.adjusted_slug)
- )
- return;
- this.updateMessageNotification(
- unopenedChannels.filter(
- (unopenedChannel) => unopenedChannel.adjusted_slug !== e.adjusted_slug,
- ),
- );
- };
-
- receiveNewMessage = (e) => {
- if (
- e.user_id === window.currentUser.id ||
- (window.location.pathname.startsWith('/connect') &&
- e.user_id === window.currentUser.id &&
- e.channel_type !== 'direct') ||
- window.location.pathname.includes(e.chat_channel_adjusted_slug)
- ) {
- return;
- }
- const { unopenedChannels } = this.state;
- const newObj = { adjusted_slug: e.chat_channel_adjusted_slug };
-
- const ifMessageExist = unopenedChannels.some(
- (channel) => channel.adjusted_slug === newObj.adjusted_slug,
- );
-
- if (
- !ifMessageExist &&
- newObj.adjusted_slug !== `@${window.currentUser.username}`
- ) {
- unopenedChannels.push(newObj);
- }
- if (ifMessageExist) {
- const index = unopenedChannels.findIndex(
- (channel) => channel.adjusted_slug === newObj.adjusted_slug,
- );
- unopenedChannels[index].notified = false;
- }
-
- if (!window.location.pathname.startsWith('/connect')) {
- this.setState({
- visible:
- unopenedChannels.length > 0 &&
- e.user_id !== window.currentUser.id &&
- e.channel_type === 'direct',
- });
- }
- this.updateMessageNotification(unopenedChannels);
- this.hideNotice();
- };
-
- handleClick = () => {
- this.hideNotice();
- };
-
- hideNotice = () => {
- setTimeout(() => {
- this.setState((prevState) => ({
- unopenedChannels: prevState.unopenedChannels.map((unopenedChannel) =>
- !unopenedChannel.notified
- ? { ...unopenedChannel, notified: true }
- : unopenedChannel,
- ),
- visible: false,
- }));
- }, 7500);
- };
-
- fetchUnopenedChannel = (successCb) => {
- fetch('/chat_channels?state=unopened', {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- credentials: 'same-origin',
- })
- .then((response) => response.json())
- .then(successCb);
- };
-
- render() {
- const { visible, unopenedChannels } = this.state;
- if (visible && unopenedChannels.some((channel) => !channel.notified)) {
- const message = unopenedChannels.map((channel) => {
- if (channel.notified) return null;
- return (
-
- );
- });
-
- return (
-
- {message}
-
- );
- }
-
- return '';
- }
-}
-
-export function getUnopenedChannels() {
- if (window.frameElement) {
- return;
- }
- render(
- ,
- document.getElementById('message-notice'),
- );
-}
diff --git a/app/javascript/utilities/connect/index.js b/app/javascript/utilities/connect/index.js
deleted file mode 100644
index 00097da1e..000000000
--- a/app/javascript/utilities/connect/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './getUnopenedChannels';
-export * from './pusher';
diff --git a/app/javascript/utilities/connect/newMessageNotify.js b/app/javascript/utilities/connect/newMessageNotify.js
deleted file mode 100644
index 493b8d902..000000000
--- a/app/javascript/utilities/connect/newMessageNotify.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export function notifyUser() {
- modifyTitle();
-}
-
-const modifyTitle = () => {
- const oldTitle = document.title;
- const titleAlert = setInterval(() => {
- if (document.title === oldTitle) document.title = 'New Message 👋';
- else document.title = oldTitle;
- }, 2000);
-
- setTimeout(() => {
- clearInterval(titleAlert);
- document.title = oldTitle;
- }, 12000);
-};
diff --git a/app/javascript/utilities/connect/pusher.js b/app/javascript/utilities/connect/pusher.js
deleted file mode 100644
index b97e3d09b..000000000
--- a/app/javascript/utilities/connect/pusher.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// import Pusher from 'pusher-js';
-
-export function setupPusher(key, callbackObjects) {
- return import('pusher-js').then((_) => {
- const {
- pusher = new Pusher(key, {
- authEndpoint: '/pusher/auth',
- auth: {
- headers: {
- 'X-CSRF-Token': window.csrfToken,
- },
- },
- cluster: 'us2',
- encrypted: true,
- }),
- } = window;
-
- window.pusher = pusher;
-
- const channel = pusher.subscribe(callbackObjects.channelId.toString());
- channel.bind('message-created', callbackObjects.messageCreated);
- channel.bind('message-deleted', callbackObjects.messageDeleted);
- channel.bind('message-edited', callbackObjects.messageEdited);
- channel.bind('mentioned', callbackObjects.mentioned);
- channel.bind('message-opened', callbackObjects.messageOpened);
- channel.bind('channel-cleared', callbackObjects.channelCleared);
- channel.bind('user-banned', callbackObjects.redactUserMessages);
-
- channel.bind('pusher:subscription_error', callbackObjects.channelError);
-
- return channel;
- });
-}
diff --git a/app/javascript/utilities/getUserDataAndCsrfToken.js b/app/javascript/utilities/getUserDataAndCsrfToken.js
new file mode 100644
index 000000000..7f4cfc619
--- /dev/null
+++ b/app/javascript/utilities/getUserDataAndCsrfToken.js
@@ -0,0 +1,35 @@
+export function getCsrfToken() {
+ const element = document.querySelector(`meta[name='csrf-token']`);
+
+ return element !== null ? element.content : undefined;
+}
+
+const getWaitOnUserDataHandler = ({ resolve, reject, waitTime = 20 }) => {
+ let totalTimeWaiting = 0;
+
+ return function waitingOnUserData() {
+ if (totalTimeWaiting === 3000) {
+ reject(new Error("Couldn't find user data on page."));
+ return;
+ }
+
+ const csrfToken = getCsrfToken(document);
+ const { user } = document.body.dataset;
+
+ if (user && csrfToken !== undefined) {
+ const currentUser = JSON.parse(user);
+
+ resolve({ currentUser, csrfToken });
+ return;
+ }
+
+ totalTimeWaiting += waitTime;
+ setTimeout(waitingOnUserData, waitTime);
+ };
+};
+
+export function getUserDataAndCsrfToken() {
+ return new Promise((resolve, reject) => {
+ getWaitOnUserDataHandler({ resolve, reject })();
+ });
+}
diff --git a/app/lib/constants/role.rb b/app/lib/constants/role.rb
index 7959da71a..85fe881f9 100644
--- a/app/lib/constants/role.rb
+++ b/app/lib/constants/role.rb
@@ -16,7 +16,6 @@ module Constants
"Resource Admin: Badge",
"Resource Admin: BadgeAchievement",
"Resource Admin: Broadcast",
- "Resource Admin: ChatChannel",
"Resource Admin: Comment",
"Resource Admin: Config",
"Resource Admin: DisplayAd",
diff --git a/app/mailers/notify_mailer.rb b/app/mailers/notify_mailer.rb
index 46ba9e1ce..d79702c7d 100644
--- a/app/mailers/notify_mailer.rb
+++ b/app/mailers/notify_mailer.rb
@@ -85,28 +85,6 @@ class NotifyMailer < ApplicationMailer
mail(to: @user.email, subject: params[:email_subject])
end
- def new_message_email
- @message = params[:message]
- @user = @message.direct_receiver
- subject = "#{@message.user.name} just messaged you"
- @unsubscribe = generate_unsubscribe_token(@user.id, :email_connect_messages)
-
- mail(to: @user.email, subject: subject)
- end
-
- def channel_invite_email
- @membership = params[:membership]
- @inviter = params[:inviter]
-
- subject = if @membership.role == "mod"
- "You are invited to the #{@membership.chat_channel.channel_name} channel as moderator."
- else
- "You are invited to the #{@membership.chat_channel.channel_name} channel."
- end
-
- mail(to: @membership.user.email, subject: subject)
- end
-
def account_deleted_email
@name = params[:name]
@@ -142,7 +120,6 @@ class NotifyMailer < ApplicationMailer
def tag_moderator_confirmation_email
@user = params[:user]
@tag = params[:tag]
- @channel_slug = params[:channel_slug]
subject = "Congrats! You're the moderator for ##{@tag.name}"
mail(to: @user.email, subject: subject)
diff --git a/app/models/admin_menu.rb b/app/models/admin_menu.rb
index 52353e168..8b9693071 100644
--- a/app/models/admin_menu.rb
+++ b/app/models/admin_menu.rb
@@ -3,7 +3,7 @@
class AdminMenu
# On second level navigation with more children, we reference the default tabs controller. i.e look at developer_tools
# rubocop:disable Metrics/BlockLength
- FEATURE_FLAGS = %i[profile_admin data_update_scripts connect].freeze
+ FEATURE_FLAGS = %i[profile_admin data_update_scripts].freeze
ITEMS = Menu.define do
scope :people, "group-2-line", [
@@ -56,7 +56,6 @@ class AdminMenu
]
scope :apps, "palette-line", [
- item(name: "chat channels", visible: false),
item(name: "consumer apps", controller: "consumer_apps"),
item(name: "listings"),
item(name: "welcome"),
@@ -107,11 +106,6 @@ class AdminMenu
data_update_script_hash[:visible] = true
end
- if FeatureFlag.enabled?(:connect)
- connect_hash = menu_items.dig(:apps, :children).detect { |item| item[:controller] = "chat_channels" }
- connect_hash[:visible] = true
- end
-
menu_items
end
end
diff --git a/app/models/chat_channel.rb b/app/models/chat_channel.rb
deleted file mode 100644
index afab7aa9c..000000000
--- a/app/models/chat_channel.rb
+++ /dev/null
@@ -1,189 +0,0 @@
-class ChatChannel < ApplicationRecord
- attr_accessor :current_user, :usernames_string, :username_string
-
- resourcify
-
- CHANNEL_TYPES = %w[open invite_only direct].freeze
- STATUSES = %w[active inactive blocked].freeze
-
- has_many :messages, dependent: :destroy
- has_many :chat_channel_memberships, dependent: :destroy
- has_many :users, through: :chat_channel_memberships
-
- has_many :active_memberships, lambda {
- where status: "active"
- }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
- has_many :pending_memberships, lambda {
- where status: "pending"
- }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
- has_many :rejected_memberships, lambda {
- where status: "rejected"
- }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
- has_many :mod_memberships, -> { where role: "mod" }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
- has_many :requested_memberships, lambda {
- where status: "joining_request"
- }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
- has_many :active_users, through: :active_memberships, class_name: "User", source: :user
- has_many :pending_users, through: :pending_memberships, class_name: "User", source: :user
- has_many :rejected_users, through: :rejected_memberships, class_name: "User", source: :user
- has_many :mod_users, through: :mod_memberships, class_name: "User", source: :user
-
- has_one :mod_tag, class_name: "Tag", foreign_key: "mod_chat_channel_id",
- inverse_of: :mod_chat_channel, dependent: :nullify
-
- validates :channel_type, presence: true, inclusion: { in: CHANNEL_TYPES }
- validates :status, presence: true, inclusion: { in: STATUSES }
- validates :slug, uniqueness: true, presence: true
- validates :description, length: { maximum: 200 }, allow_blank: true
- validates :channel_name, presence: true
-
- def open?
- channel_type == "open"
- end
-
- def direct?
- channel_type == "direct"
- end
-
- def invite_only?
- channel_type == "invite_only"
- end
-
- def group?
- channel_type != "direct"
- end
-
- def private_org_channel?
- channel_name.to_s.ends_with?(" private group chat") # e.g. @devteam private group chat
- end
-
- def clear_channel
- messages.destroy_all
- Pusher.trigger(pusher_channels, "channel-cleared", { chat_channel_id: id }.to_json)
- true
- rescue Pusher::Error => e
- logger.info "PUSHER ERROR: #{e.message}"
- end
-
- def has_member?(user)
- active_users.include?(user)
- end
-
- def last_opened_at(user = nil)
- user ||= current_user
- chat_channel_memberships.where(user_id: user.id).pick(:last_opened_at)
- end
-
- def add_users(users)
- now = Time.current
- users_params = Array.wrap(users).map do |user|
- { user_id: user.id, chat_channel_id: id, created_at: now, updated_at: now }
- end
-
- # memberships that are not unique are automatically skipped
- ChatChannelMembership.insert_all(
- users_params,
- unique_by: :index_chat_channel_memberships_on_chat_channel_id_and_user_id,
- )
- end
-
- def invite_users(users:, membership_role: "member", inviter: nil)
- invitation_sent = 0
- Array(users).each do |user|
- existing_membership = ChatChannelMembership.find_by(user_id: user.id, chat_channel_id: id)
- if existing_membership.present? && %w[active pending].exclude?(existing_membership.status)
- if existing_membership.update(status: "pending", role: membership_role)
- NotifyMailer.with(membership: existing_membership, inviter: inviter).channel_invite_email.deliver_later
- invitation_sent += 1
- end
- else
- membership = ChatChannelMembership.create(user_id: user.id, chat_channel_id: id, role: membership_role,
- status: "pending")
- if membership.persisted?
- NotifyMailer.with(membership: membership, inviter: inviter).channel_invite_email.deliver_later
- invitation_sent += 1
- end
- end
- end
- invitation_sent
- end
-
- def remove_user(user)
- chat_channel_memberships.destroy_by(user: user)
- end
-
- def pusher_channels
- # TODO: use something more unique here (uuid?) rather than just id.
- if invite_only?
- "private-channel--#{ChatChannel.urlsafe_encoded_app_domain}-#{id}"
- elsif open?
- "open-channel--#{ChatChannel.urlsafe_encoded_app_domain}-#{id}"
- else
- chat_channel_memberships.pluck(:user_id).map { |id| ChatChannel.pm_notifications_channel(id) }
- end
- end
-
- def channel_users_ids
- chat_channel_memberships.pluck(:user_id)
- end
-
- def adjusted_slug(user = nil, caller_type = "receiver")
- user ||= current_user
- if direct? && caller_type == "receiver"
- cleaned_slug = slug.gsub("/#{user.username}", "").gsub("#{user.username}/", "")
- "@#{cleaned_slug}"
- elsif caller_type == "sender"
- "@#{user.username}"
- else
- slug
- end
- end
-
- def channel_human_names
- active_memberships
- .order(last_opened_at: :desc).limit(5).includes(:user).map do |membership|
- membership.user.name
- end
- end
-
- def channel_users
- obj = {}
-
- relation = active_memberships.includes(:user).select(:id, :user_id, :last_opened_at)
-
- relation.order(last_opened_at: :desc).each do |membership|
- obj[membership.user.username] = user_obj(membership)
- end
-
- obj
- end
-
- def channel_mod_ids
- mod_users.ids
- end
-
- def pending_users_select_fields
- pending_users.select(:id, :username, :name, :updated_at)
- end
-
- def self.pm_notifications_channel(user_id)
- "private-message-notifications--#{urlsafe_encoded_app_domain}-#{user_id}"
- end
-
- def self.urlsafe_encoded_app_domain
- Base64.urlsafe_encode64(ApplicationConfig["APP_DOMAIN"])
- end
-
- private
-
- def user_obj(membership)
- {
- profile_image: Images::Profile.call(membership.user.profile_image_url, length: 90),
- darker_color: membership.user.decorate.darker_color,
- name: membership.user.name,
- last_opened_at: membership.last_opened_at,
- username: membership.user.username,
- id: membership.user_id
- }
- end
-end
diff --git a/app/models/chat_channel_membership.rb b/app/models/chat_channel_membership.rb
deleted file mode 100644
index 6396dd36c..000000000
--- a/app/models/chat_channel_membership.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-class ChatChannelMembership < ApplicationRecord
- attr_accessor :invitation_usernames
-
- ROLES = %w[member mod].freeze
- STATUSES = %w[active inactive pending rejected left_channel removed_from_channel joining_request].freeze
-
- belongs_to :chat_channel
- belongs_to :user
-
- validates :chat_channel_id, presence: true, uniqueness: { scope: :user_id }
- validates :role, inclusion: { in: ROLES }
- validates :status, inclusion: { in: STATUSES }
- validates :user_id, presence: true
-
- validate :permission
-
- delegate :channel_type, to: :chat_channel
-
- scope :eager_load_serialized_data, -> { includes(:user, :channel) }
- scope :filter_by_status, ->(status) { where status: status }
- scope :filter_by_role, ->(role) { where role: role }
-
- def channel_last_message_at
- chat_channel.last_message_at
- end
-
- def channel_status
- chat_channel.status
- end
-
- def channel_text
- parsed_channel_name = chat_channel.channel_name&.gsub("chat between", "")&.gsub("and", "")
- "#{parsed_channel_name} #{chat_channel.slug} #{chat_channel.channel_human_names.join(' ')}"
- end
-
- def channel_name
- if chat_channel.channel_type == "direct"
- "@#{other_user&.username}"
- else
- chat_channel.channel_name
- end
- end
-
- def channel_image
- if chat_channel.channel_type == "direct"
- Images::Profile.call(other_user.profile_image_url, length: 90)
- else
- ActionController::Base.helpers.asset_path("organization.svg")
- end
- end
-
- def channel_messages_count
- chat_channel.messages.size
- end
-
- def channel_username
- other_user&.username if chat_channel.channel_type == "direct"
- end
-
- def channel_modified_slug
- if chat_channel.channel_type == "direct"
- "@#{other_user&.username}"
- else
- chat_channel.slug
- end
- end
-
- def viewable_by
- user_id
- end
-
- def channel_discoverable
- chat_channel.discoverable
- end
-
- private
-
- def channel_color
- if chat_channel.channel_type == "direct"
- other_user&.decorate&.darker_color
- else
- "#111111"
- end
- end
-
- def other_user
- chat_channel.users.where.not(id: user_id).first
- end
-
- def permission
- return unless chat_channel
- return unless chat_channel.direct? && chat_channel.slug.split("/").exclude?(user.username)
-
- errors.add(:user_id, "is not allowed in chat")
-
- # To be possibly implemented in future
- # if chat_channel.users.size > 128
- # errors.add(:base, "too many members in channel")
- # end
- end
-end
diff --git a/app/models/follow.rb b/app/models/follow.rb
index b4de39690..28d56ceac 100644
--- a/app/models/follow.rb
+++ b/app/models/follow.rb
@@ -30,9 +30,7 @@ class Follow < ApplicationRecord
column_names: COUNTER_CULTURE_COLUMNS_NAMES
before_save :calculate_points
after_create :send_email_notification
- before_destroy :modify_chat_channel_status
after_save :touch_follower
- after_create_commit :create_chat_channel
validates :blocked, inclusion: { in: [true, false] }
validates :followable_id, presence: true
@@ -55,23 +53,9 @@ class Follow < ApplicationRecord
follower.touch(:updated_at, :last_followed_at)
end
- def create_chat_channel
- return unless followable_type == "User"
-
- Follows::CreateChatChannelWorker.perform_async(id)
- end
-
def send_email_notification
return unless followable.instance_of?(User) && followable.email?
Follows::SendEmailNotificationWorker.perform_async(id)
end
-
- def modify_chat_channel_status
- return unless followable_type == "User" && followable.following?(follower)
-
- channel = follower.chat_channels
- .find_by("slug LIKE ? OR slug like ?", "%/#{followable.username}%", "%#{followable.username}/%")
- channel&.update(status: "inactive")
- end
end
diff --git a/app/models/listing.rb b/app/models/listing.rb
index adadc1170..a7f2b6de7 100644
--- a/app/models/listing.rb
+++ b/app/models/listing.rb
@@ -2,6 +2,7 @@ class Listing < ApplicationRecord
# We used to use both "classified listing" and "listing" throughout the app.
# We standardized on the latter, but keeping the table name was easier.
self.table_name = "classified_listings"
+ self.ignored_columns = %w[contact_via_connect].freeze
include PgSearch::Model
diff --git a/app/models/message.rb b/app/models/message.rb
deleted file mode 100644
index 47c1cc325..000000000
--- a/app/models/message.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-class Message < ApplicationRecord
- belongs_to :user
- belongs_to :chat_channel
-
- validates :message_html, presence: true
- validates :message_markdown, presence: true, length: { maximum: 1024 }
- validate :channel_permission
-
- before_validation :determine_user_validity
- before_validation :evaluate_markdown
- after_create :send_email_if_appropriate
- after_create :update_chat_channel_last_message_at
- after_create :update_all_has_unopened_messages_statuses
-
- def preferred_user_color
- color_options = [user.setting.brand_color1 || "#000000", user.setting.brand_color2 || "#000000"]
- Color::CompareHex.new(color_options).brightness(0.9)
- end
-
- def direct_receiver
- return if chat_channel.group?
-
- chat_channel.users.where.not(id: user.id).first
- end
-
- def left_channel?
- chat_action == "removed_from_channel" || chat_action == "left_channel"
- end
-
- private
-
- def update_chat_channel_last_message_at
- chat_channel.touch(:last_message_at)
- end
-
- def update_all_has_unopened_messages_statuses
- return if left_channel?
-
- chat_channel
- .chat_channel_memberships
- .where("last_opened_at < ?", 10.seconds.ago)
- .where.not(user_id: user_id)
- .update_all(has_unopened_messages: true)
- end
-
- def evaluate_markdown
- html = MarkdownProcessor::Parser.new(message_markdown).evaluate_markdown
- html = target_blank_links(html)
- html = append_rich_links(html)
- html = wrap_mentions_with_links(html)
- html = handle_slash_command(html)
- self.message_html = html
- end
-
- def wrap_mentions_with_links(html)
- return unless html
-
- html_doc = Nokogiri::HTML(html)
-
- # looks for nodes that isn't , , and contains "@"
- targets = html_doc.xpath('//html/body/*[not (self::code) and not(self::a) and contains(., "@")]').to_a
-
- # A Queue system to look for and replace possible usernames
- until targets.empty?
- node = targets.shift
-
- # only focus on portion of text with "@"
- node.xpath("text()[contains(.,'@')]").each do |el|
- el.replace(el.text.gsub(/\B@[a-z0-9_-]+/i) { |text| user_link_if_exists(text) })
- end
-
- # enqueue children that has @ in it's text
- children = node.xpath('*[not(self::code) and not(self::a) and contains(., "@")]').to_a
- targets.concat(children)
- end
-
- if html_doc.at_css("body")
- html_doc.at_css("body").inner_html
- else
- html_doc.to_html
- end
- end
-
- def user_link_if_exists(mention)
- username = mention.delete("@").downcase
- if User.find_by(username: username) && chat_channel.group?
- <<~HTML
- @#{username}
- HTML
- elsif username == "all" && chat_channel.channel_type == "invite_only"
- <<~HTML
- @#{username}
- HTML
- else
- mention
- end
- end
-
- def target_blank_links(html)
- return html if html.blank?
-
- html.gsub("
- #{"
" if article.main_image.present?}
- #{article.title}
- #{article.cached_user.name}・#{article.readable_publish_date || 'Draft Post'}
- ".html_safe
- elsif (tag = rich_link_tag(anchor))
- html += "
-
- #{" " if tag.badge_id.present?}
- ##{tag.name}
-
- ".html_safe
- elsif (user = rich_user_link(anchor))
- html += "
-
-
- #{user.name}
-
- ".html_safe
- elsif anchor["href"].include?("https://www.figma.com/file/") # Proof of concept
- html += "
- Figma File
- ".html_safe
- elsif anchor["href"].starts_with?("https://docs.google.com/") # Proof of concept
- html += "
- Google Docs
- ".html_safe
- elsif anchor["href"].starts_with?("https://remote-hands.glitch.me/") # Proof of concept
- html += "
- Glitch ~ Remote Hands
- ".html_safe
- end
- end
- html
- end
- # rubocop:enable Layout/LineLength
- # rubocop:enable Metrics/BlockLength
- # rubocop:enable Rails/OutputSafety
-
- # rubocop:disable Rails/OutputSafety
- def handle_slash_command(html)
- response = case html.to_s.strip
- when "/play codenames
" # proof of concept
- "
-
- Let's play codenames 🤐
-
- ".html_safe
- end
- html = response if response
- html
- end
- # rubocop:enable Rails/OutputSafety
-
- def cl_path(img_src)
- Images::Optimizer.call(img_src, width: 725)
- end
-
- def determine_user_validity
- return unless chat_channel
-
- user_ok = chat_channel.status == "active" && (chat_channel.has_member?(user) || chat_channel.channel_type == "open")
- errors.add(:base, "You are not a participant of this chat channel.") unless user_ok
- end
-
- def channel_permission
- errors.add(:base, "Must be part of channel.") if chat_channel_id.blank?
-
- channel = chat_channel || ChatChannel.find(chat_channel_id)
- return if channel.open?
-
- errors.add(:base, "You are not a participant of this chat channel.") unless channel.has_member?(user)
- errors.add(:base, "Something went wrong") if channel.status == "blocked"
- end
-
- def rich_link_article(link)
- return unless link["href"].include?("//#{Settings::General.app_domain}/") && link["href"].split("/")[4]
-
- Article.find_by(slug: link["href"].split("/")[4].split("?")[0])
- end
-
- def rich_link_tag(link)
- return unless link["href"].include?("//#{Settings::General.app_domain}/t/")
-
- Tag.find_by(name: link["href"].split("/t/")[1].split("/")[0])
- end
-
- def rich_user_link(link)
- return unless link["href"].include?("//#{Settings::General.app_domain}/")
-
- User.find_by(username: link["href"].split("/")[3].split("/")[0])
- end
-
- def send_email_if_appropriate
- recipient = direct_receiver
- return if !chat_channel.direct? ||
- recipient.updated_at > 1.hour.ago ||
- recipient.chat_channel_memberships.order(last_opened_at: :desc)
- .first.last_opened_at > 15.hours.ago ||
- chat_channel.last_message_at > 30.minutes.ago ||
- recipient.notification_setting.email_connect_messages == false
-
- NotifyMailer.with(message: self).new_message_email.deliver_now
- end
-end
diff --git a/app/models/organization_membership.rb b/app/models/organization_membership.rb
index 088e4a040..4752cad57 100644
--- a/app/models/organization_membership.rb
+++ b/app/models/organization_membership.rb
@@ -10,31 +10,8 @@ class OrganizationMembership < ApplicationRecord
after_create :update_user_organization_info_updated_at
after_destroy :update_user_organization_info_updated_at
- after_save :upsert_chat_channel_membership
def update_user_organization_info_updated_at
user.touch(:organization_info_updated_at)
end
-
- private
-
- def upsert_chat_channel_membership
- return if type_of_user == "guest"
-
- role = type_of_user == "admin" ? "mod" : "member"
- name = "@#{organization.slug} private group chat"
- channel = ChatChannel.find_by(channel_name: name)
-
- channel ||= ChatChannels::FindOrCreate.call("invite_only", "#{organization.slug}-private-group-chat", name)
-
- add_chat_channel_membership(user, channel, role)
- end
-
- def add_chat_channel_membership(user, channel, role)
- return unless FeatureFlag.enabled?(:connect)
-
- membership = ChatChannelMembership.find_or_initialize_by(user_id: user.id, chat_channel_id: channel.id)
- membership.role = role
- membership.save
- end
end
diff --git a/app/models/role.rb b/app/models/role.rb
index 985351a39..6d3ec6eb5 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -1,7 +1,6 @@
class Role < ApplicationRecord
ROLES = %w[
admin
- chatroom_beta_tester
codeland_admin
comment_suspended
mod_relations_admin
diff --git a/app/models/tag.rb b/app/models/tag.rb
index fd94db1d6..27882f490 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -1,4 +1,6 @@
class Tag < ActsAsTaggableOn::Tag
+ self.ignored_columns = %w[mod_chat_channel_id].freeze
+
attr_accessor :points, :tag_moderator_id, :remove_moderator_id
acts_as_followable
@@ -12,7 +14,6 @@ class Tag < ActsAsTaggableOn::Tag
HEX_COLOR_REGEXP = /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/
belongs_to :badge, optional: true
- belongs_to :mod_chat_channel, class_name: "ChatChannel", optional: true
has_many :articles, through: :taggings, source: :taggable, source_type: "Article"
diff --git a/app/models/user.rb b/app/models/user.rb
index 18a9dce0c..659460723 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -68,8 +68,6 @@ class User < ApplicationRecord
inverse_of: :blocked, dependent: :delete_all
has_many :blocker_blocks, class_name: "UserBlock", foreign_key: :blocker_id,
inverse_of: :blocker, dependent: :delete_all
- has_many :chat_channel_memberships, dependent: :destroy
- has_many :chat_channels, through: :chat_channel_memberships
has_many :collections, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :created_podcasts, class_name: "Podcast", foreign_key: :creator_id, inverse_of: :creator, dependent: :nullify
@@ -85,7 +83,6 @@ class User < ApplicationRecord
has_many :identities_enabled, -> { enabled }, class_name: "Identity", inverse_of: false
has_many :listings, dependent: :destroy
has_many :mentions, dependent: :destroy
- has_many :messages, dependent: :destroy
has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy
has_many :notification_subscriptions, dependent: :destroy
has_many :notifications, dependent: :destroy
@@ -598,10 +595,6 @@ class User < ApplicationRecord
self.old_old_username = old_username
self.old_username = username_was
- chat_channels.find_each do |channel|
- channel.slug = channel.slug.gsub(username_was, username)
- channel.save
- end
articles.find_each do |article|
article.path = article.path.gsub(username_was, username)
article.save
diff --git a/app/models/users/notification_setting.rb b/app/models/users/notification_setting.rb
index c70c7b7fc..ff06776c3 100644
--- a/app/models/users/notification_setting.rb
+++ b/app/models/users/notification_setting.rb
@@ -1,6 +1,7 @@
module Users
class NotificationSetting < ApplicationRecord
self.table_name_prefix = "users_"
+ self.ignored_columns = %w[email_connect_messages]
belongs_to :user, touch: true
diff --git a/app/policies/chat_channel_membership_policy.rb b/app/policies/chat_channel_membership_policy.rb
deleted file mode 100644
index c2bbb0577..000000000
--- a/app/policies/chat_channel_membership_policy.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class ChatChannelMembershipPolicy < ApplicationPolicy
- def update?
- record.present? && user.id == record.user_id
- end
-
- def find_by_chat_channel_id?
- record.present? && user.id == record.user_id
- end
-
- def destroy?
- record.present? && user.id == record.user_id
- end
-
- def leave_membership?
- record.present? && user.id == record.user_id
- end
-
- def update_membership?
- record.present? && user.id == record.user_id
- end
-
- def invitation?
- record.present? && user.id == record.user_id
- end
-
- def chat_channel_info?
- record.present? && user.id == record.user_id
- end
-
- def request_details?
- record.present? && user.id == record.user_id
- end
-end
diff --git a/app/policies/chat_channel_policy.rb b/app/policies/chat_channel_policy.rb
deleted file mode 100644
index 1cd1d9774..000000000
--- a/app/policies/chat_channel_policy.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-class ChatChannelPolicy < ApplicationPolicy
- def index?
- user
- end
-
- def create?
- true
- end
-
- def update?
- user_can_edit_channel?
- end
-
- def moderate?
- !user_suspended? && codeland_admin?
- end
-
- def show?
- user_part_of_channel_or_open
- end
-
- def open?
- user_part_of_channel
- end
-
- def permitted_attributes
- %i[channel_name slug command description discoverable]
- end
-
- def create_chat?
- true
- end
-
- def block_chat?
- user_part_of_channel && channel_direct?
- end
-
- def update_channel?
- user_can_edit_channel?
- end
-
- def join_channel_invitation?
- record.present? && user.id
- end
-
- def set_channel?
- user_can_edit_channel?
- end
-
- def joining_invitation_response?
- record.present?
- end
-
- def create_channel?
- record.present? && user.tag_moderator?
- end
-
- private
-
- def user_can_edit_channel?
- record.present? &&
- (user.has_role?(:super_admin) || record.channel_mod_ids.include?(user.id)) &&
- !record.private_org_channel?
- end
-
- def user_part_of_channel_or_open
- record.present? && (record.channel_type == "open" || record.has_member?(user))
- end
-
- def user_part_of_channel
- record.present? && record.has_member?(user)
- end
-
- def channel_direct?
- record.channel_type == "direct"
- end
-
- def codeland_admin?
- user.has_role?(:codeland_admin)
- end
-end
diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb
index 5758f6afe..aab398b9d 100644
--- a/app/policies/user_policy.rb
+++ b/app/policies/user_policy.rb
@@ -15,7 +15,6 @@ class UserPolicy < ApplicationPolicy
email_badge_notifications
email_comment_notifications
email_community_mod_newsletter
- email_connect_messages
email_digest_periodic
email_follower_notifications
email_membership_newsletter
diff --git a/app/serializers/search/chat_channel_membership_serializer.rb b/app/serializers/search/chat_channel_membership_serializer.rb
deleted file mode 100644
index 41b7f2c80..000000000
--- a/app/serializers/search/chat_channel_membership_serializer.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Search
- class ChatChannelMembershipSerializer < ApplicationSerializer
- attributes :id, :status, :viewable_by, :chat_channel_id, :last_opened_at,
- :channel_text, :channel_last_message_at, :channel_status,
- :channel_type, :channel_username, :channel_name, :channel_image,
- :channel_modified_slug, :channel_discoverable,
- :channel_messages_count
- end
-end
diff --git a/app/serializers/search/listing_serializer.rb b/app/serializers/search/listing_serializer.rb
index 918692644..ee0291027 100644
--- a/app/serializers/search/listing_serializer.rb
+++ b/app/serializers/search/listing_serializer.rb
@@ -4,7 +4,6 @@ module Search
:body_markdown,
:bumped_at,
:category,
- :contact_via_connect,
:expires_at,
:originally_published_at,
:location,
diff --git a/app/services/chat_channels/create_with_users.rb b/app/services/chat_channels/create_with_users.rb
deleted file mode 100644
index 14749f86a..000000000
--- a/app/services/chat_channels/create_with_users.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-module ChatChannels
- class CreateWithUsers
- def initialize(users: [], channel_type: "direct", contrived_name: "New Channel", membership_role: "member")
- @users = users
- @channel_type = channel_type
- @contrived_name = contrived_name
- @membership_role = membership_role
- end
-
- def self.call(...)
- new(...).call
- end
-
- def call
- raise "Invalid direct channel" if invalid_direct_channel?(users, channel_type)
-
- usernames = users.map(&:username).sort
- slug = if channel_type == "direct"
- usernames.join("/")
- else
- "#{contrived_name.to_s.parameterize}-#{rand(100_000).to_s(26)}"
- end
-
- channel = ChatChannels::FindOrCreate.call(channel_type, slug, verify_contrived_name(usernames))
- if channel_type == "direct"
- channel.add_users(users)
- else
- channel.invite_users(users: users, membership_role: membership_role)
- end
- channel
- end
-
- private
-
- attr_reader :users, :channel_type, :membership_role, :contrived_name
-
- def invalid_direct_channel?(users, channel_type)
- (users.size != 2 || users.map(&:id).uniq.count < 2) && channel_type == "direct"
- end
-
- def verify_contrived_name(usernames)
- channel_type == "direct" ? "Direct chat between #{usernames.join(' and ')}" : contrived_name
- end
- end
-end
diff --git a/app/services/chat_channels/find_or_create.rb b/app/services/chat_channels/find_or_create.rb
deleted file mode 100644
index e98c31bd8..000000000
--- a/app/services/chat_channels/find_or_create.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module ChatChannels
- class FindOrCreate
- def initialize(channel_type, slug, contrived_name)
- @channel_type = channel_type
- @slug = slug
- @contrived_name = contrived_name
- end
-
- def self.call(...)
- new(...).call
- end
-
- def call
- channel = ChatChannel.find_by(slug: slug)
- if channel
- raise "Blocked channel" if channel.status == "blocked"
-
- channel.update(status: "active")
- else
- channel = ChatChannel.create(
- channel_type: channel_type,
- channel_name: contrived_name,
- slug: slug,
- last_message_at: 1.week.ago,
- status: "active",
- )
- end
- channel
- end
-
- private
-
- attr_reader :channel_type, :slug, :contrived_name
- end
-end
diff --git a/app/services/chat_channels/send_invitation.rb b/app/services/chat_channels/send_invitation.rb
deleted file mode 100644
index a2a9cdd9c..000000000
--- a/app/services/chat_channels/send_invitation.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module ChatChannels
- class SendInvitation
- attr_accessor :invitation_usernames, :current_user, :chat_channel
-
- def initialize(invitation_usernames, current_user, chat_channel)
- @invitation_usernames = invitation_usernames
- @current_user = current_user
- @chat_channel = chat_channel
- end
-
- def self.call(...)
- new(...).call
- end
-
- def call
- if invitation_usernames.present?
- usernames = invitation_usernames.split(",").map do |username|
- username.strip.delete("@")
- end
- users = User.where(username: usernames)
- invitations_sent = chat_channel.invite_users(users: users, membership_role: "member", inviter: current_user)
- message = if invitations_sent.zero?
- "No invitations sent. Check for username typos."
- else
- "#{invitations_sent} #{'invitation'.pluralize(invitations_sent)} sent."
- end
- end
- message
- end
- end
-end
diff --git a/app/services/chat_channels/update_channel.rb b/app/services/chat_channels/update_channel.rb
deleted file mode 100644
index f82ee6fc0..000000000
--- a/app/services/chat_channels/update_channel.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module ChatChannels
- class UpdateChannel
- attr_accessor :chat_channel, :params
-
- def initialize(chat_channel, params)
- @chat_channel = chat_channel
- @params = params
- end
-
- def self.call(...)
- new(...).call
- end
-
- def call
- chat_channel.update(params)
- chat_channel
- end
- end
-end
diff --git a/app/services/moderator/banish_user.rb b/app/services/moderator/banish_user.rb
index c8b88c81b..31cb7edec 100644
--- a/app/services/moderator/banish_user.rb
+++ b/app/services/moderator/banish_user.rb
@@ -21,7 +21,6 @@ module Moderator
delete_user_activity
delete_comments
delete_articles
- Users::CleanupChatChannels.call(user)
reassign_and_bust_username
delete_vomit_reactions
end
diff --git a/app/services/moderator/merge_user.rb b/app/services/moderator/merge_user.rb
index 3e7d8af52..31c47f42c 100644
--- a/app/services/moderator/merge_user.rb
+++ b/app/services/moderator/merge_user.rb
@@ -34,7 +34,7 @@ module Moderator
handle_identities
merge_content
merge_follows
- merge_chat_mentions
+ merge_mentions
merge_profile
update_social
Users::DeleteWorker.new.perform(@delete_user.id, true)
@@ -80,18 +80,16 @@ module Moderator
@keep_user.update_columns(created_at: @delete_user.created_at) if @delete_user.created_at < @keep_user.created_at
end
- def merge_chat_mentions
- any_memberships = @delete_user.chat_channel_memberships.any?
- @delete_user.chat_channel_memberships.update_all(user_id: @keep_user.id) if any_memberships
- @delete_user.mentions.update_all(user_id: @keep_user.id) if @delete_user.mentions.any?
- end
-
def merge_follows
@delete_user.follows&.update_all(follower_id: @keep_user.id) if @delete_user.follows.any?
@delete_user_followers = Follow.followable_user(@delete_user.id)
@delete_user_followers.update_all(followable_id: @keep_user.id) if @delete_user_followers.any?
end
+ def merge_mentions
+ @delete_user.mentions.update_all(user_id: @keep_user.id) if @delete_user.mentions.any?
+ end
+
def merge_content
merge_reactions if @delete_user.reactions.any?
merge_comments if @delete_user.comments.any?
diff --git a/app/services/search/chat_channel_membership.rb b/app/services/search/chat_channel_membership.rb
deleted file mode 100644
index 6f7d93de6..000000000
--- a/app/services/search/chat_channel_membership.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-module Search
- class ChatChannelMembership
- ATTRIBUTES = %w[
- chat_channel_memberships.id
- chat_channel_memberships.chat_channel_id
- chat_channel_memberships.last_opened_at
- chat_channel_memberships.status
- chat_channel_memberships.user_id
- chat_channels.channel_name
- chat_channels.discoverable
- chat_channels.last_message_at
- chat_channels.slug
- chat_channels.status
- users.name
- users.profile_image
- users.username
- ].freeze
- private_constant :ATTRIBUTES
-
- # TODO: @mstruve: When we want to allow people like admins to search ALL
- # memberships this will need to change
- PERMITTED_STATUSES = %w[
- active
- joining_request
- ].freeze
-
- DEFAULT_PER_PAGE = 30
- private_constant :DEFAULT_PER_PAGE
-
- MAX_PER_PAGE = 60 # to avoid querying too many items, we set a maximum amount for a page
- private_constant :MAX_PER_PAGE
-
- def self.search_documents(user_ids:, page: 0, per_page: DEFAULT_PER_PAGE)
- # NOTE: [@rhymes/atsmith813] we should eventually update the frontend
- # to start from page 1
- page = page.to_i + 1
- per_page = [(per_page || DEFAULT_PER_PAGE).to_i, MAX_PER_PAGE].min
-
- relation = ::ChatChannelMembership
- .includes(:user, chat_channel: :messages)
- .where("chat_channel_memberships.status": PERMITTED_STATUSES)
- .where("chat_channel_memberships.user_id": user_ids)
- .select(*ATTRIBUTES)
- .order("chat_channels.last_message_at desc")
-
- results = relation.page(page).per(per_page)
-
- serialize(results)
- end
-
- def self.serialize(results)
- Search::ChatChannelMembershipSerializer
- .new(results, is_collection: true)
- .serializable_hash[:data]
- .pluck(:attributes)
- end
- private_class_method :serialize
- end
-end
diff --git a/app/services/search/listing.rb b/app/services/search/listing.rb
index f1946a7f2..955f160a2 100644
--- a/app/services/search/listing.rb
+++ b/app/services/search/listing.rb
@@ -6,7 +6,6 @@ module Search
bumped_at
cached_tag_list
classified_listing_category_id
- contact_via_connect
expires_at
organization_id
originally_published_at
diff --git a/app/services/tag_moderators/add.rb b/app/services/tag_moderators/add.rb
index 42b3cc663..4c386cb17 100644
--- a/app/services/tag_moderators/add.rb
+++ b/app/services/tag_moderators/add.rb
@@ -15,11 +15,10 @@ module TagModerators
tag = Tag.find(tag_ids[index])
add_tag_mod_role(user, tag)
::TagModerators::AddTrustedRole.call(user)
- add_to_chat_channels(user, tag) if FeatureFlag.enabled?(:connect)
tag.update(supported: true) unless tag.supported?
NotifyMailer
- .with(user: user, tag: tag, channel_slug: chat_channel_slug(tag))
+ .with(user: user, tag: tag)
.tag_moderator_confirmation_email
.deliver_now
end
@@ -29,25 +28,6 @@ module TagModerators
attr_accessor :user_ids, :tag_ids
- def add_to_chat_channels(user, tag)
- user_channels = user.chat_channels
-
- unless user_channels.exists?(slug: "tag-moderators")
- ChatChannel.find_by(slug: "tag-moderators")&.add_users(user)
- end
-
- if tag.mod_chat_channel_id && !user_channels.exists?(id: tag.mod_chat_channel_id)
- ChatChannel.find(tag.mod_chat_channel_id).add_users(user)
- elsif tag.mod_chat_channel_id.blank?
- channel = ChatChannels::CreateWithUsers.call(
- users: ([user] + User.with_role(:mod_relations_admin)).flatten.uniq,
- channel_type: "invite_only",
- contrived_name: "##{tag.name} mods",
- )
- tag.update_column(:mod_chat_channel_id, channel.id)
- end
- end
-
def add_tag_mod_role(user, tag)
unless user.notification_setting.email_tag_mod_newsletter?
user.notification_setting.update(email_tag_mod_newsletter: true)
@@ -63,9 +43,5 @@ module TagModerators
Settings::General.mailchimp_api_key.present? &&
Settings::General.mailchimp_tag_moderators_id.present?
end
-
- def chat_channel_slug(tag)
- tag.mod_chat_channel&.slug
- end
end
end
diff --git a/app/services/user_blocks/channel_handler.rb b/app/services/user_blocks/channel_handler.rb
deleted file mode 100644
index ba525cfe4..000000000
--- a/app/services/user_blocks/channel_handler.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module UserBlocks
- class ChannelHandler
- attr_reader :user_block
-
- def initialize(user_block)
- @user_block = user_block
- end
-
- def get_potential_chat_channel
- blocked_user = User.select(:id, :username).find(user_block.blocked_id)
- blocker = User.select(:id, :username).find(user_block.blocker_id)
- potential_slugs = ["#{blocked_user.username}/#{blocker.username}", "#{blocker.username}/#{blocked_user.username}"]
- blocker.chat_channels.where(slug: potential_slugs, channel_type: "direct").first
- end
-
- def block_chat_channel
- chat_channel = get_potential_chat_channel
- return if chat_channel.blank?
-
- chat_channel.update(status: "blocked")
- chat_channel.chat_channel_memberships.includes([:user]).each do |membership|
- membership.update(status: "left_channel")
- end
- end
-
- def unblock_chat_channel
- chat_channel = get_potential_chat_channel
- return if chat_channel.blank?
-
- chat_channel.update(status: "active")
- chat_channel.chat_channel_memberships.includes([:user]).each do |membership|
- membership.update(status: "active")
- end
- end
- end
-end
diff --git a/app/services/users/cleanup_chat_channels.rb b/app/services/users/cleanup_chat_channels.rb
deleted file mode 100644
index a9c71d8c6..000000000
--- a/app/services/users/cleanup_chat_channels.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module Users
- module CleanupChatChannels
- def self.call(user)
- # We only destroy direct message channels, not open and invite-only ones
- direct_channels = user.chat_channels.where(channel_type: "direct")
- direct_channels.each(&:destroy!)
-
- # Clean up the banished user's remaining channel memberships
- user.reload.chat_channel_memberships.each(&:destroy!)
- end
- end
-end
diff --git a/app/services/users/delete_activity.rb b/app/services/users/delete_activity.rb
index 83054c027..37ebac5d8 100644
--- a/app/services/users/delete_activity.rb
+++ b/app/services/users/delete_activity.rb
@@ -39,8 +39,6 @@ module Users
user.reactions.delete_all
user.follows.delete_all
Follow.followable_user(user.id).delete_all
- user.messages.delete_all
- Users::CleanupChatChannels.call(user)
user.mentions.delete_all
user.badge_achievements.delete_all
user.collections.delete_all
diff --git a/app/views/admin/chat_channels/index.html.erb b/app/views/admin/chat_channels/index.html.erb
deleted file mode 100644
index 610fa7511..000000000
--- a/app/views/admin/chat_channels/index.html.erb
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
Create Channel
- <%= form_for [:admin, ChatChannel.new], html: { class: "inline-form" } do |f| %>
-
- <% end %>
-
-
-
-
- Channels
- <%= search_form_for @q, url: admin_chat_channels_path, class: "form-inline ml-auto" do |f| %>
- <%= f.label :channel_name_cont, "Channel Name", class: "sr-only" %>
- <%= f.search_field :channel_name_cont, placeholder: "Channel Name", class: "form-control mx-3" %>
- <%= f.submit "Search", class: "btn btn-secondary" %>
- <% end %>
-
-
- <%= paginate @group_chat_channels %>
-
-
-
-
- Channel Name
- Users
- Add Users
- Remove User
- <% if current_user.any_admin? %>
- Delete Channel
- <% end %>
-
-
-
- <% @group_chat_channels.each do |channel| %>
-
- <%= channel.channel_name %>
- <%= channel.users.pluck(:username).join(", ") %>
-
- <%= form_for [:admin, channel] do |f| %>
- <%= f.text_field :usernames_string, placeholder: "Usernames to add" %>
- <%= f.submit "Add users", class: "btn btn-secondary p-1 my-1" %>
- <% end %>
-
-
- <%= form_with url: remove_user_admin_chat_channel_url(channel), model: [:admin, channel], method: :delete, local: true do |f| %>
- <%= f.text_field :username_string, placeholder: "Username to remove" %>
- <%= f.submit "Remove user", data: { confirm: "Are you sure you want to remove this user?" }, class: "btn btn-secondary p-1 my-1" %>
- <% end %>
-
- <% if current_user.any_admin? %>
-
- <% if channel.users.count.zero? %>
- <%= link_to "Delete Channel", admin_chat_channel_path(channel), class: "crayons-btn crayons-btn--danger", method: :delete, data: { confirm: "Are you sure?" } %>
- <% else %>
- Cannot delete a channel with users
- <% end %>
-
- <% end %>
-
- <% end %>
-
-
- <%= paginate @group_chat_channels %>
-
diff --git a/app/views/admin/settings/forms/authentication/_apple_auth_provider_settings.html.erb b/app/views/admin/settings/forms/authentication/_apple_auth_provider_settings.html.erb
index 6a8504b85..fa1c02204 100644
--- a/app/views/admin/settings/forms/authentication/_apple_auth_provider_settings.html.erb
+++ b/app/views/admin/settings/forms/authentication/_apple_auth_provider_settings.html.erb
@@ -37,7 +37,7 @@ requires a custom partial
class: "crayons-textfield",
value: Settings::Authentication.apple_pem,
placeholder: Constants::Settings::Authentication::DETAILS[:apple_pem][:placeholder],
- style: "height: 175px;"%>
+ style: "height: 175px;" %>
<%= admin_config_label :apple_team_id %>
diff --git a/app/views/chat_channel_memberships/chat_channel_info.json.jbuilder b/app/views/chat_channel_memberships/chat_channel_info.json.jbuilder
deleted file mode 100644
index 0fb748613..000000000
--- a/app/views/chat_channel_memberships/chat_channel_info.json.jbuilder
+++ /dev/null
@@ -1,20 +0,0 @@
-json.success true
-json.result do
- json.chat_channel do
- json.name @channel.channel_name
- json.type @channel.channel_type
- json.description @channel.description
- json.discoverable @channel.discoverable
- json.slug @channel.slug
- json.status @channel.status
- json.id @channel.id
- end
-
- json.memberships do
- json.active membership_users(@channel.active_memberships)
- json.pending membership_users(@channel.pending_memberships)
- json.requested membership_users(@channel.requested_memberships)
- end
- json.current_membership @membership
- json.invitation_link URL.url(@invitation_link)
-end
diff --git a/app/views/chat_channel_memberships/index.html.erb b/app/views/chat_channel_memberships/index.html.erb
deleted file mode 100644
index 4df967e17..000000000
--- a/app/views/chat_channel_memberships/index.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-<% if flash[:settings_notice] %>
-
- <%= flash[:settings_notice] %>
-
-<% end %>
-
- <% if @pending_invites.any? %>
-
Pending Invitations
-
You may leave a group channel at any point in the future.
- <% @pending_invites.each do |membership| %>
-
-
<%= membership.chat_channel.channel_name %>
-
<%= membership.chat_channel.description %>
- <%= form_for(membership, html: { class: "grid grid-cols-5" }) do |f| %>
- <%= f.hidden_field :user_action, value: "accept" %>
- <%= f.submit "Accept", class: "crayons-btn" %>
- <% end %>
- <%= form_for(membership, html: { class: "grid grid-cols-5" }) do |f| %>
- <%= f.hidden_field :user_action, value: "decline" %>
- <%= f.submit "Decline", class: "crayons-btn crayons-btn--danger" %>
- <% end %>
-
- <% end %>
- <% else %>
-
- You have no pending invitations
-
- <% end %>
-
diff --git a/app/views/chat_channel_memberships/join_channel_invitation.html.erb b/app/views/chat_channel_memberships/join_channel_invitation.html.erb
deleted file mode 100644
index d00674a6e..000000000
--- a/app/views/chat_channel_memberships/join_channel_invitation.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
- <% if @link_expired %>
-
This Invitation link is expired. Please contact the channel mod for new Invitation link
- <% else %>
- Would you like to join the <%= @chat_channel.channel_name %> channel
- <%= form_with(url: joining_invitation_response_path, html: { class: "align-center" }) do |f| %>
- <%= f.hidden_field :user_action, value: "accept" %>
- <%= f.hidden_field :chat_channel_id, value: @chat_channel.id %>
- <%= f.submit "Accept", class: "crayons-btn crayons-btn--s" %>
- <% end %>
- <%= form_with(url: joining_invitation_response_path, html: { class: "align-center" }) do |f| %>
- <%= f.hidden_field :user_action, value: "decline" %>
- <%= f.hidden_field :chat_channel_id, value: @chat_channel.id %>
- <%= f.submit "Decline", class: "crayons-btn crayons-btn--danger mb-5 crayons-btn--s" %>
- <% end %>
- <% end %>
-
diff --git a/app/views/chat_channel_memberships/request_details.json.jbuilder b/app/views/chat_channel_memberships/request_details.json.jbuilder
deleted file mode 100644
index 82f9bbe81..000000000
--- a/app/views/chat_channel_memberships/request_details.json.jbuilder
+++ /dev/null
@@ -1,5 +0,0 @@
-json.success true
-json.result do
- json.channel_joining_memberships formatted_membership_user(@memberships)
- json.user_joining_requests @user_invitations ? formatted_membership_user(@user_invitations) : []
-end
diff --git a/app/views/chat_channels/channel_info.json.jbuilder b/app/views/chat_channels/channel_info.json.jbuilder
deleted file mode 100644
index eeb5a5771..000000000
--- a/app/views/chat_channels/channel_info.json.jbuilder
+++ /dev/null
@@ -1,13 +0,0 @@
-json.type_of "chat_channel"
-
-json.extract!(
- @chat_channel,
- :id,
- :description,
- :channel_name,
- :channel_users,
- :channel_mod_ids,
- :pending_users_select_fields,
-)
-
-json.username @chat_channel.channel_name
diff --git a/app/views/chat_channels/index.html.erb b/app/views/chat_channels/index.html.erb
deleted file mode 100644
index 9edd60699..000000000
--- a/app/views/chat_channels/index.html.erb
+++ /dev/null
@@ -1,46 +0,0 @@
-<% title("#{community_name} Connect") %>
-<%= content_for :page_meta do %>
-
-
-<% end %>
-<%= csrf_meta_tags %>
-
-<% if user_signed_in? %>
- <%= javascript_packs_with_chunks_tag "Chat", defer: true %>
-
- "
- data-github-token="<%= @github_token %>"
- data-chat-channels="<%= [] %>"
- data-chat-options="<%= { showChannelsList: true, showTimestamp: true, activeChannelId: @active_channel&.id, currentUserId: current_user.id }.to_json %>"
- data-tag-moderator="<%= { isTagModerator: current_user.tag_moderator? }.to_json %>">
-
-
-
-<% else %>
- <%= render "devise/registrations/registration_form" %>
-<% end %>
-
-
diff --git a/app/views/chat_channels/index.json.jbuilder b/app/views/chat_channels/index.json.jbuilder
deleted file mode 100644
index f750d25f1..000000000
--- a/app/views/chat_channels/index.json.jbuilder
+++ /dev/null
@@ -1,20 +0,0 @@
-memberships = @chat_channels_memberships.sort_by { |m| m.chat_channel.last_message_at }.reverse!
-
-json.array!(memberships) do |membership|
- membership.chat_channel.current_user = current_user
-
- json.extract!(
- membership.chat_channel,
- :id,
- :slug,
- :channel_name,
- :channel_type,
- :last_opened_at,
- :last_message_at,
- :description,
- )
-
- json.adjusted_slug membership.chat_channel.adjusted_slug(current_user)
- json.membership_id membership.id
- json.member_name membership.user.username
-end
diff --git a/app/views/chat_channels/show.json.jbuilder b/app/views/chat_channels/show.json.jbuilder
deleted file mode 100644
index 1fab47d65..000000000
--- a/app/views/chat_channels/show.json.jbuilder
+++ /dev/null
@@ -1,15 +0,0 @@
-json.messages @chat_messages.reverse do |message|
- json.extract!(message, :id, :user_id, :edited_at)
-
- json.username message.user.username
- json.profile_image_url Images::Profile.call(message.user.profile_image_url, length: 90)
- json.message message.message_html
- json.markdown message.message_markdown
- json.timestamp message.created_at
- json.color message.preferred_user_color
- json.action message.chat_action
-end
-
-json.key_format! camelize: :lower
-
-json.chat_channel_id @chat_channel.id
diff --git a/app/views/layouts/_top_bar.html.erb b/app/views/layouts/_top_bar.html.erb
index a83f59c98..d1649c391 100644
--- a/app/views/layouts/_top_bar.html.erb
+++ b/app/views/layouts/_top_bar.html.erb
@@ -46,13 +46,6 @@
- <% if FeatureFlag.enabled?(:connect) %>
-
- <% end %>
-
<% end %>
-
-
-
-
-
- <%= t("views.listings.form.connect.subtitle") %>
- <%= t("views.listings.form.connect.description") %>
-
-
diff --git a/app/views/listings/edit.html.erb b/app/views/listings/edit.html.erb
index 74e59614b..0d163ad7e 100644
--- a/app/views/listings/edit.html.erb
+++ b/app/views/listings/edit.html.erb
@@ -33,13 +33,6 @@
<%= t("views.listings.form.expiry.description") %>
-
- <%= f.check_box "contact_via_connect", class: "crayons-checkbox" %>
-
- <%= t("views.listings.form.connect.subtitle") %>
- <%= t("views.listings.form.connect.description") %>
-
-
<%= f.label "location", class: "crayons-field__label" %>
<%= f.text_field "location", maxlength: 32, placeholder: t("views.listings.form.location.placeholder"), class: "crayons-textfield m:max-w-50" %>
diff --git a/app/views/mailers/notify_mailer/channel_invite_email.html.erb b/app/views/mailers/notify_mailer/channel_invite_email.html.erb
deleted file mode 100644
index f1b0443d8..000000000
--- a/app/views/mailers/notify_mailer/channel_invite_email.html.erb
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
- <% if @membership.role == "mod" %>
-
- You have been invited to be a Moderator of a Connect group on <%= community_name %>.
-
- <% elsif @inviter %>
-
- <%= link_to(@inviter.name, ApplicationController.helpers.user_url(@inviter)) %> sent you an invitation to join a Connect group on <%= community_name %>.
-
- <% elsif @membership.status == "joining_request" %>
-
- Your request to join <%= community_name %> has been accepted.
-
- <% else %>
-
- You have been invited to a Connect group on <%= community_name %>.
-
- <% end %>
-
-
-
-
-
-
-
-
-
-
-
<%= @membership.chat_channel.channel_name %>
-
-
- <% if @membership.role == "mod" %>
-
- <% else %>
-
- <% end %>
-
-
-
-
- <%= link_to("Check Invitation", ApplicationController.helpers.app_url("connect?ref=group_invite"), style: "color: white;font-size:1.4em;font-weight: bold;text-decoration: none;padding: 15px 0px; display: block;") %>
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/views/mailers/notify_mailer/channel_invite_email.text.erb b/app/views/mailers/notify_mailer/channel_invite_email.text.erb
deleted file mode 100644
index 66c150ee9..000000000
--- a/app/views/mailers/notify_mailer/channel_invite_email.text.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-You are invited to the <%= community_name %> Connect channel <%= @membership.chat_channel.channel_name %>
-
-View Invitation: <%= ApplicationController.helpers.app_url("connect") %>
diff --git a/app/views/mailers/notify_mailer/new_message_email.html.erb b/app/views/mailers/notify_mailer/new_message_email.html.erb
deleted file mode 100644
index efa6ab061..000000000
--- a/app/views/mailers/notify_mailer/new_message_email.html.erb
+++ /dev/null
@@ -1,18 +0,0 @@
-
<%= link_to(@message.user.name, user_url(@message.user)) %> sent you a message on <%= community_name %> Connect
-
-
-
-
You only get emails like this if you have not been active on
- <%= community_name %> Connect in the past day. You may disable this type of email in your settings.
diff --git a/app/views/mailers/notify_mailer/new_message_email.text.erb b/app/views/mailers/notify_mailer/new_message_email.text.erb
deleted file mode 100644
index 55f25ecfe..000000000
--- a/app/views/mailers/notify_mailer/new_message_email.text.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= ActionController::Base.helpers.strip_tags(@message.message_html.html_safe) %>
-
-View now: <%= app_url("/connect/@#{@message.user.username}") %>
diff --git a/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.html.erb b/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.html.erb
index 84d08ec11..46bdd0e00 100644
--- a/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.html.erb
+++ b/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.html.erb
@@ -24,26 +24,6 @@
tag moderation page.
-<% if FeatureFlag.enabled?(:connect) %>
-
- To aid in communication, we’ve added you to the following <%= community_name %> Connect channels:
-
-
-
-
- You can use these channels to meet other tag moderators across the site and co-moderators within your tag while coordinating with the <%= community_name %> team. When in doubt about how to exercise your new privileges, please ask! If these Connect channels become too distracting, you can mute or leave any channel as you wish.
-
-<% end %>
-
Tag moderation is something we're continuously iterating on, so you can expect adjustments and expanding features over time as we receive feedback. We regularly send out a biweekly Mod Newsletter to keep mods up to date on these changes, so look out for it!
Of course, don't hesitate to reach out to us at any moment if you have any feedback — feel free to write to <%= email_link %> and share your thoughts.
diff --git a/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.text.erb b/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.text.erb
index c446fd817..cd3c64fa0 100644
--- a/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.text.erb
+++ b/app/views/mailers/notify_mailer/tag_moderator_confirmation_email.text.erb
@@ -10,16 +10,6 @@ As a tag moderator, you are able to:
For details on all available features and how to access them, visit our tag moderation page.
-<% if FeatureFlag.enabled?(:connect) %>
-To aid in communication, we’ve added you to the following <%= community_name %> Connect channels:
-
-- Tag Moderators <%= app_url("/connect/tag-moderators") %>
-- #<%= @tag %>
-
-You can use these channels to meet other tag moderators across the site and co-moderators within your tag while coordinating with the <%= community_name %> team.
-When in doubt about how to exercise your new privileges, please ask! If these Connect channels become too distracting, you can mute or leave any channel as you wish.
-<% end %>
-
Tag moderation is something we're continuously iterating on, so you can expect adjustments and expanding features over time as we receive feedback.
We regularly send out a biweekly Mod Newsletter to keep mods up to date on these changes, so look out for it!
Of course, don't hesitate to reach out to us at any moment if you have any feedback — feel free to write to <%= ForemInstance.email %> and share your thoughts.
diff --git a/app/views/users/_account.html.erb b/app/views/users/_account.html.erb
index ad8ca1d18..3caf6efe6 100644
--- a/app/views/users/_account.html.erb
+++ b/app/views/users/_account.html.erb
@@ -119,7 +119,7 @@
<%# TODO: expand the delete messaging later %>
-
Delete any and all content you have, such as articles, comments, your reading list or chat messages.
+
Delete any and all content you have, such as articles, comments, or your reading list.
Allow your username to become available to anyone.
Delete Account
diff --git a/app/views/users/_extensions.html.erb b/app/views/users/_extensions.html.erb
index 6d5a85cfc..542ae956b 100644
--- a/app/views/users/_extensions.html.erb
+++ b/app/views/users/_extensions.html.erb
@@ -1,34 +1,5 @@
<%= render partial: "response_templates" %>
-<% if FeatureFlag.enabled?(:connect) %>
-
-
- Connect settings
-
- <%= form_for(@users_setting, url: users_settings_path, html: { id: nil, class: "grid gap-6" }) do |f| %>
-
- <%= f.label :inbox_type, "Inbox privacy", class: "crayons-field__label" %>
-
Open your inbox to messages from people you don't follow or keep your inbox private to mutual follows.
- <%= f.select :inbox_type, [%w[Open open], %w[Private private]], {}, { class: "crayons-select" } %>
-
-
-
- <%= f.label :inbox_guidelines, "Open inbox guidelines/instructions", class: "crayons-field__label" %>
-
- Optional
-
-
- <%= f.text_area :inbox_guidelines, maxlength: 200, class: "crayons-textfield", rows: 3, placeholder: "Please allow a few days for a response." %>
-
-
- <%= f.hidden_field :tab, value: @tab, id: nil %>
-
- Save Connect Settings
-
- <% end %>
-
-<% end %>
-
<%= render partial: "publishing_from_rss" %>
diff --git a/app/views/users/_notifications.html.erb b/app/views/users/_notifications.html.erb
index 1b987ea01..a499ee6a4 100644
--- a/app/views/users/_notifications.html.erb
+++ b/app/views/users/_notifications.html.erb
@@ -47,10 +47,6 @@
<%= f.check_box :email_badge_notifications, class: "crayons-checkbox" %>
<%= f.label :email_badge_notifications, "Send me an email when I receive a badge", class: "crayons-field__label" %>
-
- <%= f.check_box :email_connect_messages, class: "crayons-checkbox" %>
- <%= f.label :email_connect_messages, "Send me an email when I receive a direct message (while inactive)", class: "crayons-field__label" %>
-
<%= f.check_box :email_unread_notifications, class: "crayons-checkbox" %>
<%= f.label :email_unread_notifications, "Send me occasional reminders that I have unread notifications on #{community_name}", class: "crayons-field__label" %>
diff --git a/app/views/users/confirm_destroy.html.erb b/app/views/users/confirm_destroy.html.erb
index 1883ea640..bdee762e6 100644
--- a/app/views/users/confirm_destroy.html.erb
+++ b/app/views/users/confirm_destroy.html.erb
@@ -11,7 +11,7 @@
GitHub profile settings .
<%# TODO: expand the delete messaging later %>
-
delete any and all content you have, such as articles, comments, your reading list or chat messages.
+
delete any and all content you have, such as articles, comments, or your reading list.
allow your username to become available to anyone.
To delete your account:
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 033e3a16f..3aca424cf 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -32,15 +32,8 @@