Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve feedback widget #197

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1dc739e
First stab
stefano-ottolenghi Sep 20, 2023
8fed75f
.
stefano-ottolenghi Sep 20, 2023
aeca887
Move to left
stefano-ottolenghi Oct 6, 2023
2c155d3
Fix widget not expanding
stefano-ottolenghi Oct 6, 2023
d6292d8
Only lint browser wise
stefano-ottolenghi Oct 6, 2023
54e2f10
fix footer behavior
stefano-ottolenghi Oct 11, 2023
237d076
Merge branch 'neo4j-documentation:master' into feedback
stefano-ottolenghi Oct 16, 2023
79fda35
uncomment/comment stuff
stefano-ottolenghi Oct 16, 2023
713efdf
make x on helpful close widget
stefano-ottolenghi Oct 18, 2023
b099bcc
on x vanish immediately
stefano-ottolenghi Oct 19, 2023
0689e46
First stab
stefano-ottolenghi Sep 20, 2023
efe614e
.
stefano-ottolenghi Sep 20, 2023
85b01d2
Move to left
stefano-ottolenghi Oct 6, 2023
386151e
Fix widget not expanding
stefano-ottolenghi Oct 6, 2023
2709362
Only lint browser wise
stefano-ottolenghi Oct 6, 2023
58afec2
fix footer behavior
stefano-ottolenghi Oct 11, 2023
5e2fa3b
uncomment/comment stuff
stefano-ottolenghi Oct 16, 2023
015afeb
make x on helpful close widget
stefano-ottolenghi Oct 18, 2023
ae8be75
on x vanish immediately
stefano-ottolenghi Oct 19, 2023
837608f
Merge branch 'neo4j-documentation:master' into feedback
stefano-ottolenghi Oct 30, 2023
f43d91e
restore user journey
stefano-ottolenghi Nov 1, 2023
998890f
Merge branch 'feedback' of github.com:stefano-ottolenghi/docs-ui into…
stefano-ottolenghi Nov 1, 2023
679e3da
lint
stefano-ottolenghi Nov 1, 2023
71da77c
comments cleanup
stefano-ottolenghi Nov 2, 2023
2ad64ce
mixpanel
stefano-ottolenghi Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
"brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
"max-len": [1, 160, 2],
"spaced-comment": "off"
},
"env": {
"browser": true
}
}
15 changes: 12 additions & 3 deletions src/css/feedback.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.feedback {
position: fixed;
bottom: 0;
right: 2rem;
left: 1rem;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
background: var(--feedback-background-color);
color: var(--feedback-color);
padding: 0.5rem 1rem;
width: 320px;
width: calc(var(--nav-width) - 2rem);
font-size: 0.8rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
z-index: 1000;
Expand Down Expand Up @@ -74,6 +74,10 @@
font-size: 0.8rem;
}

.feedback div.more-information {
margin: 10px 0;
}

.feedback textarea {
border-radius: 0.25rem;
border: 1px solid var(--color-blue-300);
Expand Down Expand Up @@ -105,6 +109,7 @@
font-weight: 600;
margin-right: 0.5rem;
margin-bottom: 1rem;
cursor: pointer;
}

.feedback .primary:focus,
Expand Down Expand Up @@ -151,6 +156,10 @@
margin-bottom: 0.5rem;
}

.feedback .error {
font-size: 0.8rem;
}

@media all and (max-width: 1024px) {
.feedback {
position: relative;
Expand All @@ -159,7 +168,7 @@
max-width: var(--doc-max-width);
min-width: 0;
right: auto;
width: auto;
width: calc(var(--nav-width) - 2rem);
box-shadow: none;
margin-bottom: 2rem;
}
Expand Down
6 changes: 4 additions & 2 deletions src/css/vars.css
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,9 @@
--nav-panel-height: calc(var(--nav-height) - var(--drawer-height));
--nav-panel-height--desktop:
calc(
var(--nav-height--desktop) - var(--drawer-height)
);
var(--nav-height--desktop) - var(--drawer-height) - var(--feedback-height) - 1rem
); /* 1rem is feedback padding */

