Skip to content

Commit

Permalink
Feature: Rich Message Types (#610)
Browse files Browse the repository at this point in the history
Co-authored-by: Pranav Raj S <pranavrajs@gmail.com>
Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
  • Loading branch information
3 people committed Apr 10, 2020
1 parent 48f6037 commit b0950d6
Show file tree
Hide file tree
Showing 58 changed files with 996 additions and 145 deletions.
8 changes: 6 additions & 2 deletions app/builders/messages/outgoing/normal_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ class Messages::Outgoing::NormalBuilder
attr_reader :message

def initialize(user, conversation, params)
@content = params[:message]
@content = params[:content]
@private = params[:private] || false
@conversation = conversation
@user = user
@fb_id = params[:fb_id]
@content_type = params[:content_type]
@items = params.to_unsafe_h&.dig(:content_attributes, :items)
@attachment = params[:attachment]
end

Expand All @@ -34,7 +36,9 @@ def message_params
content: @content,
private: @private,
user_id: @user&.id,
source_id: @fb_id
source_id: @fb_id,
content_type: @content_type,
items: @items
}
end
end
18 changes: 18 additions & 0 deletions app/controllers/api/v1/accounts/conversations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
class Api::V1::Accounts::ConversationsController < Api::BaseController
before_action :conversation, except: [:index]
before_action :contact_inbox, only: [:create]

def index
result = conversation_finder.perform
@conversations = result[:conversations]
@conversations_count = result[:count]
end

def create
@conversation = ::Conversation.create!(conversation_params)
end

def show; end

def toggle_status
Expand All @@ -29,6 +34,19 @@ def conversation
@conversation ||= current_account.conversations.find_by(display_id: params[:id])
end

def contact_inbox
@contact_inbox ||= ::ContactInbox.find_by!(source_id: params[:source_id])
end

def conversation_params
{
account_id: current_account.id,
inbox_id: @contact_inbox.inbox_id,
contact_id: @contact_inbox.contact_id,
contact_inbox_id: @contact_inbox.id
}
end

def conversation_finder
@conversation_finder ||= ConversationFinder.new(current_user, params)
end
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/api/v1/widget/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ class Api::V1::Widget::BaseController < ApplicationController
private

def conversation
@conversation ||= @contact_inbox.conversations.find_by(
@conversation ||= @contact_inbox.conversations.where(
inbox_id: auth_token_params[:inbox_id]
)
).last
end

def auth_token_params
Expand Down
16 changes: 16 additions & 0 deletions app/controllers/api/v1/widget/events_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Api::V1::Widget::EventsController < Api::V1::Widget::BaseController
include Events::Types
before_action :set_web_widget
before_action :set_contact

def create
Rails.configuration.dispatcher.dispatch(permitted_params[:name], Time.zone.now, contact_inbox: @contact_inbox)
head :no_content
end

private

def permitted_params
params.permit(:name, :website_token)
end
end
12 changes: 10 additions & 2 deletions app/controllers/api/v1/widget/messages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ def create
end

def update
@message.update!(input_submitted_email: contact_email)
update_contact(contact_email)
if @message.content_type == 'input_email'
@message.update!(submitted_email: contact_email)
update_contact(contact_email)
else
@message.update!(message_update_params[:message])
end
rescue StandardError => e
render json: { error: @contact.errors, message: e.message }.to_json, status: 500
end
Expand Down Expand Up @@ -116,6 +120,10 @@ def contact_name
contact_email.split('@')[0]
end

def message_update_params
params.permit(message: [submitted_values: [:name, :title, :value]])
end

def permitted_params
params.permit(:id, :before, :website_token, contact: [:email], message: [:content, :referer_url, :timestamp])
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/access_token_auth_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module AccessTokenAuthHelper
BOT_ACCESSIBLE_ENDPOINTS = {
'api/v1/accounts/conversations' => ['toggle_status'],
'api/v1/accounts/conversations' => %w[toggle_status create],
'api/v1/accounts/conversations/messages' => ['create']
}.freeze

