Skip to content

Commit f4d8223

Browse files
ojimba01pwolanin
andauthored
Use Google form for Feedback (#279)
* Create Vue feedback form to replace jot form and keep the user in app Send data to a google form via POST --------- Co-authored-by: pwolanin <107691+pwolanin@users.noreply.github.com>
1 parent 0c5b04c commit f4d8223

6 files changed

Lines changed: 216 additions & 51 deletions

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@
9494
"expect",
9595
"jest",
9696
"test",
97-
"beforeEach"
97+
"beforeEach",
98+
"FormData"
9899
]
99100
}
100101
}

src/components/ask-detail.vue

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
<template>
2-
<a :href="href">{{ label }}</a>
2+
<router-link :to="feedbackLink">{{ label }}</router-link>
33
</template>
44

55
<script>
6-
import qs from 'query-string'
7-
8-
const FEEDBACK_URL = 'http://form.jotform.us/form/50926595605160'
96
107
export default {
118
props: {
12-
fullName: { type: String },
9+
thePage: { type: String },
1310
detail: { type: String },
14-
label: { type: String, default: 'Know it?' }
11+
label: { type: String, default: 'Know it?' },
12+
defaultValue: { type: String, default: '' }
1513
},
1614
computed: {
17-
href () {
15+
feedbackLink () {
1816
const opts = {
19-
thePage: this.fullName,
20-
whatHappened: 'I found a content or data error'
17+
thePage: this.thePage,
18+
defaultValue: this.defaultValue
2119
}
2220
if (this.detail) {
23-
opts.tellUs = `${this.detail} should be: `
21+
opts.selectedOption = 'what-error'
22+
opts.defaultValue = `${this.detail} should be: `
23+
}
24+
return {
25+
name: 'feedback',
26+
query: opts
2427
}
25-
const query = qs.stringify(opts)
26-
return `${FEEDBACK_URL}?${query}`
2728
}
2829
}
2930
}
3031
</script>
32+
33+
34+

src/components/nav-bar.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
<router-link to="/about" class="navbar-item">
3131
About
3232
</router-link>
33-
<a class="navbar-item" href="https://form.jotform.us/form/50926595605160">
33+
<router-link to="/feedback" class="navbar-item">
3434
Feedback
35-
</a>
35+
</router-link>
3636
</div>
3737
</div>
3838
</nav>

src/router/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import WardLeaderList from '../views/ward-leader-list.vue'
66
import WardLeader from '../views/ward-leader.vue'
77
import CityMap from '../views/city-map.vue'
88
import ContentPage from '../views/content-page.vue'
9+
import Feedback from '../views/feedback.vue'
910

1011
Vue.use(VueRouter)
1112

@@ -36,6 +37,11 @@ const routes = [
3637
name: 'city-map',
3738
component: CityMap
3839
},
40+
{
41+
path: '/feedback',
42+
name: 'feedback',
43+
component: Feedback
44+
},
3945
{
4046
path: '/:slug',
4147
name: 'content-page',

src/views/feedback.vue

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<template>
2+
<section class="hero is-info">
3+
<div class="container">
4+
<div class="box">
5+
<div class="hero-body">
6+
<div class="feedback">
7+
<h1 class="title">Feedback Form</h1>
8+
<h1>{{ msg }}</h1>
9+
<br>
10+
<form v-if="!submitted">
11+
<div class="radio-form">
12+
<div v-for="radio in radioList" :key="radio.id">
13+
<input :name="radio.id" required v-model="formData.selectedOption" type="radio" :id="radio.id"
14+
:value="radio.id" />
15+
<label :for="radio.id">{{ radio.label }}</label>
16+
</div>
17+
</div>
18+
<div class="form-text" v-if="formData.selectedOption === 'what-other'">
19+
<label for="otherText">Please specify</label>
20+
<input type="text" id="otherText" name="otherText" v-model="formData.otherText" size="40"/>
21+
</div>
22+
<br>
23+
<div class="form-text">
24+
<label for="tellUsAboutIt">Tell us about it <span aria-label="Required question">*</span></label>
25+
<textarea name="tellUsAboutIt" id="tellUsAboutIt" v-model="formData.tellUsAboutIt" cols="40"
26+
rows="4" required></textarea>
27+
</div>
28+
<div class="form-text">
29+
<label for="howDoYouKnow">How do you know</label>
30+
<textarea name="howDoYouKnow" id="howDoYouKnow" v-model="formData.howDoYouKnow" cols="40"
31+
rows="2" size="40"></textarea>
32+
</div>
33+
<div class="form-text">
34+
<label for="thePageWhereItHappened">The page where it happened</label>
35+
<input type="text" id="thePageWhereItHappened" name="thePageWhereItHappened"
36+
v-model="formData.thePageWhereItHappened" size="40"/>
37+
</div>
38+
<div class="form-text">
39+
<label for="yourEmail">Your email</label>
40+
<input type='text' id='yourEmail' name='yourEmail' v-model="formData.yourEmail" size="40"/>
41+
</div>
42+
<br>
43+
<div class="form-text">
44+
<button :disabled="noInput" class="button is-primary is-small" type="submit"
45+
@click.prevent="submitFormPost">Submit
46+
Feedback</button>
47+
</div>
48+
</form>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
</section>
54+
</template>
55+
56+
<script>
57+
import axios from 'axios'
58+
export default {
59+
name: 'Feedback',
60+
data () {
61+
return {
62+
submitted: false,
63+
msg: 'What happened?',
64+
radioList: [
65+
{ id: 'what-wrong', label: 'Something went wrong' },
66+
{ id: 'what-suggest', label: 'I have a suggestion' },
67+
{ id: 'what-error', label: 'I found a content or data error' },
68+
{ id: 'what-confused', label: 'Something is confusing' },
69+
{ id: 'what-nice', label: 'Nothing, I just want to say something nice' },
70+
{ id: 'what-other', label: 'Other' }
71+
],
72+
73+
formData: {
74+
selectedOption: 'what-suggest',
75+
otherText: '',
76+
tellUsAboutIt: '',
77+
howDoYouKnow: '',
78+
thePageWhereItHappened: '',
79+
yourEmail: ''
80+
}
81+
}
82+
},
83+
mounted () {
84+
if (this.$route.query.selectedOption) {
85+
this.formData.selectedOption = this.$route.query.selectedOption
86+
}
87+
if (this.$route.query.thePage) {
88+
this.formData.thePageWhereItHappened = this.$route.query.thePage
89+
}
90+
if (this.$route.query.defaultValue) {
91+
this.formData.tellUsAboutIt = this.$route.query.defaultValue
92+
}
93+
},
94+
computed: {
95+
formParams () {
96+
const selectedRadio = this.radioList.find(radio => radio.id === this.formData.selectedOption)
97+
const params = {
98+
submit: 'Submit',
99+
'entry.843445704': this.formData.tellUsAboutIt,
100+
'entry.584749072': this.formData.howDoYouKnow,
101+
'entry.1794541886': this.formData.thePageWhereItHappened,
102+
'entry.1040622557': this.formData.yourEmail,
103+
'entry.852279778': Date.now().toString()
104+
}
105+
106+
if (selectedRadio) {
107+
const entryId = 'entry.564578111'
108+
if (selectedRadio.id === 'what-other') {
109+
params[entryId] = '__other_option__'
110+
params[`${entryId}.other_option_response`] = this.formData.otherText
111+
} else {
112+
params[entryId] = selectedRadio.label
113+
}
114+
}
115+
return params
116+
},
117+
118+
noInput () {
119+
return this.formData.tellUsAboutIt.length === 0
120+
},
121+
formUrl () {
122+
return 'https://docs.google.com/forms/d/e/1FAIpQLSf5gGHLck-Uv6WayZjgEYysfLxe_xpPxB9jiB9qv7LWEpbjZg/formResponse'
123+
}
124+
},
125+
methods: {
126+
submitFormPost () {
127+
const bodyFormData = new FormData()
128+
Object.entries(this.formParams).forEach(([key, value]) => {
129+
bodyFormData.append(key, value)
130+
})
131+
axios.post(this.formUrl, bodyFormData)
132+
.catch(function (error) {
133+
console.log(error)
134+
})
135+
this.submitted = true
136+
this.msg = 'Thank you for your feedback!'
137+
}
138+
}
139+
}
140+
</script>
141+
142+
<style scoped lang="sass">
143+
.hero.is-info
144+
display: flex
145+
justify-content: center
146+
align-items: center
147+
min-height: 100vh
148+
149+
.container
150+
max-width: 600px
151+
152+
.box
153+
background-color: rgba(255, 255, 255, 0.7)
154+
border-radius: 8px
155+
padding: 30px
156+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08)
157+
158+
.feedback
159+
width: 100%
160+
161+
.form-text label
162+
display: block
163+
margin-top: 5px
164+
165+
.button
166+
min-width: 250px
167+
margin-bottom: 15px
168+
169+
p
170+
margin-bottom: 15px
171+
172+
abbr
173+
border-bottom: dotted 1px #333
174+
cursor: help
175+
</style>

0 commit comments

Comments
 (0)