fix: Update tweet character count logic (#2709)

This commit is contained in:
Pranav Raj S
2021-08-02 16:07:30 +05:30
committed by GitHub
parent d88e3e3596
commit faf104c1fe
10 changed files with 174 additions and 38 deletions

View File

@@ -2,6 +2,33 @@
/* global axios */ /* global axios */
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
export const buildCreatePayload = ({
message,
isPrivate,
contentAttributes,
echoId,
file,
}) => {
let payload;
if (file) {
payload = new FormData();
payload.append('attachments[]', file, file.name);
if (message) {
payload.append('content', message);
}
payload.append('private', isPrivate);
payload.append('echo_id', echoId);
} else {
payload = {
content: message,
private: isPrivate,
echo_id: echoId,
content_attributes: contentAttributes,
};
}
return payload;
};
class MessageApi extends ApiClient { class MessageApi extends ApiClient {
constructor() { constructor() {
super('conversations', { accountScoped: true }); super('conversations', { accountScoped: true });
@@ -15,18 +42,16 @@ class MessageApi extends ApiClient {
echo_id: echoId, echo_id: echoId,
file, file,
}) { }) {
const formData = new FormData();
if (file) formData.append('attachments[]', file, file.name);
if (message) formData.append('content', message);
if (contentAttributes)
formData.append('content_attributes', JSON.stringify(contentAttributes));
formData.append('private', isPrivate);
formData.append('echo_id', echoId);
return axios({ return axios({
method: 'post', method: 'post',
url: `${this.url}/${conversationId}/messages`, url: `${this.url}/${conversationId}/messages`,
data: formData, data: buildCreatePayload({
message,
isPrivate,
contentAttributes,
echoId,
file,
}),
}); });
} }

View File

@@ -1,4 +1,4 @@
import messageAPI from '../../inbox/message'; import messageAPI, { buildCreatePayload } from '../../inbox/message';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper'; import describeWithAPIMock from '../apiSpecHelper';
@@ -29,4 +29,34 @@ describe('#ConversationAPI', () => {
); );
}); });
}); });
describe('#buildCreatePayload', () => {
it('builds form payload if file is available', () => {
const formPayload = buildCreatePayload({
message: 'test content',
echoId: 12,
isPrivate: true,
file: new Blob(['test-content'], { type: 'application/pdf' }),
});
expect(formPayload).toBeInstanceOf(FormData);
expect(formPayload.get('content')).toEqual('test content');
expect(formPayload.get('echo_id')).toEqual('12');
expect(formPayload.get('private')).toEqual('true');
});
it('builds object payload if file is not available', () => {
expect(
buildCreatePayload({
message: 'test content',
isPrivate: false,
echoId: 12,
contentAttributes: { in_reply_to: 12 },
})
).toEqual({
content: 'test content',
private: false,
echo_id: 12,
content_attributes: { in_reply_to: 12 },
});
});
});
}); });

View File

@@ -53,9 +53,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapGetters({ ...mapGetters({ currentChat: 'getSelectedChat' }),
currentChat: 'getSelectedChat',
}),
showContactPanel() { showContactPanel() {
return this.isContactPanelOpen && this.currentChat.id; return this.isContactPanelOpen && this.currentChat.id;
}, },

View File

@@ -46,6 +46,7 @@
:message-type="data.message_type" :message-type="data.message_type"
:readable-time="readableTime" :readable-time="readableTime"
:source-id="data.source_id" :source-id="data.source_id"
:inbox-id="data.inbox_id"
/> />
</div> </div>
<spinner v-if="isPending" size="tiny" /> <spinner v-if="isPending" size="tiny" />

View File