Expand Down
2 changes: 1 addition & 1 deletion app/javascript/dashboard/api/inbox/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class MessageApi extends ApiClient {

create({ conversationId, message, private: isPrivate }) {
return axios.post(`${this.url}/${conversationId}/messages`, {
message,
content: message,
private: isPrivate,
});
}
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/dashboard/i18n/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export default {
DOWNLOAD: 'Herunterladen',
UPLOADING: 'Hochladen...',
},

FORM_BUBBLE: {
SUBMIT: 'Einreichen',
},
},
CONFIRM_EMAIL: 'Überprüfen...',
SETTINGS: {
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/dashboard/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export default {
DOWNLOAD: 'Download',
UPLOADING: 'Uploading...',
},
FORM_BUBBLE: {
SUBMIT: 'Submit',
},
},
CONFIRM_EMAIL: 'Verifying...',
SETTINGS: {
Expand Down
5 changes: 2 additions & 3 deletions app/javascript/packs/sdk.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Cookies from 'js-cookie';
import { IFrameHelper } from '../sdk/IFrameHelper';
import { onBubbleClick } from '../sdk/bubbleHelpers';

const runSDK = ({ baseUrl, websiteToken }) => {
const chatwootSettings = window.chatwootSettings || {};
Expand All @@ -13,7 +12,7 @@ const runSDK = ({ baseUrl, websiteToken }) => {
websiteToken,

toggle() {
onBubbleClick();
IFrameHelper.events.toggleBubble();
},

setUser(identifier, user) {
Expand All @@ -39,7 +38,7 @@ const runSDK = ({ baseUrl, websiteToken }) => {

reset() {
if (window.$chatwoot.isOpen) {
onBubbleClick();
IFrameHelper.events.toggleBubble();
}

Cookies.remove('cw_conversation');
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/sdk/IFrameHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export const IFrameHelper = {

toggleBubble: () => {
onBubbleClick();
if (window.$chatwoot.isOpen) {
IFrameHelper.pushEvent('webwidget.triggered');
}
},
},
onLoad: ({ widget_color: widgetColor }) => {
Expand Down
13 changes: 9 additions & 4 deletions app/javascript/shared/components/CardButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
:key="action.uri"
class="action-button button"
:href="action.uri"
target="_blank"
rel="noopener nofollow noreferrer"
>
{{ action.text }}
</a>
Expand Down Expand Up @@ -44,11 +46,14 @@ export default {
@import '~dashboard/assets/scss/mixins.scss';
.action-button {
width: 100%;
padding: 0;
max-height: 34px;
margin-top: $space-smaller;
align-items: center;
border-radius: $space-micro;
display: flex;
font-weight: $font-weight-medium;
justify-content: center;
margin-top: $space-smaller;
max-height: 34px;
padding: 0;
width: 100%;
}
</style>
1 change: 0 additions & 1 deletion app/javascript/shared/components/ChatCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export default {
@import '~dashboard/assets/scss/mixins.scss';
.card-message {
@include border-normal;
background: white;
max-width: 220px;
padding: $space-small;
Expand Down
114 changes: 114 additions & 0 deletions app/javascript/shared/components/ChatForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<template>
<div class="form chat-bubble agent">
<form @submit.prevent="onSubmit">
<div v-for="item in items" :key="item.key" class="form-block">
<label>{{ item.label }}</label>
<input
v-if="item.type === 'email' || item.type === 'text'"
v-model="formValues[item.name]"
:type="item.type"
:name="item.name"
:placeholder="item.placeholder"
:disabled="!!submittedValues.length"
/>
<textarea
v-else-if="item.type === 'text_area'"
v-model="formValues[item.name]"
:name="item.name"
:placeholder="item.placeholder"
:disabled="!!submittedValues.length"
/>
</div>
<button
v-if="!submittedValues.length"
class="button small block"
type="submit"
:disabled="!isFormValid"
>
{{ $t('COMPONENTS.FORM_BUBBLE.SUBMIT') }}
</button>
</form>
</div>
</template>

<script>
export default {
props: {
items: {
type: Array,
default: () => [],
},
submittedValues: {
type: Array,
default: () => [],
},
},
data() {
return {
formValues: {},
};
},
computed: {
isFormValid() {
return this.items.reduce((acc, { name }) => {
return !!this.formValues[name] && acc;
}, true);
},
},
mounted() {
this.updateFormValues();
},
methods: {
onSubmit() {
if (!this.isFormValid) {
return;
}
this.$emit('submit', this.formValues);
},
updateFormValues() {
this.formValues = this.submittedValues.reduce((acc, obj) => {
return {
...acc,
[obj.name]: obj.value,
};
}, {});
},
},
};
</script>

<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
.form {
padding: $space-normal;
width: 100%;
.form-block {
max-width: 100%;
padding-bottom: $space-small;
}
label {
display: block;
font-weight: $font-weight-bold;
padding: $space-smaller 0;
text-transform: capitalize;
}
input,
textarea {
border-radius: $space-smaller;
border: 1px solid $color-border;
display: block;
font-size: $font-size-default;
line-height: 1.5;
padding: $space-smaller $space-small;
width: 90%;
&:disabled {
background: $color-background-light;
}
}
}
</style>
4 changes: 2 additions & 2 deletions app/javascript/shared/components/ChatOption.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<button class="option-button button" @click="onClick">
<span v-if="isSelected" class="icon ion-checkmark-circled" />
<span v-else class="icon ion-android-radio-button-off" />
<span>{{ action.text }}</span>
<span>{{ action.title }}</span>
</button>
</li>
</template>
Expand All @@ -23,7 +23,7 @@ export default {
},
methods: {
onClick() {
// Do postback here
this.$emit('click', this.action);
},
},
};
Expand Down
Loading

0 comments on commit b0950d6

Please sign in to comment.