Skip to content

Commit

Permalink
Use Google form for Feedback (#279)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
ojimba01 and pwolanin authored Jan 17, 2024
1 parent 0c5b04c commit f4d8223
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 51 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
"expect",
"jest",
"test",
"beforeEach"
"beforeEach",
"FormData"
]
}
}
28 changes: 16 additions & 12 deletions src/components/ask-detail.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
<template>
<a :href="href">{{ label }}</a>
<router-link :to="feedbackLink">{{ label }}</router-link>
</template>

<script>
import qs from 'query-string'
const FEEDBACK_URL = 'http://form.jotform.us/form/50926595605160'
export default {
props: {
fullName: { type: String },
thePage: { type: String },
detail: { type: String },
label: { type: String, default: 'Know it?' }
label: { type: String, default: 'Know it?' },
defaultValue: { type: String, default: '' }
},
computed: {
href () {
feedbackLink () {
const opts = {
thePage: this.fullName,
whatHappened: 'I found a content or data error'
thePage: this.thePage,
defaultValue: this.defaultValue
}
if (this.detail) {
opts.tellUs = `${this.detail} should be: `
opts.selectedOption = 'what-error'
opts.defaultValue = `${this.detail} should be: `
}
return {
name: 'feedback',
query: opts
}
const query = qs.stringify(opts)
return `${FEEDBACK_URL}?${query}`
}
}
}
</script>



4 changes: 2 additions & 2 deletions src/components/nav-bar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
<router-link to="/about" class="navbar-item">
About
</router-link>
<a class="navbar-item" href="https://form.jotform.us/form/50926595605160">
<router-link to="/feedback" class="navbar-item">
Feedback
</a>
</router-link>
</div>
</div>
</nav>
Expand Down
6 changes: 6 additions & 0 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import WardLeaderList from '../views/ward-leader-list.vue'
import WardLeader from '../views/ward-leader.vue'
import CityMap from '../views/city-map.vue'
import ContentPage from '../views/content-page.vue'
import Feedback from '../views/feedback.vue'

Vue.use(VueRouter)

Expand Down Expand Up @@ -36,6 +37,11 @@ const routes = [
name: 'city-map',
component: CityMap
},
{
path: '/feedback',
name: 'feedback',
component: Feedback
},
{
path: '/:slug',
name: 'content-page',
Expand Down
175 changes: 175 additions & 0 deletions src/views/feedback.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<template>
<section class="hero is-info">
<div class="container">
<div class="box">
<div class="hero-body">
<div class="feedback">
<h1 class="title">Feedback Form</h1>
<h1>{{ msg }}</h1>
<br>
<form v-if="!submitted">
<div class="radio-form">
<div v-for="radio in radioList" :key="radio.id">
<input :name="radio.id" required v-model="formData.selectedOption" type="radio" :id="radio.id"
:value="radio.id" />
<label :for="radio.id">{{ radio.label }}</label>
</div>
</div>
<div class="form-text" v-if="formData.selectedOption === 'what-other'">
<label for="otherText">Please specify</label>
<input type="text" id="otherText" name="otherText" v-model="formData.otherText" size="40"/>
</div>
<br>
<div class="form-text">
<label for="tellUsAboutIt">Tell us about it <span aria-label="Required question">*</span></label>
<textarea name="tellUsAboutIt" id="tellUsAboutIt" v-model="formData.tellUsAboutIt" cols="40"
rows="4" required></textarea>
</div>
<div class="form-text">
<label for="howDoYouKnow">How do you know</label>
<textarea name="howDoYouKnow" id="howDoYouKnow" v-model="formData.howDoYouKnow" cols="40"
rows="2" size="40"></textarea>
</div>
<div class="form-text">
<label for="thePageWhereItHappened">The page where it happened</label>
<input type="text" id="thePageWhereItHappened" name="thePageWhereItHappened"
v-model="formData.thePageWhereItHappened" size="40"/>
</div>
<div class="form-text">
<label for="yourEmail">Your email</label>
<input type='text' id='yourEmail' name='yourEmail' v-model="formData.yourEmail" size="40"/>
</div>
<br>
<div class="form-text">
<button :disabled="noInput" class="button is-primary is-small" type="submit"
@click.prevent="submitFormPost">Submit
Feedback</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</template>

<script>
import axios from 'axios'
export default {
name: 'Feedback',
data () {
return {
submitted: false,
msg: 'What happened?',
radioList: [
{ id: 'what-wrong', label: 'Something went wrong' },
{ id: 'what-suggest', label: 'I have a suggestion' },
{ id: 'what-error', label: 'I found a content or data error' },
{ id: 'what-confused', label: 'Something is confusing' },
{ id: 'what-nice', label: 'Nothing, I just want to say something nice' },
{ id: 'what-other', label: 'Other' }
],
formData: {
selectedOption: 'what-suggest',
otherText: '',
tellUsAboutIt: '',
howDoYouKnow: '',
thePageWhereItHappened: '',
yourEmail: ''
}
}
},
mounted () {
if (this.$route.query.selectedOption) {
this.formData.selectedOption = this.$route.query.selectedOption
}
if (this.$route.query.thePage) {
this.formData.thePageWhereItHappened = this.$route.query.thePage
}
if (this.$route.query.defaultValue) {
this.formData.tellUsAboutIt = this.$route.query.defaultValue
}
},
computed: {
formParams () {
const selectedRadio = this.radioList.find(radio => radio.id === this.formData.selectedOption)
const params = {
submit: 'Submit',
'entry.843445704': this.formData.tellUsAboutIt,
'entry.584749072': this.formData.howDoYouKnow,
'entry.1794541886': this.formData.thePageWhereItHappened,
'entry.1040622557': this.formData.yourEmail,
'entry.852279778': Date.now().toString()
}
if (selectedRadio) {
const entryId = 'entry.564578111'
if (selectedRadio.id === 'what-other') {
params[entryId] = '__other_option__'
params[`${entryId}.other_option_response`] = this.formData.otherText
} else {
params[entryId] = selectedRadio.label
}
}
return params
},
noInput () {
return this.formData.tellUsAboutIt.length === 0
},
formUrl () {
return 'https://docs.google.com/forms/d/e/1FAIpQLSf5gGHLck-Uv6WayZjgEYysfLxe_xpPxB9jiB9qv7LWEpbjZg/formResponse'
}
},
methods: {
submitFormPost () {
const bodyFormData = new FormData()
Object.entries(this.formParams).forEach(([key, value]) => {
bodyFormData.append(key, value)
})
axios.post(this.formUrl, bodyFormData)
.catch(function (error) {
console.log(error)
})
this.submitted = true
this.msg = 'Thank you for your feedback!'
}
}
}
</script>

<style scoped lang="sass">
.hero.is-info
display: flex
justify-content: center
align-items: center
min-height: 100vh
.container
max-width: 600px
.box
background-color: rgba(255, 255, 255, 0.7)
border-radius: 8px
padding: 30px
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08)
.feedback
width: 100%
.form-text label
display: block
margin-top: 5px
.button
min-width: 250px
margin-bottom: 15px
p
margin-bottom: 15px
abbr
border-bottom: dotted 1px #333
cursor: help
</style>
Loading

0 comments on commit f4d8223

Please sign in to comment.