feat: CSAT response collection public page (#2685)
This commit is contained in:
parent
9b01b82cc7
commit
92c14fa87d
18 changed files with 371 additions and 10 deletions
|
@ -25,7 +25,7 @@ Style/FrozenStringLiteralComment:
|
||||||
Style/SymbolArray:
|
Style/SymbolArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
Style/OptionalBooleanParameter:
|
Style/OptionalBooleanParameter:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/services/email_templates/db_resolver_service.rb'
|
- 'app/services/email_templates/db_resolver_service.rb'
|
||||||
- 'app/dispatchers/dispatcher.rb'
|
- 'app/dispatchers/dispatcher.rb'
|
||||||
Style/GlobalVars:
|
Style/GlobalVars:
|
||||||
|
@ -57,6 +57,7 @@ Rails/ApplicationController:
|
||||||
- 'app/controllers/widgets_controller.rb'
|
- 'app/controllers/widgets_controller.rb'
|
||||||
- 'app/controllers/platform_controller.rb'
|
- 'app/controllers/platform_controller.rb'
|
||||||
- 'app/controllers/public_controller.rb'
|
- 'app/controllers/public_controller.rb'
|
||||||
|
- 'app/controllers/survey/responses_controller.rb'
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
EnforcedStyle: compact
|
EnforcedStyle: compact
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -79,7 +80,7 @@ Style/GuardClause:
|
||||||
- 'app/models/message.rb'
|
- 'app/models/message.rb'
|
||||||
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/concerns/auth_helper.rb'
|
- 'app/controllers/concerns/auth_helper.rb'
|
||||||
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
||||||
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
|
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
|
||||||
|
@ -108,7 +109,7 @@ Rails/BulkChangeTable:
|
||||||
- 'db/migrate/20191027054756_create_contact_inboxes.rb'
|
- 'db/migrate/20191027054756_create_contact_inboxes.rb'
|
||||||
- 'db/migrate/20191130164019_add_template_type_to_messages.rb'
|
- 'db/migrate/20191130164019_add_template_type_to_messages.rb'
|
||||||
- 'db/migrate/20210425093724_convert_integration_hook_settings_field.rb'
|
- 'db/migrate/20210425093724_convert_integration_hook_settings_field.rb'
|
||||||
Rails/UniqueValidationWithoutIndex:
|
Rails/UniqueValidationWithoutIndex:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/channel/twitter_profile.rb'
|
- 'app/models/channel/twitter_profile.rb'
|
||||||
- 'app/models/webhook.rb'
|
- 'app/models/webhook.rb'
|
||||||
|
|
10
app/controllers/survey/responses_controller.rb
Normal file
10
app/controllers/survey/responses_controller.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class Survey::ResponsesController < ActionController::Base
|
||||||
|
before_action :set_global_config
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_global_config
|
||||||
|
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL')
|
||||||
|
end
|
||||||
|
end
|
25
app/javascript/packs/survey.js
Normal file
25
app/javascript/packs/survey.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Vuelidate from 'vuelidate';
|
||||||
|
import VueI18n from 'vue-i18n';
|
||||||
|
import App from '../survey/App.vue';
|
||||||
|
import i18n from '../survey/i18n';
|
||||||
|
|
||||||
|
Vue.use(VueI18n);
|
||||||
|
Vue.use(Vuelidate);
|
||||||
|
|
||||||
|
const i18nConfig = new VueI18n({
|
||||||
|
locale: 'en',
|
||||||
|
messages: i18n,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event Bus
|
||||||
|
window.bus = new Vue();
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
window.WOOT_SURVEY = new Vue({
|
||||||
|
i18n: i18nConfig,
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app');
|
||||||
|
};
|
|
@ -16,21 +16,28 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
|
||||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
|
|
||||||
|
const {
|
||||||
|
LOGO_THUMBNAIL: logoThumbnail,
|
||||||
|
BRAND_NAME: brandName,
|
||||||
|
WIDGET_BRAND_URL: widgetBrandURL,
|
||||||
|
} = window.globalConfig || {};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [globalConfigMixin],
|
mixins: [globalConfigMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
referrerHost: '',
|
referrerHost: '',
|
||||||
|
globalConfig: {
|
||||||
|
brandName,
|
||||||
|
logoThumbnail,
|
||||||
|
widgetBrandURL,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
|
||||||
globalConfig: 'globalConfig/get',
|
|
||||||
}),
|
|
||||||
brandRedirectURL() {
|
brandRedirectURL() {
|
||||||
const baseURL = `${this.globalConfig.widgetBrandURL}?utm_source=widget_branding`;
|
const baseURL = `${this.globalConfig.widgetBrandURL}?utm_source=widget_branding`;
|
||||||
if (this.referrerHost) {
|
if (this.referrerHost) {
|
||||||
|
@ -47,7 +54,6 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~widget/assets/scss/variables.scss';
|
@import '~widget/assets/scss/variables.scss';
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<button :class="buttonClassName" :style="buttonStyles" @click="onClick">
|
<button
|
||||||
|
:class="buttonClassName"
|
||||||
|
:style="buttonStyles"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="onClick"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -22,6 +27,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
buttonClassName() {
|
buttonClassName() {
|
||||||
|
|
74
app/javascript/shared/components/TextArea.vue
Normal file
74
app/javascript/shared/components/TextArea.vue
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<label class="block">
|
||||||
|
<div
|
||||||
|
v-if="label"
|
||||||
|
class="mb-2 text-xs font-medium"
|
||||||
|
:class="{
|
||||||
|
'text-black-800': !error,
|
||||||
|
'text-red-400': error,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
class="
|
||||||
|
resize-none
|
||||||
|
border
|
||||||
|
rounded
|
||||||
|
w-full
|
||||||
|
py-2
|
||||||
|
px-3
|
||||||
|
text-slate-700
|
||||||
|
leading-tight
|
||||||
|
outline-none
|
||||||
|
"
|
||||||
|
:class="{
|
||||||
|
'border-black-200 hover:border-black-300 focus:border-black-300':
|
||||||
|
!error,
|
||||||
|
'border-red-200 hover:border-red-300 focus:border-red-300': error,
|
||||||
|
}"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:value="value"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
<div v-if="error" class="text-red-400 mt-2 text-xs font-medium">
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(event) {
|
||||||
|
this.$emit('input', event.target.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
textarea {
|
||||||
|
min-height: 8rem;
|
||||||
|
}
|
||||||
|
</style>
|
20
app/javascript/survey/App.vue
Executable file
20
app/javascript/survey/App.vue
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<div id="app" class="woot-survey-wrap">
|
||||||
|
<response />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Response from './views/Response.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
Response,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~survey/assets/scss/woot.scss';
|
||||||
|
</style>
|
21
app/javascript/survey/assets/scss/woot.scss
Executable file
21
app/javascript/survey/assets/scss/woot.scss
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
@import 'tailwindcss/base';
|
||||||
|
@import 'tailwindcss/components';
|
||||||
|
@import 'tailwindcss/utilities';
|
||||||
|
@import 'widget/assets/scss/reset';
|
||||||
|
@import 'widget/assets/scss/variables';
|
||||||
|
@import 'widget/assets/scss/buttons';
|
||||||
|
@import 'widget/assets/scss/mixins';
|
||||||
|
@import 'widget/assets/scss/forms';
|
||||||
|
@import 'shared/assets/fonts/widget_fonts';
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: $font-family;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woot-survey-wrap {
|
||||||
|
height: 100%;
|
||||||
|
}
|
73
app/javascript/survey/components/Rating.vue
Normal file
73
app/javascript/survey/components/Rating.vue
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div class="customer-satisfcation mb-2">
|
||||||
|
<div class="ratings flex py-5 px-0">
|
||||||
|
<button
|
||||||
|
v-for="rating in ratings"
|
||||||
|
:key="rating.key"
|
||||||
|
:class="buttonClass(rating)"
|
||||||
|
@click="selectRating(rating)"
|
||||||
|
>
|
||||||
|
{{ rating.emoji }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { CSAT_RATINGS } from 'shared/constants/messages';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
messageContentAttributes: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
email: '',
|
||||||
|
ratings: CSAT_RATINGS,
|
||||||
|
selectedRating: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isRatingSubmitted() {
|
||||||
|
return this.messageContentAttributes?.csat_survey_response?.rating;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
buttonClass(rating) {
|
||||||
|
return [
|
||||||
|
{ selected: rating.value === this.selectedRating },
|
||||||
|
{ disabled: this.isRatingSubmitted },
|
||||||
|
{ hover: this.isRatingSubmitted },
|
||||||
|
'emoji-button shadow-none text-4xl outline-none mr-8',
|
||||||
|
];
|
||||||
|
},
|
||||||
|
selectRating(rating) {
|
||||||
|
this.selectedRating = rating.value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.emoji-button {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
&.selected,
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
filter: grayscale(0%);
|
||||||
|
transform: scale(1.32);
|
||||||
|
transition: transform 300ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
5
app/javascript/survey/i18n/index.js
Normal file
5
app/javascript/survey/i18n/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { default as en } from './locale/en.json';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
en,
|
||||||
|
};
|
15
app/javascript/survey/i18n/locale/en.json
Normal file
15
app/javascript/survey/i18n/locale/en.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"SURVEY": {
|
||||||
|
"DESCRIPTION": "Dear customer 👋 , please take a few moments to complete the feedback about the conversation.",
|
||||||
|
"RATING": {
|
||||||
|
"LABEL": "Rate your conversation",
|
||||||
|
"SUCCESS_MESSAGE": "Thank you for submitting the rating"
|
||||||
|
},
|
||||||
|
"FEEDBACK": {
|
||||||
|
"LABEL": "Do you have any thoughts you'd like to share?",
|
||||||
|
"PLACEHOLDER": "Your feedback (optional)",
|
||||||
|
"BUTTON_TEXT": "Submit feedback"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"POWERED_BY": "Powered by Chatwoot"
|
||||||
|
}
|
64
app/javascript/survey/views/Response.vue
Normal file
64
app/javascript/survey/views/Response.vue
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-full h-full flex flex-col flex-no-wrap overflow-hidden bg-white"
|
||||||
|
>
|
||||||
|
<div class="flex flex-1 overflow-auto">
|
||||||
|
<div class="max-w-screen-sm w-full my-0 m-auto px-8 py-12">
|
||||||
|
<img src="/brand-assets/logo.svg" alt="Chatwoot logo" class="logo" />
|
||||||
|
<p class="text-black-700 text-lg leading-relaxed mt-4 mb-4">
|
||||||
|
{{ $t('SURVEY.DESCRIPTION') }}
|
||||||
|
</p>
|
||||||
|
<label class="text-base font-medium text-black-800">
|
||||||
|
{{ $t('SURVEY.RATING.LABEL') }}
|
||||||
|
</label>
|
||||||
|
<rating />
|
||||||
|
<label class="text-base font-medium text-black-800">
|
||||||
|
{{ $t('SURVEY.FEEDBACK.LABEL') }}
|
||||||
|
</label>
|
||||||
|
<text-area
|
||||||
|
v-model="message"
|
||||||
|
class="my-5"
|
||||||
|
:placeholder="$t('SURVEY.FEEDBACK.PLACEHOLDER')"
|
||||||
|
/>
|
||||||
|
<custom-button class="font-medium float-right">
|
||||||
|
<spinner v-if="isSubmitted" class="p-0" />
|
||||||
|
{{ $t('SURVEY.FEEDBACK.BUTTON_TEXT') }}
|
||||||
|
</custom-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-wrap flex-shrink-0 w-full flex flex-col relative">
|
||||||
|
<branding></branding>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Branding from 'shared/components/Branding.vue';
|
||||||
|
import Rating from 'survey/components/Rating.vue';
|
||||||
|
import CustomButton from 'shared/components/Button';
|
||||||
|
import TextArea from 'shared/components/TextArea.vue';
|
||||||
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
|
export default {
|
||||||
|
name: 'Home',
|
||||||
|
components: {
|
||||||
|
Branding,
|
||||||
|
Rating,
|
||||||
|
CustomButton,
|
||||||
|
TextArea,
|
||||||
|
},
|
||||||
|
mixins: [configMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
message: '',
|
||||||
|
isSubmitted: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~widget/assets/scss/variables.scss';
|
||||||
|
.logo {
|
||||||
|
max-height: $space-large;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -69,7 +69,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Branding from 'widget/components/Branding.vue';
|
import Branding from 'shared/components/Branding.vue';
|
||||||
import ChatFooter from 'widget/components/ChatFooter.vue';
|
import ChatFooter from 'widget/components/ChatFooter.vue';
|
||||||
import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue';
|
import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue';
|
||||||
import ChatHeader from 'widget/components/ChatHeader.vue';
|
import ChatHeader from 'widget/components/ChatHeader.vue';
|
||||||
|
|
17
app/views/survey/responses/show.html.erb
Normal file
17
app/views/survey/responses/show.html.erb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><%= @global_config['INSTALLATION_NAME'] %></title>
|
||||||
|
<%= csrf_meta_tags %>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||||
|
<script>
|
||||||
|
window.globalConfig = <%= raw @global_config.to_json %>
|
||||||
|
</script>
|
||||||
|
<%= javascript_pack_tag 'survey' %>
|
||||||
|
<%= stylesheet_pack_tag 'survey' %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<%= yield %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -20,6 +20,9 @@ Rails.application.routes.draw do
|
||||||
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_twitter_inbox_agents'
|
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_twitter_inbox_agents'
|
||||||
|
|
||||||
resource :widget, only: [:show]
|
resource :widget, only: [:show]
|
||||||
|
namespace :survey do
|
||||||
|
resources :responses, only: [:show]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/api', to: 'api#index'
|
get '/api', to: 'api#index'
|
||||||
|
|
|
@ -6,6 +6,7 @@ const resolve = {
|
||||||
vue$: 'vue/dist/vue.common.js',
|
vue$: 'vue/dist/vue.common.js',
|
||||||
dashboard: path.resolve('./app/javascript/dashboard'),
|
dashboard: path.resolve('./app/javascript/dashboard'),
|
||||||
widget: path.resolve('./app/javascript/widget'),
|
widget: path.resolve('./app/javascript/widget'),
|
||||||
|
survey: path.resolve('./app/javascript/survey'),
|
||||||
assets: path.resolve('./app/javascript/dashboard/assets'),
|
assets: path.resolve('./app/javascript/dashboard/assets'),
|
||||||
components: path.resolve('./app/javascript/dashboard/components'),
|
components: path.resolve('./app/javascript/dashboard/components'),
|
||||||
'./iconfont.eot': 'vue-easytable/libs/font/iconfont.eot',
|
'./iconfont.eot': 'vue-easytable/libs/font/iconfont.eot',
|
||||||
|
|
16
spec/controllers/service/responses_controller_spec.rb
Normal file
16
spec/controllers/service/responses_controller_spec.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe '/survey/response', type: :request do
|
||||||
|
describe 'GET survey/responses/{uuid}' do
|
||||||
|
it 'renders the page correctly when called' do
|
||||||
|
conversation = create(:conversation)
|
||||||
|
get survey_response_url(id: conversation.uuid)
|
||||||
|
expect(response).to be_successful
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 when called with invalid conversation uuid' do
|
||||||
|
get survey_response_url(id: '')
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,7 @@ module.exports = {
|
||||||
purge: [
|
purge: [
|
||||||
'./app/javascript/widget/**/*.vue',
|
'./app/javascript/widget/**/*.vue',
|
||||||
'./app/javascript/shared/**/*.vue',
|
'./app/javascript/shared/**/*.vue',
|
||||||
|
'./app/javascript/survey/**/*.vue',
|
||||||
],
|
],
|
||||||
future: {
|
future: {
|
||||||
removeDeprecatedGapUtilities: true,
|
removeDeprecatedGapUtilities: true,
|
||||||
|
|
Loading…
Reference in a new issue