@@ -33,11 +33,11 @@
<div v-if="isATweet" class="banner"> <div v-if="isATweet" class="banner">
<span v-if="!selectedTweetId"> <span v-if="!selectedTweetId">
{{ $t('CONVERSATION.LAST_INCOMING_TWEET') }} {{ $t('CONVERSATION.SELECT_A_TWEET_TO_REPLY') }}
</span> </span>
<span v-else> <span v-else>
{{ $t('CONVERSATION.REPLYING_TO') }} {{ $t('CONVERSATION.REPLYING_TO') }}
{{ selectedTweet }} {{ selectedTweet.content || '' }}
</span> </span>
<button <button
v-if="selectedTweetId" v-if="selectedTweetId"
@@ -89,9 +89,10 @@
/> />
</div> </div>
</div> </div>
<ReplyBox <reply-box
:conversation-id="currentChat.id" :conversation-id="currentChat.id"
:in-reply-to="selectedTweetId" :is-a-tweet="isATweet"
:selected-tweet="selectedTweet"
@scrollToMessage="scrollToBottom" @scrollToMessage="scrollToBottom"
/> />
</div> </div>
@@ -207,10 +208,10 @@ export default {
selectedTweet() { selectedTweet() {
if (this.selectedTweetId) { if (this.selectedTweetId) {
const { messages = [] } = this.getMessages; const { messages = [] } = this.getMessages;
const [selectedMessage = {}] = messages.filter( const [selectedMessage] = messages.filter(
message => message.id === this.selectedTweetId message => message.id === this.selectedTweetId
); );
return selectedMessage.content || ''; return selectedMessage || {};
} }
return ''; return '';
}, },

View File

@@ -107,9 +107,13 @@ export default {
}, },
mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin], mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin],
props: { props: {
inReplyTo: { selectedTweet: {
type: [String, Number], type: [Object, String],
default: '', default: () => ({}),
},
isATweet: {
type: Boolean,
default: false,
}, },
}, },
data() { data() {
@@ -169,11 +173,14 @@ export default {
return this.maxLength - this.message.length; return this.maxLength - this.message.length;
}, },
isReplyButtonDisabled() { isReplyButtonDisabled() {
const isMessageEmpty = this.isMessageEmpty; if (this.isATweet && !this.inReplyTo) {
return true;
}
if (this.hasAttachments) return false; if (this.hasAttachments) return false;
return ( return (
isMessageEmpty || this.isMessageEmpty ||
this.message.length === 0 || this.message.length === 0 ||
this.message.length > this.maxLength this.message.length > this.maxLength
); );
@@ -198,7 +205,7 @@ export default {
} }
if (this.isATwitterInbox) { if (this.isATwitterInbox) {
if (this.conversationType === 'tweet') { if (this.conversationType === 'tweet') {
return MESSAGE_MAX_LENGTH.TWEET; return MESSAGE_MAX_LENGTH.TWEET - this.replyToUserLength - 2;
} }
} }
return MESSAGE_MAX_LENGTH.GENERAL; return MESSAGE_MAX_LENGTH.GENERAL;
@@ -235,9 +242,22 @@ export default {
isOnPrivateNote() { isOnPrivateNote() {
return this.replyType === REPLY_EDITOR_MODES.NOTE; return this.replyType === REPLY_EDITOR_MODES.NOTE;
}, },
inReplyTo() {
const selectedTweet = this.selectedTweet || {};
return selectedTweet.id;
},
replyToUserLength() {
const selectedTweet = this.selectedTweet || {};
const {
sender: {
additional_attributes: { screen_name: screenName = '' } = {},
} = {},
} = selectedTweet;
return screenName ? screenName.length : 0;
},
isMessageEmpty() { isMessageEmpty() {
if(!this.message) { if (!this.message) {
this.message = ''; return true;
} }
return !this.message.trim().replace(/\n/g, '').length; return !this.message.trim().replace(/\n/g, '').length;
}, },

View File

@@ -14,13 +14,13 @@
@mouseleave="isHovered = false" @mouseleave="isHovered = false"
/> />
<i <i
v-if="isATweet && isIncoming" v-if="isATweet && (isIncoming || isOutgoing) && sourceId"
v-tooltip.top-start="$t('CHAT_LIST.REPLY_TO_TWEET')" v-tooltip.top-start="$t('CHAT_LIST.REPLY_TO_TWEET')"
class="icon ion-reply cursor-pointer" class="icon ion-reply cursor-pointer"
@click="onTweetReply" @click="onTweetReply"
/> />
<a <a
v-if="isATweet && isIncoming" v-if="isATweet && (isOutgoing || isIncoming) && linkToTweet"
:href="linkToTweet" :href="linkToTweet"
target="_blank" target="_blank"
rel="noopener noreferrer nofollow" rel="noopener noreferrer nofollow"
@@ -71,19 +71,33 @@ export default {
type: [String, Number], type: [String, Number],
default: '', default: '',
}, },
inboxId: {
type: [String, Number],
default: 0,
},
}, },
computed: { computed: {
inbox() {
return this.$store.getters['inboxes/getInbox'](this.inboxId);
},
isIncoming() { isIncoming() {
return MESSAGE_TYPE.INCOMING === this.messageType; return MESSAGE_TYPE.INCOMING === this.messageType;
}, },
isOutgoing() {
return MESSAGE_TYPE.OUTGOING === this.messageType;
},
screenName() { screenName() {
const { additional_attributes: additionalAttributes = {} } = const { additional_attributes: additionalAttributes = {} } =
this.sender || {}; this.sender || {};
return additionalAttributes?.screen_name || ''; return additionalAttributes?.screen_name || '';
}, },
linkToTweet() { linkToTweet() {
if (!this.sourceId || !this.inbox.name) {
return '';
}
const { screenName, sourceId } = this; const { screenName, sourceId } = this;
return `https://twitter.com/${screenName}/status/${sourceId}`; return `https://twitter.com/${screenName ||
this.inbox.name}/status/${sourceId}`;
}, },
}, },
methods: { methods: {
@@ -113,6 +127,13 @@ export default {
} }
} }
.right {
.ion-reply,
.ion-android-open {
color: var(--white);
}
}
.message-text--metadata { .message-text--metadata {
align-items: flex-end; align-items: flex-end;
display: flex; display: flex;

View File

@@ -23,7 +23,7 @@
"24_HOURS_WINDOW": "24 hour message window restriction", "24_HOURS_WINDOW": "24 hour message window restriction",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to", "TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction", "TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
"LAST_INCOMING_TWEET": "You are replying to the last incoming tweet", "SELECT_A_TWEET_TO_REPLY": "Please select a tweet to reply to.",
"REPLYING_TO": "You are replying to:", "REPLYING_TO": "You are replying to:",
"REMOVE_SELECTION": "Remove Selection", "REMOVE_SELECTION": "Remove Selection",
"DOWNLOAD": "Download", "DOWNLOAD": "Download",

View File

@@ -29,6 +29,8 @@ class Twitter::SendOnTwitterService < Base::SendOnChannelService
end end
def screen_name def screen_name
return "@#{reply_to_message.inbox.name}" if reply_to_message.outgoing?
"@#{reply_to_message.sender&.additional_attributes.try(:[], 'screen_name') || ''}" "@#{reply_to_message.sender&.additional_attributes.try(:[], 'screen_name') || ''}"
end end

View File

@@ -9,7 +9,7 @@ describe Twitter::SendOnTwitterService do
let(:widget_inbox) { create(:inbox, account: account) } let(:widget_inbox) { create(:inbox, account: account) }
let(:twitter_channel) { create(:channel_twitter_profile, account: account) } let(:twitter_channel) { create(:channel_twitter_profile, account: account) }
let(:twitter_inbox) { create(:inbox, channel: twitter_channel, account: account) } let(:twitter_inbox) { create(:inbox, channel: twitter_channel, account: account) }
let(:contact) { create(:contact, account: account) } let(:contact) { create(:contact, account: account, additional_attributes: { screen_name: 'test_user' }) }
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: twitter_inbox) } let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: twitter_inbox) }
let(:dm_conversation) do let(:dm_conversation) do
create( create(
@@ -73,12 +73,50 @@ describe Twitter::SendOnTwitterService do
expect(twitter_client).to have_received(:send_direct_message) expect(twitter_client).to have_received(:send_direct_message)
end end
it 'if conversation is a tweet' do context 'when conversation is a tweet' do
create(:message, message_type: :incoming, inbox: twitter_inbox, account: account, conversation: tweet_conversation) it 'creates a response with correct reply if reply to message is incoming' do
message = create(:message, message_type: :outgoing, inbox: twitter_inbox, account: account, conversation: tweet_conversation) create(
::Twitter::SendOnTwitterService.new(message: message).perform :message,
expect(twitter_client).to have_received(:send_tweet_reply) message_type: :incoming,
expect(message.reload.source_id).to eq '12345' sender: contact,
source_id: 'test-source-id-1',
inbox: twitter_inbox,
account: account,
conversation: tweet_conversation
)
message = create(:message, message_type: :outgoing, inbox: twitter_inbox, account: account, conversation: tweet_conversation)
::Twitter::SendOnTwitterService.new(message: message).perform
expect(twitter_client).to have_received(:send_tweet_reply).with(
reply_to_tweet_id: 'test-source-id-1',
tweet: "@test_user #{message.content}"
)
expect(message.reload.source_id).to eq '12345'
end
it 'creates a response with correct reply if reply to message is outgoing' do
outgoing_message = create(
:message,
message_type: :outgoing,
source_id: 'test-source-id-1',
inbox: twitter_inbox,
account: account,
conversation: tweet_conversation
)
reply_message = create(
:message,
message_type: :outgoing,
inbox: twitter_inbox,
account: account,
conversation: tweet_conversation,
in_reply_to: outgoing_message.id
)
::Twitter::SendOnTwitterService.new(message: reply_message).perform
expect(twitter_client).to have_received(:send_tweet_reply).with(
reply_to_tweet_id: 'test-source-id-1',
tweet: "@#{twitter_inbox.name} #{reply_message.content}"
)
expect(reply_message.reload.source_id).to eq '12345'
end
end end
end end
end end