--nav-width: 18rem;
--toc-top: calc(var(--body-top) + var(--toolbar-height));
--kb-metadata-top: calc(var(--body-top) + var(--toolbar-height));
Expand All @@ -392,6 +393,7 @@
--doc-max-width: calc(720 / var(--rem-base) * 1rem);
--doc-max-width--desktop: calc(980 / var(--rem-base) * 1rem);
--cheat-sheet-max-width--desktop: calc(1100 / var(--rem-base) * 1rem);
--feedback-height: 2.75rem;

/* stacking */
--z-index-nav: 1;
Expand Down
180 changes: 128 additions & 52 deletions src/js/11-feedback.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
const { getCookie } = require('./modules/cookies')
const URL = 'https://uglfznxroe.execute-api.us-east-1.amazonaws.com/dev/Feedback'

/* global fetch */
;(function () {
'use strict'

var url = 'https://uglfznxroe.execute-api.us-east-1.amazonaws.com/dev/Feedback'
const updateUserJourney = function () {
var journey = JSON.parse(localStorage.getItem('userJourney'))
if (journey == null) journey = []
journey.push({
url: window.location.href,
title: document.title,
landTime: Math.round(Date.now() / 1000),
})
localStorage.setItem('userJourney', JSON.stringify(journey))
}
updateUserJourney()

var feedback = document.querySelector('.feedback')
if (!feedback) return

var original = feedback.innerHTML

var edit = ''
var editLink = document.querySelector('.edit-this-page a')
/*var editLink = document.querySelector('.edit-this-page a')

if (editLink) {
edit = ' <a href="' + editLink.getAttribute('href') + '" target="_blank">Edit this page</a>'
}
}*/

var sendFeedback = function (helpful, reason, moreInformation) {
var sendRequest = function (parameters) {
const identity = getCookie('neo_identity')
const gid = getCookie('_gid')
const uetsid = getCookie('_uetsid')
Expand All @@ -30,7 +42,6 @@ const { getCookie } = require('./modules/cookies')

var body = 'project=' + encodeURIComponent(project)
body += '&url=' + encodeURIComponent(window.location.href)
body += '&helpful=' + helpful.toString()

if (identity) {
body += '&identity=' + identity
Expand All @@ -42,72 +53,125 @@ const { getCookie } = require('./modules/cookies')
body += '&uetsid=' + uetsid
}

if (!helpful) {
body += '&reason=' + encodeURIComponent(reason)
for (const [paramKey, paramVal] of Object.entries(parameters)) {
body += '&' + paramKey + '=' + encodeURIComponent(paramVal)
}

if (moreInformation) {
body += '&moreInformation=' + encodeURIComponent(moreInformation)
}
var userJourney = localStorage.getItem('userJourney')
if (JSON.parse(userJourney).length > 1) {
body += '&userJourney=' + encodeURIComponent(userJourney)
}

fetch(url, {
//console.log(body)
fetch(URL, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: body,
})
localStorage.removeItem('userJourney')
}

var isHelpful = function () {
sendFeedback(true)

feedback.classList.add('positive')
feedback.style.height = null
feedback.innerHTML = `<form class="form">
<div class="header">
<p><strong>Thank you! Would you like to share some feedback?</strong></p>
<svg width="14px" height="22px" viewBox="0 0 22 22" role="button" class="cancel" aria-label="Cancel Feedback">
<line x1="19.5833333" y1="0.416666667" x2="0.416666667" y2="19.5833333"></line>
<line x1="19.5833333" y1="19.5833333" x2="0.416666667" y2="0.416666667"></line>
</svg>
</div>
<div class="more-information">
<label for="more-information"><strong>More information</strong></label>
<textarea id="more-information" type="text" rows="3" cols="50" name="more-information" style="resize:none"></textarea>
</div>
<div class="buttons">
<input type="button" class="primary" data-submit="submit" value="Submit feedback">
<!--<input type="button" class="secondary" data-submit="skip" value="Skip">-->
</div>
</form>
`

feedback.querySelector('.cancel').addEventListener('click', function (e) {
e.preventDefault()
sendRequest({ helpful: true }) // get positive feedback even if thet bail out before completion
setTimeout(() => { fadeOut(feedback, 50) }, 0)

if (window.mixpanel) {
window.mixpanel.track('DOCS_FEEDBACK_POSITIVE', {
pathname: window.location.origin + window.location.pathname,
search: window.location.search,
hash: window.location.hash,
})
}
})

feedback.querySelector('.primary').addEventListener('click', function (e) {
e.preventDefault()

var moreInformation = feedback.querySelector('textarea[name="more-information"]').value

sendRequest({
helpful: true,
moreInformation: moreInformation,
})
feedback.innerHTML = '<div class="header thank-you-positive"><p><strong>Thank you for your feedback!</strong></p></div>'
setTimeout(() => { fadeOut(feedback, 50) }, 2000)

feedback.innerHTML = '<div class="header thank-you-positive"><p><strong>Thank you for your feedback!</strong></p></div>'
if (window.mixpanel) {
window.mixpanel.track('DOCS_FEEDBACK_POSITIVE', {
pathname: window.location.origin + window.location.pathname,
search: window.location.search,
hash: window.location.hash,
})
}
})
}

var isUnhelpful = function () {
feedback.classList.add('negative')
feedback.style.height = null
feedback.innerHTML = `<form class="form">
<div class="header">
<p><strong>We&rsquo;re sorry to hear that. How could we improve this page?</strong></p>
<p><strong>How is this page unhelpful?</strong></p>
<svg width="14px" height="22px" viewBox="0 0 22 22" role="button" class="cancel" aria-label="Cancel Feedback">
<line x1="19.5833333" y1="0.416666667" x2="0.416666667" y2="19.5833333"></line>
<line x1="19.5833333" y1="19.5833333" x2="0.416666667" y2="0.416666667"></line>
</svg>
</div>
<div>
<input id="missing" type="radio" class="feedback-option" data-reason="missing" name="specific" value="missing" checked="true"><label
for="missing">It has missing information</label>
for="missing">Missing information</label>
</div>
<div>
<input id="hard-to-follow" type="radio" class="feedback-option" data-reason="hard-to-follow" name="specific" value="hard-to-follow">
<label for="hard-to-follow">It&rsquo;s hard to follow or confusing</label>
<label for="hard-to-follow">Hard to follow or confusing</label>
</div>
<div>
<input id="inaccurate" type="radio" class="feedback-option" data-reason="inaccurate" name="specific" value="inaccurate">
<label for="inaccurate">It&rsquo;s inaccurate, out of date, or doesn&rsquo;t work</label>
<label for="inaccurate">Inaccurate, out of date, or doesn&rsquo;t work</label>
</div>
<div><input id="other" type="radio" class="feedback-option" data-reason="other" name="specific" value="other"><label for="other">Something else
${edit}</label></div>
<div class="more-information"><label for="more-information"><strong>More information</strong></label><textarea
<div class="more-information"><label for="more-information"><strong>More information *</strong></label><textarea
id="more-information" type="text" rows="3" cols="50" name="more-information" style="resize:none"></textarea>
</div>
<div class="buttons"><input type="button" class="primary" data-submit="submit" value="Submit feedback"><input
type="button" class="secondary" data-submit="skip" value="Skip"></div>
<div class="buttons"><input type="button" class="primary" data-submit="submit" value="Submit feedback"></div>
</div>
</form>
`

var thankyou = `<div class="header thank-you-positive">
<p><strong>Thank you for your feedback!</strong></p>
<p>We will take this information into account while updating our documentation.</p>
<p><strong>Thank you!</strong></p>
<p>We will consider your feedback while updating our documentation.</p>
`

if (editLink) {
/*if (editLink) {
thankyou += '<p>You can also help us by ' + edit.replace('Edit', 'editing') + '.</p></div>'
}
}*/

feedback.querySelector('.cancel').addEventListener('click', function (e) {
e.preventDefault()
Expand All @@ -124,37 +188,35 @@ const { getCookie } = require('./modules/cookies')
})

feedback.querySelector('.primary').addEventListener('click', function (e) {
feedback.classList.remove('negative')
feedback.classList.add('positive')

e.preventDefault()

var reason = feedback.querySelector('input[name="specific"]:checked').value
var moreInformation = feedback.querySelector('textarea[name="more-information"]').value

sendFeedback(false, reason, moreInformation)
feedback.innerHTML = thankyou

if (window.mixpanel) {
window.mixpanel.track('DOCS_FEEDBACK_POSITIVE', {
pathname: window.location.origin + window.location.pathname,
search: window.location.search,
hash: window.location.hash,
})
// check more information not empty
var moreInformation = feedback.querySelector('textarea[name="more-information"]')
if (moreInformation.value === '') {
if (feedback.querySelector('p[class="error"]')) return //stubborn people
const error = document.createElement('p')
error.classList.add('error')
error.innerHTML = 'Please elaborate on your feedback.'
feedback.querySelector('div[class="more-information"]')
.insertAdjacentElement('afterend', error)
return
}
})

feedback.querySelector('.secondary').addEventListener('click', function (e) {
e.preventDefault()

var reason = feedback.querySelector('input[name="specific"]:checked').value
var moreInformation = feedback.querySelector('textarea[name="more-information"]').value
var reason = feedback.querySelector('input[name="specific"]:checked')

sendFeedback(false, reason, moreInformation)
sendRequest({
helpful: false,
reason: reason.value,
moreInformation: moreInformation.value,
})
feedback.innerHTML = thankyou

feedback.classList.remove('negative')
feedback.classList.add('positive')
setTimeout(() => { fadeOut(feedback, 50) }, 2000)

if (window.mixpanel) {
window.mixpanel.track('DOCS_FEEDBACK_SKIP', {
window.mixpanel.track('DOCS_FEEDBACK_POSITIVE', {
pathname: window.location.origin + window.location.pathname,
search: window.location.search,
hash: window.location.hash,
Expand All @@ -167,6 +229,7 @@ const { getCookie } = require('./modules/cookies')
feedback.classList.remove('negative')
feedback.classList.remove('positive')
feedback.innerHTML = original
feedback.style.height = 'var(--feedback-height)'

var yes = feedback.querySelector('.yes')
var no = feedback.querySelector('.no')
Expand All @@ -191,14 +254,27 @@ const { getCookie } = require('./modules/cookies')

if (position + windowHeight > footerOffset) {
feedback.classList.add('absolute')
feedback.style.top = (footerOffset - feedback.clientHeight) + 'px'
feedback.style.bottom = 'auto'
} else {
feedback.classList.remove('absolute')
feedback.style.top = 'auto'
feedback.style.bottom = '0px'
}
})

reset()
})()

function fadeOut (element, speed) {
var op = 1 // initial opacity
var timer = setInterval(function () {
if (op <= 0.1) {
clearInterval(timer)
element.style.display = 'none'
element.style.opacity = null
}
element.style.opacity = op
element.style.filter = 'alpha(opacity=' + op * 100 + ')'
op -= op * 0.1
}, speed)

// enlarge navigation to fill hole left by feedback widget faded out
document.documentElement.style.setProperty('--feedback-height', '0rem')
}
4 changes: 0 additions & 4 deletions src/partials/article.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,5 @@ If you typed the URL of this page manually, please double check that you entered
{{> comments}}
{{#if (eq page.layout 'training')}}
{{> training-help}}
{{else}}
{{#unless page.attributes.disablefeedback}}
{{> feedback}}
{{/unless}}
{{/if}}
</article>
Loading
Loading